From 7f985f06feb03a51c0fd13aa37f8d9c9facdd0bc Mon Sep 17 00:00:00 2001 From: Laurent Mignon Date: Mon, 27 Apr 2015 09:01:55 +0200 Subject: [PATCH] [ADD] new timeline widget --- README.rst | 7 + __init__.py | 1 + __openerp__.py | 15 + i18n/ar.po | 152 + i18n/bg.po | 152 + i18n/bn.po | 152 + i18n/bs.po | 152 + i18n/ca.po | 152 + i18n/cs.po | 152 + i18n/da.po | 154 + i18n/de.po | 152 + i18n/en_AU.po | 152 + i18n/en_GB.po | 152 + i18n/es.po | 152 + i18n/es_AR.po | 152 + i18n/es_CL.po | 152 + i18n/es_CR.po | 152 + i18n/es_DO.po | 152 + i18n/es_EC.po | 152 + i18n/es_MX.po | 152 + i18n/es_PE.po | 152 + i18n/et.po | 152 + i18n/eu.po | 152 + i18n/fa.po | 152 + i18n/fi.po | 152 + i18n/fr.po | 152 + i18n/fr_CA.po | 152 + i18n/gl.po | 152 + i18n/gu.po | 152 + i18n/hr.po | 153 + i18n/hu.po | 152 + i18n/id.po | 152 + i18n/it.po | 152 + i18n/ja.po | 152 + i18n/ka.po | 152 + i18n/ko.po | 152 + i18n/lt.po | 152 + i18n/mk.po | 152 + i18n/mn.po | 152 + i18n/nb.po | 152 + i18n/nl.po | 153 + i18n/nl_BE.po | 152 + i18n/pl.po | 152 + i18n/pt.po | 152 + i18n/pt_BR.po | 155 + i18n/ro.po | 152 + i18n/ru.po | 152 + i18n/sk.po | 152 + i18n/sl.po | 152 + i18n/sq.po | 152 + i18n/sr@latin.po | 152 + i18n/sv.po | 152 + i18n/th.po | 152 + i18n/tr.po | 152 + i18n/uk.po | 152 + i18n/web_calendar.pot | 151 + i18n/zh_CN.po | 152 + i18n/zh_TW.po | 152 + ir_view.py | 40 + static/lib/timeline/CHANGELOG | 199 + static/lib/timeline/LICENSE | 176 + static/lib/timeline/NOTICE | 14 + static/lib/timeline/README | 66 + static/lib/timeline/doc/default.css | 92 + static/lib/timeline/doc/img/structure_box.png | Bin 0 -> 17555 bytes static/lib/timeline/doc/img/structure_box.svg | 310 + static/lib/timeline/doc/img/structure_dot.png | Bin 0 -> 11252 bytes static/lib/timeline/doc/img/structure_dot.svg | 286 + .../lib/timeline/doc/img/structure_range.png | Bin 0 -> 19561 bytes .../lib/timeline/doc/img/structure_range.svg | 327 + static/lib/timeline/doc/index.html | 1696 ++ static/lib/timeline/doc/jsdoc/files.html | 234 + static/lib/timeline/doc/jsdoc/index.html | 282 + .../lib/timeline/doc/jsdoc/symbols/Array.html | 392 + .../timeline/doc/jsdoc/symbols/_global_.html | 325 + .../links.Timeline.ClusterGenerator.html | 570 + .../jsdoc/symbols/links.Timeline.Item.html | 1039 ++ .../jsdoc/symbols/links.Timeline.ItemBox.html | 895 + .../jsdoc/symbols/links.Timeline.ItemDot.html | 893 + .../links.Timeline.ItemFloatingRange.html | 906 + .../symbols/links.Timeline.ItemRange.html | 906 + .../symbols/links.Timeline.StepDate.html | 1016 ++ .../doc/jsdoc/symbols/links.Timeline.html | 5812 ++++++ .../doc/jsdoc/symbols/src/timeline.js.html | 7013 ++++++++ .../lib/timeline/doc/prettify/lang-apollo.js | 2 + static/lib/timeline/doc/prettify/lang-css.js | 2 + static/lib/timeline/doc/prettify/lang-hs.js | 2 + static/lib/timeline/doc/prettify/lang-lisp.js | 2 + static/lib/timeline/doc/prettify/lang-lua.js | 2 + static/lib/timeline/doc/prettify/lang-ml.js | 2 + .../lib/timeline/doc/prettify/lang-proto.js | 1 + .../lib/timeline/doc/prettify/lang-scala.js | 2 + static/lib/timeline/doc/prettify/lang-sql.js | 2 + static/lib/timeline/doc/prettify/lang-vb.js | 2 + static/lib/timeline/doc/prettify/lang-vhdl.js | 3 + static/lib/timeline/doc/prettify/lang-wiki.js | 2 + static/lib/timeline/doc/prettify/lang-yaml.js | 2 + static/lib/timeline/doc/prettify/prettify.css | 1 + static/lib/timeline/doc/prettify/prettify.js | 33 + static/lib/timeline/doc/sourcecode.html | 63 + static/lib/timeline/doc/timeline.png | Bin 0 -> 23229 bytes static/lib/timeline/doc/timeline120x60.png | Bin 0 -> 6671 bytes static/lib/timeline/examples/data.php | 51 + static/lib/timeline/examples/default.css | 87 + .../timeline/examples/example01_basis.html | 71 + .../examples/example02_interactive.html | 205 + .../examples/example03_performance.html | 125 + .../examples/example04_format_dot.html | 80 + .../example05_format_custom_html.html | 174 + .../examples/example06_format_custom_css.html | 138 + .../examples/example07_confirm_changes.html | 166 + .../timeline/examples/example08_calendar.html | 99 + .../timeline/examples/example09_editable.html | 196 + .../example10_link_two_timelines.html | 120 + .../examples/example11_datasource.html | 106 + .../examples/example12_millisecondscale.html | 72 + .../timeline/examples/example13_grouping.html | 144 + .../examples/example14_past_and_future.html | 91 + .../timeline/examples/example15_mobile.html | 201 + .../example16_performance_grouping.html | 159 + .../examples/example17_json_data.html | 103 + .../examples/example18_limit_range.html | 49 + .../examples/example19_bar_graph.html | 145 + .../example20_custom_class_names.html | 127 + .../example21_animate_visible_range.html | 117 + .../examples/example22_clustering.html | 106 + .../example24_individual_editable_events.html | 100 + .../examples/example25_new_item_type.html | 182 + .../examples/example26_localization.html | 93 + .../example27_jquery_themeroller.html | 110 + .../examples/example28_custom_controls.html | 120 + .../example29_stacking_with_grouping.html | 142 + .../examples/example30_floatingRange.html | 73 + .../img/Hardware-Mobile-Phone-icon.png | Bin 0 -> 3463 bytes .../timeline/examples/img/attachment-icon.png | Bin 0 -> 2774 bytes .../examples/img/blog-post-edit-icon.png | Bin 0 -> 4225 bytes .../timeline/examples/img/comments-icon.png | Bin 0 -> 3173 bytes .../examples/img/community-users-icon.png | Bin 0 -> 4664 bytes static/lib/timeline/examples/img/license.txt | 17 + .../examples/img/license_aesthetica-2.txt | 36 + .../examples/img/license_refresh-cl.txt | 26 + .../lib/timeline/examples/img/mail-icon.png | Bin 0 -> 3298 bytes .../timeline/examples/img/notes-edit-icon.png | Bin 0 -> 2913 bytes .../timeline/examples/img/product-icon.png | Bin 0 -> 1594 bytes .../lib/timeline/examples/img/truck-icon.png | Bin 0 -> 1703 bytes static/lib/timeline/examples/index.html | 41 + static/lib/timeline/img/16/delete.png | Bin 0 -> 665 bytes static/lib/timeline/img/16/moveleft.png | Bin 0 -> 553 bytes static/lib/timeline/img/16/moveright.png | Bin 0 -> 557 bytes static/lib/timeline/img/16/new.png | Bin 0 -> 593 bytes static/lib/timeline/img/16/zoomin.png | Bin 0 -> 441 bytes static/lib/timeline/img/16/zoomout.png | Bin 0 -> 361 bytes static/lib/timeline/img/24/delete.png | Bin 0 -> 944 bytes static/lib/timeline/img/24/moveleft.png | Bin 0 -> 679 bytes static/lib/timeline/img/24/moveright.png | Bin 0 -> 685 bytes static/lib/timeline/img/24/new.png | Bin 0 -> 667 bytes static/lib/timeline/img/24/zoomin.png | Bin 0 -> 454 bytes static/lib/timeline/img/24/zoomout.png | Bin 0 -> 367 bytes static/lib/timeline/img/32/delete.png | Bin 0 -> 725 bytes static/lib/timeline/img/32/moveleft.png | Bin 0 -> 590 bytes static/lib/timeline/img/32/moveright.png | Bin 0 -> 596 bytes static/lib/timeline/img/32/new.png | Bin 0 -> 250 bytes static/lib/timeline/img/32/zoomin.png | Bin 0 -> 235 bytes static/lib/timeline/img/32/zoomout.png | Bin 0 -> 233 bytes static/lib/timeline/img/cluster_bg.png | Bin 0 -> 209 bytes static/lib/timeline/img/deleteEvent.png | Bin 0 -> 473 bytes .../timeline/img/themeswitcher/buttonbg.png | Bin 0 -> 4176 bytes .../img/themeswitcher/icon_color_arrow.gif | Bin 0 -> 46 bytes .../img/themeswitcher/menuhoverbg.png | Bin 0 -> 546 bytes .../themeswitcher/theme_90_black_matte.png | Bin 0 -> 3309 bytes .../img/themeswitcher/theme_90_black_tie.png | Bin 0 -> 3623 bytes .../img/themeswitcher/theme_90_blitzer.png | Bin 0 -> 7533 bytes .../img/themeswitcher/theme_90_cupertino.png | Bin 0 -> 8530 bytes .../img/themeswitcher/theme_90_dark_hive.png | Bin 0 -> 10481 bytes .../img/themeswitcher/theme_90_dot_luv.png | Bin 0 -> 3166 bytes .../img/themeswitcher/theme_90_eggplant.png | Bin 0 -> 9041 bytes .../themeswitcher/theme_90_excite_bike.png | Bin 0 -> 3697 bytes .../img/themeswitcher/theme_90_flick.png | Bin 0 -> 6432 bytes .../img/themeswitcher/theme_90_hot_sneaks.png | Bin 0 -> 2961 bytes .../img/themeswitcher/theme_90_humanity.png | Bin 0 -> 3259 bytes .../img/themeswitcher/theme_90_le_frog.png | Bin 0 -> 9124 bytes .../img/themeswitcher/theme_90_mint_choco.png | Bin 0 -> 8620 bytes .../img/themeswitcher/theme_90_overcast.png | Bin 0 -> 7103 bytes .../themeswitcher/theme_90_pepper_grinder.png | Bin 0 -> 11553 bytes .../img/themeswitcher/theme_90_smoothness.png | Bin 0 -> 3417 bytes .../themeswitcher/theme_90_south_street.png | Bin 0 -> 8417 bytes .../img/themeswitcher/theme_90_start_menu.png | Bin 0 -> 3260 bytes .../img/themeswitcher/theme_90_sunny.png | Bin 0 -> 8581 bytes .../themeswitcher/theme_90_swanky_purse.png | Bin 0 -> 5367 bytes .../img/themeswitcher/theme_90_trontastic.png | Bin 0 -> 4191 bytes .../img/themeswitcher/theme_90_ui_dark.png | Bin 0 -> 8760 bytes .../img/themeswitcher/theme_90_ui_light.png | Bin 0 -> 5153 bytes .../img/themeswitcher/theme_90_windoze.png | Bin 0 -> 3370 bytes static/lib/timeline/lib/jquery-1.9.1.js | 9597 ++++++++++ static/lib/timeline/lib/jquery-ui.js | 14987 ++++++++++++++++ .../lib/timeline/lib/jquery.themeswitcher.js | 466 + static/lib/timeline/timeline-locales.js | 284 + static/lib/timeline/timeline-min.js | 218 + static/lib/timeline/timeline-theme.css | 157 + static/lib/timeline/timeline.css | 211 + static/lib/timeline/timeline.js | 7005 ++++++++ static/src/css/web_timeline.css | 0 static/src/js/web_timeline.js | 1429 ++ static/src/xml/web_timeline.xml | 74 + views/web_timeline.xml | 16 + 205 files changed, 70317 insertions(+) create mode 100755 README.rst create mode 100644 __init__.py create mode 100644 __openerp__.py create mode 100644 i18n/ar.po create mode 100644 i18n/bg.po create mode 100644 i18n/bn.po create mode 100644 i18n/bs.po create mode 100644 i18n/ca.po create mode 100644 i18n/cs.po create mode 100644 i18n/da.po create mode 100644 i18n/de.po create mode 100644 i18n/en_AU.po create mode 100644 i18n/en_GB.po create mode 100644 i18n/es.po create mode 100644 i18n/es_AR.po create mode 100644 i18n/es_CL.po create mode 100644 i18n/es_CR.po create mode 100644 i18n/es_DO.po create mode 100644 i18n/es_EC.po create mode 100644 i18n/es_MX.po create mode 100644 i18n/es_PE.po create mode 100644 i18n/et.po create mode 100644 i18n/eu.po create mode 100644 i18n/fa.po create mode 100644 i18n/fi.po create mode 100644 i18n/fr.po create mode 100644 i18n/fr_CA.po create mode 100644 i18n/gl.po create mode 100644 i18n/gu.po create mode 100644 i18n/hr.po create mode 100644 i18n/hu.po create mode 100644 i18n/id.po create mode 100644 i18n/it.po create mode 100644 i18n/ja.po create mode 100644 i18n/ka.po create mode 100644 i18n/ko.po create mode 100644 i18n/lt.po create mode 100644 i18n/mk.po create mode 100644 i18n/mn.po create mode 100644 i18n/nb.po create mode 100644 i18n/nl.po create mode 100644 i18n/nl_BE.po create mode 100644 i18n/pl.po create mode 100644 i18n/pt.po create mode 100644 i18n/pt_BR.po create mode 100644 i18n/ro.po create mode 100644 i18n/ru.po create mode 100644 i18n/sk.po create mode 100644 i18n/sl.po create mode 100644 i18n/sq.po create mode 100644 i18n/sr@latin.po create mode 100644 i18n/sv.po create mode 100644 i18n/th.po create mode 100644 i18n/tr.po create mode 100644 i18n/uk.po create mode 100644 i18n/web_calendar.pot create mode 100644 i18n/zh_CN.po create mode 100644 i18n/zh_TW.po create mode 100644 ir_view.py create mode 100644 static/lib/timeline/CHANGELOG create mode 100644 static/lib/timeline/LICENSE create mode 100644 static/lib/timeline/NOTICE create mode 100644 static/lib/timeline/README create mode 100644 static/lib/timeline/doc/default.css create mode 100644 static/lib/timeline/doc/img/structure_box.png create mode 100644 static/lib/timeline/doc/img/structure_box.svg create mode 100644 static/lib/timeline/doc/img/structure_dot.png create mode 100644 static/lib/timeline/doc/img/structure_dot.svg create mode 100644 static/lib/timeline/doc/img/structure_range.png create mode 100644 static/lib/timeline/doc/img/structure_range.svg create mode 100644 static/lib/timeline/doc/index.html create mode 100644 static/lib/timeline/doc/jsdoc/files.html create mode 100644 static/lib/timeline/doc/jsdoc/index.html create mode 100644 static/lib/timeline/doc/jsdoc/symbols/Array.html create mode 100644 static/lib/timeline/doc/jsdoc/symbols/_global_.html create mode 100644 static/lib/timeline/doc/jsdoc/symbols/links.Timeline.ClusterGenerator.html create mode 100644 static/lib/timeline/doc/jsdoc/symbols/links.Timeline.Item.html create mode 100644 static/lib/timeline/doc/jsdoc/symbols/links.Timeline.ItemBox.html create mode 100644 static/lib/timeline/doc/jsdoc/symbols/links.Timeline.ItemDot.html create mode 100644 static/lib/timeline/doc/jsdoc/symbols/links.Timeline.ItemFloatingRange.html create mode 100644 static/lib/timeline/doc/jsdoc/symbols/links.Timeline.ItemRange.html create mode 100644 static/lib/timeline/doc/jsdoc/symbols/links.Timeline.StepDate.html create mode 100644 static/lib/timeline/doc/jsdoc/symbols/links.Timeline.html create mode 100644 static/lib/timeline/doc/jsdoc/symbols/src/timeline.js.html create mode 100644 static/lib/timeline/doc/prettify/lang-apollo.js create mode 100644 static/lib/timeline/doc/prettify/lang-css.js create mode 100644 static/lib/timeline/doc/prettify/lang-hs.js create mode 100644 static/lib/timeline/doc/prettify/lang-lisp.js create mode 100644 static/lib/timeline/doc/prettify/lang-lua.js create mode 100644 static/lib/timeline/doc/prettify/lang-ml.js create mode 100644 static/lib/timeline/doc/prettify/lang-proto.js create mode 100644 static/lib/timeline/doc/prettify/lang-scala.js create mode 100644 static/lib/timeline/doc/prettify/lang-sql.js create mode 100644 static/lib/timeline/doc/prettify/lang-vb.js create mode 100644 static/lib/timeline/doc/prettify/lang-vhdl.js create mode 100644 static/lib/timeline/doc/prettify/lang-wiki.js create mode 100644 static/lib/timeline/doc/prettify/lang-yaml.js create mode 100644 static/lib/timeline/doc/prettify/prettify.css create mode 100644 static/lib/timeline/doc/prettify/prettify.js create mode 100644 static/lib/timeline/doc/sourcecode.html create mode 100644 static/lib/timeline/doc/timeline.png create mode 100644 static/lib/timeline/doc/timeline120x60.png create mode 100644 static/lib/timeline/examples/data.php create mode 100644 static/lib/timeline/examples/default.css create mode 100644 static/lib/timeline/examples/example01_basis.html create mode 100644 static/lib/timeline/examples/example02_interactive.html create mode 100644 static/lib/timeline/examples/example03_performance.html create mode 100755 static/lib/timeline/examples/example04_format_dot.html create mode 100755 static/lib/timeline/examples/example05_format_custom_html.html create mode 100644 static/lib/timeline/examples/example06_format_custom_css.html create mode 100644 static/lib/timeline/examples/example07_confirm_changes.html create mode 100644 static/lib/timeline/examples/example08_calendar.html create mode 100644 static/lib/timeline/examples/example09_editable.html create mode 100644 static/lib/timeline/examples/example10_link_two_timelines.html create mode 100644 static/lib/timeline/examples/example11_datasource.html create mode 100644 static/lib/timeline/examples/example12_millisecondscale.html create mode 100755 static/lib/timeline/examples/example13_grouping.html create mode 100644 static/lib/timeline/examples/example14_past_and_future.html create mode 100644 static/lib/timeline/examples/example15_mobile.html create mode 100644 static/lib/timeline/examples/example16_performance_grouping.html create mode 100644 static/lib/timeline/examples/example17_json_data.html create mode 100644 static/lib/timeline/examples/example18_limit_range.html create mode 100644 static/lib/timeline/examples/example19_bar_graph.html create mode 100755 static/lib/timeline/examples/example20_custom_class_names.html create mode 100644 static/lib/timeline/examples/example21_animate_visible_range.html create mode 100644 static/lib/timeline/examples/example22_clustering.html create mode 100644 static/lib/timeline/examples/example24_individual_editable_events.html create mode 100644 static/lib/timeline/examples/example25_new_item_type.html create mode 100644 static/lib/timeline/examples/example26_localization.html create mode 100644 static/lib/timeline/examples/example27_jquery_themeroller.html create mode 100644 static/lib/timeline/examples/example28_custom_controls.html create mode 100755 static/lib/timeline/examples/example29_stacking_with_grouping.html create mode 100644 static/lib/timeline/examples/example30_floatingRange.html create mode 100644 static/lib/timeline/examples/img/Hardware-Mobile-Phone-icon.png create mode 100755 static/lib/timeline/examples/img/attachment-icon.png create mode 100755 static/lib/timeline/examples/img/blog-post-edit-icon.png create mode 100755 static/lib/timeline/examples/img/comments-icon.png create mode 100755 static/lib/timeline/examples/img/community-users-icon.png create mode 100644 static/lib/timeline/examples/img/license.txt create mode 100644 static/lib/timeline/examples/img/license_aesthetica-2.txt create mode 100644 static/lib/timeline/examples/img/license_refresh-cl.txt create mode 100755 static/lib/timeline/examples/img/mail-icon.png create mode 100755 static/lib/timeline/examples/img/notes-edit-icon.png create mode 100644 static/lib/timeline/examples/img/product-icon.png create mode 100644 static/lib/timeline/examples/img/truck-icon.png create mode 100644 static/lib/timeline/examples/index.html create mode 100644 static/lib/timeline/img/16/delete.png create mode 100644 static/lib/timeline/img/16/moveleft.png create mode 100644 static/lib/timeline/img/16/moveright.png create mode 100644 static/lib/timeline/img/16/new.png create mode 100644 static/lib/timeline/img/16/zoomin.png create mode 100644 static/lib/timeline/img/16/zoomout.png create mode 100644 static/lib/timeline/img/24/delete.png create mode 100644 static/lib/timeline/img/24/moveleft.png create mode 100644 static/lib/timeline/img/24/moveright.png create mode 100644 static/lib/timeline/img/24/new.png create mode 100644 static/lib/timeline/img/24/zoomin.png create mode 100644 static/lib/timeline/img/24/zoomout.png create mode 100644 static/lib/timeline/img/32/delete.png create mode 100644 static/lib/timeline/img/32/moveleft.png create mode 100644 static/lib/timeline/img/32/moveright.png create mode 100644 static/lib/timeline/img/32/new.png create mode 100644 static/lib/timeline/img/32/zoomin.png create mode 100644 static/lib/timeline/img/32/zoomout.png create mode 100644 static/lib/timeline/img/cluster_bg.png create mode 100644 static/lib/timeline/img/deleteEvent.png create mode 100644 static/lib/timeline/img/themeswitcher/buttonbg.png create mode 100644 static/lib/timeline/img/themeswitcher/icon_color_arrow.gif create mode 100644 static/lib/timeline/img/themeswitcher/menuhoverbg.png create mode 100644 static/lib/timeline/img/themeswitcher/theme_90_black_matte.png create mode 100644 static/lib/timeline/img/themeswitcher/theme_90_black_tie.png create mode 100644 static/lib/timeline/img/themeswitcher/theme_90_blitzer.png create mode 100644 static/lib/timeline/img/themeswitcher/theme_90_cupertino.png create mode 100644 static/lib/timeline/img/themeswitcher/theme_90_dark_hive.png create mode 100644 static/lib/timeline/img/themeswitcher/theme_90_dot_luv.png create mode 100644 static/lib/timeline/img/themeswitcher/theme_90_eggplant.png create mode 100644 static/lib/timeline/img/themeswitcher/theme_90_excite_bike.png create mode 100644 static/lib/timeline/img/themeswitcher/theme_90_flick.png create mode 100644 static/lib/timeline/img/themeswitcher/theme_90_hot_sneaks.png create mode 100644 static/lib/timeline/img/themeswitcher/theme_90_humanity.png create mode 100644 static/lib/timeline/img/themeswitcher/theme_90_le_frog.png create mode 100644 static/lib/timeline/img/themeswitcher/theme_90_mint_choco.png create mode 100644 static/lib/timeline/img/themeswitcher/theme_90_overcast.png create mode 100644 static/lib/timeline/img/themeswitcher/theme_90_pepper_grinder.png create mode 100644 static/lib/timeline/img/themeswitcher/theme_90_smoothness.png create mode 100644 static/lib/timeline/img/themeswitcher/theme_90_south_street.png create mode 100644 static/lib/timeline/img/themeswitcher/theme_90_start_menu.png create mode 100644 static/lib/timeline/img/themeswitcher/theme_90_sunny.png create mode 100644 static/lib/timeline/img/themeswitcher/theme_90_swanky_purse.png create mode 100644 static/lib/timeline/img/themeswitcher/theme_90_trontastic.png create mode 100644 static/lib/timeline/img/themeswitcher/theme_90_ui_dark.png create mode 100644 static/lib/timeline/img/themeswitcher/theme_90_ui_light.png create mode 100644 static/lib/timeline/img/themeswitcher/theme_90_windoze.png create mode 100644 static/lib/timeline/lib/jquery-1.9.1.js create mode 100644 static/lib/timeline/lib/jquery-ui.js create mode 100644 static/lib/timeline/lib/jquery.themeswitcher.js create mode 100644 static/lib/timeline/timeline-locales.js create mode 100644 static/lib/timeline/timeline-min.js create mode 100755 static/lib/timeline/timeline-theme.css create mode 100644 static/lib/timeline/timeline.css create mode 100755 static/lib/timeline/timeline.js create mode 100644 static/src/css/web_timeline.css create mode 100644 static/src/js/web_timeline.js create mode 100644 static/src/xml/web_timeline.xml create mode 100644 views/web_timeline.xml diff --git a/README.rst b/README.rst new file mode 100755 index 00000000..18c63ad4 --- /dev/null +++ b/README.rst @@ -0,0 +1,7 @@ +Timeline Widget +=============== + +!Prototype! +Define a new widget displaying events in an interactive visualization chart. +The widget is based on the external library +http://almende.github.io/chap-links-library/timeline.html diff --git a/__init__.py b/__init__.py new file mode 100644 index 00000000..68f25f6b --- /dev/null +++ b/__init__.py @@ -0,0 +1 @@ +from . import ir_view diff --git a/__openerp__.py b/__openerp__.py new file mode 100644 index 00000000..b6e921ba --- /dev/null +++ b/__openerp__.py @@ -0,0 +1,15 @@ +{ + 'name': "Web timeline", + 'summary': """ + Interactive visualization chart to visualize events in time + """, + "version": "0.1", + "author": "ACSONE SA/NV", + "category": "Acsone", + "website": "http://acsone.eu", + 'depends': ['web'], + 'qweb': ['static/src/xml/timeline.xml'], + 'data': [ + 'views/web_timeline.xml', + ], +} diff --git a/i18n/ar.po b/i18n/ar.po new file mode 100644 index 00000000..8c4430df --- /dev/null +++ b/i18n/ar.po @@ -0,0 +1,152 @@ +# Arabic translation for openerp-web +# Copyright (c) 2014 Rosetta Contributors and Canonical Ltd 2014 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR , 2014. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2015-01-21 14:08+0000\n" +"PO-Revision-Date: 2014-08-14 16:14+0000\n" +"Last-Translator: FULL NAME \n" +"Language-Team: Arabic \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2015-01-22 08:55+0000\n" +"X-Generator: Launchpad (build 17306)\n" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1295 +#, python-format +msgid "Add" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:27 +#, python-format +msgid "All day" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:917 +#, python-format +msgid "Are you sure you want to delete this record ?" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:75 +#, python-format +msgid "Calendar" +msgstr "التقويم" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:131 +#, python-format +msgid "Calendar view has not defined 'date_start' attribute." +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:950 +#, python-format +msgid "Create" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:66 +#, python-format +msgid "Create event" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:955 +#, python-format +msgid "Create: " +msgstr "إنشاء: " + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1227 +#, python-format +msgid "Dataset for type '%s' is not defined." +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:32 +#, python-format +msgid "Day" +msgstr "اليوم" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:837 +#, python-format +msgid "Delete" +msgstr "حذف" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:838 +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:67 +#, python-format +msgid "Edit Event" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:60 +#, python-format +msgid "Event summary:" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1205 +#, python-format +msgid "Missing required fields %s" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:30 +#, python-format +msgid "Month" +msgstr "الشهر" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1347 +#, python-format +msgid "Open: " +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:29 +#, python-format +msgid "Today" +msgstr "اليوم" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:828 +#, python-format +msgid "View: %s" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:31 +#, python-format +msgid "Week" +msgstr "الأسبوع" diff --git a/i18n/bg.po b/i18n/bg.po new file mode 100644 index 00000000..5c7695df --- /dev/null +++ b/i18n/bg.po @@ -0,0 +1,152 @@ +# Bulgarian translation for openerp-web +# Copyright (c) 2014 Rosetta Contributors and Canonical Ltd 2014 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR , 2014. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2015-01-21 14:08+0000\n" +"PO-Revision-Date: 2014-08-14 16:14+0000\n" +"Last-Translator: FULL NAME \n" +"Language-Team: Bulgarian \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2015-01-22 08:55+0000\n" +"X-Generator: Launchpad (build 17306)\n" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1295 +#, python-format +msgid "Add" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:27 +#, python-format +msgid "All day" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:917 +#, python-format +msgid "Are you sure you want to delete this record ?" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:75 +#, python-format +msgid "Calendar" +msgstr "Календар" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:131 +#, python-format +msgid "Calendar view has not defined 'date_start' attribute." +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:950 +#, python-format +msgid "Create" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:66 +#, python-format +msgid "Create event" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:955 +#, python-format +msgid "Create: " +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1227 +#, python-format +msgid "Dataset for type '%s' is not defined." +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:32 +#, python-format +msgid "Day" +msgstr "Ден" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:837 +#, python-format +msgid "Delete" +msgstr "Изтриване" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:838 +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:67 +#, python-format +msgid "Edit Event" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:60 +#, python-format +msgid "Event summary:" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1205 +#, python-format +msgid "Missing required fields %s" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:30 +#, python-format +msgid "Month" +msgstr "Месец" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1347 +#, python-format +msgid "Open: " +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:29 +#, python-format +msgid "Today" +msgstr "Днес" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:828 +#, python-format +msgid "View: %s" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:31 +#, python-format +msgid "Week" +msgstr "Седмица" diff --git a/i18n/bn.po b/i18n/bn.po new file mode 100644 index 00000000..d7b7a8ff --- /dev/null +++ b/i18n/bn.po @@ -0,0 +1,152 @@ +# Bengali translation for openerp-web +# Copyright (c) 2014 Rosetta Contributors and Canonical Ltd 2014 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR , 2014. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2015-01-21 14:08+0000\n" +"PO-Revision-Date: 2014-08-14 16:14+0000\n" +"Last-Translator: FULL NAME \n" +"Language-Team: Bengali \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2015-01-22 08:55+0000\n" +"X-Generator: Launchpad (build 17306)\n" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1295 +#, python-format +msgid "Add" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:27 +#, python-format +msgid "All day" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:917 +#, python-format +msgid "Are you sure you want to delete this record ?" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:75 +#, python-format +msgid "Calendar" +msgstr "পুঞ্জিকা" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:131 +#, python-format +msgid "Calendar view has not defined 'date_start' attribute." +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:950 +#, python-format +msgid "Create" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:66 +#, python-format +msgid "Create event" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:955 +#, python-format +msgid "Create: " +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1227 +#, python-format +msgid "Dataset for type '%s' is not defined." +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:32 +#, python-format +msgid "Day" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:837 +#, python-format +msgid "Delete" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:838 +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:67 +#, python-format +msgid "Edit Event" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:60 +#, python-format +msgid "Event summary:" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1205 +#, python-format +msgid "Missing required fields %s" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:30 +#, python-format +msgid "Month" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1347 +#, python-format +msgid "Open: " +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:29 +#, python-format +msgid "Today" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:828 +#, python-format +msgid "View: %s" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:31 +#, python-format +msgid "Week" +msgstr "" diff --git a/i18n/bs.po b/i18n/bs.po new file mode 100644 index 00000000..a9b4e20a --- /dev/null +++ b/i18n/bs.po @@ -0,0 +1,152 @@ +# Bosnian translation for openerp-web +# Copyright (c) 2014 Rosetta Contributors and Canonical Ltd 2014 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR , 2014. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2015-01-21 14:08+0000\n" +"PO-Revision-Date: 2014-08-14 16:14+0000\n" +"Last-Translator: FULL NAME \n" +"Language-Team: Bosnian \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2015-01-22 08:55+0000\n" +"X-Generator: Launchpad (build 17306)\n" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1295 +#, python-format +msgid "Add" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:27 +#, python-format +msgid "All day" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:917 +#, python-format +msgid "Are you sure you want to delete this record ?" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:75 +#, python-format +msgid "Calendar" +msgstr "Kalendar" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:131 +#, python-format +msgid "Calendar view has not defined 'date_start' attribute." +msgstr "Pogled kalendara nema definisan atribut 'date_start'." + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:950 +#, python-format +msgid "Create" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:66 +#, python-format +msgid "Create event" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:955 +#, python-format +msgid "Create: " +msgstr "Kreiraj: " + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1227 +#, python-format +msgid "Dataset for type '%s' is not defined." +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:32 +#, python-format +msgid "Day" +msgstr "Dan" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:837 +#, python-format +msgid "Delete" +msgstr "Obriši" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:838 +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:67 +#, python-format +msgid "Edit Event" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:60 +#, python-format +msgid "Event summary:" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1205 +#, python-format +msgid "Missing required fields %s" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:30 +#, python-format +msgid "Month" +msgstr "Mjesec" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1347 +#, python-format +msgid "Open: " +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:29 +#, python-format +msgid "Today" +msgstr "Danas" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:828 +#, python-format +msgid "View: %s" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:31 +#, python-format +msgid "Week" +msgstr "Sedmica" diff --git a/i18n/ca.po b/i18n/ca.po new file mode 100644 index 00000000..011da0ad --- /dev/null +++ b/i18n/ca.po @@ -0,0 +1,152 @@ +# Catalan translation for openerp-web +# Copyright (c) 2014 Rosetta Contributors and Canonical Ltd 2014 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR , 2014. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2015-01-21 14:08+0000\n" +"PO-Revision-Date: 2014-08-14 16:14+0000\n" +"Last-Translator: FULL NAME \n" +"Language-Team: Catalan \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2015-01-22 08:55+0000\n" +"X-Generator: Launchpad (build 17306)\n" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1295 +#, python-format +msgid "Add" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:27 +#, python-format +msgid "All day" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:917 +#, python-format +msgid "Are you sure you want to delete this record ?" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:75 +#, python-format +msgid "Calendar" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:131 +#, python-format +msgid "Calendar view has not defined 'date_start' attribute." +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:950 +#, python-format +msgid "Create" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:66 +#, python-format +msgid "Create event" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:955 +#, python-format +msgid "Create: " +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1227 +#, python-format +msgid "Dataset for type '%s' is not defined." +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:32 +#, python-format +msgid "Day" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:837 +#, python-format +msgid "Delete" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:838 +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:67 +#, python-format +msgid "Edit Event" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:60 +#, python-format +msgid "Event summary:" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1205 +#, python-format +msgid "Missing required fields %s" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:30 +#, python-format +msgid "Month" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1347 +#, python-format +msgid "Open: " +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:29 +#, python-format +msgid "Today" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:828 +#, python-format +msgid "View: %s" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:31 +#, python-format +msgid "Week" +msgstr "" diff --git a/i18n/cs.po b/i18n/cs.po new file mode 100644 index 00000000..937e3526 --- /dev/null +++ b/i18n/cs.po @@ -0,0 +1,152 @@ +# Czech translation for openerp-web +# Copyright (c) 2014 Rosetta Contributors and Canonical Ltd 2014 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR , 2014. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2015-01-21 14:08+0000\n" +"PO-Revision-Date: 2014-08-14 16:14+0000\n" +"Last-Translator: FULL NAME \n" +"Language-Team: Czech \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2015-01-22 08:55+0000\n" +"X-Generator: Launchpad (build 17306)\n" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1295 +#, python-format +msgid "Add" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:27 +#, python-format +msgid "All day" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:917 +#, python-format +msgid "Are you sure you want to delete this record ?" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:75 +#, python-format +msgid "Calendar" +msgstr "Kalendář" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:131 +#, python-format +msgid "Calendar view has not defined 'date_start' attribute." +msgstr "Pohled kalendáře nemá definovaný atribut 'date_start'." + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:950 +#, python-format +msgid "Create" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:66 +#, python-format +msgid "Create event" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:955 +#, python-format +msgid "Create: " +msgstr "Vytvořit: " + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1227 +#, python-format +msgid "Dataset for type '%s' is not defined." +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:32 +#, python-format +msgid "Day" +msgstr "Den" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:837 +#, python-format +msgid "Delete" +msgstr "Smazat" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:838 +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:67 +#, python-format +msgid "Edit Event" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:60 +#, python-format +msgid "Event summary:" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1205 +#, python-format +msgid "Missing required fields %s" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:30 +#, python-format +msgid "Month" +msgstr "Měsíc" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1347 +#, python-format +msgid "Open: " +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:29 +#, python-format +msgid "Today" +msgstr "Dnes" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:828 +#, python-format +msgid "View: %s" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:31 +#, python-format +msgid "Week" +msgstr "Týden" diff --git a/i18n/da.po b/i18n/da.po new file mode 100644 index 00000000..f7ff6b1d --- /dev/null +++ b/i18n/da.po @@ -0,0 +1,154 @@ +# Danish translation for openerp-web +# Copyright (c) 2014 Rosetta Contributors and Canonical Ltd 2014 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR , 2014. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2015-01-21 14:08+0000\n" +"PO-Revision-Date: 2014-08-14 16:14+0000\n" +"Last-Translator: FULL NAME \n" +"Language-Team: Danish \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2015-01-22 08:55+0000\n" +"X-Generator: Launchpad (build 17306)\n" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1295 +#, python-format +msgid "Add" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:27 +#, python-format +msgid "All day" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:917 +#, python-format +msgid "Are you sure you want to delete this record ?" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:75 +#, python-format +msgid "Calendar" +msgstr "Kalender" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:131 +#, python-format +msgid "Calendar view has not defined 'date_start' attribute." +msgstr "" +"Calendar view has not defined 'date_start' attribute.\r\n" +"Kalender visning har ikke en defineret 'date_start' attribut." + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:950 +#, python-format +msgid "Create" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:66 +#, python-format +msgid "Create event" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:955 +#, python-format +msgid "Create: " +msgstr "Opret: " + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1227 +#, python-format +msgid "Dataset for type '%s' is not defined." +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:32 +#, python-format +msgid "Day" +msgstr "Dag" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:837 +#, python-format +msgid "Delete" +msgstr "Slet" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:838 +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:67 +#, python-format +msgid "Edit Event" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:60 +#, python-format +msgid "Event summary:" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1205 +#, python-format +msgid "Missing required fields %s" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:30 +#, python-format +msgid "Month" +msgstr "Måned" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1347 +#, python-format +msgid "Open: " +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:29 +#, python-format +msgid "Today" +msgstr "I dag" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:828 +#, python-format +msgid "View: %s" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:31 +#, python-format +msgid "Week" +msgstr "Uge" diff --git a/i18n/de.po b/i18n/de.po new file mode 100644 index 00000000..94810497 --- /dev/null +++ b/i18n/de.po @@ -0,0 +1,152 @@ +# German translation for openerp-web +# Copyright (c) 2014 Rosetta Contributors and Canonical Ltd 2014 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR , 2014. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2015-01-21 14:08+0000\n" +"PO-Revision-Date: 2014-10-03 08:46+0000\n" +"Last-Translator: Ralf Hilgenstock \n" +"Language-Team: German \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2015-01-22 08:55+0000\n" +"X-Generator: Launchpad (build 17306)\n" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1295 +#, python-format +msgid "Add" +msgstr "Hinzufügen" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:27 +#, python-format +msgid "All day" +msgstr "Ganztägig" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:917 +#, python-format +msgid "Are you sure you want to delete this record ?" +msgstr "Wollen Sie diesen Datensatz wirklich löschen?" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:75 +#, python-format +msgid "Calendar" +msgstr "Kalender" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:131 +#, python-format +msgid "Calendar view has not defined 'date_start' attribute." +msgstr "Kalender Ansicht Start Datum fehlt" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:950 +#, python-format +msgid "Create" +msgstr "Erstellen" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:66 +#, python-format +msgid "Create event" +msgstr "Termin erstellen" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:955 +#, python-format +msgid "Create: " +msgstr "Erstelle: " + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1227 +#, python-format +msgid "Dataset for type '%s' is not defined." +msgstr "Datensatz für Typ '%s' ist noch nicht definiert" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:32 +#, python-format +msgid "Day" +msgstr "Tag" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:837 +#, python-format +msgid "Delete" +msgstr "Löschen" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:838 +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:67 +#, python-format +msgid "Edit Event" +msgstr "Termin bearbeiten" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:60 +#, python-format +msgid "Event summary:" +msgstr "Ereignis-Zusammenfassung:" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1205 +#, python-format +msgid "Missing required fields %s" +msgstr "Eintrag in Pflichtfeldern %s fehlen" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:30 +#, python-format +msgid "Month" +msgstr "Monat" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1347 +#, python-format +msgid "Open: " +msgstr "Öffnen " + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:29 +#, python-format +msgid "Today" +msgstr "Heute" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:828 +#, python-format +msgid "View: %s" +msgstr "Anzeigen: %s" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:31 +#, python-format +msgid "Week" +msgstr "Woche" diff --git a/i18n/en_AU.po b/i18n/en_AU.po new file mode 100644 index 00000000..3c873d42 --- /dev/null +++ b/i18n/en_AU.po @@ -0,0 +1,152 @@ +# English (Australia) translation for openerp-web +# Copyright (c) 2014 Rosetta Contributors and Canonical Ltd 2014 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR , 2014. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2015-01-21 14:08+0000\n" +"PO-Revision-Date: 2014-08-15 18:10+0000\n" +"Last-Translator: Lionel Page \n" +"Language-Team: English (Australia) \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2015-01-22 08:55+0000\n" +"X-Generator: Launchpad (build 17306)\n" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1295 +#, python-format +msgid "Add" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:27 +#, python-format +msgid "All day" +msgstr "All day" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:917 +#, python-format +msgid "Are you sure you want to delete this record ?" +msgstr "Are you sure you want to delete this record ?" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:75 +#, python-format +msgid "Calendar" +msgstr "Calendar" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:131 +#, python-format +msgid "Calendar view has not defined 'date_start' attribute." +msgstr "Calendar view has not defined the 'date_start' attribute." + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:950 +#, python-format +msgid "Create" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:66 +#, python-format +msgid "Create event" +msgstr "Create event" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:955 +#, python-format +msgid "Create: " +msgstr "Create: " + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1227 +#, python-format +msgid "Dataset for type '%s' is not defined." +msgstr "Dataset for type '%s' is not defined." + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:32 +#, python-format +msgid "Day" +msgstr "Day" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:837 +#, python-format +msgid "Delete" +msgstr "Delete" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:838 +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:67 +#, python-format +msgid "Edit Event" +msgstr "Edit Event" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:60 +#, python-format +msgid "Event summary:" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1205 +#, python-format +msgid "Missing required fields %s" +msgstr "Missing required fields %s" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:30 +#, python-format +msgid "Month" +msgstr "Month" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1347 +#, python-format +msgid "Open: " +msgstr "Open: " + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:29 +#, python-format +msgid "Today" +msgstr "Today" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:828 +#, python-format +msgid "View: %s" +msgstr "View: %s" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:31 +#, python-format +msgid "Week" +msgstr "Week" diff --git a/i18n/en_GB.po b/i18n/en_GB.po new file mode 100644 index 00000000..fa22f7ad --- /dev/null +++ b/i18n/en_GB.po @@ -0,0 +1,152 @@ +# English (United Kingdom) translation for openerp-web +# Copyright (c) 2014 Rosetta Contributors and Canonical Ltd 2014 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR , 2014. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2015-01-21 14:08+0000\n" +"PO-Revision-Date: 2014-10-05 02:54+0000\n" +"Last-Translator: Pedro Manuel Baeza \n" +"Language-Team: English (United Kingdom) \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2015-01-22 08:55+0000\n" +"X-Generator: Launchpad (build 17306)\n" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1295 +#, python-format +msgid "Add" +msgstr "Add" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:27 +#, python-format +msgid "All day" +msgstr "All day" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:917 +#, python-format +msgid "Are you sure you want to delete this record ?" +msgstr "Are you sure you want to delete this record ?" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:75 +#, python-format +msgid "Calendar" +msgstr "Calendar" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:131 +#, python-format +msgid "Calendar view has not defined 'date_start' attribute." +msgstr "Calendar view has not defined 'date_start' attribute." + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:950 +#, python-format +msgid "Create" +msgstr "Create" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:66 +#, python-format +msgid "Create event" +msgstr "Create event" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:955 +#, python-format +msgid "Create: " +msgstr "Create: " + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1227 +#, python-format +msgid "Dataset for type '%s' is not defined." +msgstr "Dataset for type '%s' is not defined." + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:32 +#, python-format +msgid "Day" +msgstr "Day" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:837 +#, python-format +msgid "Delete" +msgstr "Delete" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:838 +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:67 +#, python-format +msgid "Edit Event" +msgstr "Edit Event" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:60 +#, python-format +msgid "Event summary:" +msgstr "Event summary:" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1205 +#, python-format +msgid "Missing required fields %s" +msgstr "Missing required fields %s" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:30 +#, python-format +msgid "Month" +msgstr "Month" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1347 +#, python-format +msgid "Open: " +msgstr "Open: " + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:29 +#, python-format +msgid "Today" +msgstr "Today" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:828 +#, python-format +msgid "View: %s" +msgstr "View: %s" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:31 +#, python-format +msgid "Week" +msgstr "Week" diff --git a/i18n/es.po b/i18n/es.po new file mode 100644 index 00000000..1af45e6d --- /dev/null +++ b/i18n/es.po @@ -0,0 +1,152 @@ +# Spanish translation for openerp-web +# Copyright (c) 2014 Rosetta Contributors and Canonical Ltd 2014 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR , 2014. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2015-01-21 14:08+0000\n" +"PO-Revision-Date: 2014-09-24 20:59+0000\n" +"Last-Translator: Roberto Lizana (trey.es) \n" +"Language-Team: Spanish \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2015-01-22 08:55+0000\n" +"X-Generator: Launchpad (build 17306)\n" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1295 +#, python-format +msgid "Add" +msgstr "Añadir" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:27 +#, python-format +msgid "All day" +msgstr "Todo el día" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:917 +#, python-format +msgid "Are you sure you want to delete this record ?" +msgstr "¿Está seguro que quiere eliminar este registro?" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:75 +#, python-format +msgid "Calendar" +msgstr "Calendario" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:131 +#, python-format +msgid "Calendar view has not defined 'date_start' attribute." +msgstr "La vista calendario no tiene definido el atributo 'date_start'" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:950 +#, python-format +msgid "Create" +msgstr "Crear" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:66 +#, python-format +msgid "Create event" +msgstr "Crear evento" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:955 +#, python-format +msgid "Create: " +msgstr "Crear: " + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1227 +#, python-format +msgid "Dataset for type '%s' is not defined." +msgstr "El conjunto de datos para el tipo '%s' no está definido." + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:32 +#, python-format +msgid "Day" +msgstr "Día" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:837 +#, python-format +msgid "Delete" +msgstr "Suprimir" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:838 +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:67 +#, python-format +msgid "Edit Event" +msgstr "Editar evento" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:60 +#, python-format +msgid "Event summary:" +msgstr "Resumen del evento:" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1205 +#, python-format +msgid "Missing required fields %s" +msgstr "Campo requerido %s no presente" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:30 +#, python-format +msgid "Month" +msgstr "Mes" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1347 +#, python-format +msgid "Open: " +msgstr "Abrir: " + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:29 +#, python-format +msgid "Today" +msgstr "Hoy" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:828 +#, python-format +msgid "View: %s" +msgstr "Vista: %s" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:31 +#, python-format +msgid "Week" +msgstr "Semana" diff --git a/i18n/es_AR.po b/i18n/es_AR.po new file mode 100644 index 00000000..7f8f80bd --- /dev/null +++ b/i18n/es_AR.po @@ -0,0 +1,152 @@ +# Spanish (Argentina) translation for openerp-web +# Copyright (c) 2014 Rosetta Contributors and Canonical Ltd 2014 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR , 2014. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2015-01-21 14:08+0000\n" +"PO-Revision-Date: 2014-08-14 16:14+0000\n" +"Last-Translator: FULL NAME \n" +"Language-Team: Spanish (Argentina) \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2015-01-22 08:55+0000\n" +"X-Generator: Launchpad (build 17306)\n" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1295 +#, python-format +msgid "Add" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:27 +#, python-format +msgid "All day" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:917 +#, python-format +msgid "Are you sure you want to delete this record ?" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:75 +#, python-format +msgid "Calendar" +msgstr "Calendario" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:131 +#, python-format +msgid "Calendar view has not defined 'date_start' attribute." +msgstr "La vista calendario no tiene definido el atributo 'date_start'" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:950 +#, python-format +msgid "Create" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:66 +#, python-format +msgid "Create event" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:955 +#, python-format +msgid "Create: " +msgstr "Crear: " + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1227 +#, python-format +msgid "Dataset for type '%s' is not defined." +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:32 +#, python-format +msgid "Day" +msgstr "Día" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:837 +#, python-format +msgid "Delete" +msgstr "Suprimir" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:838 +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:67 +#, python-format +msgid "Edit Event" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:60 +#, python-format +msgid "Event summary:" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1205 +#, python-format +msgid "Missing required fields %s" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:30 +#, python-format +msgid "Month" +msgstr "Mes" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1347 +#, python-format +msgid "Open: " +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:29 +#, python-format +msgid "Today" +msgstr "Hoy" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:828 +#, python-format +msgid "View: %s" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:31 +#, python-format +msgid "Week" +msgstr "Semana" diff --git a/i18n/es_CL.po b/i18n/es_CL.po new file mode 100644 index 00000000..83454495 --- /dev/null +++ b/i18n/es_CL.po @@ -0,0 +1,152 @@ +# Spanish (Chile) translation for openerp-web +# Copyright (c) 2014 Rosetta Contributors and Canonical Ltd 2014 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR , 2014. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2015-01-21 14:08+0000\n" +"PO-Revision-Date: 2014-08-14 16:14+0000\n" +"Last-Translator: FULL NAME \n" +"Language-Team: Spanish (Chile) \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2015-01-22 08:55+0000\n" +"X-Generator: Launchpad (build 17306)\n" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1295 +#, python-format +msgid "Add" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:27 +#, python-format +msgid "All day" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:917 +#, python-format +msgid "Are you sure you want to delete this record ?" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:75 +#, python-format +msgid "Calendar" +msgstr "Calendario" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:131 +#, python-format +msgid "Calendar view has not defined 'date_start' attribute." +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:950 +#, python-format +msgid "Create" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:66 +#, python-format +msgid "Create event" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:955 +#, python-format +msgid "Create: " +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1227 +#, python-format +msgid "Dataset for type '%s' is not defined." +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:32 +#, python-format +msgid "Day" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:837 +#, python-format +msgid "Delete" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:838 +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:67 +#, python-format +msgid "Edit Event" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:60 +#, python-format +msgid "Event summary:" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1205 +#, python-format +msgid "Missing required fields %s" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:30 +#, python-format +msgid "Month" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1347 +#, python-format +msgid "Open: " +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:29 +#, python-format +msgid "Today" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:828 +#, python-format +msgid "View: %s" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:31 +#, python-format +msgid "Week" +msgstr "" diff --git a/i18n/es_CR.po b/i18n/es_CR.po new file mode 100644 index 00000000..3291d044 --- /dev/null +++ b/i18n/es_CR.po @@ -0,0 +1,152 @@ +# Spanish (Costa Rica) translation for openerp-web +# Copyright (c) 2014 Rosetta Contributors and Canonical Ltd 2014 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR , 2014. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2015-01-21 14:08+0000\n" +"PO-Revision-Date: 2014-08-14 16:14+0000\n" +"Last-Translator: FULL NAME \n" +"Language-Team: Spanish (Costa Rica) \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2015-01-22 08:55+0000\n" +"X-Generator: Launchpad (build 17306)\n" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1295 +#, python-format +msgid "Add" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:27 +#, python-format +msgid "All day" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:917 +#, python-format +msgid "Are you sure you want to delete this record ?" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:75 +#, python-format +msgid "Calendar" +msgstr "Calendario" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:131 +#, python-format +msgid "Calendar view has not defined 'date_start' attribute." +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:950 +#, python-format +msgid "Create" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:66 +#, python-format +msgid "Create event" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:955 +#, python-format +msgid "Create: " +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1227 +#, python-format +msgid "Dataset for type '%s' is not defined." +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:32 +#, python-format +msgid "Day" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:837 +#, python-format +msgid "Delete" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:838 +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:67 +#, python-format +msgid "Edit Event" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:60 +#, python-format +msgid "Event summary:" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1205 +#, python-format +msgid "Missing required fields %s" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:30 +#, python-format +msgid "Month" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1347 +#, python-format +msgid "Open: " +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:29 +#, python-format +msgid "Today" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:828 +#, python-format +msgid "View: %s" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:31 +#, python-format +msgid "Week" +msgstr "" diff --git a/i18n/es_DO.po b/i18n/es_DO.po new file mode 100644 index 00000000..f1944144 --- /dev/null +++ b/i18n/es_DO.po @@ -0,0 +1,152 @@ +# Spanish (Dominican Republic) translation for openerp-web +# Copyright (c) 2014 Rosetta Contributors and Canonical Ltd 2014 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR , 2014. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2015-01-21 14:08+0000\n" +"PO-Revision-Date: 2014-08-14 16:14+0000\n" +"Last-Translator: FULL NAME \n" +"Language-Team: Spanish (Dominican Republic) \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2015-01-22 08:55+0000\n" +"X-Generator: Launchpad (build 17306)\n" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1295 +#, python-format +msgid "Add" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:27 +#, python-format +msgid "All day" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:917 +#, python-format +msgid "Are you sure you want to delete this record ?" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:75 +#, python-format +msgid "Calendar" +msgstr "Calendario" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:131 +#, python-format +msgid "Calendar view has not defined 'date_start' attribute." +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:950 +#, python-format +msgid "Create" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:66 +#, python-format +msgid "Create event" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:955 +#, python-format +msgid "Create: " +msgstr "Crear: " + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1227 +#, python-format +msgid "Dataset for type '%s' is not defined." +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:32 +#, python-format +msgid "Day" +msgstr "Día" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:837 +#, python-format +msgid "Delete" +msgstr "Eliminar" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:838 +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:67 +#, python-format +msgid "Edit Event" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:60 +#, python-format +msgid "Event summary:" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1205 +#, python-format +msgid "Missing required fields %s" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:30 +#, python-format +msgid "Month" +msgstr "Mes" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1347 +#, python-format +msgid "Open: " +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:29 +#, python-format +msgid "Today" +msgstr "Hoy" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:828 +#, python-format +msgid "View: %s" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:31 +#, python-format +msgid "Week" +msgstr "Semana" diff --git a/i18n/es_EC.po b/i18n/es_EC.po new file mode 100644 index 00000000..48ab37d7 --- /dev/null +++ b/i18n/es_EC.po @@ -0,0 +1,152 @@ +# Spanish (Ecuador) translation for openerp-web +# Copyright (c) 2014 Rosetta Contributors and Canonical Ltd 2014 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR , 2014. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2015-01-21 14:08+0000\n" +"PO-Revision-Date: 2014-08-14 16:14+0000\n" +"Last-Translator: FULL NAME \n" +"Language-Team: Spanish (Ecuador) \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2015-01-22 08:55+0000\n" +"X-Generator: Launchpad (build 17306)\n" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1295 +#, python-format +msgid "Add" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:27 +#, python-format +msgid "All day" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:917 +#, python-format +msgid "Are you sure you want to delete this record ?" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:75 +#, python-format +msgid "Calendar" +msgstr "Calendario" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:131 +#, python-format +msgid "Calendar view has not defined 'date_start' attribute." +msgstr "La vista calendario no tiene definido el atributo 'date_start'" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:950 +#, python-format +msgid "Create" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:66 +#, python-format +msgid "Create event" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:955 +#, python-format +msgid "Create: " +msgstr "Crear: " + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1227 +#, python-format +msgid "Dataset for type '%s' is not defined." +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:32 +#, python-format +msgid "Day" +msgstr "Día" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:837 +#, python-format +msgid "Delete" +msgstr "Borrar" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:838 +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:67 +#, python-format +msgid "Edit Event" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:60 +#, python-format +msgid "Event summary:" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1205 +#, python-format +msgid "Missing required fields %s" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:30 +#, python-format +msgid "Month" +msgstr "Mes" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1347 +#, python-format +msgid "Open: " +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:29 +#, python-format +msgid "Today" +msgstr "Hoy" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:828 +#, python-format +msgid "View: %s" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:31 +#, python-format +msgid "Week" +msgstr "Semana" diff --git a/i18n/es_MX.po b/i18n/es_MX.po new file mode 100644 index 00000000..a5695ae6 --- /dev/null +++ b/i18n/es_MX.po @@ -0,0 +1,152 @@ +# Spanish (Mexico) translation for openerp-web +# Copyright (c) 2014 Rosetta Contributors and Canonical Ltd 2014 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR , 2014. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2015-01-21 14:08+0000\n" +"PO-Revision-Date: 2014-08-14 16:14+0000\n" +"Last-Translator: FULL NAME \n" +"Language-Team: Spanish (Mexico) \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2015-01-22 08:55+0000\n" +"X-Generator: Launchpad (build 17306)\n" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1295 +#, python-format +msgid "Add" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:27 +#, python-format +msgid "All day" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:917 +#, python-format +msgid "Are you sure you want to delete this record ?" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:75 +#, python-format +msgid "Calendar" +msgstr "Calendario" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:131 +#, python-format +msgid "Calendar view has not defined 'date_start' attribute." +msgstr "La vista de calendario no tiene definido el atributo 'fecha_inicio'" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:950 +#, python-format +msgid "Create" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:66 +#, python-format +msgid "Create event" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:955 +#, python-format +msgid "Create: " +msgstr "Crear: " + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1227 +#, python-format +msgid "Dataset for type '%s' is not defined." +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:32 +#, python-format +msgid "Day" +msgstr "Día" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:837 +#, python-format +msgid "Delete" +msgstr "Borrar" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:838 +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:67 +#, python-format +msgid "Edit Event" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:60 +#, python-format +msgid "Event summary:" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1205 +#, python-format +msgid "Missing required fields %s" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:30 +#, python-format +msgid "Month" +msgstr "Mes" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1347 +#, python-format +msgid "Open: " +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:29 +#, python-format +msgid "Today" +msgstr "Hoy" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:828 +#, python-format +msgid "View: %s" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:31 +#, python-format +msgid "Week" +msgstr "Semana" diff --git a/i18n/es_PE.po b/i18n/es_PE.po new file mode 100644 index 00000000..c5f2ab0a --- /dev/null +++ b/i18n/es_PE.po @@ -0,0 +1,152 @@ +# Spanish (Peru) translation for openerp-web +# Copyright (c) 2014 Rosetta Contributors and Canonical Ltd 2014 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR , 2014. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2015-01-21 14:08+0000\n" +"PO-Revision-Date: 2014-08-14 16:14+0000\n" +"Last-Translator: FULL NAME \n" +"Language-Team: Spanish (Peru) \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2015-01-22 08:55+0000\n" +"X-Generator: Launchpad (build 17306)\n" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1295 +#, python-format +msgid "Add" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:27 +#, python-format +msgid "All day" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:917 +#, python-format +msgid "Are you sure you want to delete this record ?" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:75 +#, python-format +msgid "Calendar" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:131 +#, python-format +msgid "Calendar view has not defined 'date_start' attribute." +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:950 +#, python-format +msgid "Create" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:66 +#, python-format +msgid "Create event" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:955 +#, python-format +msgid "Create: " +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1227 +#, python-format +msgid "Dataset for type '%s' is not defined." +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:32 +#, python-format +msgid "Day" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:837 +#, python-format +msgid "Delete" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:838 +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:67 +#, python-format +msgid "Edit Event" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:60 +#, python-format +msgid "Event summary:" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1205 +#, python-format +msgid "Missing required fields %s" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:30 +#, python-format +msgid "Month" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1347 +#, python-format +msgid "Open: " +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:29 +#, python-format +msgid "Today" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:828 +#, python-format +msgid "View: %s" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:31 +#, python-format +msgid "Week" +msgstr "" diff --git a/i18n/et.po b/i18n/et.po new file mode 100644 index 00000000..d017f36b --- /dev/null +++ b/i18n/et.po @@ -0,0 +1,152 @@ +# Estonian translation for openerp-web +# Copyright (c) 2014 Rosetta Contributors and Canonical Ltd 2014 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR , 2014. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2015-01-21 14:08+0000\n" +"PO-Revision-Date: 2014-08-14 16:14+0000\n" +"Last-Translator: FULL NAME \n" +"Language-Team: Estonian \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2015-01-22 08:55+0000\n" +"X-Generator: Launchpad (build 17306)\n" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1295 +#, python-format +msgid "Add" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:27 +#, python-format +msgid "All day" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:917 +#, python-format +msgid "Are you sure you want to delete this record ?" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:75 +#, python-format +msgid "Calendar" +msgstr "Kalender" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:131 +#, python-format +msgid "Calendar view has not defined 'date_start' attribute." +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:950 +#, python-format +msgid "Create" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:66 +#, python-format +msgid "Create event" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:955 +#, python-format +msgid "Create: " +msgstr "Loo: " + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1227 +#, python-format +msgid "Dataset for type '%s' is not defined." +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:32 +#, python-format +msgid "Day" +msgstr "Päev" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:837 +#, python-format +msgid "Delete" +msgstr "Kustuta" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:838 +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:67 +#, python-format +msgid "Edit Event" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:60 +#, python-format +msgid "Event summary:" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1205 +#, python-format +msgid "Missing required fields %s" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:30 +#, python-format +msgid "Month" +msgstr "Kuu" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1347 +#, python-format +msgid "Open: " +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:29 +#, python-format +msgid "Today" +msgstr "Täna" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:828 +#, python-format +msgid "View: %s" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:31 +#, python-format +msgid "Week" +msgstr "Nädal" diff --git a/i18n/eu.po b/i18n/eu.po new file mode 100644 index 00000000..0a64a7d9 --- /dev/null +++ b/i18n/eu.po @@ -0,0 +1,152 @@ +# Basque translation for openerp-web +# Copyright (c) 2014 Rosetta Contributors and Canonical Ltd 2014 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR , 2014. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2015-01-21 14:08+0000\n" +"PO-Revision-Date: 2014-08-14 16:14+0000\n" +"Last-Translator: FULL NAME \n" +"Language-Team: Basque \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2015-01-22 08:55+0000\n" +"X-Generator: Launchpad (build 17306)\n" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1295 +#, python-format +msgid "Add" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:27 +#, python-format +msgid "All day" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:917 +#, python-format +msgid "Are you sure you want to delete this record ?" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:75 +#, python-format +msgid "Calendar" +msgstr "Egutegia" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:131 +#, python-format +msgid "Calendar view has not defined 'date_start' attribute." +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:950 +#, python-format +msgid "Create" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:66 +#, python-format +msgid "Create event" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:955 +#, python-format +msgid "Create: " +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1227 +#, python-format +msgid "Dataset for type '%s' is not defined." +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:32 +#, python-format +msgid "Day" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:837 +#, python-format +msgid "Delete" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:838 +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:67 +#, python-format +msgid "Edit Event" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:60 +#, python-format +msgid "Event summary:" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1205 +#, python-format +msgid "Missing required fields %s" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:30 +#, python-format +msgid "Month" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1347 +#, python-format +msgid "Open: " +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:29 +#, python-format +msgid "Today" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:828 +#, python-format +msgid "View: %s" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:31 +#, python-format +msgid "Week" +msgstr "" diff --git a/i18n/fa.po b/i18n/fa.po new file mode 100644 index 00000000..1cf150fb --- /dev/null +++ b/i18n/fa.po @@ -0,0 +1,152 @@ +# Persian translation for openerp-web +# Copyright (c) 2014 Rosetta Contributors and Canonical Ltd 2014 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR , 2014. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2015-01-21 14:08+0000\n" +"PO-Revision-Date: 2014-08-14 16:14+0000\n" +"Last-Translator: FULL NAME \n" +"Language-Team: Persian \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2015-01-22 08:55+0000\n" +"X-Generator: Launchpad (build 17306)\n" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1295 +#, python-format +msgid "Add" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:27 +#, python-format +msgid "All day" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:917 +#, python-format +msgid "Are you sure you want to delete this record ?" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:75 +#, python-format +msgid "Calendar" +msgstr "تقویم" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:131 +#, python-format +msgid "Calendar view has not defined 'date_start' attribute." +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:950 +#, python-format +msgid "Create" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:66 +#, python-format +msgid "Create event" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:955 +#, python-format +msgid "Create: " +msgstr "ایجاد: " + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1227 +#, python-format +msgid "Dataset for type '%s' is not defined." +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:32 +#, python-format +msgid "Day" +msgstr "روز" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:837 +#, python-format +msgid "Delete" +msgstr "حذف" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:838 +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:67 +#, python-format +msgid "Edit Event" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:60 +#, python-format +msgid "Event summary:" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1205 +#, python-format +msgid "Missing required fields %s" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:30 +#, python-format +msgid "Month" +msgstr "ماه" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1347 +#, python-format +msgid "Open: " +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:29 +#, python-format +msgid "Today" +msgstr "امروز" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:828 +#, python-format +msgid "View: %s" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:31 +#, python-format +msgid "Week" +msgstr "هفته" diff --git a/i18n/fi.po b/i18n/fi.po new file mode 100644 index 00000000..80d8e535 --- /dev/null +++ b/i18n/fi.po @@ -0,0 +1,152 @@ +# Finnish translation for openerp-web +# Copyright (c) 2014 Rosetta Contributors and Canonical Ltd 2014 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR , 2014. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2015-01-21 14:08+0000\n" +"PO-Revision-Date: 2014-08-14 16:14+0000\n" +"Last-Translator: FULL NAME \n" +"Language-Team: Finnish \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2015-01-22 08:55+0000\n" +"X-Generator: Launchpad (build 17306)\n" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1295 +#, python-format +msgid "Add" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:27 +#, python-format +msgid "All day" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:917 +#, python-format +msgid "Are you sure you want to delete this record ?" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:75 +#, python-format +msgid "Calendar" +msgstr "kalenteri" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:131 +#, python-format +msgid "Calendar view has not defined 'date_start' attribute." +msgstr "Kalenterinäkymään ei ole määritelty aloituspäivää 'date_start'." + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:950 +#, python-format +msgid "Create" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:66 +#, python-format +msgid "Create event" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:955 +#, python-format +msgid "Create: " +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1227 +#, python-format +msgid "Dataset for type '%s' is not defined." +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:32 +#, python-format +msgid "Day" +msgstr "Päivä" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:837 +#, python-format +msgid "Delete" +msgstr "Poista" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:838 +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:67 +#, python-format +msgid "Edit Event" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:60 +#, python-format +msgid "Event summary:" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1205 +#, python-format +msgid "Missing required fields %s" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:30 +#, python-format +msgid "Month" +msgstr "Kuukausi" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1347 +#, python-format +msgid "Open: " +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:29 +#, python-format +msgid "Today" +msgstr "Tänään" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:828 +#, python-format +msgid "View: %s" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:31 +#, python-format +msgid "Week" +msgstr "Viikko" diff --git a/i18n/fr.po b/i18n/fr.po new file mode 100644 index 00000000..4a2a5f4f --- /dev/null +++ b/i18n/fr.po @@ -0,0 +1,152 @@ +# French translation for openerp-web +# Copyright (c) 2014 Rosetta Contributors and Canonical Ltd 2014 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR , 2014. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2015-01-21 14:08+0000\n" +"PO-Revision-Date: 2015-01-25 20:01+0000\n" +"Last-Translator: Jean-Marc Vandel \n" +"Language-Team: French \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2015-01-26 07:07+0000\n" +"X-Generator: Launchpad (build 17306)\n" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1295 +#, python-format +msgid "Add" +msgstr "Ajouter" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:27 +#, python-format +msgid "All day" +msgstr "Journée entière" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:917 +#, python-format +msgid "Are you sure you want to delete this record ?" +msgstr "Voulez-vous réellement supprimer cet enregistrement?" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:75 +#, python-format +msgid "Calendar" +msgstr "Calendrier" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:131 +#, python-format +msgid "Calendar view has not defined 'date_start' attribute." +msgstr "La vue calendrier n'a pas d'attribut 'date_start' défini" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:950 +#, python-format +msgid "Create" +msgstr "Créer" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:66 +#, python-format +msgid "Create event" +msgstr "Créer un événement" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:955 +#, python-format +msgid "Create: " +msgstr "Créer : " + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1227 +#, python-format +msgid "Dataset for type '%s' is not defined." +msgstr "L'ensemble de données pour le type '% s' n'est pas défini." + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:32 +#, python-format +msgid "Day" +msgstr "Jour" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:837 +#, python-format +msgid "Delete" +msgstr "Supprimer" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:838 +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:67 +#, python-format +msgid "Edit Event" +msgstr "Modifier l'événement" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:60 +#, python-format +msgid "Event summary:" +msgstr "Résumé de l’événement :" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1205 +#, python-format +msgid "Missing required fields %s" +msgstr "Champ obligatoire '%s' manquant" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:30 +#, python-format +msgid "Month" +msgstr "Mois" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1347 +#, python-format +msgid "Open: " +msgstr "Ouvrir : " + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:29 +#, python-format +msgid "Today" +msgstr "Aujourd'hui" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:828 +#, python-format +msgid "View: %s" +msgstr "Vue: %s" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:31 +#, python-format +msgid "Week" +msgstr "Semaine" diff --git a/i18n/fr_CA.po b/i18n/fr_CA.po new file mode 100644 index 00000000..4ac778a2 --- /dev/null +++ b/i18n/fr_CA.po @@ -0,0 +1,152 @@ +# French (Canada) translation for openerp-web +# Copyright (c) 2014 Rosetta Contributors and Canonical Ltd 2014 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR , 2014. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2015-01-21 14:08+0000\n" +"PO-Revision-Date: 2014-08-14 16:14+0000\n" +"Last-Translator: FULL NAME \n" +"Language-Team: French (Canada) \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2015-01-22 08:55+0000\n" +"X-Generator: Launchpad (build 17306)\n" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1295 +#, python-format +msgid "Add" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:27 +#, python-format +msgid "All day" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:917 +#, python-format +msgid "Are you sure you want to delete this record ?" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:75 +#, python-format +msgid "Calendar" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:131 +#, python-format +msgid "Calendar view has not defined 'date_start' attribute." +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:950 +#, python-format +msgid "Create" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:66 +#, python-format +msgid "Create event" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:955 +#, python-format +msgid "Create: " +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1227 +#, python-format +msgid "Dataset for type '%s' is not defined." +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:32 +#, python-format +msgid "Day" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:837 +#, python-format +msgid "Delete" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:838 +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:67 +#, python-format +msgid "Edit Event" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:60 +#, python-format +msgid "Event summary:" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1205 +#, python-format +msgid "Missing required fields %s" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:30 +#, python-format +msgid "Month" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1347 +#, python-format +msgid "Open: " +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:29 +#, python-format +msgid "Today" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:828 +#, python-format +msgid "View: %s" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:31 +#, python-format +msgid "Week" +msgstr "" diff --git a/i18n/gl.po b/i18n/gl.po new file mode 100644 index 00000000..dd1cace1 --- /dev/null +++ b/i18n/gl.po @@ -0,0 +1,152 @@ +# Galician translation for openerp-web +# Copyright (c) 2014 Rosetta Contributors and Canonical Ltd 2014 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR , 2014. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2015-01-21 14:08+0000\n" +"PO-Revision-Date: 2014-08-14 16:14+0000\n" +"Last-Translator: FULL NAME \n" +"Language-Team: Galician \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2015-01-22 08:55+0000\n" +"X-Generator: Launchpad (build 17306)\n" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1295 +#, python-format +msgid "Add" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:27 +#, python-format +msgid "All day" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:917 +#, python-format +msgid "Are you sure you want to delete this record ?" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:75 +#, python-format +msgid "Calendar" +msgstr "Calendario" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:131 +#, python-format +msgid "Calendar view has not defined 'date_start' attribute." +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:950 +#, python-format +msgid "Create" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:66 +#, python-format +msgid "Create event" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:955 +#, python-format +msgid "Create: " +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1227 +#, python-format +msgid "Dataset for type '%s' is not defined." +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:32 +#, python-format +msgid "Day" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:837 +#, python-format +msgid "Delete" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:838 +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:67 +#, python-format +msgid "Edit Event" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:60 +#, python-format +msgid "Event summary:" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1205 +#, python-format +msgid "Missing required fields %s" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:30 +#, python-format +msgid "Month" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1347 +#, python-format +msgid "Open: " +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:29 +#, python-format +msgid "Today" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:828 +#, python-format +msgid "View: %s" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:31 +#, python-format +msgid "Week" +msgstr "" diff --git a/i18n/gu.po b/i18n/gu.po new file mode 100644 index 00000000..974114c6 --- /dev/null +++ b/i18n/gu.po @@ -0,0 +1,152 @@ +# Gujarati translation for openerp-web +# Copyright (c) 2014 Rosetta Contributors and Canonical Ltd 2014 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR , 2014. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2015-01-21 14:08+0000\n" +"PO-Revision-Date: 2014-08-14 16:14+0000\n" +"Last-Translator: FULL NAME \n" +"Language-Team: Gujarati \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2015-01-22 08:55+0000\n" +"X-Generator: Launchpad (build 17306)\n" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1295 +#, python-format +msgid "Add" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:27 +#, python-format +msgid "All day" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:917 +#, python-format +msgid "Are you sure you want to delete this record ?" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:75 +#, python-format +msgid "Calendar" +msgstr "કૅલેન્ડર" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:131 +#, python-format +msgid "Calendar view has not defined 'date_start' attribute." +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:950 +#, python-format +msgid "Create" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:66 +#, python-format +msgid "Create event" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:955 +#, python-format +msgid "Create: " +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1227 +#, python-format +msgid "Dataset for type '%s' is not defined." +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:32 +#, python-format +msgid "Day" +msgstr "દિવસ" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:837 +#, python-format +msgid "Delete" +msgstr "કાઢી નાંખો" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:838 +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:67 +#, python-format +msgid "Edit Event" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:60 +#, python-format +msgid "Event summary:" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1205 +#, python-format +msgid "Missing required fields %s" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:30 +#, python-format +msgid "Month" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1347 +#, python-format +msgid "Open: " +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:29 +#, python-format +msgid "Today" +msgstr "આજે" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:828 +#, python-format +msgid "View: %s" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:31 +#, python-format +msgid "Week" +msgstr "" diff --git a/i18n/hr.po b/i18n/hr.po new file mode 100644 index 00000000..692eed4d --- /dev/null +++ b/i18n/hr.po @@ -0,0 +1,153 @@ +# Croatian translation for openerp-web +# Copyright (c) 2014 Rosetta Contributors and Canonical Ltd 2014 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR , 2014. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2015-01-21 14:08+0000\n" +"PO-Revision-Date: 2014-08-14 16:14+0000\n" +"Last-Translator: FULL NAME \n" +"Language-Team: Croatian \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2015-01-22 08:55+0000\n" +"X-Generator: Launchpad (build 17306)\n" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1295 +#, python-format +msgid "Add" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:27 +#, python-format +msgid "All day" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:917 +#, python-format +msgid "Are you sure you want to delete this record ?" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:75 +#, python-format +msgid "Calendar" +msgstr "Kalendar" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:131 +#, python-format +msgid "Calendar view has not defined 'date_start' attribute." +msgstr "" +"U pogledu tipa kalendar obavezno je polje 'date_start' - početno vrijeme." + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:950 +#, python-format +msgid "Create" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:66 +#, python-format +msgid "Create event" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:955 +#, python-format +msgid "Create: " +msgstr "Kreiraj: " + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1227 +#, python-format +msgid "Dataset for type '%s' is not defined." +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:32 +#, python-format +msgid "Day" +msgstr "Dan" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:837 +#, python-format +msgid "Delete" +msgstr "Obriši" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:838 +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:67 +#, python-format +msgid "Edit Event" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:60 +#, python-format +msgid "Event summary:" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1205 +#, python-format +msgid "Missing required fields %s" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:30 +#, python-format +msgid "Month" +msgstr "Mjesec" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1347 +#, python-format +msgid "Open: " +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:29 +#, python-format +msgid "Today" +msgstr "Danas" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:828 +#, python-format +msgid "View: %s" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:31 +#, python-format +msgid "Week" +msgstr "Tjedan" diff --git a/i18n/hu.po b/i18n/hu.po new file mode 100644 index 00000000..a6d86e6c --- /dev/null +++ b/i18n/hu.po @@ -0,0 +1,152 @@ +# Hungarian translation for openerp-web +# Copyright (c) 2014 Rosetta Contributors and Canonical Ltd 2014 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR , 2014. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2015-01-21 14:08+0000\n" +"PO-Revision-Date: 2014-10-05 07:27+0000\n" +"Last-Translator: krnkris \n" +"Language-Team: Hungarian \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2015-01-22 08:55+0000\n" +"X-Generator: Launchpad (build 17306)\n" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1295 +#, python-format +msgid "Add" +msgstr "Hozzáad" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:27 +#, python-format +msgid "All day" +msgstr "Egész nap" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:917 +#, python-format +msgid "Are you sure you want to delete this record ?" +msgstr "Biztosan törölni szeretné ezt a bejegyzést?" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:75 +#, python-format +msgid "Calendar" +msgstr "Naptár" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:131 +#, python-format +msgid "Calendar view has not defined 'date_start' attribute." +msgstr "Naptár nézetnek nincs definiálva 'induló_dátum' értéke" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:950 +#, python-format +msgid "Create" +msgstr "Létrehozás" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:66 +#, python-format +msgid "Create event" +msgstr "Esemény létrehozás" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:955 +#, python-format +msgid "Create: " +msgstr "Létrehoz: " + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1227 +#, python-format +msgid "Dataset for type '%s' is not defined." +msgstr "Nincs meghatározva adatsor a '%s' tipushoz." + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:32 +#, python-format +msgid "Day" +msgstr "Nap" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:837 +#, python-format +msgid "Delete" +msgstr "Törlés" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:838 +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:67 +#, python-format +msgid "Edit Event" +msgstr "Esemény szerkesztése" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:60 +#, python-format +msgid "Event summary:" +msgstr "Az esemény összegzése:" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1205 +#, python-format +msgid "Missing required fields %s" +msgstr "Hiányoznak a szükséges mezők %s" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:30 +#, python-format +msgid "Month" +msgstr "Hó" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1347 +#, python-format +msgid "Open: " +msgstr "Megnyitás: " + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:29 +#, python-format +msgid "Today" +msgstr "Ma" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:828 +#, python-format +msgid "View: %s" +msgstr "Nézet: %s" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:31 +#, python-format +msgid "Week" +msgstr "Hét" diff --git a/i18n/id.po b/i18n/id.po new file mode 100644 index 00000000..221a4f4a --- /dev/null +++ b/i18n/id.po @@ -0,0 +1,152 @@ +# Indonesian translation for openerp-web +# Copyright (c) 2014 Rosetta Contributors and Canonical Ltd 2014 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR , 2014. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2015-01-21 14:08+0000\n" +"PO-Revision-Date: 2014-08-14 16:14+0000\n" +"Last-Translator: FULL NAME \n" +"Language-Team: Indonesian \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2015-01-22 08:55+0000\n" +"X-Generator: Launchpad (build 17306)\n" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1295 +#, python-format +msgid "Add" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:27 +#, python-format +msgid "All day" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:917 +#, python-format +msgid "Are you sure you want to delete this record ?" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:75 +#, python-format +msgid "Calendar" +msgstr "Kalender" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:131 +#, python-format +msgid "Calendar view has not defined 'date_start' attribute." +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:950 +#, python-format +msgid "Create" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:66 +#, python-format +msgid "Create event" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:955 +#, python-format +msgid "Create: " +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1227 +#, python-format +msgid "Dataset for type '%s' is not defined." +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:32 +#, python-format +msgid "Day" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:837 +#, python-format +msgid "Delete" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:838 +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:67 +#, python-format +msgid "Edit Event" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:60 +#, python-format +msgid "Event summary:" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1205 +#, python-format +msgid "Missing required fields %s" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:30 +#, python-format +msgid "Month" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1347 +#, python-format +msgid "Open: " +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:29 +#, python-format +msgid "Today" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:828 +#, python-format +msgid "View: %s" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:31 +#, python-format +msgid "Week" +msgstr "" diff --git a/i18n/it.po b/i18n/it.po new file mode 100644 index 00000000..450d0402 --- /dev/null +++ b/i18n/it.po @@ -0,0 +1,152 @@ +# Italian translation for openerp-web +# Copyright (c) 2014 Rosetta Contributors and Canonical Ltd 2014 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR , 2014. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2015-01-21 14:08+0000\n" +"PO-Revision-Date: 2014-08-14 16:14+0000\n" +"Last-Translator: FULL NAME \n" +"Language-Team: Italian \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2015-01-22 08:55+0000\n" +"X-Generator: Launchpad (build 17306)\n" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1295 +#, python-format +msgid "Add" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:27 +#, python-format +msgid "All day" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:917 +#, python-format +msgid "Are you sure you want to delete this record ?" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:75 +#, python-format +msgid "Calendar" +msgstr "Calendario" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:131 +#, python-format +msgid "Calendar view has not defined 'date_start' attribute." +msgstr "La vista calendario non ha definito l'attributo 'data_start'" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:950 +#, python-format +msgid "Create" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:66 +#, python-format +msgid "Create event" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:955 +#, python-format +msgid "Create: " +msgstr "Crea: " + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1227 +#, python-format +msgid "Dataset for type '%s' is not defined." +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:32 +#, python-format +msgid "Day" +msgstr "Giorno" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:837 +#, python-format +msgid "Delete" +msgstr "Elimina" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:838 +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:67 +#, python-format +msgid "Edit Event" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:60 +#, python-format +msgid "Event summary:" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1205 +#, python-format +msgid "Missing required fields %s" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:30 +#, python-format +msgid "Month" +msgstr "Mese" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1347 +#, python-format +msgid "Open: " +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:29 +#, python-format +msgid "Today" +msgstr "Oggi" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:828 +#, python-format +msgid "View: %s" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:31 +#, python-format +msgid "Week" +msgstr "Settimana" diff --git a/i18n/ja.po b/i18n/ja.po new file mode 100644 index 00000000..10795f17 --- /dev/null +++ b/i18n/ja.po @@ -0,0 +1,152 @@ +# Japanese translation for openerp-web +# Copyright (c) 2014 Rosetta Contributors and Canonical Ltd 2014 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR , 2014. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2015-01-21 14:08+0000\n" +"PO-Revision-Date: 2014-08-14 16:14+0000\n" +"Last-Translator: FULL NAME \n" +"Language-Team: Japanese \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2015-01-22 08:55+0000\n" +"X-Generator: Launchpad (build 17306)\n" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1295 +#, python-format +msgid "Add" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:27 +#, python-format +msgid "All day" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:917 +#, python-format +msgid "Are you sure you want to delete this record ?" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:75 +#, python-format +msgid "Calendar" +msgstr "カレンダー" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:131 +#, python-format +msgid "Calendar view has not defined 'date_start' attribute." +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:950 +#, python-format +msgid "Create" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:66 +#, python-format +msgid "Create event" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:955 +#, python-format +msgid "Create: " +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1227 +#, python-format +msgid "Dataset for type '%s' is not defined." +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:32 +#, python-format +msgid "Day" +msgstr "日" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:837 +#, python-format +msgid "Delete" +msgstr "削除" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:838 +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:67 +#, python-format +msgid "Edit Event" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:60 +#, python-format +msgid "Event summary:" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1205 +#, python-format +msgid "Missing required fields %s" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:30 +#, python-format +msgid "Month" +msgstr "月" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1347 +#, python-format +msgid "Open: " +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:29 +#, python-format +msgid "Today" +msgstr "本日" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:828 +#, python-format +msgid "View: %s" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:31 +#, python-format +msgid "Week" +msgstr "週" diff --git a/i18n/ka.po b/i18n/ka.po new file mode 100644 index 00000000..59a05b32 --- /dev/null +++ b/i18n/ka.po @@ -0,0 +1,152 @@ +# Georgian translation for openerp-web +# Copyright (c) 2014 Rosetta Contributors and Canonical Ltd 2014 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR , 2014. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2015-01-21 14:08+0000\n" +"PO-Revision-Date: 2014-08-14 16:14+0000\n" +"Last-Translator: FULL NAME \n" +"Language-Team: Georgian \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2015-01-22 08:55+0000\n" +"X-Generator: Launchpad (build 17306)\n" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1295 +#, python-format +msgid "Add" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:27 +#, python-format +msgid "All day" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:917 +#, python-format +msgid "Are you sure you want to delete this record ?" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:75 +#, python-format +msgid "Calendar" +msgstr "კალენდარი" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:131 +#, python-format +msgid "Calendar view has not defined 'date_start' attribute." +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:950 +#, python-format +msgid "Create" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:66 +#, python-format +msgid "Create event" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:955 +#, python-format +msgid "Create: " +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1227 +#, python-format +msgid "Dataset for type '%s' is not defined." +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:32 +#, python-format +msgid "Day" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:837 +#, python-format +msgid "Delete" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:838 +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:67 +#, python-format +msgid "Edit Event" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:60 +#, python-format +msgid "Event summary:" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1205 +#, python-format +msgid "Missing required fields %s" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:30 +#, python-format +msgid "Month" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1347 +#, python-format +msgid "Open: " +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:29 +#, python-format +msgid "Today" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:828 +#, python-format +msgid "View: %s" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:31 +#, python-format +msgid "Week" +msgstr "" diff --git a/i18n/ko.po b/i18n/ko.po new file mode 100644 index 00000000..cec76123 --- /dev/null +++ b/i18n/ko.po @@ -0,0 +1,152 @@ +# Korean translation for openerp-web +# Copyright (c) 2014 Rosetta Contributors and Canonical Ltd 2014 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR , 2014. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2015-01-21 14:08+0000\n" +"PO-Revision-Date: 2014-08-14 16:14+0000\n" +"Last-Translator: FULL NAME \n" +"Language-Team: Korean \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2015-01-22 08:55+0000\n" +"X-Generator: Launchpad (build 17306)\n" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1295 +#, python-format +msgid "Add" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:27 +#, python-format +msgid "All day" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:917 +#, python-format +msgid "Are you sure you want to delete this record ?" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:75 +#, python-format +msgid "Calendar" +msgstr "달력" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:131 +#, python-format +msgid "Calendar view has not defined 'date_start' attribute." +msgstr "달력 화면이 'date_start' 속성을 정의하지 않았습니다." + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:950 +#, python-format +msgid "Create" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:66 +#, python-format +msgid "Create event" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:955 +#, python-format +msgid "Create: " +msgstr "생성: " + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1227 +#, python-format +msgid "Dataset for type '%s' is not defined." +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:32 +#, python-format +msgid "Day" +msgstr "일" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:837 +#, python-format +msgid "Delete" +msgstr "삭제" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:838 +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:67 +#, python-format +msgid "Edit Event" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:60 +#, python-format +msgid "Event summary:" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1205 +#, python-format +msgid "Missing required fields %s" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:30 +#, python-format +msgid "Month" +msgstr "월" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1347 +#, python-format +msgid "Open: " +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:29 +#, python-format +msgid "Today" +msgstr "오늘" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:828 +#, python-format +msgid "View: %s" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:31 +#, python-format +msgid "Week" +msgstr "주" diff --git a/i18n/lt.po b/i18n/lt.po new file mode 100644 index 00000000..9e30cc97 --- /dev/null +++ b/i18n/lt.po @@ -0,0 +1,152 @@ +# Lithuanian translation for openerp-web +# Copyright (c) 2014 Rosetta Contributors and Canonical Ltd 2014 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR , 2014. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2015-01-21 14:08+0000\n" +"PO-Revision-Date: 2014-08-14 16:14+0000\n" +"Last-Translator: FULL NAME \n" +"Language-Team: Lithuanian \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2015-01-22 08:55+0000\n" +"X-Generator: Launchpad (build 17306)\n" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1295 +#, python-format +msgid "Add" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:27 +#, python-format +msgid "All day" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:917 +#, python-format +msgid "Are you sure you want to delete this record ?" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:75 +#, python-format +msgid "Calendar" +msgstr "Kalendorius" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:131 +#, python-format +msgid "Calendar view has not defined 'date_start' attribute." +msgstr "Calendar view has not defined 'date_start' attribute." + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:950 +#, python-format +msgid "Create" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:66 +#, python-format +msgid "Create event" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:955 +#, python-format +msgid "Create: " +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1227 +#, python-format +msgid "Dataset for type '%s' is not defined." +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:32 +#, python-format +msgid "Day" +msgstr "Diena" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:837 +#, python-format +msgid "Delete" +msgstr "Trinti" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:838 +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:67 +#, python-format +msgid "Edit Event" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:60 +#, python-format +msgid "Event summary:" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1205 +#, python-format +msgid "Missing required fields %s" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:30 +#, python-format +msgid "Month" +msgstr "Mėnesis" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1347 +#, python-format +msgid "Open: " +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:29 +#, python-format +msgid "Today" +msgstr "Šiandien" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:828 +#, python-format +msgid "View: %s" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:31 +#, python-format +msgid "Week" +msgstr "Savaitė" diff --git a/i18n/mk.po b/i18n/mk.po new file mode 100644 index 00000000..cf0fcc1e --- /dev/null +++ b/i18n/mk.po @@ -0,0 +1,152 @@ +# Macedonian translation for openerp-web +# Copyright (c) 2014 Rosetta Contributors and Canonical Ltd 2014 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR , 2014. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2015-01-21 14:08+0000\n" +"PO-Revision-Date: 2014-08-14 16:14+0000\n" +"Last-Translator: FULL NAME \n" +"Language-Team: Macedonian \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2015-01-22 08:55+0000\n" +"X-Generator: Launchpad (build 17306)\n" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1295 +#, python-format +msgid "Add" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:27 +#, python-format +msgid "All day" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:917 +#, python-format +msgid "Are you sure you want to delete this record ?" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:75 +#, python-format +msgid "Calendar" +msgstr "Календар" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:131 +#, python-format +msgid "Calendar view has not defined 'date_start' attribute." +msgstr "Каленарскиот приказ нема дефинирано 'date_start' атрибут." + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:950 +#, python-format +msgid "Create" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:66 +#, python-format +msgid "Create event" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:955 +#, python-format +msgid "Create: " +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1227 +#, python-format +msgid "Dataset for type '%s' is not defined." +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:32 +#, python-format +msgid "Day" +msgstr "Ден" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:837 +#, python-format +msgid "Delete" +msgstr "Избриши" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:838 +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:67 +#, python-format +msgid "Edit Event" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:60 +#, python-format +msgid "Event summary:" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1205 +#, python-format +msgid "Missing required fields %s" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:30 +#, python-format +msgid "Month" +msgstr "Месец" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1347 +#, python-format +msgid "Open: " +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:29 +#, python-format +msgid "Today" +msgstr "Денес" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:828 +#, python-format +msgid "View: %s" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:31 +#, python-format +msgid "Week" +msgstr "Седмица" diff --git a/i18n/mn.po b/i18n/mn.po new file mode 100644 index 00000000..32a9ce39 --- /dev/null +++ b/i18n/mn.po @@ -0,0 +1,152 @@ +# Mongolian translation for openerp-web +# Copyright (c) 2014 Rosetta Contributors and Canonical Ltd 2014 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR , 2014. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2015-01-21 14:08+0000\n" +"PO-Revision-Date: 2014-08-14 16:14+0000\n" +"Last-Translator: FULL NAME \n" +"Language-Team: Mongolian \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2015-01-22 08:55+0000\n" +"X-Generator: Launchpad (build 17306)\n" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1295 +#, python-format +msgid "Add" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:27 +#, python-format +msgid "All day" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:917 +#, python-format +msgid "Are you sure you want to delete this record ?" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:75 +#, python-format +msgid "Calendar" +msgstr "Хуанли" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:131 +#, python-format +msgid "Calendar view has not defined 'date_start' attribute." +msgstr "Цагалбар харагдац нь 'date_start' аттрибютыг тодорхойлоогүй байна." + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:950 +#, python-format +msgid "Create" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:66 +#, python-format +msgid "Create event" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:955 +#, python-format +msgid "Create: " +msgstr "Үүсгэх: " + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1227 +#, python-format +msgid "Dataset for type '%s' is not defined." +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:32 +#, python-format +msgid "Day" +msgstr "Өдөр" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:837 +#, python-format +msgid "Delete" +msgstr "Устгах" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:838 +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:67 +#, python-format +msgid "Edit Event" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:60 +#, python-format +msgid "Event summary:" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1205 +#, python-format +msgid "Missing required fields %s" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:30 +#, python-format +msgid "Month" +msgstr "Сар" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1347 +#, python-format +msgid "Open: " +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:29 +#, python-format +msgid "Today" +msgstr "Өнөөдөр" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:828 +#, python-format +msgid "View: %s" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:31 +#, python-format +msgid "Week" +msgstr "7 хоног" diff --git a/i18n/nb.po b/i18n/nb.po new file mode 100644 index 00000000..85d0d4c3 --- /dev/null +++ b/i18n/nb.po @@ -0,0 +1,152 @@ +# Norwegian Bokmal translation for openerp-web +# Copyright (c) 2014 Rosetta Contributors and Canonical Ltd 2014 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR , 2014. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2015-01-21 14:08+0000\n" +"PO-Revision-Date: 2014-08-14 16:14+0000\n" +"Last-Translator: FULL NAME \n" +"Language-Team: Norwegian Bokmal \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2015-01-22 08:55+0000\n" +"X-Generator: Launchpad (build 17306)\n" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1295 +#, python-format +msgid "Add" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:27 +#, python-format +msgid "All day" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:917 +#, python-format +msgid "Are you sure you want to delete this record ?" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:75 +#, python-format +msgid "Calendar" +msgstr "Kalender" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:131 +#, python-format +msgid "Calendar view has not defined 'date_start' attribute." +msgstr "'date_start' attributt er ikke definert i kalendervisning." + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:950 +#, python-format +msgid "Create" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:66 +#, python-format +msgid "Create event" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:955 +#, python-format +msgid "Create: " +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1227 +#, python-format +msgid "Dataset for type '%s' is not defined." +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:32 +#, python-format +msgid "Day" +msgstr "Dag" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:837 +#, python-format +msgid "Delete" +msgstr "Slett" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:838 +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:67 +#, python-format +msgid "Edit Event" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:60 +#, python-format +msgid "Event summary:" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1205 +#, python-format +msgid "Missing required fields %s" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:30 +#, python-format +msgid "Month" +msgstr "Måned" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1347 +#, python-format +msgid "Open: " +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:29 +#, python-format +msgid "Today" +msgstr "I dag" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:828 +#, python-format +msgid "View: %s" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:31 +#, python-format +msgid "Week" +msgstr "Uke" diff --git a/i18n/nl.po b/i18n/nl.po new file mode 100644 index 00000000..146aa3ac --- /dev/null +++ b/i18n/nl.po @@ -0,0 +1,153 @@ +# Dutch translation for openerp-web +# Copyright (c) 2014 Rosetta Contributors and Canonical Ltd 2014 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR , 2014. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2015-01-21 14:08+0000\n" +"PO-Revision-Date: 2014-09-24 09:38+0000\n" +"Last-Translator: Erwin van der Ploeg (BAS Solutions) \n" +"Language-Team: Dutch \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2015-01-22 08:55+0000\n" +"X-Generator: Launchpad (build 17306)\n" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1295 +#, python-format +msgid "Add" +msgstr "Toevoegen" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:27 +#, python-format +msgid "All day" +msgstr "Hele dag" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:917 +#, python-format +msgid "Are you sure you want to delete this record ?" +msgstr "Weet u zeker dat u dit record wilt verwijderen?" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:75 +#, python-format +msgid "Calendar" +msgstr "Agenda" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:131 +#, python-format +msgid "Calendar view has not defined 'date_start' attribute." +msgstr "" +"Agenda weergave heeft een niet gedefinieerde 'date_start' eigenschap." + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:950 +#, python-format +msgid "Create" +msgstr "Aanmaken" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:66 +#, python-format +msgid "Create event" +msgstr "Maak gebeurtenis aan" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:955 +#, python-format +msgid "Create: " +msgstr "Maken: " + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1227 +#, python-format +msgid "Dataset for type '%s' is not defined." +msgstr "Dataset voor type '%s' is niet gedefinieerd." + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:32 +#, python-format +msgid "Day" +msgstr "Dag" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:837 +#, python-format +msgid "Delete" +msgstr "Verwijder" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:838 +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:67 +#, python-format +msgid "Edit Event" +msgstr "Gebeurtenis bewerken" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:60 +#, python-format +msgid "Event summary:" +msgstr "Afspraak samenvatting:" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1205 +#, python-format +msgid "Missing required fields %s" +msgstr "Vereiste velden %s ontbreken" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:30 +#, python-format +msgid "Month" +msgstr "Maand" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1347 +#, python-format +msgid "Open: " +msgstr "Open: " + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:29 +#, python-format +msgid "Today" +msgstr "Vandaag" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:828 +#, python-format +msgid "View: %s" +msgstr "Bekijk: %s" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:31 +#, python-format +msgid "Week" +msgstr "Week" diff --git a/i18n/nl_BE.po b/i18n/nl_BE.po new file mode 100644 index 00000000..67f24b6b --- /dev/null +++ b/i18n/nl_BE.po @@ -0,0 +1,152 @@ +# Dutch (Belgium) translation for openerp-web +# Copyright (c) 2014 Rosetta Contributors and Canonical Ltd 2014 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR , 2014. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2015-01-21 14:08+0000\n" +"PO-Revision-Date: 2014-08-14 16:14+0000\n" +"Last-Translator: FULL NAME \n" +"Language-Team: Dutch (Belgium) \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2015-01-22 08:55+0000\n" +"X-Generator: Launchpad (build 17306)\n" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1295 +#, python-format +msgid "Add" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:27 +#, python-format +msgid "All day" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:917 +#, python-format +msgid "Are you sure you want to delete this record ?" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:75 +#, python-format +msgid "Calendar" +msgstr "Kalender" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:131 +#, python-format +msgid "Calendar view has not defined 'date_start' attribute." +msgstr "Kalenderweergave heeft geen attribuut 'date_start'" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:950 +#, python-format +msgid "Create" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:66 +#, python-format +msgid "Create event" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:955 +#, python-format +msgid "Create: " +msgstr "Maken: " + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1227 +#, python-format +msgid "Dataset for type '%s' is not defined." +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:32 +#, python-format +msgid "Day" +msgstr "Dag" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:837 +#, python-format +msgid "Delete" +msgstr "Verwijderen" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:838 +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:67 +#, python-format +msgid "Edit Event" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:60 +#, python-format +msgid "Event summary:" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1205 +#, python-format +msgid "Missing required fields %s" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:30 +#, python-format +msgid "Month" +msgstr "Maand" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1347 +#, python-format +msgid "Open: " +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:29 +#, python-format +msgid "Today" +msgstr "Vandaag" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:828 +#, python-format +msgid "View: %s" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:31 +#, python-format +msgid "Week" +msgstr "Week" diff --git a/i18n/pl.po b/i18n/pl.po new file mode 100644 index 00000000..b6821b6e --- /dev/null +++ b/i18n/pl.po @@ -0,0 +1,152 @@ +# Polish translation for openerp-web +# Copyright (c) 2014 Rosetta Contributors and Canonical Ltd 2014 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR , 2014. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2015-01-21 14:08+0000\n" +"PO-Revision-Date: 2015-02-02 22:03+0000\n" +"Last-Translator: Dariusz Żbikowski (Krokus) \n" +"Language-Team: Polish \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2015-02-03 08:08+0000\n" +"X-Generator: Launchpad (build 17330)\n" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1295 +#, python-format +msgid "Add" +msgstr "Dodaj" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:27 +#, python-format +msgid "All day" +msgstr "Cały dzień" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:917 +#, python-format +msgid "Are you sure you want to delete this record ?" +msgstr "Jesteś pewien, że chcesz usunąć ten rekord?" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:75 +#, python-format +msgid "Calendar" +msgstr "Kalendarz" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:131 +#, python-format +msgid "Calendar view has not defined 'date_start' attribute." +msgstr "Widok kalendarza nie ma zdefiniowanego atrybutu 'date_start'." + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:950 +#, python-format +msgid "Create" +msgstr "Utwórz" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:66 +#, python-format +msgid "Create event" +msgstr "Utwórz zdarzenie" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:955 +#, python-format +msgid "Create: " +msgstr "Utwórz: " + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1227 +#, python-format +msgid "Dataset for type '%s' is not defined." +msgstr "Nie zdefiniowano Dataset dla typu '%s'." + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:32 +#, python-format +msgid "Day" +msgstr "Dzień" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:837 +#, python-format +msgid "Delete" +msgstr "Usuń" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:838 +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:67 +#, python-format +msgid "Edit Event" +msgstr "Edytuj zdarzenie" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:60 +#, python-format +msgid "Event summary:" +msgstr "Podsumowanie zdarzenia:" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1205 +#, python-format +msgid "Missing required fields %s" +msgstr "Brakuje wymaganych pól %s" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:30 +#, python-format +msgid "Month" +msgstr "Miesiąc" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1347 +#, python-format +msgid "Open: " +msgstr "Otwarte: " + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:29 +#, python-format +msgid "Today" +msgstr "Dzisiaj" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:828 +#, python-format +msgid "View: %s" +msgstr "Pokaż: %s" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:31 +#, python-format +msgid "Week" +msgstr "Tydzień" diff --git a/i18n/pt.po b/i18n/pt.po new file mode 100644 index 00000000..595753a1 --- /dev/null +++ b/i18n/pt.po @@ -0,0 +1,152 @@ +# Portuguese translation for openerp-web +# Copyright (c) 2014 Rosetta Contributors and Canonical Ltd 2014 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR , 2014. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2015-01-21 14:08+0000\n" +"PO-Revision-Date: 2014-09-16 13:51+0000\n" +"Last-Translator: Opencloud - PT \n" +"Language-Team: Portuguese \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2015-01-22 08:55+0000\n" +"X-Generator: Launchpad (build 17306)\n" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1295 +#, python-format +msgid "Add" +msgstr "Adicionar" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:27 +#, python-format +msgid "All day" +msgstr "Todo o dia" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:917 +#, python-format +msgid "Are you sure you want to delete this record ?" +msgstr "Tem certeza que quer remover este registo?" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:75 +#, python-format +msgid "Calendar" +msgstr "Calendário" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:131 +#, python-format +msgid "Calendar view has not defined 'date_start' attribute." +msgstr "A vista de calendário não tem definido o atributo 'date_start'." + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:950 +#, python-format +msgid "Create" +msgstr "Criar" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:66 +#, python-format +msgid "Create event" +msgstr "Criar evento" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:955 +#, python-format +msgid "Create: " +msgstr "Criar: " + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1227 +#, python-format +msgid "Dataset for type '%s' is not defined." +msgstr "Dados para o tipo '%s' não estão definidos." + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:32 +#, python-format +msgid "Day" +msgstr "Dia" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:837 +#, python-format +msgid "Delete" +msgstr "Apagar" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:838 +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:67 +#, python-format +msgid "Edit Event" +msgstr "Editar Evento" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:60 +#, python-format +msgid "Event summary:" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1205 +#, python-format +msgid "Missing required fields %s" +msgstr "Campos %s obrigatórios por preencher" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:30 +#, python-format +msgid "Month" +msgstr "Mês" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1347 +#, python-format +msgid "Open: " +msgstr "Abrir: " + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:29 +#, python-format +msgid "Today" +msgstr "Hoje" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:828 +#, python-format +msgid "View: %s" +msgstr "Vista: %s" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:31 +#, python-format +msgid "Week" +msgstr "Semana" diff --git a/i18n/pt_BR.po b/i18n/pt_BR.po new file mode 100644 index 00000000..c622b7c0 --- /dev/null +++ b/i18n/pt_BR.po @@ -0,0 +1,155 @@ +# Brazilian Portuguese translation for openerp-web +# Copyright (c) 2014 Rosetta Contributors and Canonical Ltd 2014 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR , 2014. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2015-01-21 14:08+0000\n" +"PO-Revision-Date: 2014-08-18 17:52+0000\n" +"Last-Translator: Fábio Martinelli - http://zupy.com.br " +"\n" +"Language-Team: Brazilian Portuguese \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2015-01-22 08:55+0000\n" +"X-Generator: Launchpad (build 17306)\n" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1295 +#, python-format +msgid "Add" +msgstr "Incluir" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:27 +#, python-format +msgid "All day" +msgstr "Dia inteiro" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:917 +#, python-format +msgid "Are you sure you want to delete this record ?" +msgstr "Você tem certeza que quer excluir este registro ?" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:75 +#, python-format +msgid "Calendar" +msgstr "Calendário" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:131 +#, python-format +msgid "Calendar view has not defined 'date_start' attribute." +msgstr "" +"Não está definido o atibuto 'date_start' Data de Início na visão de " +"Calendário" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:950 +#, python-format +msgid "Create" +msgstr "Criar" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:66 +#, python-format +msgid "Create event" +msgstr "Criar evento" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:955 +#, python-format +msgid "Create: " +msgstr "Criar: " + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1227 +#, python-format +msgid "Dataset for type '%s' is not defined." +msgstr "Não foi definido um conjunto de dados para o tipo '%s'" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:32 +#, python-format +msgid "Day" +msgstr "Dia" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:837 +#, python-format +msgid "Delete" +msgstr "Excluir" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:838 +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:67 +#, python-format +msgid "Edit Event" +msgstr "Editar evento" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:60 +#, python-format +msgid "Event summary:" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1205 +#, python-format +msgid "Missing required fields %s" +msgstr "o campo %s é obrigatório" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:30 +#, python-format +msgid "Month" +msgstr "Mês" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1347 +#, python-format +msgid "Open: " +msgstr "Aberto: " + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:29 +#, python-format +msgid "Today" +msgstr "Hoje" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:828 +#, python-format +msgid "View: %s" +msgstr "Visão: %s" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:31 +#, python-format +msgid "Week" +msgstr "Semana" diff --git a/i18n/ro.po b/i18n/ro.po new file mode 100644 index 00000000..20951acd --- /dev/null +++ b/i18n/ro.po @@ -0,0 +1,152 @@ +# Romanian translation for openerp-web +# Copyright (c) 2014 Rosetta Contributors and Canonical Ltd 2014 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR , 2014. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2015-01-21 14:08+0000\n" +"PO-Revision-Date: 2014-10-13 16:43+0000\n" +"Last-Translator: Dorin \n" +"Language-Team: Romanian \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2015-01-22 08:55+0000\n" +"X-Generator: Launchpad (build 17306)\n" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1295 +#, python-format +msgid "Add" +msgstr "Adăugați" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:27 +#, python-format +msgid "All day" +msgstr "Toată ziua" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:917 +#, python-format +msgid "Are you sure you want to delete this record ?" +msgstr "Sunteți sigur(ă) ca doriți să ștergeți această înregistrare?" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:75 +#, python-format +msgid "Calendar" +msgstr "Calendar" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:131 +#, python-format +msgid "Calendar view has not defined 'date_start' attribute." +msgstr "Vizualizarea Calendar nu a definit atributul 'data_inceput'." + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:950 +#, python-format +msgid "Create" +msgstr "Creați" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:66 +#, python-format +msgid "Create event" +msgstr "Creare eveniment" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:955 +#, python-format +msgid "Create: " +msgstr "Creează: " + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1227 +#, python-format +msgid "Dataset for type '%s' is not defined." +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:32 +#, python-format +msgid "Day" +msgstr "Ziua" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:837 +#, python-format +msgid "Delete" +msgstr "Ștergeți" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:838 +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:67 +#, python-format +msgid "Edit Event" +msgstr "Editare eveniment" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:60 +#, python-format +msgid "Event summary:" +msgstr "Subiect eveniment:" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1205 +#, python-format +msgid "Missing required fields %s" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:30 +#, python-format +msgid "Month" +msgstr "Luna" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1347 +#, python-format +msgid "Open: " +msgstr "Deschide: " + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:29 +#, python-format +msgid "Today" +msgstr "Astăzi" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:828 +#, python-format +msgid "View: %s" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:31 +#, python-format +msgid "Week" +msgstr "Săptămână" diff --git a/i18n/ru.po b/i18n/ru.po new file mode 100644 index 00000000..cca0cdeb --- /dev/null +++ b/i18n/ru.po @@ -0,0 +1,152 @@ +# Russian translation for openerp-web +# Copyright (c) 2014 Rosetta Contributors and Canonical Ltd 2014 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR , 2014. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2015-01-21 14:08+0000\n" +"PO-Revision-Date: 2014-08-14 16:14+0000\n" +"Last-Translator: FULL NAME \n" +"Language-Team: Russian \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2015-01-22 08:55+0000\n" +"X-Generator: Launchpad (build 17306)\n" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1295 +#, python-format +msgid "Add" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:27 +#, python-format +msgid "All day" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:917 +#, python-format +msgid "Are you sure you want to delete this record ?" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:75 +#, python-format +msgid "Calendar" +msgstr "Календарь" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:131 +#, python-format +msgid "Calendar view has not defined 'date_start' attribute." +msgstr "Вид календаря имеет не определенный 'date_start' аттрибут." + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:950 +#, python-format +msgid "Create" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:66 +#, python-format +msgid "Create event" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:955 +#, python-format +msgid "Create: " +msgstr "Создать: " + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1227 +#, python-format +msgid "Dataset for type '%s' is not defined." +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:32 +#, python-format +msgid "Day" +msgstr "День" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:837 +#, python-format +msgid "Delete" +msgstr "Удалить" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:838 +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:67 +#, python-format +msgid "Edit Event" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:60 +#, python-format +msgid "Event summary:" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1205 +#, python-format +msgid "Missing required fields %s" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:30 +#, python-format +msgid "Month" +msgstr "Месяц" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1347 +#, python-format +msgid "Open: " +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:29 +#, python-format +msgid "Today" +msgstr "Сегодня" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:828 +#, python-format +msgid "View: %s" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:31 +#, python-format +msgid "Week" +msgstr "Неделя" diff --git a/i18n/sk.po b/i18n/sk.po new file mode 100644 index 00000000..34e6ad98 --- /dev/null +++ b/i18n/sk.po @@ -0,0 +1,152 @@ +# Slovak translation for openerp-web +# Copyright (c) 2014 Rosetta Contributors and Canonical Ltd 2014 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR , 2014. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2015-01-21 14:08+0000\n" +"PO-Revision-Date: 2014-08-14 16:14+0000\n" +"Last-Translator: FULL NAME \n" +"Language-Team: Slovak \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2015-01-22 08:55+0000\n" +"X-Generator: Launchpad (build 17306)\n" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1295 +#, python-format +msgid "Add" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:27 +#, python-format +msgid "All day" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:917 +#, python-format +msgid "Are you sure you want to delete this record ?" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:75 +#, python-format +msgid "Calendar" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:131 +#, python-format +msgid "Calendar view has not defined 'date_start' attribute." +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:950 +#, python-format +msgid "Create" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:66 +#, python-format +msgid "Create event" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:955 +#, python-format +msgid "Create: " +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1227 +#, python-format +msgid "Dataset for type '%s' is not defined." +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:32 +#, python-format +msgid "Day" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:837 +#, python-format +msgid "Delete" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:838 +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:67 +#, python-format +msgid "Edit Event" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:60 +#, python-format +msgid "Event summary:" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1205 +#, python-format +msgid "Missing required fields %s" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:30 +#, python-format +msgid "Month" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1347 +#, python-format +msgid "Open: " +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:29 +#, python-format +msgid "Today" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:828 +#, python-format +msgid "View: %s" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:31 +#, python-format +msgid "Week" +msgstr "" diff --git a/i18n/sl.po b/i18n/sl.po new file mode 100644 index 00000000..4c457f63 --- /dev/null +++ b/i18n/sl.po @@ -0,0 +1,152 @@ +# Slovenian translation for openerp-web +# Copyright (c) 2014 Rosetta Contributors and Canonical Ltd 2014 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR , 2014. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2015-01-21 14:08+0000\n" +"PO-Revision-Date: 2014-08-14 16:14+0000\n" +"Last-Translator: FULL NAME \n" +"Language-Team: Slovenian \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2015-01-22 08:55+0000\n" +"X-Generator: Launchpad (build 17306)\n" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1295 +#, python-format +msgid "Add" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:27 +#, python-format +msgid "All day" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:917 +#, python-format +msgid "Are you sure you want to delete this record ?" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:75 +#, python-format +msgid "Calendar" +msgstr "Koledar" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:131 +#, python-format +msgid "Calendar view has not defined 'date_start' attribute." +msgstr "Začetni datum ni definiran" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:950 +#, python-format +msgid "Create" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:66 +#, python-format +msgid "Create event" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:955 +#, python-format +msgid "Create: " +msgstr "Ustvari: " + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1227 +#, python-format +msgid "Dataset for type '%s' is not defined." +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:32 +#, python-format +msgid "Day" +msgstr "Dan" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:837 +#, python-format +msgid "Delete" +msgstr "Izbriši" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:838 +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:67 +#, python-format +msgid "Edit Event" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:60 +#, python-format +msgid "Event summary:" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1205 +#, python-format +msgid "Missing required fields %s" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:30 +#, python-format +msgid "Month" +msgstr "Mesec" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1347 +#, python-format +msgid "Open: " +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:29 +#, python-format +msgid "Today" +msgstr "Danes" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:828 +#, python-format +msgid "View: %s" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:31 +#, python-format +msgid "Week" +msgstr "Teden" diff --git a/i18n/sq.po b/i18n/sq.po new file mode 100644 index 00000000..1e61a932 --- /dev/null +++ b/i18n/sq.po @@ -0,0 +1,152 @@ +# Albanian translation for openerp-web +# Copyright (c) 2014 Rosetta Contributors and Canonical Ltd 2014 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR , 2014. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2015-01-21 14:08+0000\n" +"PO-Revision-Date: 2014-08-14 16:14+0000\n" +"Last-Translator: FULL NAME \n" +"Language-Team: Albanian \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2015-01-22 08:55+0000\n" +"X-Generator: Launchpad (build 17306)\n" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1295 +#, python-format +msgid "Add" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:27 +#, python-format +msgid "All day" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:917 +#, python-format +msgid "Are you sure you want to delete this record ?" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:75 +#, python-format +msgid "Calendar" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:131 +#, python-format +msgid "Calendar view has not defined 'date_start' attribute." +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:950 +#, python-format +msgid "Create" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:66 +#, python-format +msgid "Create event" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:955 +#, python-format +msgid "Create: " +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1227 +#, python-format +msgid "Dataset for type '%s' is not defined." +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:32 +#, python-format +msgid "Day" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:837 +#, python-format +msgid "Delete" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:838 +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:67 +#, python-format +msgid "Edit Event" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:60 +#, python-format +msgid "Event summary:" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1205 +#, python-format +msgid "Missing required fields %s" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:30 +#, python-format +msgid "Month" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1347 +#, python-format +msgid "Open: " +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:29 +#, python-format +msgid "Today" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:828 +#, python-format +msgid "View: %s" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:31 +#, python-format +msgid "Week" +msgstr "" diff --git a/i18n/sr@latin.po b/i18n/sr@latin.po new file mode 100644 index 00000000..2fd66523 --- /dev/null +++ b/i18n/sr@latin.po @@ -0,0 +1,152 @@ +# Serbian Latin translation for openerp-web +# Copyright (c) 2014 Rosetta Contributors and Canonical Ltd 2014 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR , 2014. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2015-01-21 14:08+0000\n" +"PO-Revision-Date: 2014-08-15 06:51+0000\n" +"Last-Translator: zmmaj \n" +"Language-Team: Serbian Latin \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2015-01-22 08:55+0000\n" +"X-Generator: Launchpad (build 17306)\n" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1295 +#, python-format +msgid "Add" +msgstr "Dodaj" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:27 +#, python-format +msgid "All day" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:917 +#, python-format +msgid "Are you sure you want to delete this record ?" +msgstr "Jeste li sigurni da želite obrisati obaj zapis?" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:75 +#, python-format +msgid "Calendar" +msgstr "Kalendar" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:131 +#, python-format +msgid "Calendar view has not defined 'date_start' attribute." +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:950 +#, python-format +msgid "Create" +msgstr "Kreiraj" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:66 +#, python-format +msgid "Create event" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:955 +#, python-format +msgid "Create: " +msgstr "Kreiraj: " + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1227 +#, python-format +msgid "Dataset for type '%s' is not defined." +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:32 +#, python-format +msgid "Day" +msgstr "Dan" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:837 +#, python-format +msgid "Delete" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:838 +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:67 +#, python-format +msgid "Edit Event" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:60 +#, python-format +msgid "Event summary:" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1205 +#, python-format +msgid "Missing required fields %s" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:30 +#, python-format +msgid "Month" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1347 +#, python-format +msgid "Open: " +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:29 +#, python-format +msgid "Today" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:828 +#, python-format +msgid "View: %s" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:31 +#, python-format +msgid "Week" +msgstr "" diff --git a/i18n/sv.po b/i18n/sv.po new file mode 100644 index 00000000..9e2e23b9 --- /dev/null +++ b/i18n/sv.po @@ -0,0 +1,152 @@ +# Swedish translation for openerp-web +# Copyright (c) 2014 Rosetta Contributors and Canonical Ltd 2014 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR , 2014. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2015-01-21 14:08+0000\n" +"PO-Revision-Date: 2014-08-14 16:14+0000\n" +"Last-Translator: FULL NAME \n" +"Language-Team: Swedish \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2015-01-22 08:55+0000\n" +"X-Generator: Launchpad (build 17306)\n" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1295 +#, python-format +msgid "Add" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:27 +#, python-format +msgid "All day" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:917 +#, python-format +msgid "Are you sure you want to delete this record ?" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:75 +#, python-format +msgid "Calendar" +msgstr "Kalender" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:131 +#, python-format +msgid "Calendar view has not defined 'date_start' attribute." +msgstr "Kalendervyn har inte definierat 'Startdatum' attributet" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:950 +#, python-format +msgid "Create" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:66 +#, python-format +msgid "Create event" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:955 +#, python-format +msgid "Create: " +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1227 +#, python-format +msgid "Dataset for type '%s' is not defined." +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:32 +#, python-format +msgid "Day" +msgstr "Dag" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:837 +#, python-format +msgid "Delete" +msgstr "Ta bort" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:838 +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:67 +#, python-format +msgid "Edit Event" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:60 +#, python-format +msgid "Event summary:" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1205 +#, python-format +msgid "Missing required fields %s" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:30 +#, python-format +msgid "Month" +msgstr "Månad" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1347 +#, python-format +msgid "Open: " +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:29 +#, python-format +msgid "Today" +msgstr "Idag" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:828 +#, python-format +msgid "View: %s" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:31 +#, python-format +msgid "Week" +msgstr "Vecka" diff --git a/i18n/th.po b/i18n/th.po new file mode 100644 index 00000000..d58f4e2e --- /dev/null +++ b/i18n/th.po @@ -0,0 +1,152 @@ +# Thai translation for openerp-web +# Copyright (c) 2014 Rosetta Contributors and Canonical Ltd 2014 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR , 2014. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2015-01-21 14:08+0000\n" +"PO-Revision-Date: 2014-08-14 16:14+0000\n" +"Last-Translator: FULL NAME \n" +"Language-Team: Thai \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2015-01-22 08:55+0000\n" +"X-Generator: Launchpad (build 17306)\n" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1295 +#, python-format +msgid "Add" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:27 +#, python-format +msgid "All day" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:917 +#, python-format +msgid "Are you sure you want to delete this record ?" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:75 +#, python-format +msgid "Calendar" +msgstr "ปฏิทิน" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:131 +#, python-format +msgid "Calendar view has not defined 'date_start' attribute." +msgstr "มุมมองปฏิทินยังไม่ได้กำหนด 'date_start'" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:950 +#, python-format +msgid "Create" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:66 +#, python-format +msgid "Create event" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:955 +#, python-format +msgid "Create: " +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1227 +#, python-format +msgid "Dataset for type '%s' is not defined." +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:32 +#, python-format +msgid "Day" +msgstr "วัน" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:837 +#, python-format +msgid "Delete" +msgstr "ลบ" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:838 +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:67 +#, python-format +msgid "Edit Event" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:60 +#, python-format +msgid "Event summary:" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1205 +#, python-format +msgid "Missing required fields %s" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:30 +#, python-format +msgid "Month" +msgstr "เดือน" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1347 +#, python-format +msgid "Open: " +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:29 +#, python-format +msgid "Today" +msgstr "วันนี้" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:828 +#, python-format +msgid "View: %s" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:31 +#, python-format +msgid "Week" +msgstr "สัปดาห์" diff --git a/i18n/tr.po b/i18n/tr.po new file mode 100644 index 00000000..ae090521 --- /dev/null +++ b/i18n/tr.po @@ -0,0 +1,152 @@ +# Turkish translation for openerp-web +# Copyright (c) 2014 Rosetta Contributors and Canonical Ltd 2014 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR , 2014. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2015-01-21 14:08+0000\n" +"PO-Revision-Date: 2014-09-24 15:54+0000\n" +"Last-Translator: Ayhan KIZILTAN \n" +"Language-Team: Turkish \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2015-01-22 08:55+0000\n" +"X-Generator: Launchpad (build 17306)\n" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1295 +#, python-format +msgid "Add" +msgstr "Ekle" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:27 +#, python-format +msgid "All day" +msgstr "Tüm gün" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:917 +#, python-format +msgid "Are you sure you want to delete this record ?" +msgstr "Bu kayıdı silmek istediğinizden emin misiniz?" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:75 +#, python-format +msgid "Calendar" +msgstr "Takvim" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:131 +#, python-format +msgid "Calendar view has not defined 'date_start' attribute." +msgstr "Takvim görünümünde 'tarih_başla' özniteliği tanımlanmamış." + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:950 +#, python-format +msgid "Create" +msgstr "Oluştur" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:66 +#, python-format +msgid "Create event" +msgstr "Etkinlik oluştur" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:955 +#, python-format +msgid "Create: " +msgstr "Oluştur: " + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1227 +#, python-format +msgid "Dataset for type '%s' is not defined." +msgstr "Türü '% s' için veri kümesi tanımlı değil." + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:32 +#, python-format +msgid "Day" +msgstr "Gün" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:837 +#, python-format +msgid "Delete" +msgstr "Sil" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:838 +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:67 +#, python-format +msgid "Edit Event" +msgstr "Etkinliği Düzenle" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:60 +#, python-format +msgid "Event summary:" +msgstr "Olay özeti:" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1205 +#, python-format +msgid "Missing required fields %s" +msgstr "Gerekli alanlar eksik % s" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:30 +#, python-format +msgid "Month" +msgstr "Ay" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1347 +#, python-format +msgid "Open: " +msgstr "Aç: " + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:29 +#, python-format +msgid "Today" +msgstr "Bugün" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:828 +#, python-format +msgid "View: %s" +msgstr "Görünüm:%s" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:31 +#, python-format +msgid "Week" +msgstr "Hafta" diff --git a/i18n/uk.po b/i18n/uk.po new file mode 100644 index 00000000..1adffeb7 --- /dev/null +++ b/i18n/uk.po @@ -0,0 +1,152 @@ +# Ukrainian translation for openerp-web +# Copyright (c) 2014 Rosetta Contributors and Canonical Ltd 2014 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR , 2014. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2015-01-21 14:08+0000\n" +"PO-Revision-Date: 2014-08-14 16:14+0000\n" +"Last-Translator: FULL NAME \n" +"Language-Team: Ukrainian \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2015-01-22 08:55+0000\n" +"X-Generator: Launchpad (build 17306)\n" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1295 +#, python-format +msgid "Add" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:27 +#, python-format +msgid "All day" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:917 +#, python-format +msgid "Are you sure you want to delete this record ?" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:75 +#, python-format +msgid "Calendar" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:131 +#, python-format +msgid "Calendar view has not defined 'date_start' attribute." +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:950 +#, python-format +msgid "Create" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:66 +#, python-format +msgid "Create event" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:955 +#, python-format +msgid "Create: " +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1227 +#, python-format +msgid "Dataset for type '%s' is not defined." +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:32 +#, python-format +msgid "Day" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:837 +#, python-format +msgid "Delete" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:838 +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:67 +#, python-format +msgid "Edit Event" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:60 +#, python-format +msgid "Event summary:" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1205 +#, python-format +msgid "Missing required fields %s" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:30 +#, python-format +msgid "Month" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1347 +#, python-format +msgid "Open: " +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:29 +#, python-format +msgid "Today" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:828 +#, python-format +msgid "View: %s" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:31 +#, python-format +msgid "Week" +msgstr "" diff --git a/i18n/web_calendar.pot b/i18n/web_calendar.pot new file mode 100644 index 00000000..125becf0 --- /dev/null +++ b/i18n/web_calendar.pot @@ -0,0 +1,151 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_calendar +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 8.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2015-01-21 14:08+0000\n" +"PO-Revision-Date: 2015-01-21 14:08+0000\n" +"Last-Translator: <>\n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1295 +#, python-format +msgid "Add" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:27 +#, python-format +msgid "All day" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:917 +#, python-format +msgid "Are you sure you want to delete this record ?" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:75 +#, python-format +msgid "Calendar" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:131 +#, python-format +msgid "Calendar view has not defined 'date_start' attribute." +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:950 +#, python-format +msgid "Create" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:66 +#, python-format +msgid "Create event" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:955 +#, python-format +msgid "Create: " +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1227 +#, python-format +msgid "Dataset for type '%s' is not defined." +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:32 +#, python-format +msgid "Day" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:837 +#, python-format +msgid "Delete" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:838 +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:67 +#, python-format +msgid "Edit Event" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:60 +#, python-format +msgid "Event summary:" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1205 +#, python-format +msgid "Missing required fields %s" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:30 +#, python-format +msgid "Month" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1347 +#, python-format +msgid "Open: " +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:29 +#, python-format +msgid "Today" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:828 +#, python-format +msgid "View: %s" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:31 +#, python-format +msgid "Week" +msgstr "" + diff --git a/i18n/zh_CN.po b/i18n/zh_CN.po new file mode 100644 index 00000000..2c2531af --- /dev/null +++ b/i18n/zh_CN.po @@ -0,0 +1,152 @@ +# Chinese (Simplified) translation for openerp-web +# Copyright (c) 2014 Rosetta Contributors and Canonical Ltd 2014 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR , 2014. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2015-01-21 14:08+0000\n" +"PO-Revision-Date: 2014-10-19 11:47+0000\n" +"Last-Translator: Wei \"oldrev\" Li \n" +"Language-Team: Chinese (Simplified) \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2015-01-22 08:55+0000\n" +"X-Generator: Launchpad (build 17306)\n" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1295 +#, python-format +msgid "Add" +msgstr "添加" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:27 +#, python-format +msgid "All day" +msgstr "全天" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:917 +#, python-format +msgid "Are you sure you want to delete this record ?" +msgstr "您确定要删除此记录吗?" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:75 +#, python-format +msgid "Calendar" +msgstr "日历" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:131 +#, python-format +msgid "Calendar view has not defined 'date_start' attribute." +msgstr "日历视图未定义 'date_start'属性" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:950 +#, python-format +msgid "Create" +msgstr "创建" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:66 +#, python-format +msgid "Create event" +msgstr "创建事件" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:955 +#, python-format +msgid "Create: " +msgstr "创建: " + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1227 +#, python-format +msgid "Dataset for type '%s' is not defined." +msgstr "类型“%s”的数据集未定义。" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:32 +#, python-format +msgid "Day" +msgstr "日" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:837 +#, python-format +msgid "Delete" +msgstr "删除" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:838 +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:67 +#, python-format +msgid "Edit Event" +msgstr "编辑事件" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:60 +#, python-format +msgid "Event summary:" +msgstr "事件摘要:" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1205 +#, python-format +msgid "Missing required fields %s" +msgstr "缺失必须的字段“%s”" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:30 +#, python-format +msgid "Month" +msgstr "月份" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1347 +#, python-format +msgid "Open: " +msgstr "打开: " + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:29 +#, python-format +msgid "Today" +msgstr "今天" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:828 +#, python-format +msgid "View: %s" +msgstr "查看:%s" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:31 +#, python-format +msgid "Week" +msgstr "周" diff --git a/i18n/zh_TW.po b/i18n/zh_TW.po new file mode 100644 index 00000000..b0130508 --- /dev/null +++ b/i18n/zh_TW.po @@ -0,0 +1,152 @@ +# Chinese (Traditional) translation for openerp-web +# Copyright (c) 2014 Rosetta Contributors and Canonical Ltd 2014 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR , 2014. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2015-01-21 14:08+0000\n" +"PO-Revision-Date: 2014-08-14 16:14+0000\n" +"Last-Translator: FULL NAME \n" +"Language-Team: Chinese (Traditional) \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2015-01-22 08:55+0000\n" +"X-Generator: Launchpad (build 17306)\n" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1295 +#, python-format +msgid "Add" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:27 +#, python-format +msgid "All day" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:917 +#, python-format +msgid "Are you sure you want to delete this record ?" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:75 +#, python-format +msgid "Calendar" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:131 +#, python-format +msgid "Calendar view has not defined 'date_start' attribute." +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:950 +#, python-format +msgid "Create" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:66 +#, python-format +msgid "Create event" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:955 +#, python-format +msgid "Create: " +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1227 +#, python-format +msgid "Dataset for type '%s' is not defined." +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:32 +#, python-format +msgid "Day" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:837 +#, python-format +msgid "Delete" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:838 +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:67 +#, python-format +msgid "Edit Event" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/xml/web_fullcalendar.xml:60 +#, python-format +msgid "Event summary:" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1205 +#, python-format +msgid "Missing required fields %s" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:30 +#, python-format +msgid "Month" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:1347 +#, python-format +msgid "Open: " +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:29 +#, python-format +msgid "Today" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:828 +#, python-format +msgid "View: %s" +msgstr "" + +#. module: web_calendar +#. openerp-web +#: code:addons/web_calendar/static/src/js/web_calendar.js:31 +#, python-format +msgid "Week" +msgstr "" diff --git a/ir_view.py b/ir_view.py new file mode 100644 index 00000000..efbd8d67 --- /dev/null +++ b/ir_view.py @@ -0,0 +1,40 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Copyright 2015 ACSONE SA/NV +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## +from openerp import models +from openerp import api + + +TIMELINE_VIEW = ('timeline', 'Timeline') + + +class IrUIView(models.Model): + _inherit = 'ir.ui.view' + + @api.model + def _setup_fields(self): + """Hack due since the field 'type' is not defined with the new api. + """ + cls = type(self) + type_selection = cls._fields['type'].selection + if TIMELINE_VIEW not in type_selection: + tmp = list(type_selection) + tmp.append(TIMELINE_VIEW) + cls._fields['type'].selection = tuple(set(tmp)) + super(IrUIView, self)._setup_fields() diff --git a/static/lib/timeline/CHANGELOG b/static/lib/timeline/CHANGELOG new file mode 100644 index 00000000..5e196ef4 --- /dev/null +++ b/static/lib/timeline/CHANGELOG @@ -0,0 +1,199 @@ +CHAP Links Library - Timeline + + +2015-03-04, version 2.9.1 + +- Fixed broken option `groupsWidth`. +- Fixed group height collapsing when there are no items, height now reckons + with the label height. +- Added Brazilian Portuguese locale, thanks @gmmoreira. +- Added locales Portuguese, Chinese, Arabic, Japanese, Korean. Thanks Mario + Fischer. +- Added Polish locale, thanks @pbrzoski. + + +2014-07-28, version 2.9.0 + +- Implemented function `getCluster()`, `getClusterIndex()` and `getSelection()`. + Thanks @igui. +- Added option `clusterMaxItems`. Thanks @igui. +- Fixed 'change' event not being fired when dragging the left or right side + of a range. +- Fixed restoring original dates after canceling a changed item. + + +2014-05-16, version 2.8.0 + +- Implemented a new item type, `FloatingRange`. Thanks Nick Hardy (@NickHardy). +- Implemented options `groupMinHeight`. Thanks @sapeish. +- Fixed event `add` not triggered in case of ctrl+click to add a new item. + Thanks @sapeish. + + +2014-04-09, version 2.7.0 + +- Implemented option `timeChangeable` which allows to have items which can be + moved to a different group but not moved in time. + Thanks Martin Fischer (hansmaulwurf23). +- Implemented function `getVisibleItems(start, end)`. Thanks StephanieHe. +- Added Finish locale. Thanks magandrez. +- Changed default type of a newly created item from range to box. + + +2014-01-14, version 2.6.1 + +- Function `Timeline.getItem` now also returns foreign fields available in the + items data. + + +2014-01-13, version 2.6.0 + +- Implemented support for stacking items within groups. Thanks Stefano Fornari. +- Added Turkish locale. Thanks Batuhan Kucukali (LadyArch3r). + + +2013-12-13, version 2.5.1 + +- Added option groupsOrder, which is `true` by default and can be used to provide + a custom group order (or no ordering at all by setting the option to `false`). + (Thanks hansmaulwurf23). +- Rename event `change` to `changed`, added event `change` which fires + repeatedly when an item is being changed. (Thanks bensleveritt). +- Fixed an off-by-one error in mapping columns of a Google DataTable. +- Fixed `type` not being read correctly from a Google DataTable. + Thanks boblepepeur. +- Fixed getting the className of an item. Thanks Pedro Heliodoro. + + +2013-08-20, version 2.5.0 + +- Added French and Dutch localization. Thanks sp0ken and jeroenvg. +- Integration with jQuery Themeroller. Thanks Oleg Varaksin. +- Implemented Shift+Scroll to move the timeline. Thanks Olivier Aubert (oaubert). +- Implemented support for a field `type` to give events a type individually. +- Improved: Timeline is more robust against invalid data (data without + start and end fields). Thanks Roberto Tyley. +- Added an option 'unselectable'. Thanks judge. +- Fixed: when updating a selected item using changeItem, the selection was not + restored correctly. +- Fixed not being able to define columns for fields `group`, `className`, and + `editable` in a Google SpreadSheet. +- Fixed non-working touch events. + + +2013-04-18, version 2.4.2 + +- Implemented localization. (Thanks bjarkebech and José Renato). +- Changed: renamed option intervalMin to zoomMin and intervalMax to zoomMax + (Thanks Oleg Varaksin). +- Fixed: could not change an items field editable using method changeItem. +- Fixed: fields editable and className could not be retrieved from method + getItem (Thanks Oleg Varaksin). + + +2013-03-04, version 2.4.1 + +- Fixed: issue with calculating absolute positions of mouse and elements in + scrolled elements or body. + + +2013-02-26, version 2.4.0 + +- Added a new scale "WEEKDAY", which shows the weekday in the minor label. +- Implemented clustering of items. +- Implemented support for custom item types (besides the built in types box, + range, and dot). See example 25. Thanks Alexander Parshin. +- events can be made editable/read-only on an individual basis by providing + them with a field "editable". +- changed: data can now have custom fields (like an id). +- changed: method addItem has a second, optional parameter "preventRedraw", + which can be used to prevent redrawing the timeline after every addItem. +- changed: option showButtonAdd renamed to showButtonNew, and is now false by + default. +- changed: new items created via a double-click or the "Add" button are now + rendered after add trigger (which can cancel the create action). +- fixed: issues with dates on millisecond scale or with negative years + (issues #19 and #54). +- fixed: options scale and step did not work (method setScale worked correctly + though). +- fixed: alignment of the delete button for selected events with style box, + when the option box.align was "left" or "right" instead of the default + "center". +- fixed: DataTable columns may now have their name defined as label or id, + and the first three columns can have any order now. More robust and flexible. +- fixed: when deleting an item via deleteItem, the currently selection is + maintained instead of unselected (issue #47). +- fixed: When dragging the edges of a range, it was possible to move the range + to another group. +- fixed: non reachable event 'ready" (issue #69). + + +2012-09-18, version 2.3.2 + +- fixed mouseover/dragging of the vertical lines with current time and custom + time, which did only work in the axis area but not in the contents area. + + +2012-09-13, version 2.3.1 + +- added: double tap events on mobile devices will now fire the edit/new event. +- fixed/updated example 09, 15, 17, and 18. +- created example 21. + + +2012-09-05, version 2.3.0 + +- new: items can now have an individual class name which allows styling of + individual items. This gives a lot of extra flexibility. +- fixed issue #26: pinching on Ipad did throw an error "ReferenceError: Can't + find variable: timeline". +- fixed issue #28: in some cases, clicking an item would not select the item + but move the timeline slightly (less than 1px). + + +2012-07-30, version 2.2.1 + +- fixed the 'select' event not being fired when an item gets unselected. +- fixed method changeItem not dealing with changing the type of the item + from box to range or vice versa. + + +2012-07-27, version 2.2.0 + +- added an option showMinorLabels. By setting both showMinorLabels and + showMajorLabels, true, the axis will not be visible. +- fixed issue #6: items and axis did not move with the speed when moving + the Timeline under IE8 and older. +- fixed issue #8: start, end, min, max not working correctly around Date(0). +- fixed issue #9. It is now possible to specify only start or end in the + options, instead of having to specify both. +- fixed issue #12: the group of an item was not restored after canceling a + change. + + +2012-06-18, version 2.1.2 + +- fixed issue #4 again: sorting groups still not working correctly + + +2012-06-15, version 2.1.1 + +- fixed issue #3: broken option stackEvents=false +- fixed issue #4: sorting groups not working correctly + + +2012-06-04, version 2.1 + +- Documentation has a new layout +- Source code cleaned up + + +2012-05-02, version 2.0.1 + +- bug fix: areas on the left and right end of a range (for changing start/end) + where displayed below the range instead of on top of it. + + +2012-05-02, version 2.0 + +- initial upload to github (formerly located at sourceforge) diff --git a/static/lib/timeline/LICENSE b/static/lib/timeline/LICENSE new file mode 100644 index 00000000..ea2712c0 --- /dev/null +++ b/static/lib/timeline/LICENSE @@ -0,0 +1,176 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS diff --git a/static/lib/timeline/NOTICE b/static/lib/timeline/NOTICE new file mode 100644 index 00000000..f5e1fe8a --- /dev/null +++ b/static/lib/timeline/NOTICE @@ -0,0 +1,14 @@ +CHAP Links Timeline +Copyright 2010-2015 Almende B.V. + + 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. diff --git a/static/lib/timeline/README b/static/lib/timeline/README new file mode 100644 index 00000000..07dbd2b5 --- /dev/null +++ b/static/lib/timeline/README @@ -0,0 +1,66 @@ +CHAP Links Network + +http://www.almende.com +http://almende.github.com/chap-links-library/ + +DESCRIPTION + +The Timeline is an interactive visualization chart to visualize events in time. +The events can take place on a single date, or have a start and end date +(a range). You can freely move and zoom in the timeline by dragging and +scrolling in the Timeline. Events can be created, edited, and deleted in the +timeline. The time scale on the axis is adjusted automatically, and supports +scales ranging from milliseconds to years. + +When the timeline is defined as editable, events can be moved to another time +by dragging them. By double clicking, the contents of an event can be changed. +An event can be deleted by clicking the delete button on the upper right. A new +event can be added in different ways: by double clicking in the timeline, or by +keeping the Ctrl key down and clicking or dragging in the timeline, or by +clicking the add button in the upper left of the timeline, and then clicking or +dragging at the right location in the timeline. + +The Timeline is developed as a Google Visualization Chart in javascript. It +runs in every browser without additional requirements. There is a GWT wrapper +available to use the Timeline in GWT (Google Web Toolkit), you can find relevant +documentation here. + +The Timeline is designed to display up to 100 events smoothly on any modern +browser. + + +USAGE + +The Timeline is no built-in visualization of Google. To load the Timeline, +download the file timeline.zip and unzip it in a sub directory timeline on your +html page. Include the google API and the two downloaded files in the head of +your html code: + + + + + +The google visualization needs to be loaded in order to use DataTable. + + google.load("visualization", "1"); + google.setOnLoadCallback(drawTimeline); + function drawTimeline() { + // load data and create the timeline here + } + +The class name of the Timeline is links.Timeline + + var timeline = new links.Timeline(container); + +After being loaded, the timeline can be drawn via the function draw(), provided +with data and options. + + timeline.draw(data, options); + +where data is a DataTable, and options is a name-value map in the JSON format. + + +DOCUMENTATION + +Documentation can be found in the directory doc +Examples can be found in the directory examples diff --git a/static/lib/timeline/doc/default.css b/static/lib/timeline/doc/default.css new file mode 100644 index 00000000..85f3bd3f --- /dev/null +++ b/static/lib/timeline/doc/default.css @@ -0,0 +1,92 @@ +html, body { + width: 100%; + height: 100%; + padding: 0; + margin: 0; +} + +body, td, th { + font-family: arial, sans-serif; + font-size: 11pt; + color: #4D4D4D; + line-height: 1.7em; +} + +#container { + margin: 0 auto; + padding-bottom: 50px; + width: 900px; +} + +h1 { + font-size: 180%; + font-weight: bold; + padding: 0; + margin: 1em 0 1em 0; +} + +h2 { + padding-top: 20px; + padding-bottom: 10px; + border-bottom: 1px solid #a0c0f0; + color: #2B7CE9; +} + +h3 { + font-size: 140%; +} + + +a { + color: #2B7CE9; + text-decoration: none; +} +a:visited { + color: #2E60A4; +} +a:hover { + color: red; + text-decoration: underline; +} + +hr { + border: none 0; + border-top: 1px solid #abc; + height: 1px; +} + +pre { + display: block; + font-size: 10pt; + line-height: 1.5em; + font-family: monospace; +} + +pre, code { + background-color: #f5f5f5; +} + +table +{ + border-collapse: collapse; +} + +th { + font-weight: bold; + border: 1px solid lightgray; + background-color: #E5E5E5; + text-align: left; + vertical-align: top; + padding: 5px; +} + +td { + border: 1px solid lightgray; + padding: 5px; + vertical-align: top; +} + +img.structure { + border: 1px solid gray; + background-color: #f5f5f5; +} \ No newline at end of file diff --git a/static/lib/timeline/doc/img/structure_box.png b/static/lib/timeline/doc/img/structure_box.png new file mode 100644 index 0000000000000000000000000000000000000000..323199a0e7c9a8b8d74f81fa1e804340184d8410 GIT binary patch literal 17555 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 JWt~$(69E6huDk#M literal 0 HcmV?d00001 diff --git a/static/lib/timeline/doc/img/structure_box.svg b/static/lib/timeline/doc/img/structure_box.svg new file mode 100644 index 00000000..95153c19 --- /dev/null +++ b/static/lib/timeline/doc/img/structure_box.svg @@ -0,0 +1,310 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + timeline-event-content + timeline-event timeline-event-box + timeline-event timeline-event-line + timeline-event timeline-event-dot + + + + + + diff --git a/static/lib/timeline/doc/img/structure_dot.png b/static/lib/timeline/doc/img/structure_dot.png new file mode 100644 index 0000000000000000000000000000000000000000..668ae55c630b56d7054e3f3fcfdec822ca18c631 GIT binary patch literal 11252 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 literal 0 HcmV?d00001 diff --git a/static/lib/timeline/doc/img/structure_dot.svg b/static/lib/timeline/doc/img/structure_dot.svg new file mode 100644 index 00000000..f6c4720f --- /dev/null +++ b/static/lib/timeline/doc/img/structure_dot.svg @@ -0,0 +1,286 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + timeline-event-content + timeline-event timeline-event-box + timeline-event timeline-event-dot + + + + + (no class) + + diff --git a/static/lib/timeline/doc/img/structure_range.png b/static/lib/timeline/doc/img/structure_range.png new file mode 100644 index 0000000000000000000000000000000000000000..3189b766cb1505891bbf2c9f80b524eddec357c7 GIT binary patch literal 19561 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 ckXVT(p<&zgVa6#xJL literal 0 HcmV?d00001 diff --git a/static/lib/timeline/doc/img/structure_range.svg b/static/lib/timeline/doc/img/structure_range.svg new file mode 100644 index 00000000..7646f2b1 --- /dev/null +++ b/static/lib/timeline/doc/img/structure_range.svg @@ -0,0 +1,327 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + timeline-event-content + timeline-event timeline-event-range + timeline-event-range-drag-left + timeline-event-range-drag-right + + + + + + + + diff --git a/static/lib/timeline/doc/index.html b/static/lib/timeline/doc/index.html new file mode 100644 index 00000000..bb953696 --- /dev/null +++ b/static/lib/timeline/doc/index.html @@ -0,0 +1,1696 @@ + + + + Timeline documentation + + + + + + + +
+ +

Timeline documentation

+ + + + + + + + + + + + + + + +
AuthorJos de Jong, Almende B.V.
WebpageChap Links Library
License Apache License, Version 2.0
+ + +

Contents

+
+ +

Overview

+

+ The Timeline is an interactive visualization chart to visualize events in time. + The events can take place on a single date, or have a start and end date (a range). + You can freely move and zoom in the timeline by dragging and scrolling in the + Timeline. Events can be created, edited, and deleted in the timeline. + The time scale on the axis is adjusted automatically, and supports scales ranging + from milliseconds to years. +

+ +

+ When the timeline is defined as editable (and groupsChangeable and timeChangeable are set accordingly), events can be moved to another time + by dragging them. By double clicking, the contents of an event can be changed. + An event can be deleted by clicking the delete button on the upper right. + A new event can be added in different + ways: by double clicking in the timeline, or by keeping the Ctrl key down and + clicking or dragging in the timeline, or by clicking the add button in the + upper left of the timeline, and then clicking or dragging at the right location + in the timeline. + +

+ +

+ The Timeline is developed as a Google Visualization Chart in javascript. + It runs in every browser without additional requirements. + There is a GWT wrapper available to use the Timeline in GWT (Google Web Toolkit), + you can find relevant documentation here. +

+ +

+ The Timeline is designed to display up to 1000 events smoothly on any modern browser. +

+ +

Example

+

+ Here a timeline example. Click and drag to move the timeline, scroll to zoom the timeline. +

+

+ More examples can be found in the examples directory. +

+ + + +
<html>
+  <head>
+    <title>Timeline demo</title>
+
+    <style>
+      body {font: 10pt arial;}
+    </style>
+
+    <script type="text/javascript" src="http://www.google.com/jsapi"></script>
+    <script type="text/javascript" src="../timeline.js"></script>
+    <link rel="stylesheet" type="text/css" href="../timeline.css">
+
+    <script type="text/javascript">
+      google.load("visualization", "1");
+
+      // Set callback to run when API is loaded
+      google.setOnLoadCallback(drawVisualization);
+
+      // Called when the Visualization API is loaded.
+      function drawVisualization() {
+        // Create and populate a data table.
+        var data = new google.visualization.DataTable();
+        data.addColumn('datetime', 'start');
+        data.addColumn('datetime', 'end');
+        data.addColumn('string', 'content');
+
+        data.addRows([
+          [new Date(2010,7,23), , 'Conversation<br>' +
+            '<img src="img/comments-icon.png" style="width:32px; height:32px;">'],
+          [new Date(2010,7,23,23,0,0), , 'Mail from boss<br>' +
+            '<img src="img/mail-icon.png" style="width:32px; height:32px;">'],
+          [new Date(2010,7,24,16,0,0), , 'Report'],
+          [new Date(2010,7,26), new Date(2010,8,2), 'Traject A'],
+          [new Date(2010,7,28), , 'Memo<br>' +
+            '<img src="img/notes-edit-icon.png" style="width:48px; height:48px;">'],
+          [new Date(2010,7,29), , 'Phone call<br>' +
+            '<img src="img/Hardware-Mobile-Phone-icon.png" style="width:32px; height:32px;">'],
+          [new Date(2010,7,31), new Date(2010,8,3), 'Traject B'],
+          [new Date(2010,8,4,12,0,0), , 'Report<br>' +
+            '<img src="img/attachment-icon.png" style="width:32px; height:32px;">']
+        ]);
+
+        // specify options
+        var options = {
+          "width":  "100%",
+          "height": "99%",
+          "style": "box" // optional
+        };
+
+        // Instantiate our timeline object.
+        var timeline = new links.Timeline(document.getElementById('mytimeline'));
+
+        // Draw our timeline with the created data and options
+        timeline.draw(data, options);
+      }
+   </script>
+  </head>
+
+  <body>
+    <div id="mytimeline"></div>
+  </body>
+</html>
+
+ + +

Loading

+ +

+ To load the Timeline, download the file + timeline.zip + and unzip it in a sub directory timeline on your html page. + Include the two downloaded files (timeline.js and timeline.css) in the head of your html code. + When you use a Google DataTable for providing the data, + the Google API must be included too. + + Note that the Google API is only available online, so it is not possible + to use it in an offline application. +

+ +
<script type="text/javascript" src="http://www.google.com/jsapi"></script>
+<script type="text/javascript" src="timeline/timeline.js"></script>
+<link rel="stylesheet" type="text/css" href="timeline/timeline.css">
+ +

+ When the Google API is used, the google visualization tools needs to be + loaded. This is not needed when using a JSON Array as data type. +

+
google.load("visualization", "1");
+google.setOnLoadCallback(drawTimeline);
+function drawTimeline() {
+  // load data and create the timeline here
+}
+
+ +The class name of the Timeline is links.Timeline +
var timeline = new links.Timeline(container);
+ +After being loaded, the timeline can be drawn via the method draw, +provided with data and options. +
timeline.draw(data, options);
+

+ where data is a DataTable or a JSON Array, + and options is a name-value map in the JSON format. +

+ +

+ The Timeline stores a link to the original data table, and applies changes + made from within the Timeline to this data table. + When the data table is changed externally, the Timeline can be updated by executing + redraw(). The Timeline can be linked to an other/new table + via draw(data) (without providing options). + When the website layout has been changed or resized, use checkResize() + to update the size of the timeline. +

+ + +

Data Format

+

+ The Timeline supports two data types: a JSON Array or a Google DataTable. +

+ + +

JSON

+

+ The Timeline supports a JSON Array as data format. The Array must contain + JSON Objects with fields start, end (optional), + content, group (optional), and + className (optional). + When JSON is used as data format (instead of Google DataTable), the + Timeline can be used offline. +

+ +

+ A table is constructed as: +

+ +
+var data = [];
+
+data.push({
+  'start': new Date(2010, 7, 15),
+  'end': new Date(2010, 8, 2),  // end is optional
+  'content': 'Trajectory A'
+  // Optional: a field 'group'
+  // Optional: a field 'className'
+  // Optional: a field 'editable'
+});
+
+ + +

Google DataTable

+

+ The Timeline requires a data table with two required and three optional + columns. + It is possible to use a Google DataTable or DataView, and the data + can be queried from an external data source using Google Query. + Note that the needed Google API is only available online and cannot be + downloaded for offline usage. +

+ +

+ A table is constructed as: +

+ +
+var data = new google.visualization.DataTable();
+data.addColumn('datetime', 'start');
+data.addColumn('datetime', 'end');
+data.addColumn('string', 'content');
+// Optional: a column 'group'
+// Optional: a column 'className'
+// Optional: a column 'editable'
+// Optional: a column 'type'
+
+data.addRow([new Date(2010,7,15), new Date(2010,8,2), "Trajectory A"]);
+// ...
+
+ +

+ The Timeline checks the type of the columns by first reading the + column id, and if not provided read the column label. + If both the column id's and label's are undefined, the Timeline will use + column 0 as start, column 1 as end, column 2 as content, column 3 as group, + column 4 as className, and column 5 as editable. +

+ +

Fields

+ +

+ The fields are defined as: +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeRequiredDescription
startDateyes* + The start date of the event, for example new Date(2010,2,23). +
+
+ Remark: Months in the JavaScript Date object are zero-based,
+ so new Date(2010,2,23) represents 23th of March, 2010. +
+ * If the type is set to floatingRange, the start is optional. +
endDatenoThe end date of the event. The end date is optional, and can be left null. + If end date is provided, the event is displayed as a range. + If not, the event is displayed as a box.
contentStringyesThe contents of the event. This can be plain text or html code.
groupany typenoThis field is optional. When the group column is provided, + all events with the same group are placed on one line. + A vertical axis is displayed showing the groups. + Grouping events can be useful for example when showing availability of multiple + people, rooms, or other resources next to each other.
+ + If none of the events has a group, + the events will be drawn on top of the horizontal axis. + When events overlap each other, the will be stacked automatically. +
classNameStringnoThis field is optional. A className can be used to give events + and individual css style. For example, when an event has className + 'red', one can define a css style + + .red { + background-color: red; + border-color: dark-red; + } + . + Depending on how you apply your css styles, it may be needed to + (re)define the style for selected events + (class timeline-event-selected). + More details on how to style events can be found in the section + Styles. +
editableBooleannoThis field is optional. By providing the field editable, events + can be made editable or read-only on an individual basis. + If editable is true, the event can be edited and deleted. + The editable setting of an individual event overwrites the global + setting options.editable. So when the Timeline as a whole is + read-only, individual events may be made editable, and vice versa. +
typeStringnoType of the event, optional. Available values: "box", "range", "dot", "floatingRange". + By default, the type is "range" for events having a start and end + date, and "box" for events with a start date. This default can be + overwritten by the global option "style". +
+ +

Custom fields

+ +It is possible to add custom fields to items. The Timeline will ignore them and leave +them intact. When retrieving an item via getItem, these custom fields +will be returned along with the known fields. + + +

Configuration Options

+ +

+ Options can be used to customize the timeline. Options are defined as a JSON object. + All options are optional. +

+ +
+var options = {
+  "width":  "100%",
+  "height": "auto",
+  "style": "box",
+  "editable": true
+};
+
+ +

+ The following options are available. +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
animatebooleantrueWhen true, events are moved animated when resizing or moving them. + This is very pleasing for the eye, but does require more computational power.
animateZoombooleantrueWhen true, events are moved animated when zooming the Timeline. + This looks cool, but does require more computational power.
axisOnTopbooleanfalseIf false (default), the horizontal axis is drawn at the bottom. + If true, the axis is drawn on top.
clusterbooleanfalseIf true, events will be clustered together when zooming out. + This keeps the Timeline clear and fast also with a larger amount of + events. +
experimental +
clusterMaxItemsNumber5The maximum quantity of items that can be shown outside a cluster. Setting a low value is useful to limit the + height of the container element. This value must be at least one. +
experimental +
customStackOrderfunctionnoneProvide a custom sort function to order the items. The order of the + items is determining the way they are stacked. The function + customStackOrder is called with two parameters, both of type + `timeline.Item`. +
box.alignString"center"Alignment of items with style "box". Available values are + "center" (default), "left", or "right").
dragAreaWidthNumber10The width of the drag areas in pixels. + When an event range is selected, it has a drag area on the left and right + side, with which the start or end time of the even can be manipulated.
editablebooleanfalseIf true, the events can be edited, created and deleted. + Events can only be editable when th option selectable is true + (default). When editable is true, the Timeline can fire events + change, changed, edit, + add, delete. +
+ This global setting editable can be overwritten for individual events + by providing the events with a field editable, + as described in section Data Format. +
endDatenoneThe initial end date for the axis of the timeline. + If not provided, the latest date present in the events is taken as end date.
eventMarginint10The minimal margin in pixels between events.
eventMarginAxisint10The minimal margin in pixels between events and the horizontal axis.
groupsChangeablebooleanfalseIf true, items can be moved from one group to another. + Only applicable when groups are used. See also option timeChangeable.
groupsOnRightbooleanfalseIf false, the groups legend is drawn at the left side of the timeline. + If true, the groups legend is drawn on the right side.
groupsOrderboolean | functiontrue + Allows to customize the way groups are ordered. + When true (default), groups will be ordered alphabetically. + When false, groups will not be ordered at all. + When a function, groups will be ordered using this sort function. + While sorting, the sort function is called with two groups to compare + as parameters, and the function must return 0 when a and b are equal, + a value larger than 0 when a is larger than b, + and a value smaller than 0 when a is smaller than b. +
groupsWidthstringnoneBy default, the width of the groups legend is adjusted to the group + names. A fixed width can be set for the groups legend by specifying the + groupsWidth as a string, for example "200px".
groupMinHeightint0The minimum height of each individual group even if they have no items. + The group height is set as the greatest value between items height and the groupMinHeight.
heightstring"auto"The height of the timeline in pixels, as a percentage, or "auto". + When the height is set to "auto", the height of the timeline is automatically + adjusted to fit the contents. If not, it is possible that events get stacked + so high, that they are not visible in the timeline. + When height is set to "auto", a minimum height can be specified with the + option minHeight. +
localestring"en"Choose locale for the Timeline. + The Built-in locale is english (en). + More locales are available in the file timeline-locales.js: + +
    +
  • Arabic, ar (aliases: ar_AR)
  • +
  • Catalan, ca (aliases: ca_ES)
  • +
  • Brazilian Portuguese, pt_BR
  • +
  • Chinese, zh (aliases: zh_CN, zh_TR)
  • +
  • Danish, da (aliases: da_DK)
  • +
  • Dutch, nl (aliases: nl_NL, nl_BE)
  • +
  • English, en (aliases: en_US, en_UK)
  • +
  • Finnish, fi (aliases: fi_FI)
  • +
  • French, fr (aliases: fr_FR, fr_BE, fr_CA)
  • +
  • German, de (aliases: de_DE, de_CH)
  • +
  • Hungarian, hu (aliases: hu_HU)
  • +
  • Japanese, ja (aliases: ja_JA)
  • +
  • Korean, ko (aliases: ko_KO)
  • +
  • Portuguese, pt (aliases: pt_PT)
  • +
  • Russian, ru (aliases: ru_RU)
  • +
  • Spanish, es (aliases: es_ES)
  • +
  • Turkish, tr (aliases: tr_TR)
  • +
+
maxDatenoneSet a maximum Date for the visible range. + It will not be possible to move beyond this maximum. + The maximum date itself is excluded. +
minDatenoneSet a minimum Date for the visible range. + It will not be possible to move beyond this minimum. +
minHeightNumber0Specifies a minimum height for the Timeline in pixels. + Useful when height is set to "auto". +
moveablebooleantrueIf true, the timeline is movable. + When the timeline moved, the rangechange events are fired. +
scalelinks.Timeline.StepDate.SCALEnoneSet a custom scale. Automatic scaling will be disabled. + Both options scale and step must be set. + + For example scale=SCALE.MINUTES and step=5 will result in minor steps of + 5 minutes, and major steps of an hour. + Available scales: MILLISECOND, SECOND, + MINUTE, HOUR, WEEKDAY, + DAY, MONTH, YEAR. + As step size, choose for example 1, 2, 5, or 10. +
selectablebooleantrueIf true, the events on the timeline are selectable. + When an event is selected, the select event is fired. +
snapEventsbooleantrueIf true, the start and end of an event will be snapped nice integer + values when moving or resizing the event. +
stackEventsbooleantrueIf true, the events are stacked above each other to prevent overlapping events. + This option cannot be used in combination with grouped events.
startDatenoneThe initial start date for the axis of the timeline. + If not provided, the earliest date present in the events is taken as start date.
stepnumbernoneSee option scale. +
stylestring"box"Specifies the style for the timeline events. + Choose from "dot" or "box". + Note that the content of the events may contain additional html formatting. + It is possible to implement custom styles using the method addItemType. +
showCurrentTimebooleantrueIf true, the timeline shows a red, vertical line displaying the current + time. This time can be synchronized with a server via the method + setCurrentTime.
showCustomTimebooleanfalseIf true, the timeline shows a blue vertical line displaying a custom + time. This line can be dragged by the user. + The custom time can be utilized to show a state in the past or in the future. + When the custom time bar is dragged by the user, an event is triggered, on + which the contents of the timeline can be changed in to the state at that + moment in time. +
showMajorLabelsbooleantrueBy default, the timeline shows both minor and major date labels on the + horizontal axis. + For example the minor labels show minutes and the major labels show hours. + When showMajorLabels is false, no major labels + are shown.
showMinorLabelsbooleantrueBy default, the timeline shows both minor and major date labels on the + horizontal axis. + For example the minor labels show minutes and the major labels show hours. + When showMinorLabels is false, no minor labels + are shown. When both showMajorLabels and + showMinorLabels are false, no horizontal axis will be + visible.
showButtonNewbooleanfalseShow the button "Create new event" in the a navigation menu. + Only applicable when option `editable` is true.
showNavigationbooleanfalseShow a navigation menu with buttons to move and zoom the timeline. + The zoom buttons are only visible when option `zoomable` is true, + and and move buttons are only visible when option `moveable` is true. +
timeChangeablebooleantrueIf false, items can not be moved or dragged horizontally (neither start time nor end time is changable). + This is useful when items should be editable but can only be changed regarding group or content (typical use case: scheduling events). See also the option groupsChangeable.
unselectablebooleantrueIf true, a selected event on the timeline can be un unselected. + If false, a selected event cannot be unselected unless when selecting + an other event. This means that as soon as the Timeline has a selected + event, it will remain in a state where there is always an event selected. + See also the option selectable. +
widthstring"100%"The width of the timeline in pixels or as a percentage.
zoomablebooleantrueIf true, the timeline is zoomable. + When the timeline is zoomed, the rangechange event is fired. +
zoomMaxNumber315360000000000Set a maximum zoom interval for the visible range in milliseconds. + It will not be possible to zoom out further than this maximum. + Default value equals about 10000 years. +
zoomMinNumber10Set a minimum zoom interval for the visible range in milliseconds. + It will not be possible to zoom in further than this minimum. +
+ +

Methods

+

+ The Timeline supports the following methods. +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
MethodReturn TypeDescription
addItem(properties)noneAdd an item to the Timeline. + The provided parameter properties is an Object, + containing parameters start (Date), end (Date), + content (String), group (String), + className (String), and editable (Boolean). + Parameters start and content are required, + the others are optional. +
addItemType(typeName, typeFactory)noneAdd a custom item type to the Timeline, extending the built-in types + "box" and "dot". + Parameter typeName is a String, + and typeFactory is a constructor implementing the abstract + prototype links.Timeline.Item. To use a custom type, + specify the option style with the name of the custom type. +
+ + See + example25_new_item_type.html + for an example, or study the implementations of links.Timeline.ItemBox, + links.Timeline.ItemRange, + and links.Timeline.ItemDot in the sourcecode of the Timeline. +
cancelAdd()noneAn add event can be canceled by calling the method + cancelAdd from within an event listener that listens for + add events. This is useful when additions need to be approved. +
cancelChange()noneA changed event can be canceled by calling the method + cancelChange from within an event listener that listens for + changed events. This is useful when changes need to be approved. +
cancelDelete()noneA delete event can be canceled by calling the method + cancelDelete from within an event listener that listens for + delete events. This is useful when deletions need to be + approved. +
changeItem(index, properties)noneChange properties of an existing item in the Timeline. + index (Number) is the index of the item. + The provided parameter properties is an Object, + and can contain parameters start (Date), + end (Date), content (String), + group (String), className (String), + and editable (Boolean). +
checkResize()noneCheck if the timeline container is resized, and if so, resize the timeline. + Useful when the webpage is resized.
deleteAllItems()noneDelete all items from the timeline. +
deleteItem(index, preventRender)noneDelete an existing item. + index (Number) is the index of the item. + preventRender (Boolean) is optional parameter to prevent re-render timeline immediately after delete (for multiple deletions). Default is false. +
draw(data, options)noneLoads data, sets options, adjusts the visible range, + and lastly (re)draws the Timeline. + data is a Google DataTable or a JSON Array. + options is an (optional) JSON Object containing values for options. +
getCluster(index)ObjectRetrieve the properties of a single cluster. The returned object can + contain parameters start (Date), and items that has + each item contained in the cluster. Each item have the same properties as in a call to + getItem. +
getCustomTime()DateRetrieve the custom time. + Only applicable when the option showCustomTime is true. + + time is a Date object. +
getData()Google DataTable or JSON ArrayRetrieve the current datatable from the Timeline.
getItem(index)ObjectRetrieve the properties of a single item. The returned object can + contain parameters start (Date), end (Date), + content (String), group (String).
getSelection()Array of selection elementsStandard getSelection() implementation. + Returns an array with one or multiple selections. Each selection contains + the property row (if an item is selected) or cluster if + a cluster is selected. +
getVisibleChartRange()An object with start and end propertiesReturns an object with start and end properties, + which each one of them is a Date object, + representing the currently visible time range.
getVisibleItems(start, end)Array of row indices Returns an array of item indices whose range or value falls within the + start and end properties, which each one of + them is a Date object. +
redraw()noneRedraw the timeline. + Reloads the (linked) data table and redraws the timeline when resized. + See also the method checkResize.
setAutoScale(enable)noneEnable or disable autoscaling. + If enable true or not defined, autoscaling is enabled. + If false, autoscaling is disabled. +
setCurrentTime(time)noneAdjust the current time of the timeline. This can for example be + changed to match the time of a server or a time offset of another time zone. + time is a Date object. +
setCustomTime(time)noneAdjust the custom time in the timeline. + Only applicable when the option showCustomTime is true. + time is a Date object. +
setData(data)noneSet new data in the Timeline. All settings (such as visible range) stay + unchanged, and the timeline must be redrawn afterwards with the method + redraw. + data is a Google DataTable object or a JSON Array. +
setSelection(selection)noneStandard setSelection(selection) implementation. + selection is an array with selection elements. The timeline + accepts only one selection element, which must have the property row. + The visible chart range will be moved such that the selected event is placed in the middle. + To unselect all items, use set selection with an empty array. + Example usage: timeline.setSelection([{row: 3}]);. +
setSize(width, height)noneParameters width and height are strings, + containing a new size for the timeline. Size can be provided in pixels + or in percentages.
setScale(scale, step)noneSet a custom scale. Automatic scaling will be disabled. + For example setScale(SCALE.MINUTES, 5) will result in minor steps of + 5 minutes, and major steps of an hour. + Available scales: MILLISECOND, SECOND, + MINUTE, HOUR, WEEKDAY, + DAY, MONTH, YEAR. + As step size, choose for example 1, 2, 5, or 10. +
setVisibleChartRange(start, end)noneSets the visible range (zoom) to the specified range. + Accepts two parameters of type Date that represent the first and last times + of the wanted selected visible range. + Set start to null to include everything from the earliest date to end; + set end to null to include everything from start to the last date.
setVisibleChartRangeNow()noneMove the visible range such that the current time is located in the + center of the timeline. This method does not trigger a + rangechange event.
setVisibleChartRangeAuto()noneAdjust the visible time range such that all events are visible.
move(moveFactor)noneMove the timeline the given movefactor to the left or right. + Start and end date will be adjusted, and the timeline will be redrawn. + For example, try moveFactor = 0.1 or -0.1. + moveFactor is a Number that determines the moving amount. + A positive value will move right, a negative value will move left. +
zoom(zoomFactor, zoomAroundDate)noneZoom the timeline the given zoomfactor in or out. Start and end date + will be adjusted, and the timeline will be redrawn. + You can optionally give a date around which to zoom. + For example, try zoomfactor = 0.1 or -0.1. + zoomFactor is a Number that determines the zooming amount. + Positive value will zoom in, negative value will zoom out. + zoomAroundDate is a Date around which to zoom and it is optional. +
+ +

Events

+ +

+ The Timeline fires events after an event is selected, the visible range changed, + or when an event is changed. The events can be cached by creating a listener. + Listeners can be registered using the event messages from the Google API + or event messages from the CHAP Links library. +

+

+ Here an example on how to catch a select event. +

+ +
+function onselect() {
+  var sel = mytimeline.getSelection();
+  if (sel.length) {
+    if (sel[0].row != undefined) {
+      var row = sel[0].row;
+      document.title = "event " + row + " selected";
+    }
+  }
+}
+
+google.visualization.events.addListener(mytimeline, 'select', onselect);
+// Or, when not using the Google API:
+//   links.events.addListener(mytimeline, 'select', onselect);
+
+ +

+ The following events are available. +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
nameDescriptionProperties
addAn event is about the be added. + Fired after the user has clicked the button "Add event" and created a new + event by clicking or moving an event into the Timeline. +
+ The selected row can be retrieved via the method getSelection, + and new start and end data can be read in the according row in the data table. +
+ The add event can be canceled by calling the method + cancelAdd from within the event listener. This is useful + when additions need to be approved. +
+ none +
changeThe properties of an event are changing. + Fired repeatedly while the user is modifying the start date or end + date of an event by moving (dragging) the event in the Timeline. +
+ The selected row can be retrieved via the method getSelection, + and new start and end data can be read in the according row in the data table. +
+
+ none +
changedThe properties of an event changed. + Fired after the user modified the start date or end date of an event + by moving (dragging) the event in the Timeline. +
+ The selected row can be retrieved via the method getSelection, + and new start and end data can be read in the according row in the data table. +
+ The changed event can be canceled by calling the method + cancelChange from within the event listener. This is useful + when changes need to be approved. +
+ none +
editAn event is about to be edited. + This event is fired when the user double clicks on an event. + The selected row can be retrieved via the method getSelection. + + none +
deleteAn event is about to be deleted. + Fired after the user clicked the "Delete Event" button on the right of + an event. +
+ The selected row can be retrieved via the method getSelection, + and new start and end data can be read in the according row in the data table. +
+ The delete event can be canceled by calling the method + cancelDelete from within the event listener. This is useful + when deletions need to be approved. +
+ none +
rangechangeVisible range is changing. Fired repeatedly while the user is modifying + the visible time by moving (dragging) the timeline, or by zooming (scrolling), + but not after a call to setVisibleChartRange or + setRangeToCurrentTime methods. + The new range can be retrieved by calling getVisibleChartRange + method. +
    +
  • start: Date. The start time of the visible range.
  • +
  • end: Date. The end time of the visible range.
  • +
+
rangechangedVisible range has been changed. Fired once after the user has modified + the visible time by moving (dragging) the timeline, or by zooming (scrolling), + but not after a call to setVisibleChartRange or + setRangeToCurrentTime methods. + The new range can be retrieved by calling getVisibleChartRange + method. +
    +
  • start: Date. The start time of the visible range.
  • +
  • end: Date. The end time of the visible range.
  • +
+
readyThe chart is ready for external method calls. + If you want to interact with the chart, and call methods after you draw it, + you should set up a listener for this event before you call the draw method, + and call them only after the event was fired.none
selectWhen the user clicks on an event or a cluster on the timeline, + the corresponding row in the data table is selected. + The visualization then fires this event. +
+ The selected row or cluster can be retrieved via the method getSelection. +
none
timechangeThe custom time bar is changing. Fired repeatedly when the user is + dragging the blue custom time bar, but not after a call to the + setCustomTime method. + The new custom time can be retrieved by calling getCustomTime + method. +
    +
  • time: Date. The new custom time.
  • +
+
timechangedThe custom time bar has been changed. Fired once after the user has + dragged the blue custom time bar, but not after a call to the + setCustomTime method. The new custom time can be retrieved by + calling getCustomTime method. +
    +
  • time: Date. The new custom time.
  • +
+
+ +

Styles

+

+ All parts of the Timeline have a class name and a default css style. + The styles can be overwritten, which enables full customization of the layout + of the Timeline. +

+ +

For example, to change the border and background color of all events, include the + following code inside the head of your html code or in a separate stylesheet.

+
+<style>
+div.timeline-event {
+  border-color: orange;
+  background-color: yellow;
+}
+</style>
+
+ + +

Structure

+ +

+ The events of type box, range, and dot + have the following structure. +

+ +

Box

+Box structure +

Range

+Range structure +

Dot

+Dot structure + + + +

Definitions

+ + ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Class nameDescriptionDefault style
div.timeline-frameThe frame contains the canvas. + It determines the size and the border of the Timeline. + border: 1px solid #BEBEBE;
+ overflow: hidden;
+
div.timeline-axisA horizontal line forms the axis. + border-color: #BEBEBE;
+ border-width: 1px;
+ border-top-style: solid;
+
div.timeline-axis-gridThe axis has a horizontal grid. + border-left-style: solid;
+ border-width: 1px;
+
div.timeline-axis-grid-minorThe axis has two grid lines: minor and major. When the scale is in days, + each day gets a minor grid line, and each month a major grid line. + border-color: #e5e5e5;
+
div.timeline-axis-grid-majorSee div.timeline-axis-grid-major + border-color: #bfbfbf;
+
div.timeline-axis-textBoth div.timeline-axis-text-minor and div.timeline-axis-text-major have + also the class div.timeline-axis-text. Use this class to set font styles + for both classes at once. + color: #4D4D4D;
+ padding: 3px;
+ white-space: nowrap;
+
div.timeline-axis-text-minorThe axis has two grid types: minor and major. When the scale is in days, + each day gets a minor text, and each month a major text. +
div.timeline-axis-text-majorSee div.timeline-axis-text-minor +
div.timeline-eventAll different events (box, dot, range, line) have the class div.timeline-event. + Use this class for example to set background and foreground colors. + color: #1A1A1A;
+ border-color: #97B0F8;
+ background-color: #D5DDF6;
+
div.timeline-event-selectedAll different events (box, dot, range, line) get the class + div.timeline-event-selected when they are currently selected. + Use this class to visually show the currently selected event. + border-color: #FFC200;
+ background-color: #FFF785;
+ z-index: 999;
+
div.timeline-event-boxBy default (option style="box"), events with only a start-date are drawn as a Box, having + this class name. + text-align: center;
+ border-style: solid;
+ border-width: 1px;
+ border-radius: 5px;
+ -moz-border-radius: 5px;
+
div.timeline-event-dotDivs with the class div.timeline-event-dot are used + when the option style="dot" is used: a dot is drawn left from the event text. + Dots are also drawn with style="box", to draw the dot at the axis below each event. + border-style: solid;
+ border-width: 5px;
+ border-radius: 5px;
+ -moz-border-radius: 5px;
+
div.timeline-event-rangeA range is drawn when an event has both start date and end date provided. + border-width: 1px;
+ border-style: solid;
+ border-radius: 2px;
+ -moz-border-radius: 2px;
+
div.timeline-event-range-drag-leftDrag area on the left side of the range + cursor: w-resize;
+ z-index: 1000;
+
div.timeline-event-range-drag-rightDrag area on the right side of the range + cursor: e-resize;
+ z-index: 1000;
+
div.timeline-event-lineWhen option style="box" is used (the default value), each event + is drawn as a box with a vertical line towards the axis. This line has the + class div.timeline-event-line. + border-left-width: 1px;
+ border-left-style: solid;
+
div.timeline-event-contentEach events from class box, dot, and range contain a div with class + div.timeline-event-content. This class contains the text of the event. + margin: 5px;
+ white-space: nowrap;
+ overflow: hidden;
+
div.timeline-groups-axisThe right border of the vertical axis showing the different event groups. + border-color: #BEBEBE;
+ border-width: 1px;
+
div.timeline-groups-textThe text labels of the event groups on the vertical axis. + color: #4D4D4D;
+ padding-left: 10px;
+ padding-right: 10px;
+
div.timeline-currenttime The vertical line showing the current time. + border-color: #FF7F6E;
+ border-right-width: 2px;
+ border-right-style: solid;
+
div.timeline-navigation The navigation menu. Only visible when option showNavigation + is true. + font-family: arial;
+ font-size: 20px;
+ font-weight: bold;
+ color: gray;
+ border: 1px solid #BEBEBE;
+ background-color: #F5F5F5;
+ border-radius: 5px;
+ -moz-border-radius: 5px;
+
div.timeline-navigation-new, div.timeline-navigation-delete, + div.timeline-navigation-zoom-in, div.timeline-navigation-zoom-out, + div.timeline-navigation-move-left, div.timeline-navigation-move-right The menu buttons in the navigation menu. + You can change the images to your own icon set. + + cursor: pointer;
+ margin: 2px 10px;
+ float: left;
+ text-decoration: none;
+ border-color: #BEBEBE;
+
div.timeline-navigation-newMenu button to create a new event. + + background: url('img/16/new.png') no-repeat center;
+
div.timeline-navigation-deleteButton to delete a selected event. + The button is displayed at the top right of a selected event. + + padding: 0px;
+ padding-left: 5px;
+ background: url('img/16/delete.png') no-repeat center;
+
div.timeline-navigation-zoom-inButton to zoom in on the timeline. + + background: url('img/16/zoomin.png') no-repeat center;
+
div.timeline-navigation-zoom-outButton to zoom out on the timeline. + + background: url('img/16/zoomout.png') no-repeat center;
+
div.timeline-navigation-move-leftButton to move the timeline to the right, + such that more of the left side of the timeline becomes visible. + + background: url('img/16/moveleft.png') no-repeat center;
+
div.timeline-navigation-move-rightButton to move the timeline to the left, + such that more of the right side of the timeline becomes visible. + + background: url('img/16/moveright.png') no-repeat center;
+
+ +

jQuery Themeroller integration

+

+ Most of jQuery widgets are theme aware in terms of jQuery Themeroller CSS framework. + If you would like to make the Timeline aware of jQuery themes, please include in your page a Themeroller theme of your choice + (ui.theme.css) and the CSS file timeline-theme.css. The file timeline.css should not be included. + These two files are enough to style the Timeline according to the selected theme. +

+ + +

Data Policy

+

+ All code and data are processed and rendered in the browser. No data is sent to any server. +

+ +
+ + diff --git a/static/lib/timeline/doc/jsdoc/files.html b/static/lib/timeline/doc/jsdoc/files.html new file mode 100644 index 00000000..256f1948 --- /dev/null +++ b/static/lib/timeline/doc/jsdoc/files.html @@ -0,0 +1,234 @@ + + + + + + JsDoc Reference - File Index + + + + + + + + + + +
+

File Index

+ + +
+

timeline.js

+ +
+ + + + +
+
+
+ + +
+
+ + Documentation generated by JsDoc Toolkit 2.3.2 on Wed Mar 04 2015 09:58:28 GMT+0100 (CET) +
+ + \ No newline at end of file diff --git a/static/lib/timeline/doc/jsdoc/index.html b/static/lib/timeline/doc/jsdoc/index.html new file mode 100644 index 00000000..c46afc9b --- /dev/null +++ b/static/lib/timeline/doc/jsdoc/index.html @@ -0,0 +1,282 @@ + + + + + + JsDoc Reference - Index + + + + + + + + + + +
+

Class Index

+ + +
+

_global_

+ +
+
+ +
+

Array

+ +
+
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+
+ + Documentation generated by JsDoc Toolkit 2.3.2 on Wed Mar 04 2015 09:58:28 GMT+0100 (CET) +
+ + \ No newline at end of file diff --git a/static/lib/timeline/doc/jsdoc/symbols/Array.html b/static/lib/timeline/doc/jsdoc/symbols/Array.html new file mode 100644 index 00000000..beb81d67 --- /dev/null +++ b/static/lib/timeline/doc/jsdoc/symbols/Array.html @@ -0,0 +1,392 @@ + + + + + + + JsDoc Reference - Array + + + + + + + + + + + + + +
+ +

+ + Built-In Namespace Array +

+ + +

+ + + + + + +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Method Summary
Method AttributesMethod Name and Description
  +
forEach(fn, scope) +
+
+
  +
indexOf(obj) +
+
+
+ + + + + + + + + + + + + + + +
+ Method Detail +
+ + +
+ + + forEach(fn, scope) + +
+
+ + +
+ Defined in: timeline.js. + + +
+ + + + +
+
Parameters:
+ +
+ fn + +
+
+ +
+ scope + +
+
+ +
+ + + + + + + + +
+ + +
+ + + indexOf(obj) + +
+
+ + +
+ Defined in: timeline.js. + + +
+ + + + +
+
Parameters:
+ +
+ obj + +
+
+ +
+ + + + + + + + + + + + + + + +
+
+ + + +
+ + Documentation generated by JsDoc Toolkit 2.3.2 on Wed Mar 04 2015 09:58:27 GMT+0100 (CET) +
+ + diff --git a/static/lib/timeline/doc/jsdoc/symbols/_global_.html b/static/lib/timeline/doc/jsdoc/symbols/_global_.html new file mode 100644 index 00000000..ae7ad237 --- /dev/null +++ b/static/lib/timeline/doc/jsdoc/symbols/_global_.html @@ -0,0 +1,325 @@ + + + + + + + JsDoc Reference - _global_ + + + + + + + + + + + + + +
+ +

+ + Built-In Namespace _global_ +

+ + +

+ + + + + + +

+ + + + + + + + + + + + + + + + + + + + + + + + +
Field Summary
Field AttributesField Name and Description
  +
+ listeners +
+
Remove all registered event listeners
+
+ + + + + + + + + + + + + + + +
+ Field Detail +
+ + +
+ + + listeners + +
+
+ Remove all registered event listeners + +
+ Defined in: timeline.js. + + +
+ + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + Documentation generated by JsDoc Toolkit 2.3.2 on Wed Mar 04 2015 09:58:27 GMT+0100 (CET) +
+ + diff --git a/static/lib/timeline/doc/jsdoc/symbols/links.Timeline.ClusterGenerator.html b/static/lib/timeline/doc/jsdoc/symbols/links.Timeline.ClusterGenerator.html new file mode 100644 index 00000000..23e066bd --- /dev/null +++ b/static/lib/timeline/doc/jsdoc/symbols/links.Timeline.ClusterGenerator.html @@ -0,0 +1,570 @@ + + + + + + + JsDoc Reference - links.Timeline.ClusterGenerator + + + + + + + + + + + + + +
+ +

+ + Class links.Timeline.ClusterGenerator +

+ + +

+ + + + + + +
Defined in: timeline.js. + +

+ + + + + + + + + + + + + + + + + +
Class Summary
Constructor AttributesConstructor Name and Description
  + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Method Summary
Method AttributesMethod Name and Description
  +
clear() +
+
Clear all cached clusters and data, and initialize all variables
+
  + +
Clear the cached clusters
+
  +
getClusters(scale, maxItems) +
+
Cluster the events which are too close together
+
  +
setData(items, options) +
+
Set the items to be clustered.
+
  + +
Update the current data set: clear cache, and recalculate the clustering for +the current level
+
+ + + + + + + + + +
+
+ Class Detail +
+ +
+ links.Timeline.ClusterGenerator(timeline) +
+ +
+ + +
+ + + + + +
+
Parameters:
+ +
+ {links.Timeline} timeline + +
+
+ +
+ + + + + + + + +
+ + + + + + + +
+ Method Detail +
+ + +
+ + + clear() + +
+
+ Clear all cached clusters and data, and initialize all variables + + +
+ + + + + + + + + + + +
+ + +
+ + + clearCache() + +
+
+ Clear the cached clusters + + +
+ + + + + + + + + + + +
+ + +
+ + {Item[]} + getClusters(scale, maxItems) + +
+
+ Cluster the events which are too close together + + +
+ + + + +
+
Parameters:
+ +
+ {Number} scale + +
+
The scale of the current window, + defined as (windowWidth / (endDate - startDate))
+ +
+ maxItems + +
+
+ +
+ + + + + +
+
Returns:
+ +
{Item[]} clusters
+ +
+ + + + +
+ + +
+ + + setData(items, options) + +
+
+ Set the items to be clustered. +This will clear cached clusters. + + +
+ + + + +
+
Parameters:
+ +
+ {Item[]} items + +
+
+ +
+ {Object} options + Optional +
+
Available options: + {boolean} applyOnChangedLevel + If true (default), the changed data is applied + as soon the cluster level changes. If false, + The changed data is applied immediately
+ +
+ + + + + + + + +
+ + +
+ + + updateData() + +
+
+ Update the current data set: clear cache, and recalculate the clustering for +the current level + + +
+ + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + Documentation generated by JsDoc Toolkit 2.3.2 on Wed Mar 04 2015 09:58:28 GMT+0100 (CET) +
+ + diff --git a/static/lib/timeline/doc/jsdoc/symbols/links.Timeline.Item.html b/static/lib/timeline/doc/jsdoc/symbols/links.Timeline.Item.html new file mode 100644 index 00000000..ccc1ba10 --- /dev/null +++ b/static/lib/timeline/doc/jsdoc/symbols/links.Timeline.Item.html @@ -0,0 +1,1039 @@ + + + + + + + JsDoc Reference - links.Timeline.Item + + + + + + + + + + + + + +
+ +

+ + Class links.Timeline.Item +

+ + +

+ + + + + + +
Defined in: timeline.js. + +

+ + + + + + + + + + + + + + + + + +
Class Summary
Constructor AttributesConstructor Name and Description
  +
+ links.Timeline.Item(data, options) +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Method Summary
Method AttributesMethod Name and Description
  + +
Creates the DOM for the item, depending on its type
+
  +
getImageUrls(imageUrls) +
+
Append all image urls present in the items DOM to the provided array
+
  +
getLeft(timeline) +
+
Calculate the left position of the item
+
  +
getRight(timeline) +
+
Calculate the right position of the item
+
  +
getWidth(timeline) +
+
Calculate the width of the item
+
  +
hideDOM(container) +
+
Remove the items DOM from the current HTML container
+
  + +
Check if the item is drawn in the timeline (i.e.
+
  +
isVisible(start, end) +
+
Check if the item is located in the visible area of the timeline, and +not part of a cluster
+
  +
reflow() +
+
Reflow the Item: retrieve its actual size from the DOM
+
  +
select() +
+
Select the item
+
  +
setPosition(left, right) +
+
Reposition the item
+
  +
showDOM(container) +
+
Append the items DOM to the given HTML container.
+
  + +
Unselect the item
+
  + +
Update the DOM of the item.
+
  +
updatePosition(timeline) +
+
Reposition the item, recalculate its left, top, and width, using the current +range of the timeline and the timeline options.
+
+ + + + + + + + + +
+
+ Class Detail +
+ +
+ links.Timeline.Item(data, options) +
+ +
+ + +
+ + + + + +
+
Parameters:
+ +
+ {Object} data + +
+
Object containing parameters start, end + content, group, type, editable.
+ +
+ {Object} options + Optional +
+
Options to set initial property values + {Number} top + {Number} left + {Number} width + {Number} height
+ +
+ + + + + + + + +
+ + + + + + + +
+ Method Detail +
+ + +
+ + {Element | undefined} + createDOM() + +
+
+ Creates the DOM for the item, depending on its type + + +
+ + + + + + + + +
+
Returns:
+ +
{Element | undefined}
+ +
+ + + + +
+ + +
+ + + getImageUrls(imageUrls) + +
+
+ Append all image urls present in the items DOM to the provided array + + +
+ + + + +
+
Parameters:
+ +
+ {String[]} imageUrls + +
+
+ +
+ + + + + + + + +
+ + +
+ + {Number} + getLeft(timeline) + +
+
+ Calculate the left position of the item + + +
+ + + + +
+
Parameters:
+ +
+ {links.Timeline} timeline + +
+
+ +
+ + + + + +
+
Returns:
+ +
{Number} left
+ +
+ + + + +
+ + +
+ + {Number} + getRight(timeline) + +
+
+ Calculate the right position of the item + + +
+ + + + +
+
Parameters:
+ +
+ {links.Timeline} timeline + +
+
+ +
+ + + + + +
+
Returns:
+ +
{Number} right
+ +
+ + + + +
+ + +
+ + {Number} + getWidth(timeline) + +
+
+ Calculate the width of the item + + +
+ + + + +
+
Parameters:
+ +
+ {links.Timeline} timeline + +
+
+ +
+ + + + + +
+
Returns:
+ +
{Number} width
+ +
+ + + + +
+ + +
+ + + hideDOM(container) + +
+
+ Remove the items DOM from the current HTML container + + +
+ + + + +
+
Parameters:
+ +
+ {Element} container + +
+
+ +
+ + + + + + + + +
+ + +
+ + {boolean} + isRendered() + +
+
+ Check if the item is drawn in the timeline (i.e. the DOM of the item is +attached to the frame. You may also just request the parameter item.rendered + + +
+ + + + + + + + +
+
Returns:
+ +
{boolean} rendered
+ +
+ + + + +
+ + +
+ + {boolean} + isVisible(start, end) + +
+
+ Check if the item is located in the visible area of the timeline, and +not part of a cluster + + +
+ + + + +
+
Parameters:
+ +
+ {Date} start + +
+
+ +
+ {Date} end + +
+
+ +
+ + + + + +
+
Returns:
+ +
{boolean} visible
+ +
+ + + + +
+ + +
+ + {boolean} + reflow() + +
+
+ Reflow the Item: retrieve its actual size from the DOM + + +
+ + + + + + + + +
+
Returns:
+ +
{boolean} resized returns true if the axis is resized
+ +
+ + + + +
+ + +
+ + + select() + +
+
+ Select the item + + +
+ + + + + + + + + + + +
+ + +
+ + + setPosition(left, right) + +
+
+ Reposition the item + + +
+ + + + +
+
Parameters:
+ +
+ {Number} left + +
+
+ +
+ {Number} right + +
+
+ +
+ + + + + + + + +
+ + +
+ + + showDOM(container) + +
+
+ Append the items DOM to the given HTML container. If items DOM does not yet +exist, it will be created first. + + +
+ + + + +
+
Parameters:
+ +
+ {Element} container + +
+
+ +
+ + + + + + + + +
+ + +
+ + + unselect() + +
+
+ Unselect the item + + +
+ + + + + + + + + + + +
+ + +
+ + + updateDOM() + +
+
+ Update the DOM of the item. This will update the content and the classes +of the item + + +
+ + + + + + + + + + + +
+ + +
+ + + updatePosition(timeline) + +
+
+ Reposition the item, recalculate its left, top, and width, using the current +range of the timeline and the timeline options. + + +
+ + + + +
+
Parameters:
+ +
+ {links.Timeline} timeline + +
+
+ +
+ + + + + + + + + + + + + + + +
+
+ + + +
+ + Documentation generated by JsDoc Toolkit 2.3.2 on Wed Mar 04 2015 09:58:28 GMT+0100 (CET) +
+ + diff --git a/static/lib/timeline/doc/jsdoc/symbols/links.Timeline.ItemBox.html b/static/lib/timeline/doc/jsdoc/symbols/links.Timeline.ItemBox.html new file mode 100644 index 00000000..5747be17 --- /dev/null +++ b/static/lib/timeline/doc/jsdoc/symbols/links.Timeline.ItemBox.html @@ -0,0 +1,895 @@ + + + + + + + JsDoc Reference - links.Timeline.ItemBox + + + + + + + + + + + + + +
+ +

+ + Class links.Timeline.ItemBox +

+ + +

+ +
Extends + links.Timeline.Item.
+ + + + + +
Defined in: timeline.js. + +

+ + + + + + + + + + + + + + + + + +
Class Summary
Constructor AttributesConstructor Name and Description
  +
+ links.Timeline.ItemBox(data, options) +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Method Summary
Method AttributesMethod Name and Description
  + +
Creates the DOM for the item, depending on its type
+
  +
getLeft(timeline) +
+
Calculate the left position of the item
+
  +
getRight(timeline) +
+
Calculate the right position of the item
+
  +
hideDOM() +
+
Remove the items DOM from the current HTML container, but keep the DOM in +memory
+
  +
isVisible(start, end) +
+
Check if the item is visible in the timeline, and not part of a cluster
+
  +
reflow() +
+
Reflow the Item: retrieve its actual size from the DOM
+
  +
select() +
+
Select the item
+
  +
setPosition(left, right) +
+
Reposition the item
+
  +
showDOM(container) +
+
Append the items DOM to the given HTML container.
+
  + +
Unselect the item
+
  + +
Update the DOM of the item.
+
  +
updatePosition(timeline) +
+
Reposition the item, recalculate its left, top, and width, using the current +range of the timeline and the timeline options.
+
+ + + +
+
Methods borrowed from class links.Timeline.Item:
getImageUrls, getWidth, isRendered
+
+ + + + + + + +
+
+ Class Detail +
+ +
+ links.Timeline.ItemBox(data, options) +
+ +
+ + +
+ + + + + +
+
Parameters:
+ +
+ {Object} data + +
+
Object containing parameters start, end + content, group, type, className, editable.
+ +
+ {Object} options + Optional +
+
Options to set initial property values + {Number} top + {Number} left + {Number} width + {Number} height
+ +
+ + + + + + + + +
+ + + + + + + +
+ Method Detail +
+ + +
+ + {Element | undefined} + createDOM() + +
+
+ Creates the DOM for the item, depending on its type + + +
+ + + + + + + + +
+
Returns:
+ +
{Element | undefined}
+ +
+ + + + +
+ + +
+ + {Number} + getLeft(timeline) + +
+
+ Calculate the left position of the item + + +
+ + + + +
+
Parameters:
+ +
+ {links.Timeline} timeline + +
+
+ +
+ + + + + +
+
Returns:
+ +
{Number} left
+ +
+ + + + +
+ + +
+ + {Number} + getRight(timeline) + +
+
+ Calculate the right position of the item + + +
+ + + + +
+
Parameters:
+ +
+ {links.Timeline} timeline + +
+
+ +
+ + + + + +
+
Returns:
+ +
{Number} right
+ +
+ + + + +
+ + +
+ + + hideDOM() + +
+
+ Remove the items DOM from the current HTML container, but keep the DOM in +memory + + +
+ + + + + + + + + + + +
+ + +
+ + {Boolean} + isVisible(start, end) + +
+
+ Check if the item is visible in the timeline, and not part of a cluster + + +
+ + + + +
+
Parameters:
+ +
+ {Date} start + +
+
+ +
+ {Date} end + +
+
+ +
+ + + + + +
+
Returns:
+ +
{Boolean} visible
+ +
+ + + + +
+ + +
+ + {boolean} + reflow() + +
+
+ Reflow the Item: retrieve its actual size from the DOM + + +
+ + + + + + + + +
+
Returns:
+ +
{boolean} resized returns true if the axis is resized
+ +
+ + + + +
+ + +
+ + + select() + +
+
+ Select the item + + +
+ + + + + + + + + + + +
+ + +
+ + + setPosition(left, right) + +
+
+ Reposition the item + + +
+ + + + +
+
Parameters:
+ +
+ {Number} left + +
+
+ +
+ {Number} right + +
+
+ +
+ + + + + + + + +
+ + +
+ + + showDOM(container) + +
+
+ Append the items DOM to the given HTML container. If items DOM does not yet +exist, it will be created first. + + +
+ + + + +
+
Parameters:
+ +
+ {Element} container + +
+
+ +
+ + + + + + + + +
+ + +
+ + + unselect() + +
+
+ Unselect the item + + +
+ + + + + + + + + + + +
+ + +
+ + + updateDOM() + +
+
+ Update the DOM of the item. This will update the content and the classes +of the item + + +
+ + + + + + + + + + + +
+ + +
+ + + updatePosition(timeline) + +
+
+ Reposition the item, recalculate its left, top, and width, using the current +range of the timeline and the timeline options. + + +
+ + + + +
+
Parameters:
+ +
+ {links.Timeline} timeline + +
+
+ +
+ + + + + + + + + + + + + + + +
+
+ + + +
+ + Documentation generated by JsDoc Toolkit 2.3.2 on Wed Mar 04 2015 09:58:28 GMT+0100 (CET) +
+ + diff --git a/static/lib/timeline/doc/jsdoc/symbols/links.Timeline.ItemDot.html b/static/lib/timeline/doc/jsdoc/symbols/links.Timeline.ItemDot.html new file mode 100644 index 00000000..264768e5 --- /dev/null +++ b/static/lib/timeline/doc/jsdoc/symbols/links.Timeline.ItemDot.html @@ -0,0 +1,893 @@ + + + + + + + JsDoc Reference - links.Timeline.ItemDot + + + + + + + + + + + + + +
+ +

+ + Class links.Timeline.ItemDot +

+ + +

+ +
Extends + links.Timeline.Item.
+ + + + + +
Defined in: timeline.js. + +

+ + + + + + + + + + + + + + + + + +
Class Summary
Constructor AttributesConstructor Name and Description
  +
+ links.Timeline.ItemDot(data, options) +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Method Summary
Method AttributesMethod Name and Description
  + +
Creates the DOM for the item, depending on its type
+
  +
getLeft(timeline) +
+
Calculate the left position of the item
+
  +
getRight(timeline) +
+
Calculate the right position of the item
+
  +
hideDOM() +
+
Remove the items DOM from the current HTML container
+
  +
isVisible(start, end) +
+
Check if the item is visible in the timeline, and not part of a cluster.
+
  +
reflow() +
+
Reflow the Item: retrieve its actual size from the DOM
+
  +
select() +
+
Select the item
+
  +
setPosition(left, right) +
+
Reposition the item
+
  +
showDOM(container) +
+
Append the items DOM to the given HTML container.
+
  + +
Unselect the item
+
  + +
Update the DOM of the item.
+
  +
updatePosition(timeline) +
+
Reposition the item, recalculate its left, top, and width, using the current +range of the timeline and the timeline options.
+
+ + + +
+
Methods borrowed from class links.Timeline.Item:
getImageUrls, getWidth, isRendered
+
+ + + + + + + +
+
+ Class Detail +
+ +
+ links.Timeline.ItemDot(data, options) +
+ +
+ + +
+ + + + + +
+
Parameters:
+ +
+ {Object} data + +
+
Object containing parameters start, end + content, group, type, className, editable.
+ +
+ {Object} options + Optional +
+
Options to set initial property values + {Number} top + {Number} left + {Number} width + {Number} height
+ +
+ + + + + + + + +
+ + + + + + + +
+ Method Detail +
+ + +
+ + {Element | undefined} + createDOM() + +
+
+ Creates the DOM for the item, depending on its type + + +
+ + + + + + + + +
+
Returns:
+ +
{Element | undefined}
+ +
+ + + + +
+ + +
+ + {Number} + getLeft(timeline) + +
+
+ Calculate the left position of the item + + +
+ + + + +
+
Parameters:
+ +
+ {links.Timeline} timeline + +
+
+ +
+ + + + + +
+
Returns:
+ +
{Number} left
+ +
+ + + + +
+ + +
+ + {Number} + getRight(timeline) + +
+
+ Calculate the right position of the item + + +
+ + + + +
+
Parameters:
+ +
+ {links.Timeline} timeline + +
+
+ +
+ + + + + +
+
Returns:
+ +
{Number} right
+ +
+ + + + +
+ + +
+ + + hideDOM() + +
+
+ Remove the items DOM from the current HTML container + + +
+ + + + + + + + + + + +
+ + +
+ + {boolean} + isVisible(start, end) + +
+
+ Check if the item is visible in the timeline, and not part of a cluster. + + +
+ + + + +
+
Parameters:
+ +
+ {Date} start + +
+
+ +
+ {Date} end + +
+
+ +
+ + + + + +
+
Returns:
+ +
{boolean} visible
+ +
+ + + + +
+ + +
+ + {boolean} + reflow() + +
+
+ Reflow the Item: retrieve its actual size from the DOM + + +
+ + + + + + + + +
+
Returns:
+ +
{boolean} resized returns true if the axis is resized
+ +
+ + + + +
+ + +
+ + + select() + +
+
+ Select the item + + +
+ + + + + + + + + + + +
+ + +
+ + + setPosition(left, right) + +
+
+ Reposition the item + + +
+ + + + +
+
Parameters:
+ +
+ {Number} left + +
+
+ +
+ {Number} right + +
+
+ +
+ + + + + + + + +
+ + +
+ + + showDOM(container) + +
+
+ Append the items DOM to the given HTML container. If items DOM does not yet +exist, it will be created first. + + +
+ + + + +
+
Parameters:
+ +
+ {Element} container + +
+
+ +
+ + + + + + + + +
+ + +
+ + + unselect() + +
+
+ Unselect the item + + +
+ + + + + + + + + + + +
+ + +
+ + + updateDOM() + +
+
+ Update the DOM of the item. This will update the content and the classes +of the item + + +
+ + + + + + + + + + + +
+ + +
+ + + updatePosition(timeline) + +
+
+ Reposition the item, recalculate its left, top, and width, using the current +range of the timeline and the timeline options. * + + +
+ + + + +
+
Parameters:
+ +
+ {links.Timeline} timeline + +
+
+ +
+ + + + + + + + + + + + + + + +
+
+ + + +
+ + Documentation generated by JsDoc Toolkit 2.3.2 on Wed Mar 04 2015 09:58:28 GMT+0100 (CET) +
+ + diff --git a/static/lib/timeline/doc/jsdoc/symbols/links.Timeline.ItemFloatingRange.html b/static/lib/timeline/doc/jsdoc/symbols/links.Timeline.ItemFloatingRange.html new file mode 100644 index 00000000..a44fd552 --- /dev/null +++ b/static/lib/timeline/doc/jsdoc/symbols/links.Timeline.ItemFloatingRange.html @@ -0,0 +1,906 @@ + + + + + + + JsDoc Reference - links.Timeline.ItemFloatingRange + + + + + + + + + + + + + +
+ +

+ + Class links.Timeline.ItemFloatingRange +

+ + +

+ +
Extends + links.Timeline.Item.
+ + + + + +
Defined in: timeline.js. + +

+ + + + + + + + + + + + + + + + + +
Class Summary
Constructor AttributesConstructor Name and Description
  + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Method Summary
Method AttributesMethod Name and Description
  + +
Creates the DOM for the item, depending on its type
+
  +
getLeft(timeline) +
+
Calculate the left position of the item
+
  +
getRight(timeline) +
+
Calculate the right position of the item
+
  +
getWidth(timeline) +
+
Calculate the width of the item
+
  +
hideDOM() +
+
Remove the items DOM from the current HTML container +The DOM will be kept in memory
+
  +
isVisible(start, end) +
+
Check if the item is visible in the timeline, and not part of a cluster
+
  +
select() +
+
Select the item
+
  +
setPosition(left, right) +
+
Reposition the item
+
  +
showDOM(container) +
+
Append the items DOM to the given HTML container.
+
  + +
Unselect the item
+
  + +
Update the DOM of the item.
+
  +
updatePosition(timeline) +
+
Reposition the item, recalculate its left, top, and width, using the current +range of the timeline and the timeline options.
+
+ + + +
+
Methods borrowed from class links.Timeline.Item:
getImageUrls, isRendered, reflow
+
+ + + + + + + +
+
+ Class Detail +
+ +
+ links.Timeline.ItemFloatingRange(data, options) +
+ +
+ + +
+ + + + + +
+
Parameters:
+ +
+ {Object} data + +
+
Object containing parameters start, end + content, group, type, className, editable.
+ +
+ {Object} options + Optional +
+
Options to set initial property values + {Number} top + {Number} left + {Number} width + {Number} height
+ +
+ + + + + + + + +
+ + + + + + + +
+ Method Detail +
+ + +
+ + {Element | undefined} + createDOM() + +
+
+ Creates the DOM for the item, depending on its type + + +
+ + + + + + + + +
+
Returns:
+ +
{Element | undefined}
+ +
+ + + + +
+ + +
+ + {Number} + getLeft(timeline) + +
+
+ Calculate the left position of the item + + +
+ + + + +
+
Parameters:
+ +
+ {links.Timeline} timeline + +
+
+ +
+ + + + + +
+
Returns:
+ +
{Number} left
+ +
+ + + + +
+ + +
+ + {Number} + getRight(timeline) + +
+
+ Calculate the right position of the item + + +
+ + + + +
+
Parameters:
+ +
+ {links.Timeline} timeline + +
+
+ +
+ + + + + +
+
Returns:
+ +
{Number} right
+ +
+ + + + +
+ + +
+ + {Number} + getWidth(timeline) + +
+
+ Calculate the width of the item + + +
+ + + + +
+
Parameters:
+ +
+ {links.Timeline} timeline + +
+
+ +
+ + + + + +
+
Returns:
+ +
{Number} width
+ +
+ + + + +
+ + +
+ + + hideDOM() + +
+
+ Remove the items DOM from the current HTML container +The DOM will be kept in memory + + +
+ + + + + + + + + + + +
+ + +
+ + {boolean} + isVisible(start, end) + +
+
+ Check if the item is visible in the timeline, and not part of a cluster + + +
+ + + + +
+
Parameters:
+ +
+ {Number} start + +
+
+ +
+ {Number} end + +
+
+ +
+ + + + + +
+
Returns:
+ +
{boolean} visible
+ +
+ + + + +
+ + +
+ + + select() + +
+
+ Select the item + + +
+ + + + + + + + + + + +
+ + +
+ + + setPosition(left, right) + +
+
+ Reposition the item + + +
+ + + + +
+
Parameters:
+ +
+ {Number} left + +
+
+ +
+ {Number} right + +
+
+ +
+ + + + + + + + +
+ + +
+ + + showDOM(container) + +
+
+ Append the items DOM to the given HTML container. If items DOM does not yet +exist, it will be created first. + + +
+ + + + +
+
Parameters:
+ +
+ {Element} container + +
+
+ +
+ + + + + + + + +
+ + +
+ + + unselect() + +
+
+ Unselect the item + + +
+ + + + + + + + + + + +
+ + +
+ + + updateDOM() + +
+
+ Update the DOM of the item. This will update the content and the classes +of the item + + +
+ + + + + + + + + + + +
+ + +
+ + + updatePosition(timeline) + +
+
+ Reposition the item, recalculate its left, top, and width, using the current +range of the timeline and the timeline options. * + + +
+ + + + +
+
Parameters:
+ +
+ {links.Timeline} timeline + +
+
+ +
+ + + + + + + + + + + + + + + +
+
+ + + +
+ + Documentation generated by JsDoc Toolkit 2.3.2 on Wed Mar 04 2015 09:58:28 GMT+0100 (CET) +
+ + diff --git a/static/lib/timeline/doc/jsdoc/symbols/links.Timeline.ItemRange.html b/static/lib/timeline/doc/jsdoc/symbols/links.Timeline.ItemRange.html new file mode 100644 index 00000000..09cd4ac2 --- /dev/null +++ b/static/lib/timeline/doc/jsdoc/symbols/links.Timeline.ItemRange.html @@ -0,0 +1,906 @@ + + + + + + + JsDoc Reference - links.Timeline.ItemRange + + + + + + + + + + + + + +
+ +

+ + Class links.Timeline.ItemRange +

+ + +

+ +
Extends + links.Timeline.Item.
+ + + + + +
Defined in: timeline.js. + +

+ + + + + + + + + + + + + + + + + +
Class Summary
Constructor AttributesConstructor Name and Description
  +
+ links.Timeline.ItemRange(data, options) +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Method Summary
Method AttributesMethod Name and Description
  + +
Creates the DOM for the item, depending on its type
+
  +
getLeft(timeline) +
+
Calculate the left position of the item
+
  +
getRight(timeline) +
+
Calculate the right position of the item
+
  +
getWidth(timeline) +
+
Calculate the width of the item
+
  +
hideDOM() +
+
Remove the items DOM from the current HTML container +The DOM will be kept in memory
+
  +
isVisible(start, end) +
+
Check if the item is visible in the timeline, and not part of a cluster
+
  +
select() +
+
Select the item
+
  +
setPosition(left, right) +
+
Reposition the item
+
  +
showDOM(container) +
+
Append the items DOM to the given HTML container.
+
  + +
Unselect the item
+
  + +
Update the DOM of the item.
+
  +
updatePosition(timeline) +
+
Reposition the item, recalculate its left, top, and width, using the current +range of the timeline and the timeline options.
+
+ + + +
+
Methods borrowed from class links.Timeline.Item:
getImageUrls, isRendered, reflow
+
+ + + + + + + +
+
+ Class Detail +
+ +
+ links.Timeline.ItemRange(data, options) +
+ +
+ + +
+ + + + + +
+
Parameters:
+ +
+ {Object} data + +
+
Object containing parameters start, end + content, group, type, className, editable.
+ +
+ {Object} options + Optional +
+
Options to set initial property values + {Number} top + {Number} left + {Number} width + {Number} height
+ +
+ + + + + + + + +
+ + + + + + + +
+ Method Detail +
+ + +
+ + {Element | undefined} + createDOM() + +
+
+ Creates the DOM for the item, depending on its type + + +
+ + + + + + + + +
+
Returns:
+ +
{Element | undefined}
+ +
+ + + + +
+ + +
+ + {Number} + getLeft(timeline) + +
+
+ Calculate the left position of the item + + +
+ + + + +
+
Parameters:
+ +
+ {links.Timeline} timeline + +
+
+ +
+ + + + + +
+
Returns:
+ +
{Number} left
+ +
+ + + + +
+ + +
+ + {Number} + getRight(timeline) + +
+
+ Calculate the right position of the item + + +
+ + + + +
+
Parameters:
+ +
+ {links.Timeline} timeline + +
+
+ +
+ + + + + +
+
Returns:
+ +
{Number} right
+ +
+ + + + +
+ + +
+ + {Number} + getWidth(timeline) + +
+
+ Calculate the width of the item + + +
+ + + + +
+
Parameters:
+ +
+ {links.Timeline} timeline + +
+
+ +
+ + + + + +
+
Returns:
+ +
{Number} width
+ +
+ + + + +
+ + +
+ + + hideDOM() + +
+
+ Remove the items DOM from the current HTML container +The DOM will be kept in memory + + +
+ + + + + + + + + + + +
+ + +
+ + {boolean} + isVisible(start, end) + +
+
+ Check if the item is visible in the timeline, and not part of a cluster + + +
+ + + + +
+
Parameters:
+ +
+ {Number} start + +
+
+ +
+ {Number} end + +
+
+ +
+ + + + + +
+
Returns:
+ +
{boolean} visible
+ +
+ + + + +
+ + +
+ + + select() + +
+
+ Select the item + + +
+ + + + + + + + + + + +
+ + +
+ + + setPosition(left, right) + +
+
+ Reposition the item + + +
+ + + + +
+
Parameters:
+ +
+ {Number} left + +
+
+ +
+ {Number} right + +
+
+ +
+ + + + + + + + +
+ + +
+ + + showDOM(container) + +
+
+ Append the items DOM to the given HTML container. If items DOM does not yet +exist, it will be created first. + + +
+ + + + +
+
Parameters:
+ +
+ {Element} container + +
+
+ +
+ + + + + + + + +
+ + +
+ + + unselect() + +
+
+ Unselect the item + + +
+ + + + + + + + + + + +
+ + +
+ + + updateDOM() + +
+
+ Update the DOM of the item. This will update the content and the classes +of the item + + +
+ + + + + + + + + + + +
+ + +
+ + + updatePosition(timeline) + +
+
+ Reposition the item, recalculate its left, top, and width, using the current +range of the timeline and the timeline options. * + + +
+ + + + +
+
Parameters:
+ +
+ {links.Timeline} timeline + +
+
+ +
+ + + + + + + + + + + + + + + +
+
+ + + +
+ + Documentation generated by JsDoc Toolkit 2.3.2 on Wed Mar 04 2015 09:58:28 GMT+0100 (CET) +
+ + diff --git a/static/lib/timeline/doc/jsdoc/symbols/links.Timeline.StepDate.html b/static/lib/timeline/doc/jsdoc/symbols/links.Timeline.StepDate.html new file mode 100644 index 00000000..9ccdea22 --- /dev/null +++ b/static/lib/timeline/doc/jsdoc/symbols/links.Timeline.StepDate.html @@ -0,0 +1,1016 @@ + + + + + + + JsDoc Reference - links.Timeline.StepDate + + + + + + + + + + + + + +
+ +

+ + Class links.Timeline.StepDate +

+ + +

+ + + + + + +
Defined in: timeline.js. + +

+ + + + + + + + + + + + + + + + + +
Class Summary
Constructor AttributesConstructor Name and Description
  +
+ links.Timeline.StepDate(start, end, minimumStep) +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Method Summary
Method AttributesMethod Name and Description
  +
addZeros(value, len) +
+
Add leading zeros to the given value to match the desired length.
+
  +
end() +
+
Check if the end date is reached
+
  + +
Get the current datetime
+
  +
getLabelMajor(options, date) +
+
Returns formatted text for the major axislabel, depending on the current +date and the scale.
+
  +
getLabelMinor(options, date) +
+
Returns formatted text for the minor axislabel, depending on the current +date and the scale.
+
  +
isMajor() +
+
Check if the current step is a major step (for example when the step +is DAY, a major step is each first day of the MONTH)
+
  +
next() +
+
Do the next step
+
  + +
Round the current date to the first minor date value +This must be executed once when the current date is set to start Date
+
  +
setAutoScale(enable) +
+
Enable or disable autoscaling
+
  +
setMinimumStep(minimumStep) +
+
Automatically determine the scale that bests fits the provided minimum step
+
  +
setRange(start, end, minimumStep) +
+
Set a new range +If minimumStep is provided, the step size is chosen as close as possible +to the minimumStep but larger than minimumStep.
+
  +
setScale(newScale, newStep) +
+
Set a custom scale.
+
  +
snap(date) +
+
Snap a date to a rounded value.
+
  +
start() +
+
Set the step iterator to the start date.
+
+ + + + + + + + + +
+
+ Class Detail +
+ +
+ links.Timeline.StepDate(start, end, minimumStep) +
+ +
+ + +
+ + + + + +
+
Parameters:
+ +
+ {Date} start + +
+
The start date, for example new Date(2010, 9, 21) + or new Date(2010, 9, 21, 23, 45, 00)
+ +
+ {Date} end + +
+
The end date
+ +
+ {Number} minimumStep + +
+
Optional. Minimum step size in milliseconds
+ +
+ + + + + + + + +
+ + + + + + + +
+ Method Detail +
+ + +
+ + {string} + addZeros(value, len) + +
+
+ Add leading zeros to the given value to match the desired length. +For example addZeros(123, 5) returns "00123" + + +
+ + + + +
+
Parameters:
+ +
+ {int} value + +
+
A value
+ +
+ {int} len + +
+
Desired final length
+ +
+ + + + + +
+
Returns:
+ +
{string} value with leading zeros
+ +
+ + + + +
+ + +
+ + {boolean} + end() + +
+
+ Check if the end date is reached + + +
+ + + + + + + + +
+
Returns:
+ +
{boolean} true if the current date has passed the end date
+ +
+ + + + +
+ + +
+ + {Date} + getCurrent() + +
+
+ Get the current datetime + + +
+ + + + + + + + +
+
Returns:
+ +
{Date} current The current date
+ +
+ + + + +
+ + +
+ + + getLabelMajor(options, date) + +
+
+ Returns formatted text for the major axislabel, depending on the current +date and the scale. For example when scale is MINUTE, the major scale is +hours, and the hour will be formatted as "hh". + + +
+ + + + +
+
Parameters:
+ +
+ {Object} options + +
+
+ +
+ {Date} date + Optional +
+
custom date. if not provided, current date is taken
+ +
+ + + + + + + + +
+ + +
+ + + getLabelMinor(options, date) + +
+
+ Returns formatted text for the minor axislabel, depending on the current +date and the scale. For example when scale is MINUTE, the current time is +formatted as "hh:mm". + + +
+ + + + +
+
Parameters:
+ +
+ {Object} options + +
+
+ +
+ {Date} date + Optional +
+
custom date. if not provided, current date is taken
+ +
+ + + + + + + + +
+ + +
+ + {boolean} + isMajor() + +
+
+ Check if the current step is a major step (for example when the step +is DAY, a major step is each first day of the MONTH) + + +
+ + + + + + + + +
+
Returns:
+ +
{boolean} true if current date is major, else false.
+ +
+ + + + +
+ + +
+ + + next() + +
+
+ Do the next step + + +
+ + + + + + + + + + + +
+ + +
+ + + roundToMinor() + +
+
+ Round the current date to the first minor date value +This must be executed once when the current date is set to start Date + + +
+ + + + + + + + + + + +
+ + +
+ + + setAutoScale(enable) + +
+
+ Enable or disable autoscaling + + +
+ + + + +
+
Parameters:
+ +
+ {boolean} enable + +
+
If true, autoascaling is set true
+ +
+ + + + + + + + +
+ + +
+ + + setMinimumStep(minimumStep) + +
+
+ Automatically determine the scale that bests fits the provided minimum step + + +
+ + + + +
+
Parameters:
+ +
+ {Number} minimumStep + +
+
The minimum step size in milliseconds
+ +
+ + + + + + + + +
+ + +
+ + + setRange(start, end, minimumStep) + +
+
+ Set a new range +If minimumStep is provided, the step size is chosen as close as possible +to the minimumStep but larger than minimumStep. If minimumStep is not +provided, the scale is set to 1 DAY. +The minimumStep should correspond with the onscreen size of about 6 characters + + +
+ + + + +
+
Parameters:
+ +
+ {Date} start + +
+
The start date and time.
+ +
+ {Date} end + +
+
The end date and time.
+ +
+ {int} minimumStep + +
+
Optional. Minimum step size in milliseconds
+ +
+ + + + + + + + +
+ + +
+ + + setScale(newScale, newStep) + +
+
+ Set a custom scale. Autoscaling will be disabled. +For example setScale(SCALE.MINUTES, 5) will result +in minor steps of 5 minutes, and major steps of an hour. + + +
+ + + + +
+
Parameters:
+ +
+ {links.Timeline.StepDate.SCALE} newScale + +
+
A scale. Choose from SCALE.MILLISECOND, + SCALE.SECOND, SCALE.MINUTE, SCALE.HOUR, + SCALE.WEEKDAY, SCALE.DAY, SCALE.MONTH, + SCALE.YEAR.
+ +
+ {Number} newStep + +
+
A step size, by default 1. Choose for + example 1, 2, 5, or 10.
+ +
+ + + + + + + + +
+ + +
+ + + snap(date) + +
+
+ Snap a date to a rounded value. The snap intervals are dependent on the +current scale and step. + + +
+ + + + +
+
Parameters:
+ +
+ {Date} date + +
+
the date to be snapped
+ +
+ + + + + + + + +
+ + +
+ + + start() + +
+
+ Set the step iterator to the start date. + + +
+ + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + Documentation generated by JsDoc Toolkit 2.3.2 on Wed Mar 04 2015 09:58:28 GMT+0100 (CET) +
+ + diff --git a/static/lib/timeline/doc/jsdoc/symbols/links.Timeline.html b/static/lib/timeline/doc/jsdoc/symbols/links.Timeline.html new file mode 100644 index 00000000..6badf5c1 --- /dev/null +++ b/static/lib/timeline/doc/jsdoc/symbols/links.Timeline.html @@ -0,0 +1,5812 @@ + + + + + + + JsDoc Reference - links.Timeline + + + + + + + + + + + + + +
+ +

+ + Class links.Timeline +

+ + +

+ + + + + + +
Defined in: timeline.js. + +

+ + + + + + + + + + + + + + + + + +
Class Summary
Constructor AttributesConstructor Name and Description
  +
+ links.Timeline(container, options) +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Method Summary
Method AttributesMethod Name and Description
<static>   +
links.Timeline.addClassName(elem, className) +
+
Adds one or more className's to the given elements style
+
<static>   +
links.Timeline.addEventListener(element, action, listener, useCapture) +
+
Add and event listener.
+
  +
addItem(itemData, preventRender) +
+
Add a new item.
+
  +
addItems(itemsData, preventRender) +
+
Add new items.
+
  +
addItemType(typeName, typeFactory) +
+
Add new type of items
+
  +
applyRange(start, end, zoomAroundDate) +
+
Apply a visible range.
+
  + +
Cancel creation of a new item +This method can be called insed an event listener which catches the "new" +event.
+
  + +
Cancel a change item +This method can be called insed an event listener which catches the "change" +event.
+
  + +
Cancel deletion of an item +This method can be called insed an event listener which catches the "delete" +event.
+
  +
changeItem(index, itemData, preventRender) +
+
Edit an item
+
  + +
Check if the timeline is resized, and if so, redraw the timeline.
+
  + +
This method clears the (internal) array this.items in a safe way: neatly +cleaning up the DOM, and accompanying arrays this.renderedItems and +the created clusters.
+
<static>   +
links.Timeline.clone(object) +
+
Shallow clone an object
+
  + +
Cluster the events
+
  +
collision(item1, item2, margin) +
+
Test if the two provided items collide +The items must have parameters left, right, top, and bottom.
+
  + +
Delete an item after a confirmation.
+
  +
createItem(itemData) +
+
Create an item object, containing all needed parameters
+
  + +
Delete all items
+
  + +
Delete all groups
+
  +
deleteItem(index, preventRender) +
+
Delete an item
+
  +
draw(data, options) +
+
Main drawing logic.
+
  + +
Filter the visible events
+
  +
finalItemsPosition(items, groupBase, group) +
+
+
<static>   +
links.Timeline.getAbsoluteLeft(elem) +
+
Retrieve the absolute left value of a DOM element
+
<static>   +
links.Timeline.getAbsoluteTop(elem) +
+
Retrieve the absolute top value of a DOM element
+
  +
getCluster(index) +
+
Retrieve the properties of a cluster.
+
  +
getClusterIndex(element) +
+
Find the cluster index from a given HTML element +If no cluster index is found, undefined is returned
+
  + +
Get current time.
+
  + +
Retrieve the current custom time.
+
  +
getData() +
+
Return the original data table.
+
  +
getDataRange(withMargin) +
+
Get the date range of the items.
+
  +
getGroup(groupName) +
+
Get a group by the group name.
+
  + +
Find the group from a given height in the timeline
+
  +
getGroupName(groupObj) +
+
Get the group name from a group object.
+
  +
getItem(index) +
+
Retrieve the properties of an item.
+
  +
getItemIndex(element) +
+
Find the item index from a given HTML element +If no item index is found, undefined is returned
+
  +
getItemsByGroup(items) +
+
+
  + +
Get options for the timeline.
+
<static>   +
links.Timeline.getPageX(event) +
+
Get the absolute, horizontal mouse position from an event.
+
<static>   +
links.Timeline.getPageY(event) +
+
Get the absolute, vertical mouse position from an event.
+
  + +
Retrieve the currently selected event
+
<static>   +
links.Timeline.getTarget(event) +
+
Get HTML element which is the target of the event
+
  + +
Retrieve the current visible range in the timeline.
+
  +
getVisibleItems(start, end) +
+
Find all elements within the start and end range +If no element is found, returns an empty array
+
  +
initialItemsPosition(items, groupBase) +
+
+
<static>   +
links.Timeline.isArray(obj) +
+
Check if given object is a Javascript Array
+
  +
isEditable(item) +
+
Check whether a given item is editable
+
  +
isSelected(index) +
+
Check if an item is currently selected
+
<static>   +
links.Timeline.mapColumnIds(dataTable) +
+
Retrieve a map with the column indexes of the columns by column name.
+
  +
move(moveFactor) +
+
Move the timeline the given movefactor to the left or right.
+
  +
onDblClick(event) +
+
Double click event occurred for an item
+
  +
onMouseDown(event) +
+
Start a moving operation inside the provided parent element
+
  +
onMouseMove(event) +
+
Perform moving operating.
+
  +
onMouseUp(event) +
+
Stop moving operating.
+
  +
onMouseWheel(event) +
+
Event handler for mouse wheel event, used to zoom the timeline +Code from http://adomas.org/javascript-mouse-wheel/
+
  +
onTouchEnd(event) +
+
Event handler for touchend event on mobile devices
+
  +
onTouchMove(event) +
+
Event handler for touchmove event on mobile devices
+
  +
onTouchStart(event) +
+
Event handler for touchstart event on mobile devices
+
<static>   +
links.Timeline.parseJSONDate(date) +
+
parse a JSON date
+
<static>   +
links.Timeline.preventDefault(event) +
+
Cancels the event if it is cancelable, without stopping further propagation of the event.
+
  + +
Calculate the factor and offset to convert a position on screen to the +corresponding date and vice versa.
+
  + +
Recalculate item properties: +- the height of each group.
+
  +
redraw() +
+
Redraw the timeline +Reloads the (linked) data table and redraws the timeline when resized.
+
  + +
Reflow the timeline axis.
+
  + +
Reflow the timeline frame
+
  + +
Reflow the size of the groups
+
  + +
Reflow all items, retrieve their actual size
+
<static>   +
links.Timeline.removeClassName(elem, className) +
+
Removes one or more className's from the given elements style
+
<static>   +
links.Timeline.removeEventListener(element, action, listener, useCapture) +
+
Remove an event listener from an element
+
  +
render(options) +
+
Re-render (reflow and repaint) all components of the Timeline: frame, axis, +items, .
+
  +
repaint() +
+
Repaint all components of the Timeline
+
  + +
Redraw the timeline axis with minor and major labels
+
  + +
Create characters used to determine the size of text on the axis
+
  + +
End of overwriting HTML DOM elements of the axis.
+
  + +
Repaint the horizontal line and background of the axis
+
  + +
Create a Major line for the axis at position x
+
  + +
Create a Major label for the axis at position x
+
  + +
Create a minor line for the axis at position x
+
  + +
Create a minor label for the axis at position x
+
  + +
Initialize redraw of the axis.
+
  + +
Redraw the current time bar
+
  + +
Redraw the custom time bar
+
  + +
Redraw the delete button, on the top right of the currently selected item +if there is no item selected, the button is hidden.
+
  + +
Redraw the drag areas.
+
  + +
repaint the Timeline frame
+
  + +
Redraw the group labels
+
  + +
Repaint all items
+
  + +
Create the navigation buttons for zooming and moving
+
  + +
Convert a position on screen (pixels) to a datetime +Before this method can be used, the method calcConversionFactor must be +executed once.
+
  +
selectCluster(index) +
+
Select an cluster by its index
+
  +
selectItem(index) +
+
Select an item by its index
+
  +
setAutoScale(enable) +
+
Enable or disable autoscaling
+
  + +
Set current time.
+
  +
setCustomTime(time) +
+
Set custom time.
+
  +
setData(data) +
+
Set data for the timeline
+
  +
setOptions(options) +
+
Set options for the timeline.
+
  +
setScale(scale, step) +
+
Set a custom scale.
+
  +
setSelection(selection) +
+
Select an event.
+
  +
setSize(width, height) +
+
Set a new size for the timeline
+
  +
setVisibleChartRange(start, end, redraw) +
+
Set a new value for the visible range int the timeline.
+
  + +
Change the visible chart range such that all items become visible
+
  + +
Adjust the visible range such that the current time is located in the center +of the timeline
+
  + +
Adjust vertical positions of the events such that they don't overlap each +other.
+
  + +
Cancel any running animation
+
  +
stackItems(animate) +
+
Stack the items such that they don't overlap.
+
  +
stackItemsCheckOverlap(items, itemIndex, itemStart, itemEnd) +
+
Check if the destiny position of given item overlaps with any +of the other items from index itemStart to itemEnd.
+
  +
stackMoveOneStep(currentItems, finalItems) +
+
Move the events one step in the direction of their final positions
+
  +
stackMoveToFinal(currentItems, finalItems) +
+
Move the events from their current position to the final position
+
  +
stackOrder(items) +
+
Order the items in the array this.items.
+
<static>   +
links.Timeline.stopPropagation(event) +
+
Stop event propagation
+
  +
timeToScreen(time) +
+
Convert a datetime (Date object) into a position on the screen +Before this method can be used, the method calcConversionFactor must be +executed once.
+
  +
trigger(event) +
+
fire an event
+
  + +
Unselect the currently selected event (if any)
+
  +
updateData(index, values) +
+
Update the original data with changed start, end or group.
+
  +
zoom(zoomFactor, zoomAroundDate) +
+
Zoom the timeline the given zoomfactor in or out.
+
+ + + + + + + + + +
+
+ Class Detail +
+ +
+ links.Timeline(container, options) +
+ +
+ + +
+ + + + + +
+
Parameters:
+ +
+ {Element} container + +
+
The DOM element in which the Timeline will + be created. Normally a div element.
+ +
+ {Object} options + +
+
A name/value map containing settings for the + timeline. Optional.
+ +
+ + + + + + + + +
+ + + + + + + +
+ Method Detail +
+ + +
<static> + + + links.Timeline.addClassName(elem, className) + +
+
+ Adds one or more className's to the given elements style + + +
+ + + + +
+
Parameters:
+ +
+ {Element} elem + +
+
+ +
+ {String} className + +
+
+ +
+ + + + + + + + +
+ + +
<static> + + + links.Timeline.addEventListener(element, action, listener, useCapture) + +
+
+ Add and event listener. Works for all browsers + + +
+ + + + +
+
Parameters:
+ +
+ {Element} element + +
+
An html element
+ +
+ {string} action + +
+
The action, for example "click", + without the prefix "on"
+ +
+ {function} listener + +
+
The callback function to be executed
+ +
+ {boolean} useCapture + +
+
+ +
+ + + + + + + + +
+ + +
+ + + addItem(itemData, preventRender) + +
+
+ Add a new item. + + +
+ + + + +
+
Parameters:
+ +
+ {Object} itemData + +
+
Object containing item properties:
+ {Date} start (required), + {Date} end (optional), + {String} content (required), + {String} group (optional) + {String} className (optional) + {Boolean} editable (optional) + {String} type (optional)
+ +
+ {boolean} preventRender + Optional, Default: false +
+
Do not re-render timeline if true
+ +
+ + + + + + + + +
+ + +
+ + + addItems(itemsData, preventRender) + +
+
+ Add new items. + + +
+ + + + +
+
Parameters:
+ +
+ {Array} itemsData + +
+
An array containing Objects. + The objects must have the following parameters: + {Date} start, + {Date} end, + {String} content with text or HTML code, + {String} group (optional) + {String} className (optional) + {String} editable (optional) + {String} type (optional)
+ +
+ {boolean} preventRender + Optional, Default: false +
+
Do not re-render timeline if true
+ +
+ + + + + + + + +
+ + +
+ + + addItemType(typeName, typeFactory) + +
+
+ Add new type of items + + +
+ + + + +
+
Parameters:
+ +
+ {String} typeName + +
+
Name of new type
+ +
+ {links.Timeline.Item} typeFactory + +
+
Constructor of items
+ +
+ + + + + + + + +
+ + +
+ + + applyRange(start, end, zoomAroundDate) + +
+
+ Apply a visible range. The range is limited to feasible maximum and minimum +range. + + +
+ + + + +
+
Parameters:
+ +
+ {Date} start + +
+
+ +
+ {Date} end + +
+
+ +
+ {Date} zoomAroundDate + +
+
Optional. Date around which will be zoomed.
+ +
+ + + + + + + + +
+ + +
+ + + cancelAdd() + +
+
+ Cancel creation of a new item +This method can be called insed an event listener which catches the "new" +event. Creation of the new the event will be undone. + + +
+ + + + + + + + + + + +
+ + +
+ + + cancelChange() + +
+
+ Cancel a change item +This method can be called insed an event listener which catches the "change" +event. The changed event position will be undone. + + +
+ + + + + + + + + + + +
+ + +
+ + + cancelDelete() + +
+
+ Cancel deletion of an item +This method can be called insed an event listener which catches the "delete" +event. Deletion of the event will be undone. + + +
+ + + + + + + + + + + +
+ + +
+ + + changeItem(index, itemData, preventRender) + +
+
+ Edit an item + + +
+ + + + +
+
Parameters:
+ +
+ {Number} index + +
+
+ +
+ {Object} itemData + +
+
Object containing item properties:
+ {Date} start (required), + {Date} end (optional), + {String} content (required), + {String} group (optional)
+ +
+ {boolean} preventRender + Optional, Default: false +
+
Do not re-render timeline if true
+ +
+ + + + + + + + +
+ + +
+ + + checkResize() + +
+
+ Check if the timeline is resized, and if so, redraw the timeline. +Useful when the webpage is resized. + + +
+ + + + + + + + + + + +
+ + +
+ + + clearItems() + +
+
+ This method clears the (internal) array this.items in a safe way: neatly +cleaning up the DOM, and accompanying arrays this.renderedItems and +the created clusters. + + +
+ + + + + + + + + + + +
+ + +
<static> + + {Object} + links.Timeline.clone(object) + +
+
+ Shallow clone an object + + +
+ + + + +
+
Parameters:
+ +
+ {Object} object + +
+
+ +
+ + + + + +
+
Returns:
+ +
{Object} clone
+ +
+ + + + +
+ + +
+ + + clusterItems() + +
+
+ Cluster the events + + +
+ + + + + + + + + + + +
+ + +
+ + {boolean} + collision(item1, item2, margin) + +
+
+ Test if the two provided items collide +The items must have parameters left, right, top, and bottom. + + +
+ + + + +
+
Parameters:
+ +
+ {Element} item1 + +
+
The first item
+ +
+ {Element} item2 + +
+
The second item
+ +
+ {Number} margin + +
+
A minimum required margin. Optional. + If margin is provided, the two items will be + marked colliding when they overlap or + when the margin between the two is smaller than + the requested margin.
+ +
+ + + + + +
+
Returns:
+ +
{boolean} true if item1 and item2 collide, else false
+ +
+ + + + +
+ + +
+ + + confirmDeleteItem(index) + +
+
+ Delete an item after a confirmation. +The deletion can be cancelled by executing .cancelDelete() during the +triggered event 'delete'. + + +
+ + + + +
+
Parameters:
+ +
+ {int} index + +
+
Index of the item to be deleted
+ +
+ + + + + + + + +
+ + +
+ + {Object} + createItem(itemData) + +
+
+ Create an item object, containing all needed parameters + + +
+ + + + +
+
Parameters:
+ +
+ {Object} itemData + +
+
Object containing parameters start, end + content, group.
+ +
+ + + + + +
+
Returns:
+ +
{Object} item
+ +
+ + + + +
+ + +
+ + + deleteAllItems() + +
+
+ Delete all items + + +
+ + + + + + + + + + + +
+ + +
+ + + deleteGroups() + +
+
+ Delete all groups + + +
+ + + + + + + + + + + +
+ + +
+ + + deleteItem(index, preventRender) + +
+
+ Delete an item + + +
+ + + + +
+
Parameters:
+ +
+ {int} index + +
+
Index of the item to be deleted
+ +
+ {boolean} preventRender + Optional, Default: false +
+
Do not re-render timeline if true + (optimization for multiple delete)
+ +
+ + + + + + + + +
+ + +
+ + + draw(data, options) + +
+
+ Main drawing logic. This is the function that needs to be called +in the html page, to draw the timeline. + +A data table with the events must be provided, and an options table. + + +
+ + + + +
+
Parameters:
+ +
+ {google.visualization.DataTable} data + +
+
The data containing the events for the timeline. + Object DataTable is defined in + google.visualization.DataTable
+ +
+ {Object} options + +
+
A name/value map containing settings for the + timeline. Optional. The use of options here + is deprecated. Pass timeline options in the + constructor or use setOptions()
+ +
+ + + + + + + + +
+ + +
+ + + filterItems() + +
+
+ Filter the visible events + + +
+ + + + + + + + + + + +
+ + +
+ + + finalItemsPosition(items, groupBase, group) + +
+
+ + + +
+ + + + +
+
Parameters:
+ +
+ items + +
+
+ +
+ groupBase + +
+
+ +
+ group + +
+
+ +
+ + + + + + + + +
+ + +
<static> + + {number} + links.Timeline.getAbsoluteLeft(elem) + +
+
+ Retrieve the absolute left value of a DOM element + + +
+ + + + +
+
Parameters:
+ +
+ {Element} elem + +
+
A dom element, for example a div
+ +
+ + + + + +
+
Returns:
+ +
{number} left The absolute left position of this element + in the browser page.
+ +
+ + + + +
+ + +
<static> + + {number} + links.Timeline.getAbsoluteTop(elem) + +
+
+ Retrieve the absolute top value of a DOM element + + +
+ + + + +
+
Parameters:
+ +
+ {Element} elem + +
+
A dom element, for example a div
+ +
+ + + + + +
+
Returns:
+ +
{number} top The absolute top position of this element + in the browser page.
+ +
+ + + + +
+ + +
+ + {Object} + getCluster(index) + +
+
+ Retrieve the properties of a cluster. + + +
+ + + + +
+
Parameters:
+ +
+ {Number} index + +
+
+ +
+ + + + + +
+
Returns:
+ +
{Object} clusterdata Object containing cluster properties:
+ {Date} start (required), + {String} type (optional) + {Array} array with item data as is in getItem()
+ +
+ + + + +
+ + +
+ + {Number | undefined} + getClusterIndex(element) + +
+
+ Find the cluster index from a given HTML element +If no cluster index is found, undefined is returned + + +
+ + + + +
+
Parameters:
+ +
+ {Element} element + +
+
+ +
+ + + + + +
+
Returns:
+ +
{Number | undefined} index
+ +
+ + + + +
+ + +
+ + {Date} + getCurrentTime() + +
+
+ Get current time. The time can have an offset from the real time, when +the current time has been changed via the method setCurrentTime. + + +
+ + + + + + + + +
+
Returns:
+ +
{Date} time
+ +
+ + + + +
+ + +
+ + {Date} + getCustomTime() + +
+
+ Retrieve the current custom time. + + +
+ + + + + + + + +
+
Returns:
+ +
{Date} customTime
+ +
+ + + + +
+ + +
+ + {google.visualization.DataTable | Array} + getData() + +
+
+ Return the original data table. + + +
+ + + + + + + + +
+
Returns:
+ +
{google.visualization.DataTable | Array} data
+ +
+ + + + +
+ + +
+ + {Object} + getDataRange(withMargin) + +
+
+ Get the date range of the items. + + +
+ + + + +
+
Parameters:
+ +
+ {boolean} withMargin + Optional +
+
If true, 5% of whitespace is added to the + left and right of the range. Default is false.
+ +
+ + + + + +
+
Returns:
+ +
{Object} range An object with parameters min and max. + - {Date} min is the lowest start date of the items + - {Date} max is the highest start or end date of the items + If no data is available, the values of min and max + will be undefined
+ +
+ + + + +
+ + +
+ + {Object} + getGroup(groupName) + +
+
+ Get a group by the group name. When the group does not exist, +it will be created. + + +
+ + + + +
+
Parameters:
+ +
+ {String} groupName + +
+
the name of the group
+ +
+ + + + + +
+
Returns:
+ +
{Object} groupObject
+ +
+ + + + +
+ + +
+ + {Object | undefined} + getGroupFromHeight(height) + +
+
+ Find the group from a given height in the timeline + + +
+ + + + +
+
Parameters:
+ +
+ {Number} height + +
+
Height in the timeline
+ +
+ + + + + +
+
Returns:
+ +
{Object | undefined} group The group object, or undefined if out + of range
+ +
+ + + + +
+ + +
+ + {String} + getGroupName(groupObj) + +
+
+ Get the group name from a group object. + + +
+ + + + +
+
Parameters:
+ +
+ {Object} groupObj + +
+
+ +
+ + + + + +
+
Returns:
+ +
{String} groupName the name of the group, or undefined when group + was not provided
+ +
+ + + + +
+ + +
+ + {Object} + getItem(index) + +
+
+ Retrieve the properties of an item. + + +
+ + + + +
+
Parameters:
+ +
+ {Number} index + +
+
+ +
+ + + + + +
+
Returns:
+ +
{Object} itemData Object containing item properties:
+ {Date} start (required), + {Date} end (optional), + {String} content (required), + {String} group (optional), + {String} className (optional) + {boolean} editable (optional) + {String} type (optional)
+ +
+ + + + +
+ + +
+ + {Number | undefined} + getItemIndex(element) + +
+
+ Find the item index from a given HTML element +If no item index is found, undefined is returned + + +
+ + + + +
+
Parameters:
+ +
+ {Element} element + +
+
+ +
+ + + + + +
+
Returns:
+ +
{Number | undefined} index
+ +
+ + + + +
+ + +
+ + + getItemsByGroup(items) + +
+
+ + + +
+ + + + +
+
Parameters:
+ +
+ items + +
+
+ +
+ + + + + + + + +
+ + +
+ + + getOptions() + +
+
+ Get options for the timeline. + + +
+ + + + + + + + +
+
Returns:
+ +
the options object
+ +
+ + + + +
+ + +
<static> + + {Number} + links.Timeline.getPageX(event) + +
+
+ Get the absolute, horizontal mouse position from an event. + + +
+ + + + +
+
Parameters:
+ +
+ {Event} event + +
+
+ +
+ + + + + +
+
Returns:
+ +
{Number} pageX
+ +
+ + + + +
+ + +
<static> + + {Number} + links.Timeline.getPageY(event) + +
+
+ Get the absolute, vertical mouse position from an event. + + +
+ + + + +
+
Parameters:
+ +
+ {Event} event + +
+
+ +
+ + + + + +
+
Returns:
+ +
{Number} pageY
+ +
+ + + + +
+ + +
+ + {Array} + getSelection() + +
+
+ Retrieve the currently selected event + + +
+ + + + + + + + +
+
Returns:
+ +
{Array} sel An array with a column row, containing the row number + of the selected event. If there is no selection, an + empty array is returned.
+ +
+ + + + +
+ + +
<static> + + {Element} + links.Timeline.getTarget(event) + +
+
+ Get HTML element which is the target of the event + + +
+ + + + +
+
Parameters:
+ +
+ {Event} event + +
+
+ +
+ + + + + +
+
Returns:
+ +
{Element} target element
+ +
+ + + + +
+ + +
+ + {Object} + getVisibleChartRange() + +
+
+ Retrieve the current visible range in the timeline. + + +
+ + + + + + + + +
+
Returns:
+ +
{Object} An object with start and end properties
+ +
+ + + + +
+ + +
+ + + getVisibleItems(start, end) + +
+
+ Find all elements within the start and end range +If no element is found, returns an empty array + + +
+ + + + +
+
Parameters:
+ +
+ start + +
+
time
+ +
+ end + +
+
time
+ +
+ + + + + +
+
Returns:
+ +
Array itemsInRange
+ +
+ + + + +
+ + +
+ + + initialItemsPosition(items, groupBase) + +
+
+ + + +
+ + + + +
+
Parameters:
+ +
+ items + +
+
+ +
+ groupBase + +
+
+ +
+ + + + + + + + +
+ + +
<static> + + {Boolean} + links.Timeline.isArray(obj) + +
+
+ Check if given object is a Javascript Array + + +
+ + + + +
+
Parameters:
+ +
+ {*} obj + +
+
+ +
+ + + + + +
+
Returns:
+ +
{Boolean} isArray true if the given object is an array
+ +
+ + + + +
+ + +
+ + {boolean} + isEditable(item) + +
+
+ Check whether a given item is editable + + +
+ + + + +
+
Parameters:
+ +
+ {links.Timeline.Item} item + +
+
+ +
+ + + + + +
+
Returns:
+ +
{boolean} editable
+ +
+ + + + +
+ + +
+ + {boolean} + isSelected(index) + +
+
+ Check if an item is currently selected + + +
+ + + + +
+
Parameters:
+ +
+ {Number} index + +
+
+ +
+ + + + + +
+
Returns:
+ +
{boolean} true if row is selected, else false
+ +
+ + + + +
+ + +
<static> + + {map} + links.Timeline.mapColumnIds(dataTable) + +
+
+ Retrieve a map with the column indexes of the columns by column name. +For example, the method returns the map + { + start: 0, + end: 1, + content: 2, + group: undefined, + className: undefined + editable: undefined + type: undefined + } + + +
+ + + + +
+
Parameters:
+ +
+ {google.visualization.DataTable} dataTable + +
+
+ +
+ + + + + + + + +
+ + +
+ + + move(moveFactor) + +
+
+ Move the timeline the given movefactor to the left or right. Start and end +date will be adjusted, and the timeline will be redrawn. +For example, try moveFactor = 0.1 or -0.1 + + +
+ + + + +
+
Parameters:
+ +
+ {Number} moveFactor + +
+
Moving amount. Positive value will move right, + negative value will move left
+ +
+ + + + + + + + +
+ + +
+ + + onDblClick(event) + +
+
+ Double click event occurred for an item + + +
+ + + + +
+
Parameters:
+ +
+ {Event} event + +
+
+ +
+ + + + + + + + +
+ + +
+ + + onMouseDown(event) + +
+
+ Start a moving operation inside the provided parent element + + +
+ + + + +
+
Parameters:
+ +
+ {Event} event + +
+
The event that occurred (required for + retrieving the mouse position)
+ +
+ + + + + + + + +
+ + +
+ + + onMouseMove(event) + +
+
+ Perform moving operating. +This function activated from within the funcion links.Timeline.onMouseDown(). + + +
+ + + + +
+
Parameters:
+ +
+ {Event} event + +
+
Well, eehh, the event
+ +
+ + + + + + + + +
+ + +
+ + + onMouseUp(event) + +
+
+ Stop moving operating. +This function activated from within the funcion links.Timeline.onMouseDown(). + + +
+ + + + +
+
Parameters:
+ +
+ {event} event + +
+
The event
+ +
+ + + + + + + + +
+ + +
+ + + onMouseWheel(event) + +
+
+ Event handler for mouse wheel event, used to zoom the timeline +Code from http://adomas.org/javascript-mouse-wheel/ + + +
+ + + + +
+
Parameters:
+ +
+ {Event} event + +
+
The event
+ +
+ + + + + + + + +
+ + +
+ + + onTouchEnd(event) + +
+
+ Event handler for touchend event on mobile devices + + +
+ + + + +
+
Parameters:
+ +
+ event + +
+
+ +
+ + + + + + + + +
+ + +
+ + + onTouchMove(event) + +
+
+ Event handler for touchmove event on mobile devices + + +
+ + + + +
+
Parameters:
+ +
+ event + +
+
+ +
+ + + + + + + + +
+ + +
+ + + onTouchStart(event) + +
+
+ Event handler for touchstart event on mobile devices + + +
+ + + + +
+
Parameters:
+ +
+ event + +
+
+ +
+ + + + + + + + +
+ + +
<static> + + {Date} + links.Timeline.parseJSONDate(date) + +
+
+ parse a JSON date + + +
+ + + + +
+
Parameters:
+ +
+ {Date | String | Number} date + +
+
Date object to be parsed. Can be: + - a Date object like new Date(), + - a long like 1356970529389, + an ISO String like "2012-12-31T16:16:07.213Z", + or a .Net Date string like + "\/Date(1356970529389)\/"
+ +
+ + + + + +
+
Returns:
+ +
{Date} parsedDate
+ +
+ + + + +
+ + +
<static> + + + links.Timeline.preventDefault(event) + +
+
+ Cancels the event if it is cancelable, without stopping further propagation of the event. + + +
+ + + + +
+
Parameters:
+ +
+ event + +
+
+ +
+ + + + + + + + +
+ + +
+ + + recalcConversion() + +
+
+ Calculate the factor and offset to convert a position on screen to the +corresponding date and vice versa. +After the method calcConversionFactor is executed once, the methods screenToTime and +timeToScreen can be used. + + +
+ + + + + + + + + + + +
+ + +
+ + {boolean} + recalcItems() + +
+
+ Recalculate item properties: +- the height of each group. +- the actualHeight, from the stacked items or the sum of the group heights + + +
+ + + + + + + + +
+
Returns:
+ +
{boolean} resized returns true if any of the items properties is + changed
+ +
+ + + + +
+ + +
+ + + redraw() + +
+
+ Redraw the timeline +Reloads the (linked) data table and redraws the timeline when resized. +See also the method checkResize + + +
+ + + + + + + + + + + +
+ + +
+ + {boolean} + reflowAxis() + +
+
+ Reflow the timeline axis. Calculate its height, width, positioning, etc... + + +
+ + + + + + + + +
+
Returns:
+ +
{boolean} resized returns true if the axis is resized
+ +
+ + + + +
+ + +
+ + {boolean} + reflowFrame() + +
+
+ Reflow the timeline frame + + +
+ + + + + + + + +
+
Returns:
+ +
{boolean} resized Returns true if any of the frame elements + have been resized.
+ +
+ + + + +
+ + +
+ + {boolean} + reflowGroups() + +
+
+ Reflow the size of the groups + + +
+ + + + + + + + +
+
Returns:
+ +
{boolean} resized Returns true if any of the frame elements + have been resized.
+ +
+ + + + +
+ + +
+ + {boolean} + reflowItems() + +
+
+ Reflow all items, retrieve their actual size + + +
+ + + + + + + + +
+
Returns:
+ +
{boolean} resized returns true if any of the items is resized
+ +
+ + + + +
+ + +
<static> + + + links.Timeline.removeClassName(elem, className) + +
+
+ Removes one or more className's from the given elements style + + +
+ + + + +
+
Parameters:
+ +
+ {Element} elem + +
+
+ +
+ {String} className + +
+
+ +
+ + + + + + + + +
+ + +
<static> + + + links.Timeline.removeEventListener(element, action, listener, useCapture) + +
+
+ Remove an event listener from an element + + +
+ + + + +
+
Parameters:
+ +
+ {Element} element + +
+
An html dom element
+ +
+ {string} action + +
+
The name of the event, for example "mousedown"
+ +
+ {function} listener + +
+
The listener function
+ +
+ {boolean} useCapture + +
+
+ +
+ + + + + + + + +
+ + +
+ + + render(options) + +
+
+ Re-render (reflow and repaint) all components of the Timeline: frame, axis, +items, ... + + +
+ + + + +
+
Parameters:
+ +
+ {Object} options + Optional +
+
Available options: + {boolean} renderTimesLeft Number of times the + render may be repeated + 5 times by default. + {boolean} animate takes options.animate + as default value
+ +
+ + + + + + + + +
+ + +
+ + {boolean} + repaint() + +
+
+ Repaint all components of the Timeline + + +
+ + + + + + + + +
+
Returns:
+ +
{boolean} needsReflow Returns true if the DOM is changed such that + a reflow is needed.
+ +
+ + + + +
+ + +
+ + {boolean} + repaintAxis() + +
+
+ Redraw the timeline axis with minor and major labels + + +
+ + + + + + + + +
+
Returns:
+ +
{boolean} needsReflow Returns true if the DOM is changed such + that a reflow is needed.
+ +
+ + + + +
+ + +
+ + {boolean} + repaintAxisCharacters() + +
+
+ Create characters used to determine the size of text on the axis + + +
+ + + + + + + + +
+
Returns:
+ +
{boolean} needsReflow Returns true if the DOM is changed such that + a reflow is needed.
+ +
+ + + + +
+ + +
+ + + repaintAxisEndOverwriting() + +
+
+ End of overwriting HTML DOM elements of the axis. +remaining elements will be removed + + +
+ + + + + + + + + + + +
+ + +
+ + + repaintAxisHorizontal() + +
+
+ Repaint the horizontal line and background of the axis + + +
+ + + + + + + + + + + +
+ + +
+ + + repaintAxisMajorLine(x) + +
+
+ Create a Major line for the axis at position x + + +
+ + + + +
+
Parameters:
+ +
+ {Number} x + +
+
+ +
+ + + + + + + + +
+ + +
+ + + repaintAxisMajorText(x, text) + +
+
+ Create a Major label for the axis at position x + + +
+ + + + +
+
Parameters:
+ +
+ {Number} x + +
+
+ +
+ {String} text + +
+
+ +
+ + + + + + + + +
+ + +
+ + + repaintAxisMinorLine(x) + +
+
+ Create a minor line for the axis at position x + + +
+ + + + +
+
Parameters:
+ +
+ {Number} x + +
+
+ +
+ + + + + + + + +
+ + +
+ + + repaintAxisMinorText(x, text) + +
+
+ Create a minor label for the axis at position x + + +
+ + + + +
+
Parameters:
+ +
+ {Number} x + +
+
+ +
+ {String} text + +
+
+ +
+ + + + + + + + +
+ + +
+ + + repaintAxisStartOverwriting() + +
+
+ Initialize redraw of the axis. All existing labels and lines will be +overwritten and reused. + + +
+ + + + + + + + + + + +
+ + +
+ + + repaintCurrentTime() + +
+
+ Redraw the current time bar + + +
+ + + + + + + + + + + +
+ + +
+ + + repaintCustomTime() + +
+
+ Redraw the custom time bar + + +
+ + + + + + + + + + + +
+ + +
+ + + repaintDeleteButton() + +
+
+ Redraw the delete button, on the top right of the currently selected item +if there is no item selected, the button is hidden. + + +
+ + + + + + + + + + + +
+ + +
+ + + repaintDragAreas() + +
+
+ Redraw the drag areas. When an item (ranges only) is selected, +it gets a drag area on the left and right side, to change its width + + +
+ + + + + + + + + + + +
+ + +
+ + {boolean} + repaintFrame() + +
+
+ repaint the Timeline frame + + +
+ + + + + + + + +
+
Returns:
+ +
{boolean} needsReflow Returns true if the DOM is changed such that + a reflow is needed.
+ +
+ + + + +
+ + +
+ + + repaintGroups() + +
+
+ Redraw the group labels + + +
+ + + + + + + + + + + +
+ + +
+ + {boolean} + repaintItems() + +
+
+ Repaint all items + + +
+ + + + + + + + +
+
Returns:
+ +
{boolean} needsReflow Returns true if the DOM is changed such that + a reflow is needed.
+ +
+ + + + +
+ + +
+ + + repaintNavigation() + +
+
+ Create the navigation buttons for zooming and moving + + +
+ + + + + + + + + + + +
+ + +
+ + {Date} + screenToTime(x) + +
+
+ Convert a position on screen (pixels) to a datetime +Before this method can be used, the method calcConversionFactor must be +executed once. + + +
+ + + + +
+
Parameters:
+ +
+ {int} x + +
+
Position on the screen in pixels
+ +
+ + + + + +
+
Returns:
+ +
{Date} time The datetime the corresponds with given position x
+ +
+ + + + +
+ + +
+ + + selectCluster(index) + +
+
+ Select an cluster by its index + + +
+ + + + +
+
Parameters:
+ +
+ {Number} index + +
+
+ +
+ + + + + + + + +
+ + +
+ + + selectItem(index) + +
+
+ Select an item by its index + + +
+ + + + +
+
Parameters:
+ +
+ {Number} index + +
+
+ +
+ + + + + + + + +
+ + +
+ + + setAutoScale(enable) + +
+
+ Enable or disable autoscaling + + +
+ + + + +
+
Parameters:
+ +
+ {boolean} enable + +
+
If true or not defined, autoscaling is enabled. + If false, autoscaling is disabled.
+ +
+ + + + + + + + +
+ + +
+ + + setCurrentTime(time) + +
+
+ Set current time. This function can be used to set the time in the client +timeline equal with the time on a server. + + +
+ + + + +
+
Parameters:
+ +
+ {Date} time + +
+
+ +
+ + + + + + + + +
+ + +
+ + + setCustomTime(time) + +
+
+ Set custom time. +The custom time bar can be used to display events in past or future. + + +
+ + + + +
+
Parameters:
+ +
+ {Date} time + +
+
+ +
+ + + + + + + + +
+ + +
+ + + setData(data) + +
+
+ Set data for the timeline + + +
+ + + + +
+
Parameters:
+ +
+ {google.visualization.DataTable | Array} data + +
+
+ +
+ + + + + + + + +
+ + +
+ + + setOptions(options) + +
+
+ Set options for the timeline. +Timeline must be redrawn afterwards + + +
+ + + + +
+
Parameters:
+ +
+ {Object} options + +
+
A name/value map containing settings for the + timeline. Optional.
+ +
+ + + + + + + + +
+ + +
+ + + setScale(scale, step) + +
+
+ Set a custom scale. Autoscaling will be disabled. +For example setScale(SCALE.MINUTES, 5) will result +in minor steps of 5 minutes, and major steps of an hour. + + +
+ + + + +
+
Parameters:
+ +
+ {links.Timeline.StepDate.SCALE} scale + +
+
A scale. Choose from SCALE.MILLISECOND, + SCALE.SECOND, SCALE.MINUTE, SCALE.HOUR, + SCALE.WEEKDAY, SCALE.DAY, SCALE.MONTH, + SCALE.YEAR.
+ +
+ {int} step + +
+
A step size, by default 1. Choose for + example 1, 2, 5, or 10.
+ +
+ + + + + + + + +
+ + +
+ + {boolean} + setSelection(selection) + +
+
+ Select an event. The visible chart range will be moved such that the selected +event is placed in the middle. +For example selection = [{row: 5}]; + + +
+ + + + +
+
Parameters:
+ +
+ {Array} selection + +
+
An array with a column row, containing the row + number (the id) of the event to be selected.
+ +
+ + + + + +
+
Returns:
+ +
{boolean} true if selection is succesfully set, else false.
+ +
+ + + + +
+ + +
+ + + setSize(width, height) + +
+
+ Set a new size for the timeline + + +
+ + + + +
+
Parameters:
+ +
+ {string} width + +
+
Width in pixels or percentage (for example "800px" + or "50%")
+ +
+ {string} height + +
+
Height in pixels or percentage (for example "400px" + or "30%")
+ +
+ + + + + + + + +
+ + +
+ + + setVisibleChartRange(start, end, redraw) + +
+
+ Set a new value for the visible range int the timeline. +Set start undefined to include everything from the earliest date to end. +Set end undefined to include everything from start to the last date. +Example usage: + myTimeline.setVisibleChartRange(new Date("2010-08-22"), + new Date("2010-09-13")); + + +
+ + + + +
+
Parameters:
+ +
+ {Date} start + +
+
The start date for the timeline. optional
+ +
+ {Date} end + +
+
The end date for the timeline. optional
+ +
+ {boolean} redraw + +
+
Optional. If true (default) the Timeline is + directly redrawn
+ +
+ + + + + + + + +
+ + +
+ + + setVisibleChartRangeAuto() + +
+
+ Change the visible chart range such that all items become visible + + +
+ + + + + + + + + + + +
+ + +
+ + + setVisibleChartRangeNow() + +
+
+ Adjust the visible range such that the current time is located in the center +of the timeline + + +
+ + + + + + + + + + + +
+ + +
+ + {Object[]} + stackCalculateFinal(items) + +
+
+ Adjust vertical positions of the events such that they don't overlap each +other. + + +
+ + + + +
+
Parameters:
+ +
+ {timeline.Item[]} items + +
+
+ +
+ + + + + +
+
Returns:
+ +
{Object[]} finalItems
+ +
+ + + + +
+ + +
+ + + stackCancelAnimation() + +
+
+ Cancel any running animation + + +
+ + + + + + + + + + + +
+ + +
+ + + stackItems(animate) + +
+
+ Stack the items such that they don't overlap. The items will have a minimal +distance equal to options.eventMargin. + + +
+ + + + +
+
Parameters:
+ +
+ {boolean | undefined} animate + +
+
if animate is true, the items are + moved to their new position animated + defaults to false.
+ +
+ + + + + + + + +
+ + +
+ + {Object} + stackItemsCheckOverlap(items, itemIndex, itemStart, itemEnd) + +
+
+ Check if the destiny position of given item overlaps with any +of the other items from index itemStart to itemEnd. + + +
+ + + + +
+
Parameters:
+ +
+ {Array} items + +
+
Array with items
+ +
+ {int} itemIndex + +
+
Number of the item to be checked for overlap
+ +
+ {int} itemStart + +
+
First item to be checked.
+ +
+ {int} itemEnd + +
+
Last item to be checked.
+ +
+ + + + + +
+
Returns:
+ +
{Object} colliding item, or undefined when no collisions
+ +
+ + + + +
+ + +
+ + {boolean} + stackMoveOneStep(currentItems, finalItems) + +
+
+ Move the events one step in the direction of their final positions + + +
+ + + + +
+
Parameters:
+ +
+ {Array} currentItems + +
+
Array with the real items and their current + positions
+ +
+ {Array} finalItems + +
+
Array with objects containing the final + positions of the items
+ +
+ + + + + +
+
Returns:
+ +
{boolean} arrived True if all items have reached their final + location, else false
+ +
+ + + + +
+ + +
+ + + stackMoveToFinal(currentItems, finalItems) + +
+
+ Move the events from their current position to the final position + + +
+ + + + +
+
Parameters:
+ +
+ {Array} currentItems + +
+
Array with the real items and their current + positions
+ +
+ {Array} finalItems + +
+
Array with objects containing the final + positions of the items
+ +
+ + + + + + + + +
+ + +
+ + {Array} + stackOrder(items) + +
+
+ Order the items in the array this.items. The default order is determined via: +- Ranges go before boxes and dots. +- The item with the oldest start time goes first +If a custom function has been provided via the stackorder option, then this will be used. + + +
+ + + + +
+
Parameters:
+ +
+ {Array} items + +
+
Array with items
+ +
+ + + + + +
+
Returns:
+ +
{Array} sortedItems Array with sorted items
+ +
+ + + + +
+ + +
<static> + + + links.Timeline.stopPropagation(event) + +
+
+ Stop event propagation + + +
+ + + + +
+
Parameters:
+ +
+ event + +
+
+ +
+ + + + + + + + +
+ + +
+ + {int} + timeToScreen(time) + +
+
+ Convert a datetime (Date object) into a position on the screen +Before this method can be used, the method calcConversionFactor must be +executed once. + + +
+ + + + +
+
Parameters:
+ +
+ {Date} time + +
+
A date
+ +
+ + + + + +
+
Returns:
+ +
{int} x The position on the screen in pixels which corresponds + with the given date.
+ +
+ + + + +
+ + +
+ + + trigger(event) + +
+
+ fire an event + + +
+ + + + +
+
Parameters:
+ +
+ {String} event + +
+
The name of an event, for example "rangechange" or "edit"
+ +
+ + + + + + + + +
+ + +
+ + + unselectItem() + +
+
+ Unselect the currently selected event (if any) + + +
+ + + + + + + + + + + +
+ + +
+ + + updateData(index, values) + +
+
+ Update the original data with changed start, end or group. + + +
+ + + + +
+
Parameters:
+ +
+ {Number} index + +
+
+ +
+ {Object} values + +
+
An object containing some of the following parameters: + {Date} start, + {Date} end, + {String} content, + {String} group
+ +
+ + + + + + + + +
+ + +
+ + + zoom(zoomFactor, zoomAroundDate) + +
+
+ Zoom the timeline the given zoomfactor in or out. Start and end date will +be adjusted, and the timeline will be redrawn. You can optionally give a +date around which to zoom. +For example, try zoomfactor = 0.1 or -0.1 + + +
+ + + + +
+
Parameters:
+ +
+ {Number} zoomFactor + +
+
Zooming amount. Positive value will zoom in, + negative value will zoom out
+ +
+ {Date} zoomAroundDate + +
+
Date around which will be zoomed. Optional
+ +
+ + + + + + + + + + + + + + + +
+
+ + + +
+ + Documentation generated by JsDoc Toolkit 2.3.2 on Wed Mar 04 2015 09:58:28 GMT+0100 (CET) +
+ + diff --git a/static/lib/timeline/doc/jsdoc/symbols/src/timeline.js.html b/static/lib/timeline/doc/jsdoc/symbols/src/timeline.js.html new file mode 100644 index 00000000..964adff6 --- /dev/null +++ b/static/lib/timeline/doc/jsdoc/symbols/src/timeline.js.html @@ -0,0 +1,7013 @@ +
  1 /**
+  2  * @file timeline.js
+  3  *
+  4  * @brief
+  5  * The Timeline is an interactive visualization chart to visualize events in
+  6  * time, having a start and end date.
+  7  * You can freely move and zoom in the timeline by dragging
+  8  * and scrolling in the Timeline. Items are optionally dragable. The time
+  9  * scale on the axis is adjusted automatically, and supports scales ranging
+ 10  * from milliseconds to years.
+ 11  *
+ 12  * Timeline is part of the CHAP Links library.
+ 13  *
+ 14  * Timeline is tested on Firefox 3.6, Safari 5.0, Chrome 6.0, Opera 10.6, and
+ 15  * Internet Explorer 6+.
+ 16  *
+ 17  * @license
+ 18  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ 19  * use this file except in compliance with the License. You may obtain a copy
+ 20  * of the License at
+ 21  *
+ 22  * http://www.apache.org/licenses/LICENSE-2.0
+ 23  *
+ 24  * Unless required by applicable law or agreed to in writing, software
+ 25  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ 26  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ 27  * License for the specific language governing permissions and limitations under
+ 28  * the License.
+ 29  *
+ 30  * Copyright (c) 2011-2015 Almende B.V.
+ 31  *
+ 32  * @author  Jos de Jong, <jos@almende.org>
+ 33  * @date    2015-03-04
+ 34  * @version 2.9.1
+ 35  */
+ 36 
+ 37 /*
+ 38  * i18n mods by github user iktuz (https://gist.github.com/iktuz/3749287/)
+ 39  * added to v2.4.1 with da_DK language by @bjarkebech
+ 40  */
+ 41 
+ 42 /*
+ 43  * TODO
+ 44  *
+ 45  * Add zooming with pinching on Android
+ 46  *
+ 47  * Bug: when an item contains a javascript onclick or a link, this does not work
+ 48  *      when the item is not selected (when the item is being selected,
+ 49  *      it is redrawn, which cancels any onclick or link action)
+ 50  * Bug: when an item contains an image without size, or a css max-width, it is not sized correctly
+ 51  * Bug: neglect items when they have no valid start/end, instead of throwing an error
+ 52  * Bug: Pinching on ipad does not work very well, sometimes the page will zoom when pinching vertically
+ 53  * Bug: cannot set max width for an item, like div.timeline-event-content {white-space: normal; max-width: 100px;}
+ 54  * Bug on IE in Quirks mode. When you have groups, and delete an item, the groups become invisible
+ 55  */
+ 56 
+ 57 /**
+ 58  * Declare a unique namespace for CHAP's Common Hybrid Visualisation Library,
+ 59  * "links"
+ 60  */
+ 61 if (typeof links === 'undefined') {
+ 62     links = {};
+ 63     // important: do not use var, as "var links = {};" will overwrite
+ 64     //            the existing links variable value with undefined in IE8, IE7.
+ 65 }
+ 66 
+ 67 
+ 68 /**
+ 69  * Ensure the variable google exists
+ 70  */
+ 71 if (typeof google === 'undefined') {
+ 72     google = undefined;
+ 73     // important: do not use var, as "var google = undefined;" will overwrite
+ 74     //            the existing google variable value with undefined in IE8, IE7.
+ 75 }
+ 76 
+ 77 
+ 78 
+ 79 // Internet Explorer 8 and older does not support Array.indexOf,
+ 80 // so we define it here in that case
+ 81 // http://soledadpenades.com/2007/05/17/arrayindexof-in-internet-explorer/
+ 82 if(!Array.prototype.indexOf) {
+ 83     Array.prototype.indexOf = function(obj){
+ 84         for(var i = 0; i < this.length; i++){
+ 85             if(this[i] == obj){
+ 86                 return i;
+ 87             }
+ 88         }
+ 89         return -1;
+ 90     }
+ 91 }
+ 92 
+ 93 // Internet Explorer 8 and older does not support Array.forEach,
+ 94 // so we define it here in that case
+ 95 // https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/forEach
+ 96 if (!Array.prototype.forEach) {
+ 97     Array.prototype.forEach = function(fn, scope) {
+ 98         for(var i = 0, len = this.length; i < len; ++i) {
+ 99             fn.call(scope || this, this[i], i, this);
+100         }
+101     }
+102 }
+103 
+104 
+105 /**
+106  * @constructor links.Timeline
+107  * The timeline is a visualization chart to visualize events in time.
+108  *
+109  * The timeline is developed in javascript as a Google Visualization Chart.
+110  *
+111  * @param {Element} container   The DOM element in which the Timeline will
+112  *                              be created. Normally a div element.
+113  * @param {Object} options      A name/value map containing settings for the
+114  *                              timeline. Optional.
+115  */
+116 links.Timeline = function(container, options) {
+117     if (!container) {
+118         // this call was probably only for inheritance, no constructor-code is required
+119         return;
+120     }
+121 
+122     // create variables and set default values
+123     this.dom = {};
+124     this.conversion = {};
+125     this.eventParams = {}; // stores parameters for mouse events
+126     this.groups = [];
+127     this.groupIndexes = {};
+128     this.items = [];
+129     this.renderQueue = {
+130         show: [],   // Items made visible but not yet added to DOM
+131         hide: [],   // Items currently visible but not yet removed from DOM
+132         update: []  // Items with changed data but not yet adjusted DOM
+133     };
+134     this.renderedItems = [];  // Items currently rendered in the DOM
+135     this.clusterGenerator = new links.Timeline.ClusterGenerator(this);
+136     this.currentClusters = [];
+137     this.selection = undefined; // stores index and item which is currently selected
+138 
+139     this.listeners = {}; // event listener callbacks
+140 
+141     // Initialize sizes.
+142     // Needed for IE (which gives an error when you try to set an undefined
+143     // value in a style)
+144     this.size = {
+145         'actualHeight': 0,
+146         'axis': {
+147             'characterMajorHeight': 0,
+148             'characterMajorWidth': 0,
+149             'characterMinorHeight': 0,
+150             'characterMinorWidth': 0,
+151             'height': 0,
+152             'labelMajorTop': 0,
+153             'labelMinorTop': 0,
+154             'line': 0,
+155             'lineMajorWidth': 0,
+156             'lineMinorHeight': 0,
+157             'lineMinorTop': 0,
+158             'lineMinorWidth': 0,
+159             'top': 0
+160         },
+161         'contentHeight': 0,
+162         'contentLeft': 0,
+163         'contentWidth': 0,
+164         'frameHeight': 0,
+165         'frameWidth': 0,
+166         'groupsLeft': 0,
+167         'groupsWidth': 0,
+168         'items': {
+169             'top': 0
+170         }
+171     };
+172 
+173     this.dom.container = container;
+174 
+175     //
+176     // Let's set the default options first
+177     //
+178     this.options = {
+179         'width': "100%",
+180         'height': "auto",
+181         'minHeight': 0,        // minimal height in pixels
+182         'groupMinHeight': 0,
+183         'autoHeight': true,
+184 
+185         'eventMargin': 10,     // minimal margin between events
+186         'eventMarginAxis': 20, // minimal margin between events and the axis
+187         'dragAreaWidth': 10,   // pixels
+188 
+189         'min': undefined,
+190         'max': undefined,
+191         'zoomMin': 10,     // milliseconds
+192         'zoomMax': 1000 * 60 * 60 * 24 * 365 * 10000, // milliseconds
+193 
+194         'moveable': true,
+195         'zoomable': true,
+196         'selectable': true,
+197         'unselectable': true,
+198         'editable': false,
+199         'snapEvents': true,
+200         'groupsChangeable': true,
+201         'timeChangeable': true,
+202 
+203         'showCurrentTime': true, // show a red bar displaying the current time
+204         'showCustomTime': false, // show a blue, draggable bar displaying a custom time
+205         'showMajorLabels': true,
+206         'showMinorLabels': true,
+207         'showNavigation': false,
+208         'showButtonNew': false,
+209         'groupsOnRight': false,
+210         'groupsOrder' : true,
+211         'axisOnTop': false,
+212         'stackEvents': true,
+213         'animate': true,
+214         'animateZoom': true,
+215         'cluster': false,
+216         'clusterMaxItems': 5,
+217         'style': 'box',
+218         'customStackOrder': false, //a function(a,b) for determining stackorder amongst a group of items. Essentially a comparator, -ve value for "a before b" and vice versa
+219         
+220         // i18n: Timeline only has built-in English text per default. Include timeline-locales.js to support more localized text.
+221         'locale': 'en',
+222         'MONTHS': ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
+223         'MONTHS_SHORT': ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
+224         'DAYS': ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
+225         'DAYS_SHORT': ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
+226         'ZOOM_IN': "Zoom in",
+227         'ZOOM_OUT': "Zoom out",
+228         'MOVE_LEFT': "Move left",
+229         'MOVE_RIGHT': "Move right",
+230         'NEW': "New",
+231         'CREATE_NEW_EVENT': "Create new event"
+232     };
+233     
+234     //
+235     // Now we can set the givenproperties
+236     //
+237     this.setOptions(options);
+238 
+239     this.clientTimeOffset = 0;    // difference between client time and the time
+240     // set via Timeline.setCurrentTime()
+241     var dom = this.dom;
+242 
+243     // remove all elements from the container element.
+244     while (dom.container.hasChildNodes()) {
+245         dom.container.removeChild(dom.container.firstChild);
+246     }
+247 
+248     // create a step for drawing the axis
+249     this.step = new links.Timeline.StepDate();
+250 
+251     // add standard item types
+252     this.itemTypes = {
+253         box:           links.Timeline.ItemBox,
+254         range:         links.Timeline.ItemRange,
+255         floatingRange: links.Timeline.ItemFloatingRange,
+256         dot:           links.Timeline.ItemDot
+257     };
+258 
+259     // initialize data
+260     this.data = [];
+261     this.firstDraw = true;
+262 
+263     // date interval must be initialized
+264     this.setVisibleChartRange(undefined, undefined, false);
+265 
+266     // render for the first time
+267     this.render();
+268 
+269     // fire the ready event
+270     var me = this;
+271     setTimeout(function () {
+272         me.trigger('ready');
+273     }, 0);
+274 };
+275 
+276 
+277 /**
+278  * Main drawing logic. This is the function that needs to be called
+279  * in the html page, to draw the timeline.
+280  *
+281  * A data table with the events must be provided, and an options table.
+282  *
+283  * @param {google.visualization.DataTable}      data
+284  *                                 The data containing the events for the timeline.
+285  *                                 Object DataTable is defined in
+286  *                                 google.visualization.DataTable
+287  * @param {Object} options         A name/value map containing settings for the
+288  *                                 timeline. Optional. The use of options here
+289  *                                 is deprecated. Pass timeline options in the
+290  *                                 constructor or use setOptions()
+291  */
+292 links.Timeline.prototype.draw = function(data, options) {
+293     if (options) {
+294         console.log("WARNING: Passing options in draw() is deprecated. Pass options to the constructur or use setOptions() instead!");       
+295         this.setOptions(options);
+296     }
+297 
+298     if (this.options.selectable) {
+299         links.Timeline.addClassName(this.dom.frame, "timeline-selectable");
+300     }
+301 
+302     // read the data
+303     this.setData(data);
+304 
+305     if (this.firstDraw) {
+306         this.setVisibleChartRangeAuto();
+307     }
+308 
+309     this.firstDraw = false;
+310 };
+311 
+312 
+313 /**
+314  * Set options for the timeline.
+315  * Timeline must be redrawn afterwards
+316  * @param {Object} options A name/value map containing settings for the
+317  *                                 timeline. Optional.
+318  */
+319 links.Timeline.prototype.setOptions = function(options) {
+320     if (options) {
+321         // retrieve parameter values
+322         for (var i in options) {
+323             if (options.hasOwnProperty(i)) {
+324                 this.options[i] = options[i];
+325             }
+326         }
+327 
+328         // prepare i18n dependent on set locale
+329         if (typeof links.locales !== 'undefined' && this.options.locale !== 'en') {
+330             var localeOpts = links.locales[this.options.locale];
+331             if(localeOpts) {
+332                 for (var l in localeOpts) {
+333                     if (localeOpts.hasOwnProperty(l)) {
+334                         this.options[l] = localeOpts[l];
+335                     }
+336                 }
+337             }
+338         }
+339 
+340         // check for deprecated options
+341         if (options.showButtonAdd != undefined) {
+342             this.options.showButtonNew = options.showButtonAdd;
+343             console.log('WARNING: Option showButtonAdd is deprecated. Use showButtonNew instead');
+344         }
+345         if (options.intervalMin != undefined) {
+346             this.options.zoomMin = options.intervalMin;
+347             console.log('WARNING: Option intervalMin is deprecated. Use zoomMin instead');
+348         }
+349         if (options.intervalMax != undefined) {
+350             this.options.zoomMax = options.intervalMax;
+351             console.log('WARNING: Option intervalMax is deprecated. Use zoomMax instead');
+352         }
+353 
+354         if (options.scale && options.step) {
+355             this.step.setScale(options.scale, options.step);
+356         }
+357     }
+358 
+359     // validate options
+360     this.options.autoHeight = (this.options.height === "auto");
+361 };
+362 
+363 /**
+364  * Get options for the timeline.
+365  *
+366  * @return the options object
+367  */
+368 links.Timeline.prototype.getOptions = function() {
+369     return this.options;
+370 };
+371 
+372 /**
+373  * Add new type of items
+374  * @param {String} typeName  Name of new type
+375  * @param {links.Timeline.Item} typeFactory Constructor of items
+376  */
+377 links.Timeline.prototype.addItemType = function (typeName, typeFactory) {
+378     this.itemTypes[typeName] = typeFactory;
+379 };
+380 
+381 /**
+382  * Retrieve a map with the column indexes of the columns by column name.
+383  * For example, the method returns the map
+384  *     {
+385  *         start: 0,
+386  *         end: 1,
+387  *         content: 2,
+388  *         group: undefined,
+389  *         className: undefined
+390  *         editable: undefined
+391  *         type: undefined
+392  *     }
+393  * @param {google.visualization.DataTable} dataTable
+394  * @type {Object} map
+395  */
+396 links.Timeline.mapColumnIds = function (dataTable) {
+397     var cols = {},
+398         colCount = dataTable.getNumberOfColumns(),
+399         allUndefined = true;
+400 
+401     // loop over the columns, and map the column id's to the column indexes
+402     for (var col = 0; col < colCount; col++) {
+403         var id = dataTable.getColumnId(col) || dataTable.getColumnLabel(col);
+404         cols[id] = col;
+405         if (id == 'start' || id == 'end' || id == 'content' || id == 'group' ||
+406             id == 'className' || id == 'editable' || id == 'type') {
+407             allUndefined = false;
+408         }
+409     }
+410 
+411     // if no labels or ids are defined, use the default mapping
+412     // for start, end, content, group, className, editable, type
+413     if (allUndefined) {
+414         cols.start = 0;
+415         cols.end = 1;
+416         cols.content = 2;
+417         if (colCount > 3) {cols.group = 3}
+418         if (colCount > 4) {cols.className = 4}
+419         if (colCount > 5) {cols.editable = 5}
+420         if (colCount > 6) {cols.type = 6}
+421     }
+422 
+423     return cols;
+424 };
+425 
+426 /**
+427  * Set data for the timeline
+428  * @param {google.visualization.DataTable | Array} data
+429  */
+430 links.Timeline.prototype.setData = function(data) {
+431     // unselect any previously selected item
+432     this.unselectItem();
+433 
+434     if (!data) {
+435         data = [];
+436     }
+437 
+438     // clear all data
+439     this.stackCancelAnimation();
+440     this.clearItems();
+441     this.data = data;
+442     var items = this.items;
+443     this.deleteGroups();
+444 
+445     if (google && google.visualization &&
+446         data instanceof google.visualization.DataTable) {
+447         // map the datatable columns
+448         var cols = links.Timeline.mapColumnIds(data);
+449 
+450         // read DataTable
+451         for (var row = 0, rows = data.getNumberOfRows(); row < rows; row++) {
+452             items.push(this.createItem({
+453                 'start':     ((cols.start != undefined)     ? data.getValue(row, cols.start)     : undefined),
+454                 'end':       ((cols.end != undefined)       ? data.getValue(row, cols.end)       : undefined),
+455                 'content':   ((cols.content != undefined)   ? data.getValue(row, cols.content)   : undefined),
+456                 'group':     ((cols.group != undefined)     ? data.getValue(row, cols.group)     : undefined),
+457                 'className': ((cols.className != undefined) ? data.getValue(row, cols.className) : undefined),
+458                 'editable':  ((cols.editable != undefined)  ? data.getValue(row, cols.editable)  : undefined),
+459                 'type':      ((cols.type != undefined)      ? data.getValue(row, cols.type)      : undefined)
+460             }));
+461         }
+462     }
+463     else if (links.Timeline.isArray(data)) {
+464         // read JSON array
+465         for (var row = 0, rows = data.length; row < rows; row++) {
+466             var itemData = data[row];
+467             var item = this.createItem(itemData);
+468             items.push(item);
+469         }
+470     }
+471     else {
+472         throw "Unknown data type. DataTable or Array expected.";
+473     }
+474 
+475     // prepare data for clustering, by filtering and sorting by type
+476     if (this.options.cluster) {
+477         this.clusterGenerator.setData(this.items);
+478     }
+479 
+480     this.render({
+481         animate: false
+482     });
+483 };
+484 
+485 /**
+486  * Return the original data table.
+487  * @return {google.visualization.DataTable | Array} data
+488  */
+489 links.Timeline.prototype.getData = function  () {
+490     return this.data;
+491 };
+492 
+493 
+494 /**
+495  * Update the original data with changed start, end or group.
+496  *
+497  * @param {Number} index
+498  * @param {Object} values   An object containing some of the following parameters:
+499  *                          {Date} start,
+500  *                          {Date} end,
+501  *                          {String} content,
+502  *                          {String} group
+503  */
+504 links.Timeline.prototype.updateData = function  (index, values) {
+505     var data = this.data,
+506         prop;
+507 
+508     if (google && google.visualization &&
+509         data instanceof google.visualization.DataTable) {
+510         // update the original google DataTable
+511         var missingRows = (index + 1) - data.getNumberOfRows();
+512         if (missingRows > 0) {
+513             data.addRows(missingRows);
+514         }
+515 
+516         // map the column id's by name
+517         var cols = links.Timeline.mapColumnIds(data);
+518 
+519         // merge all fields from the provided data into the current data
+520         for (prop in values) {
+521             if (values.hasOwnProperty(prop)) {
+522                 var col = cols[prop];
+523                 if (col == undefined) {
+524                     // create new column
+525                     var value = values[prop];
+526                     var valueType = 'string';
+527                     if (typeof(value) == 'number')       {valueType = 'number';}
+528                     else if (typeof(value) == 'boolean') {valueType = 'boolean';}
+529                     else if (value instanceof Date)      {valueType = 'datetime';}
+530                     col = data.addColumn(valueType, prop);
+531                 }
+532                 data.setValue(index, col, values[prop]);
+533 
+534                 // TODO: correctly serialize the start and end Date to the desired type (Date, String, or Number)
+535             }
+536         }
+537     }
+538     else if (links.Timeline.isArray(data)) {
+539         // update the original JSON table
+540         var row = data[index];
+541         if (row == undefined) {
+542             row = {};
+543             data[index] = row;
+544         }
+545 
+546         // merge all fields from the provided data into the current data
+547         for (prop in values) {
+548             if (values.hasOwnProperty(prop)) {
+549                 row[prop] = values[prop];
+550 
+551                 // TODO: correctly serialize the start and end Date to the desired type (Date, String, or Number)
+552             }
+553         }
+554     }
+555     else {
+556         throw "Cannot update data, unknown type of data";
+557     }
+558 };
+559 
+560 /**
+561  * Find the item index from a given HTML element
+562  * If no item index is found, undefined is returned
+563  * @param {Element} element
+564  * @return {Number | undefined} index
+565  */
+566 links.Timeline.prototype.getItemIndex = function(element) {
+567     var e = element,
+568         dom = this.dom,
+569         frame = dom.items.frame,
+570         items = this.items,
+571         index = undefined;
+572 
+573     // try to find the frame where the items are located in
+574     while (e.parentNode && e.parentNode !== frame) {
+575         e = e.parentNode;
+576     }
+577 
+578     if (e.parentNode === frame) {
+579         // yes! we have found the parent element of all items
+580         // retrieve its id from the array with items
+581         for (var i = 0, iMax = items.length; i < iMax; i++) {
+582             if (items[i].dom === e) {
+583                 index = i;
+584                 break;
+585             }
+586         }
+587     }
+588 
+589     return index;
+590 };
+591 
+592 
+593 /**
+594  * Find the cluster index from a given HTML element
+595  * If no cluster index is found, undefined is returned
+596  * @param {Element} element
+597  * @return {Number | undefined} index
+598  */
+599 links.Timeline.prototype.getClusterIndex = function(element) {
+600     var e = element,
+601         dom = this.dom,
+602         frame = dom.items.frame,
+603         clusters = this.clusters,
+604         index = undefined;
+605 
+606     if (this.clusters) {
+607         // try to find the frame where the clusters are located in
+608         while (e.parentNode && e.parentNode !== frame) {
+609             e = e.parentNode;
+610         }
+611 
+612         if (e.parentNode === frame) {
+613             // yes! we have found the parent element of all clusters
+614             // retrieve its id from the array with clusters
+615             for (var i = 0, iMax = clusters.length; i < iMax; i++) {
+616                 if (clusters[i].dom === e) {
+617                     index = i;
+618                     break;
+619                 }
+620             }
+621         }
+622     }
+623 
+624     return index;
+625 };
+626 
+627 /**
+628  * Find all elements within the start and end range
+629  * If no element is found, returns an empty array
+630  * @param start time
+631  * @param end time
+632  * @return Array itemsInRange
+633  */
+634 links.Timeline.prototype.getVisibleItems = function  (start, end) {
+635     var items = this.items;
+636     var itemsInRange = [];
+637 
+638     if (items) {
+639         for (var i = 0, iMax = items.length; i < iMax; i++) {
+640             var item = items[i];
+641             if (item.end) {
+642                 // Time range object // NH use getLeft and getRight here
+643                 if (start <= item.start && item.end <= end) {
+644                     itemsInRange.push({"row": i});
+645                 }
+646             } else {
+647                 // Point object
+648                 if (start <= item.start && item.start <= end) {
+649                     itemsInRange.push({"row": i});
+650                 }
+651             }
+652         }
+653     }
+654 
+655     //     var sel = [];
+656     // if (this.selection) {
+657     //     sel.push({"row": this.selection.index});
+658     // }
+659     // return sel;
+660 
+661     return itemsInRange;
+662 };
+663 
+664 
+665 /**
+666  * Set a new size for the timeline
+667  * @param {string} width   Width in pixels or percentage (for example "800px"
+668  *                         or "50%")
+669  * @param {string} height  Height in pixels or percentage  (for example "400px"
+670  *                         or "30%")
+671  */
+672 links.Timeline.prototype.setSize = function(width, height) {
+673     if (width) {
+674         this.options.width = width;
+675         this.dom.frame.style.width = width;
+676     }
+677     if (height) {
+678         this.options.height = height;
+679         this.options.autoHeight = (this.options.height === "auto");
+680         if (height !==  "auto" ) {
+681             this.dom.frame.style.height = height;
+682         }
+683     }
+684 
+685     this.render({
+686         animate: false
+687     });
+688 };
+689 
+690 
+691 /**
+692  * Set a new value for the visible range int the timeline.
+693  * Set start undefined to include everything from the earliest date to end.
+694  * Set end undefined to include everything from start to the last date.
+695  * Example usage:
+696  *    myTimeline.setVisibleChartRange(new Date("2010-08-22"),
+697  *                                    new Date("2010-09-13"));
+698  * @param {Date}   start     The start date for the timeline. optional
+699  * @param {Date}   end       The end date for the timeline. optional
+700  * @param {boolean} redraw   Optional. If true (default) the Timeline is
+701  *                           directly redrawn
+702  */
+703 links.Timeline.prototype.setVisibleChartRange = function(start, end, redraw) {
+704     var range = {};
+705     if (!start || !end) {
+706         // retrieve the date range of the items
+707         range = this.getDataRange(true);
+708     }
+709 
+710     if (!start) {
+711         if (end) {
+712             if (range.min && range.min.valueOf() < end.valueOf()) {
+713                 // start of the data
+714                 start = range.min;
+715             }
+716             else {
+717                 // 7 days before the end
+718                 start = new Date(end.valueOf());
+719                 start.setDate(start.getDate() - 7);
+720             }
+721         }
+722         else {
+723             // default of 3 days ago
+724             start = new Date();
+725             start.setDate(start.getDate() - 3);
+726         }
+727     }
+728 
+729     if (!end) {
+730         if (range.max) {
+731             // end of the data
+732             end = range.max;
+733         }
+734         else {
+735             // 7 days after start
+736             end = new Date(start.valueOf());
+737             end.setDate(end.getDate() + 7);
+738         }
+739     }
+740 
+741     // prevent start Date <= end Date
+742     if (end <= start) {
+743         end = new Date(start.valueOf());
+744         end.setDate(end.getDate() + 7);
+745     }
+746 
+747     // limit to the allowed range (don't let this do by applyRange,
+748     // because that method will try to maintain the interval (end-start)
+749     var min = this.options.min ? this.options.min : undefined; // date
+750     if (min != undefined && start.valueOf() < min.valueOf()) {
+751         start = new Date(min.valueOf()); // date
+752     }
+753     var max = this.options.max ? this.options.max : undefined; // date
+754     if (max != undefined && end.valueOf() > max.valueOf()) {
+755         end = new Date(max.valueOf()); // date
+756     }
+757 
+758     this.applyRange(start, end);
+759 
+760     if (redraw == undefined || redraw == true) {
+761         this.render({
+762             animate: false
+763         });  // TODO: optimize, no reflow needed
+764     }
+765     else {
+766         this.recalcConversion();
+767     }
+768 };
+769 
+770 
+771 /**
+772  * Change the visible chart range such that all items become visible
+773  */
+774 links.Timeline.prototype.setVisibleChartRangeAuto = function() {
+775     var range = this.getDataRange(true);
+776     this.setVisibleChartRange(range.min, range.max);
+777 };
+778 
+779 /**
+780  * Adjust the visible range such that the current time is located in the center
+781  * of the timeline
+782  */
+783 links.Timeline.prototype.setVisibleChartRangeNow = function() {
+784     var now = new Date();
+785 
+786     var diff = (this.end.valueOf() - this.start.valueOf());
+787 
+788     var startNew = new Date(now.valueOf() - diff/2);
+789     var endNew = new Date(startNew.valueOf() + diff);
+790     this.setVisibleChartRange(startNew, endNew);
+791 };
+792 
+793 
+794 /**
+795  * Retrieve the current visible range in the timeline.
+796  * @return {Object} An object with start and end properties
+797  */
+798 links.Timeline.prototype.getVisibleChartRange = function() {
+799     return {
+800         'start': new Date(this.start.valueOf()),
+801         'end': new Date(this.end.valueOf())
+802     };
+803 };
+804 
+805 /**
+806  * Get the date range of the items.
+807  * @param {boolean} [withMargin]  If true, 5% of whitespace is added to the
+808  *                                left and right of the range. Default is false.
+809  * @return {Object} range    An object with parameters min and max.
+810  *                           - {Date} min is the lowest start date of the items
+811  *                           - {Date} max is the highest start or end date of the items
+812  *                           If no data is available, the values of min and max
+813  *                           will be undefined
+814  */
+815 links.Timeline.prototype.getDataRange = function (withMargin) {
+816     var items = this.items,
+817         min = undefined, // number
+818         max = undefined; // number
+819 
+820     if (items) {
+821         for (var i = 0, iMax = items.length; i < iMax; i++) {
+822             var item = items[i],
+823                 start = item.start != undefined ? item.start.valueOf() : undefined,
+824                 end   = item.end != undefined   ? item.end.valueOf() : start;
+825 
+826             if (start != undefined) {
+827                 min = (min != undefined) ? Math.min(min.valueOf(), start.valueOf()) : start;
+828             }
+829 
+830             if (end != undefined) {
+831                 max = (max != undefined) ? Math.max(max.valueOf(), end.valueOf()) : end;
+832             }
+833         }
+834     }
+835 
+836     if (min && max && withMargin) {
+837         // zoom out 5% such that you have a little white space on the left and right
+838         var diff = (max - min);
+839         min = min - diff * 0.05;
+840         max = max + diff * 0.05;
+841     }
+842 
+843     return {
+844         'min': min != undefined ? new Date(min) : undefined,
+845         'max': max != undefined ? new Date(max) : undefined
+846     };
+847 };
+848 
+849 /**
+850  * Re-render (reflow and repaint) all components of the Timeline: frame, axis,
+851  * items, ...
+852  * @param {Object} [options]  Available options:
+853  *                            {boolean} renderTimesLeft   Number of times the
+854  *                                                        render may be repeated
+855  *                                                        5 times by default.
+856  *                            {boolean} animate           takes options.animate
+857  *                                                        as default value
+858  */
+859 links.Timeline.prototype.render = function(options) {
+860     var frameResized = this.reflowFrame();
+861     var axisResized = this.reflowAxis();
+862     var groupsResized = this.reflowGroups();
+863     var itemsResized = this.reflowItems();
+864     var resized = (frameResized || axisResized || groupsResized || itemsResized);
+865 
+866     // TODO: only stackEvents/filterItems when resized or changed. (gives a bootstrap issue).
+867     // if (resized) {
+868     var animate = this.options.animate;
+869     if (options && options.animate != undefined) {
+870         animate = options.animate;
+871     }
+872 
+873     this.recalcConversion();
+874     this.clusterItems();
+875     this.filterItems();
+876     this.stackItems(animate);
+877     this.recalcItems();
+878 
+879     // TODO: only repaint when resized or when filterItems or stackItems gave a change?
+880     var needsReflow = this.repaint();
+881 
+882     // re-render once when needed (prevent endless re-render loop)
+883     if (needsReflow) {
+884         var renderTimesLeft = options ? options.renderTimesLeft : undefined;
+885         if (renderTimesLeft == undefined) {
+886             renderTimesLeft = 5;
+887         }
+888         if (renderTimesLeft > 0) {
+889             this.render({
+890                 'animate': options ? options.animate: undefined,
+891                 'renderTimesLeft': (renderTimesLeft - 1)
+892             });
+893         }
+894     }
+895 };
+896 
+897 /**
+898  * Repaint all components of the Timeline
+899  * @return {boolean} needsReflow   Returns true if the DOM is changed such that
+900  *                                 a reflow is needed.
+901  */
+902 links.Timeline.prototype.repaint = function() {
+903     var frameNeedsReflow = this.repaintFrame();
+904     var axisNeedsReflow  = this.repaintAxis();
+905     var groupsNeedsReflow  = this.repaintGroups();
+906     var itemsNeedsReflow = this.repaintItems();
+907     this.repaintCurrentTime();
+908     this.repaintCustomTime();
+909 
+910     return (frameNeedsReflow || axisNeedsReflow || groupsNeedsReflow || itemsNeedsReflow);
+911 };
+912 
+913 /**
+914  * Reflow the timeline frame
+915  * @return {boolean} resized    Returns true if any of the frame elements
+916  *                              have been resized.
+917  */
+918 links.Timeline.prototype.reflowFrame = function() {
+919     var dom = this.dom,
+920         options = this.options,
+921         size = this.size,
+922         resized = false;
+923 
+924     // Note: IE7 has issues with giving frame.clientWidth, therefore I use offsetWidth instead
+925     var frameWidth  = dom.frame ? dom.frame.offsetWidth : 0,
+926         frameHeight = dom.frame ? dom.frame.clientHeight : 0;
+927 
+928     resized = resized || (size.frameWidth !== frameWidth);
+929     resized = resized || (size.frameHeight !== frameHeight);
+930     size.frameWidth = frameWidth;
+931     size.frameHeight = frameHeight;
+932 
+933     return resized;
+934 };
+935 
+936 /**
+937  * repaint the Timeline frame
+938  * @return {boolean} needsReflow   Returns true if the DOM is changed such that
+939  *                                 a reflow is needed.
+940  */
+941 links.Timeline.prototype.repaintFrame = function() {
+942     var needsReflow = false,
+943         dom = this.dom,
+944         options = this.options,
+945         size = this.size;
+946 
+947     // main frame
+948     if (!dom.frame) {
+949         dom.frame = document.createElement("DIV");
+950         dom.frame.className = "timeline-frame ui-widget ui-widget-content ui-corner-all";
+951         dom.container.appendChild(dom.frame);
+952         needsReflow = true;
+953     }
+954 
+955     var height = options.autoHeight ?
+956         (size.actualHeight + "px") :
+957         (options.height || "100%");
+958     var width  = options.width || "100%";
+959     needsReflow = needsReflow || (dom.frame.style.height != height);
+960     needsReflow = needsReflow || (dom.frame.style.width != width);
+961     dom.frame.style.height = height;
+962     dom.frame.style.width = width;
+963 
+964     // contents
+965     if (!dom.content) {
+966         // create content box where the axis and items will be created
+967         dom.content = document.createElement("DIV");
+968         dom.content.className = "timeline-content";
+969         dom.frame.appendChild(dom.content);
+970 
+971         var timelines = document.createElement("DIV");
+972         timelines.style.position = "absolute";
+973         timelines.style.left = "0px";
+974         timelines.style.top = "0px";
+975         timelines.style.height = "100%";
+976         timelines.style.width = "0px";
+977         dom.content.appendChild(timelines);
+978         dom.contentTimelines = timelines;
+979 
+980         var params = this.eventParams,
+981             me = this;
+982         if (!params.onMouseDown) {
+983             params.onMouseDown = function (event) {me.onMouseDown(event);};
+984             links.Timeline.addEventListener(dom.content, "mousedown", params.onMouseDown);
+985         }
+986         if (!params.onTouchStart) {
+987             params.onTouchStart = function (event) {me.onTouchStart(event);};
+988             links.Timeline.addEventListener(dom.content, "touchstart", params.onTouchStart);
+989         }
+990         if (!params.onMouseWheel) {
+991             params.onMouseWheel = function (event) {me.onMouseWheel(event);};
+992             links.Timeline.addEventListener(dom.content, "mousewheel", params.onMouseWheel);
+993         }
+994         if (!params.onDblClick) {
+995             params.onDblClick = function (event) {me.onDblClick(event);};
+996             links.Timeline.addEventListener(dom.content, "dblclick", params.onDblClick);
+997         }
+998 
+999         needsReflow = true;
+1000     }
+1001     dom.content.style.left = size.contentLeft + "px";
+1002     dom.content.style.top = "0px";
+1003     dom.content.style.width = size.contentWidth + "px";
+1004     dom.content.style.height = size.frameHeight + "px";
+1005 
+1006     this.repaintNavigation();
+1007 
+1008     return needsReflow;
+1009 };
+1010 
+1011 /**
+1012  * Reflow the timeline axis. Calculate its height, width, positioning, etc...
+1013  * @return {boolean} resized    returns true if the axis is resized
+1014  */
+1015 links.Timeline.prototype.reflowAxis = function() {
+1016     var resized = false,
+1017         dom = this.dom,
+1018         options = this.options,
+1019         size = this.size,
+1020         axisDom = dom.axis;
+1021 
+1022     var characterMinorWidth  = (axisDom && axisDom.characterMinor) ? axisDom.characterMinor.clientWidth : 0,
+1023         characterMinorHeight = (axisDom && axisDom.characterMinor) ? axisDom.characterMinor.clientHeight : 0,
+1024         characterMajorWidth  = (axisDom && axisDom.characterMajor) ? axisDom.characterMajor.clientWidth : 0,
+1025         characterMajorHeight = (axisDom && axisDom.characterMajor) ? axisDom.characterMajor.clientHeight : 0,
+1026         axisHeight = (options.showMinorLabels ? characterMinorHeight : 0) +
+1027             (options.showMajorLabels ? characterMajorHeight : 0);
+1028 
+1029     var axisTop  = options.axisOnTop ? 0 : size.frameHeight - axisHeight,
+1030         axisLine = options.axisOnTop ? axisHeight : axisTop;
+1031 
+1032     resized = resized || (size.axis.top !== axisTop);
+1033     resized = resized || (size.axis.line !== axisLine);
+1034     resized = resized || (size.axis.height !== axisHeight);
+1035     size.axis.top = axisTop;
+1036     size.axis.line = axisLine;
+1037     size.axis.height = axisHeight;
+1038     size.axis.labelMajorTop = options.axisOnTop ? 0 : axisLine +
+1039         (options.showMinorLabels ? characterMinorHeight : 0);
+1040     size.axis.labelMinorTop = options.axisOnTop ?
+1041         (options.showMajorLabels ? characterMajorHeight : 0) :
+1042         axisLine;
+1043     size.axis.lineMinorTop = options.axisOnTop ? size.axis.labelMinorTop : 0;
+1044     size.axis.lineMinorHeight = options.showMajorLabels ?
+1045         size.frameHeight - characterMajorHeight:
+1046         size.frameHeight;
+1047     if (axisDom && axisDom.minorLines && axisDom.minorLines.length) {
+1048         size.axis.lineMinorWidth = axisDom.minorLines[0].offsetWidth;
+1049     }
+1050     else {
+1051         size.axis.lineMinorWidth = 1;
+1052     }
+1053     if (axisDom && axisDom.majorLines && axisDom.majorLines.length) {
+1054         size.axis.lineMajorWidth = axisDom.majorLines[0].offsetWidth;
+1055     }
+1056     else {
+1057         size.axis.lineMajorWidth = 1;
+1058     }
+1059 
+1060     resized = resized || (size.axis.characterMinorWidth  !== characterMinorWidth);
+1061     resized = resized || (size.axis.characterMinorHeight !== characterMinorHeight);
+1062     resized = resized || (size.axis.characterMajorWidth  !== characterMajorWidth);
+1063     resized = resized || (size.axis.characterMajorHeight !== characterMajorHeight);
+1064     size.axis.characterMinorWidth  = characterMinorWidth;
+1065     size.axis.characterMinorHeight = characterMinorHeight;
+1066     size.axis.characterMajorWidth  = characterMajorWidth;
+1067     size.axis.characterMajorHeight = characterMajorHeight;
+1068 
+1069     var contentHeight = Math.max(size.frameHeight - axisHeight, 0);
+1070     size.contentLeft = options.groupsOnRight ? 0 : size.groupsWidth;
+1071     size.contentWidth = Math.max(size.frameWidth - size.groupsWidth, 0);
+1072     size.contentHeight = contentHeight;
+1073 
+1074     return resized;
+1075 };
+1076 
+1077 /**
+1078  * Redraw the timeline axis with minor and major labels
+1079  * @return {boolean} needsReflow     Returns true if the DOM is changed such
+1080  *                                   that a reflow is needed.
+1081  */
+1082 links.Timeline.prototype.repaintAxis = function() {
+1083     var needsReflow = false,
+1084         dom = this.dom,
+1085         options = this.options,
+1086         size = this.size,
+1087         step = this.step;
+1088 
+1089     var axis = dom.axis;
+1090     if (!axis) {
+1091         axis = {};
+1092         dom.axis = axis;
+1093     }
+1094     if (!size.axis.properties) {
+1095         size.axis.properties = {};
+1096     }
+1097     if (!axis.minorTexts) {
+1098         axis.minorTexts = [];
+1099     }
+1100     if (!axis.minorLines) {
+1101         axis.minorLines = [];
+1102     }
+1103     if (!axis.majorTexts) {
+1104         axis.majorTexts = [];
+1105     }
+1106     if (!axis.majorLines) {
+1107         axis.majorLines = [];
+1108     }
+1109 
+1110     if (!axis.frame) {
+1111         axis.frame = document.createElement("DIV");
+1112         axis.frame.style.position = "absolute";
+1113         axis.frame.style.left = "0px";
+1114         axis.frame.style.top = "0px";
+1115         dom.content.appendChild(axis.frame);
+1116     }
+1117 
+1118     // take axis offline
+1119     dom.content.removeChild(axis.frame);
+1120 
+1121     axis.frame.style.width = (size.contentWidth) + "px";
+1122     axis.frame.style.height = (size.axis.height) + "px";
+1123 
+1124     // the drawn axis is more wide than the actual visual part, such that
+1125     // the axis can be dragged without having to redraw it each time again.
+1126     var start = this.screenToTime(0);
+1127     var end = this.screenToTime(size.contentWidth);
+1128 
+1129     // calculate minimum step (in milliseconds) based on character size
+1130     if (size.axis.characterMinorWidth) {
+1131         this.minimumStep = this.screenToTime(size.axis.characterMinorWidth * 6) -
+1132             this.screenToTime(0);
+1133 
+1134         step.setRange(start, end, this.minimumStep);
+1135     }
+1136 
+1137     var charsNeedsReflow = this.repaintAxisCharacters();
+1138     needsReflow = needsReflow || charsNeedsReflow;
+1139 
+1140     // The current labels on the axis will be re-used (much better performance),
+1141     // therefore, the repaintAxis method uses the mechanism with
+1142     // repaintAxisStartOverwriting, repaintAxisEndOverwriting, and
+1143     // this.size.axis.properties is used.
+1144     this.repaintAxisStartOverwriting();
+1145 
+1146     step.start();
+1147     var xFirstMajorLabel = undefined;
+1148     var max = 0;
+1149     while (!step.end() && max < 1000) {
+1150         max++;
+1151         var cur = step.getCurrent(),
+1152             x = this.timeToScreen(cur),
+1153             isMajor = step.isMajor();
+1154 
+1155         if (options.showMinorLabels) {
+1156             this.repaintAxisMinorText(x, step.getLabelMinor(options));
+1157         }
+1158 
+1159         if (isMajor && options.showMajorLabels) {
+1160             if (x > 0) {
+1161                 if (xFirstMajorLabel == undefined) {
+1162                     xFirstMajorLabel = x;
+1163                 }
+1164                 this.repaintAxisMajorText(x, step.getLabelMajor(options));
+1165             }
+1166             this.repaintAxisMajorLine(x);
+1167         }
+1168         else {
+1169             this.repaintAxisMinorLine(x);
+1170         }
+1171 
+1172         step.next();
+1173     }
+1174 
+1175     // create a major label on the left when needed
+1176     if (options.showMajorLabels) {
+1177         var leftTime = this.screenToTime(0),
+1178             leftText = this.step.getLabelMajor(options, leftTime),
+1179             width = leftText.length * size.axis.characterMajorWidth + 10; // upper bound estimation
+1180 
+1181         if (xFirstMajorLabel == undefined || width < xFirstMajorLabel) {
+1182             this.repaintAxisMajorText(0, leftText, leftTime);
+1183         }
+1184     }
+1185 
+1186     // cleanup left over labels
+1187     this.repaintAxisEndOverwriting();
+1188 
+1189     this.repaintAxisHorizontal();
+1190 
+1191     // put axis online
+1192     dom.content.insertBefore(axis.frame, dom.content.firstChild);
+1193 
+1194     return needsReflow;
+1195 };
+1196 
+1197 /**
+1198  * Create characters used to determine the size of text on the axis
+1199  * @return {boolean} needsReflow   Returns true if the DOM is changed such that
+1200  *                                 a reflow is needed.
+1201  */
+1202 links.Timeline.prototype.repaintAxisCharacters = function () {
+1203     // calculate the width and height of a single character
+1204     // this is used to calculate the step size, and also the positioning of the
+1205     // axis
+1206     var needsReflow = false,
+1207         dom = this.dom,
+1208         axis = dom.axis,
+1209         text;
+1210 
+1211     if (!axis.characterMinor) {
+1212         text = document.createTextNode("0");
+1213         var characterMinor = document.createElement("DIV");
+1214         characterMinor.className = "timeline-axis-text timeline-axis-text-minor";
+1215         characterMinor.appendChild(text);
+1216         characterMinor.style.position = "absolute";
+1217         characterMinor.style.visibility = "hidden";
+1218         characterMinor.style.paddingLeft = "0px";
+1219         characterMinor.style.paddingRight = "0px";
+1220         axis.frame.appendChild(characterMinor);
+1221 
+1222         axis.characterMinor = characterMinor;
+1223         needsReflow = true;
+1224     }
+1225 
+1226     if (!axis.characterMajor) {
+1227         text = document.createTextNode("0");
+1228         var characterMajor = document.createElement("DIV");
+1229         characterMajor.className = "timeline-axis-text timeline-axis-text-major";
+1230         characterMajor.appendChild(text);
+1231         characterMajor.style.position = "absolute";
+1232         characterMajor.style.visibility = "hidden";
+1233         characterMajor.style.paddingLeft = "0px";
+1234         characterMajor.style.paddingRight = "0px";
+1235         axis.frame.appendChild(characterMajor);
+1236 
+1237         axis.characterMajor = characterMajor;
+1238         needsReflow = true;
+1239     }
+1240 
+1241     return needsReflow;
+1242 };
+1243 
+1244 /**
+1245  * Initialize redraw of the axis. All existing labels and lines will be
+1246  * overwritten and reused.
+1247  */
+1248 links.Timeline.prototype.repaintAxisStartOverwriting = function () {
+1249     var properties = this.size.axis.properties;
+1250 
+1251     properties.minorTextNum = 0;
+1252     properties.minorLineNum = 0;
+1253     properties.majorTextNum = 0;
+1254     properties.majorLineNum = 0;
+1255 };
+1256 
+1257 /**
+1258  * End of overwriting HTML DOM elements of the axis.
+1259  * remaining elements will be removed
+1260  */
+1261 links.Timeline.prototype.repaintAxisEndOverwriting = function () {
+1262     var dom = this.dom,
+1263         props = this.size.axis.properties,
+1264         frame = this.dom.axis.frame,
+1265         num;
+1266 
+1267     // remove leftovers
+1268     var minorTexts = dom.axis.minorTexts;
+1269     num = props.minorTextNum;
+1270     while (minorTexts.length > num) {
+1271         var minorText = minorTexts[num];
+1272         frame.removeChild(minorText);
+1273         minorTexts.splice(num, 1);
+1274     }
+1275 
+1276     var minorLines = dom.axis.minorLines;
+1277     num = props.minorLineNum;
+1278     while (minorLines.length > num) {
+1279         var minorLine = minorLines[num];
+1280         frame.removeChild(minorLine);
+1281         minorLines.splice(num, 1);
+1282     }
+1283 
+1284     var majorTexts = dom.axis.majorTexts;
+1285     num = props.majorTextNum;
+1286     while (majorTexts.length > num) {
+1287         var majorText = majorTexts[num];
+1288         frame.removeChild(majorText);
+1289         majorTexts.splice(num, 1);
+1290     }
+1291 
+1292     var majorLines = dom.axis.majorLines;
+1293     num = props.majorLineNum;
+1294     while (majorLines.length > num) {
+1295         var majorLine = majorLines[num];
+1296         frame.removeChild(majorLine);
+1297         majorLines.splice(num, 1);
+1298     }
+1299 };
+1300 
+1301 /**
+1302  * Repaint the horizontal line and background of the axis
+1303  */
+1304 links.Timeline.prototype.repaintAxisHorizontal = function() {
+1305     var axis = this.dom.axis,
+1306         size = this.size,
+1307         options = this.options;
+1308 
+1309     // line behind all axis elements (possibly having a background color)
+1310     var hasAxis = (options.showMinorLabels || options.showMajorLabels);
+1311     if (hasAxis) {
+1312         if (!axis.backgroundLine) {
+1313             // create the axis line background (for a background color or so)
+1314             var backgroundLine = document.createElement("DIV");
+1315             backgroundLine.className = "timeline-axis";
+1316             backgroundLine.style.position = "absolute";
+1317             backgroundLine.style.left = "0px";
+1318             backgroundLine.style.width = "100%";
+1319             backgroundLine.style.border = "none";
+1320             axis.frame.insertBefore(backgroundLine, axis.frame.firstChild);
+1321 
+1322             axis.backgroundLine = backgroundLine;
+1323         }
+1324 
+1325         if (axis.backgroundLine) {
+1326             axis.backgroundLine.style.top = size.axis.top + "px";
+1327             axis.backgroundLine.style.height = size.axis.height + "px";
+1328         }
+1329     }
+1330     else {
+1331         if (axis.backgroundLine) {
+1332             axis.frame.removeChild(axis.backgroundLine);
+1333             delete axis.backgroundLine;
+1334         }
+1335     }
+1336 
+1337     // line before all axis elements
+1338     if (hasAxis) {
+1339         if (axis.line) {
+1340             // put this line at the end of all childs
+1341             var line = axis.frame.removeChild(axis.line);
+1342             axis.frame.appendChild(line);
+1343         }
+1344         else {
+1345             // make the axis line
+1346             var line = document.createElement("DIV");
+1347             line.className = "timeline-axis";
+1348             line.style.position = "absolute";
+1349             line.style.left = "0px";
+1350             line.style.width = "100%";
+1351             line.style.height = "0px";
+1352             axis.frame.appendChild(line);
+1353 
+1354             axis.line = line;
+1355         }
+1356 
+1357         axis.line.style.top = size.axis.line + "px";
+1358     }
+1359     else {
+1360         if (axis.line && axis.line.parentElement) {
+1361             axis.frame.removeChild(axis.line);
+1362             delete axis.line;
+1363         }
+1364     }
+1365 };
+1366 
+1367 /**
+1368  * Create a minor label for the axis at position x
+1369  * @param {Number} x
+1370  * @param {String} text
+1371  */
+1372 links.Timeline.prototype.repaintAxisMinorText = function (x, text) {
+1373     var size = this.size,
+1374         dom = this.dom,
+1375         props = size.axis.properties,
+1376         frame = dom.axis.frame,
+1377         minorTexts = dom.axis.minorTexts,
+1378         index = props.minorTextNum,
+1379         label;
+1380 
+1381     if (index < minorTexts.length) {
+1382         label = minorTexts[index]
+1383     }
+1384     else {
+1385         // create new label
+1386         var content = document.createTextNode("");
+1387         label = document.createElement("DIV");
+1388         label.appendChild(content);
+1389         label.className = "timeline-axis-text timeline-axis-text-minor";
+1390         label.style.position = "absolute";
+1391 
+1392         frame.appendChild(label);
+1393 
+1394         minorTexts.push(label);
+1395     }
+1396 
+1397     label.childNodes[0].nodeValue = text;
+1398     label.style.left = x + "px";
+1399     label.style.top  = size.axis.labelMinorTop + "px";
+1400     //label.title = title;  // TODO: this is a heavy operation
+1401 
+1402     props.minorTextNum++;
+1403 };
+1404 
+1405 /**
+1406  * Create a minor line for the axis at position x
+1407  * @param {Number} x
+1408  */
+1409 links.Timeline.prototype.repaintAxisMinorLine = function (x) {
+1410     var axis = this.size.axis,
+1411         dom = this.dom,
+1412         props = axis.properties,
+1413         frame = dom.axis.frame,
+1414         minorLines = dom.axis.minorLines,
+1415         index = props.minorLineNum,
+1416         line;
+1417 
+1418     if (index < minorLines.length) {
+1419         line = minorLines[index];
+1420     }
+1421     else {
+1422         // create vertical line
+1423         line = document.createElement("DIV");
+1424         line.className = "timeline-axis-grid timeline-axis-grid-minor";
+1425         line.style.position = "absolute";
+1426         line.style.width = "0px";
+1427 
+1428         frame.appendChild(line);
+1429         minorLines.push(line);
+1430     }
+1431 
+1432     line.style.top = axis.lineMinorTop + "px";
+1433     line.style.height = axis.lineMinorHeight + "px";
+1434     line.style.left = (x - axis.lineMinorWidth/2) + "px";
+1435 
+1436     props.minorLineNum++;
+1437 };
+1438 
+1439 /**
+1440  * Create a Major label for the axis at position x
+1441  * @param {Number} x
+1442  * @param {String} text
+1443  */
+1444 links.Timeline.prototype.repaintAxisMajorText = function (x, text) {
+1445     var size = this.size,
+1446         props = size.axis.properties,
+1447         frame = this.dom.axis.frame,
+1448         majorTexts = this.dom.axis.majorTexts,
+1449         index = props.majorTextNum,
+1450         label;
+1451 
+1452     if (index < majorTexts.length) {
+1453         label = majorTexts[index];
+1454     }
+1455     else {
+1456         // create label
+1457         var content = document.createTextNode(text);
+1458         label = document.createElement("DIV");
+1459         label.className = "timeline-axis-text timeline-axis-text-major";
+1460         label.appendChild(content);
+1461         label.style.position = "absolute";
+1462         label.style.top = "0px";
+1463 
+1464         frame.appendChild(label);
+1465         majorTexts.push(label);
+1466     }
+1467 
+1468     label.childNodes[0].nodeValue = text;
+1469     label.style.top = size.axis.labelMajorTop + "px";
+1470     label.style.left = x + "px";
+1471     //label.title = title; // TODO: this is a heavy operation
+1472 
+1473     props.majorTextNum ++;
+1474 };
+1475 
+1476 /**
+1477  * Create a Major line for the axis at position x
+1478  * @param {Number} x
+1479  */
+1480 links.Timeline.prototype.repaintAxisMajorLine = function (x) {
+1481     var size = this.size,
+1482         props = size.axis.properties,
+1483         axis = this.size.axis,
+1484         frame = this.dom.axis.frame,
+1485         majorLines = this.dom.axis.majorLines,
+1486         index = props.majorLineNum,
+1487         line;
+1488 
+1489     if (index < majorLines.length) {
+1490         line = majorLines[index];
+1491     }
+1492     else {
+1493         // create vertical line
+1494         line = document.createElement("DIV");
+1495         line.className = "timeline-axis-grid timeline-axis-grid-major";
+1496         line.style.position = "absolute";
+1497         line.style.top = "0px";
+1498         line.style.width = "0px";
+1499 
+1500         frame.appendChild(line);
+1501         majorLines.push(line);
+1502     }
+1503 
+1504     line.style.left = (x - axis.lineMajorWidth/2) + "px";
+1505     line.style.height = size.frameHeight + "px";
+1506 
+1507     props.majorLineNum ++;
+1508 };
+1509 
+1510 /**
+1511  * Reflow all items, retrieve their actual size
+1512  * @return {boolean} resized    returns true if any of the items is resized
+1513  */
+1514 links.Timeline.prototype.reflowItems = function() {
+1515     var resized = false,
+1516         i,
+1517         iMax,
+1518         group,
+1519         groups = this.groups,
+1520         renderedItems = this.renderedItems;
+1521 
+1522     if (groups) { // TODO: need to check if labels exists?
+1523         // loop through all groups to reset the items height
+1524         groups.forEach(function (group) {
+1525             group.itemsHeight = group.labelHeight || 0;
+1526         });
+1527     }
+1528 
+1529     // loop through the width and height of all visible items
+1530     for (i = 0, iMax = renderedItems.length; i < iMax; i++) {
+1531         var item = renderedItems[i],
+1532             domItem = item.dom;
+1533         group = item.group;
+1534 
+1535         if (domItem) {
+1536             // TODO: move updating width and height into item.reflow
+1537             var width = domItem ? domItem.clientWidth : 0;
+1538             var height = domItem ? domItem.clientHeight : 0;
+1539             resized = resized || (item.width != width);
+1540             resized = resized || (item.height != height);
+1541             item.width = width;
+1542             item.height = height;
+1543             //item.borderWidth = (domItem.offsetWidth - domItem.clientWidth - 2) / 2; // TODO: borderWidth
+1544             item.reflow();
+1545         }
+1546 
+1547         if (group) {
+1548             group.itemsHeight = Math.max(this.options.groupMinHeight,group.itemsHeight ?
+1549                 Math.max(group.itemsHeight, item.height) :
+1550                 item.height);
+1551         }
+1552     }
+1553 
+1554     return resized;
+1555 };
+1556 
+1557 /**
+1558  * Recalculate item properties:
+1559  * - the height of each group.
+1560  * - the actualHeight, from the stacked items or the sum of the group heights
+1561  * @return {boolean} resized    returns true if any of the items properties is
+1562  *                              changed
+1563  */
+1564 links.Timeline.prototype.recalcItems = function () {
+1565     var resized = false,
+1566         i,
+1567         iMax,
+1568         item,
+1569         finalItem,
+1570         finalItems,
+1571         group,
+1572         groups = this.groups,
+1573         size = this.size,
+1574         options = this.options,
+1575         renderedItems = this.renderedItems;
+1576 
+1577     var actualHeight = 0;
+1578     if (groups.length == 0) {
+1579         // calculate actual height of the timeline when there are no groups
+1580         // but stacked items
+1581         if (options.autoHeight || options.cluster) {
+1582             var min = 0,
+1583                 max = 0;
+1584 
+1585             if (this.stack && this.stack.finalItems) {
+1586                 // adjust the offset of all finalItems when the actualHeight has been changed
+1587                 finalItems = this.stack.finalItems;
+1588                 finalItem = finalItems[0];
+1589                 if (finalItem && finalItem.top) {
+1590                     min = finalItem.top;
+1591                     max = finalItem.top + finalItem.height;
+1592                 }
+1593                 for (i = 1, iMax = finalItems.length; i < iMax; i++) {
+1594                     finalItem = finalItems[i];
+1595                     min = Math.min(min, finalItem.top);
+1596                     max = Math.max(max, finalItem.top + finalItem.height);
+1597                 }
+1598             }
+1599             else {
+1600                 item = renderedItems[0];
+1601                 if (item && item.top) {
+1602                     min = item.top;
+1603                     max = item.top + item.height;
+1604                 }
+1605                 for (i = 1, iMax = renderedItems.length; i < iMax; i++) {
+1606                     item = renderedItems[i];
+1607                     if (item.top) {
+1608                         min = Math.min(min, item.top);
+1609                         max = Math.max(max, (item.top + item.height));
+1610                     }
+1611                 }
+1612             }
+1613 
+1614             actualHeight = (max - min) + 2 * options.eventMarginAxis + size.axis.height;
+1615             if (actualHeight < options.minHeight) {
+1616                 actualHeight = options.minHeight;
+1617             }
+1618 
+1619             if (size.actualHeight != actualHeight && options.autoHeight && !options.axisOnTop) {
+1620                 // adjust the offset of all items when the actualHeight has been changed
+1621                 var diff = actualHeight - size.actualHeight;
+1622                 if (this.stack && this.stack.finalItems) {
+1623                     finalItems = this.stack.finalItems;
+1624                     for (i = 0, iMax = finalItems.length; i < iMax; i++) {
+1625                         finalItems[i].top += diff;
+1626                         finalItems[i].item.top += diff;
+1627                     }
+1628                 }
+1629                 else {
+1630                     for (i = 0, iMax = renderedItems.length; i < iMax; i++) {
+1631                         renderedItems[i].top += diff;
+1632                     }
+1633                 }
+1634             }
+1635         }
+1636     }
+1637     else {
+1638         // loop through all groups to get the height of each group, and the
+1639         // total height
+1640         actualHeight = size.axis.height + 2 * options.eventMarginAxis;
+1641         for (i = 0, iMax = groups.length; i < iMax; i++) {
+1642             group = groups[i];
+1643 
+1644             //
+1645             // TODO: Do we want to apply a max height? how ?
+1646             //
+1647             var groupHeight = group.itemsHeight;
+1648             resized = resized || (groupHeight != group.height);
+1649             group.height = Math.max(groupHeight, options.groupMinHeight);
+1650 
+1651             actualHeight += groups[i].height + options.eventMargin;
+1652         }
+1653 
+1654         // calculate top positions of the group labels and lines
+1655         var eventMargin = options.eventMargin,
+1656             top = options.axisOnTop ?
+1657                 options.eventMarginAxis + eventMargin/2 :
+1658                 size.contentHeight - options.eventMarginAxis + eventMargin/ 2,
+1659             axisHeight = size.axis.height;
+1660 
+1661         for (i = 0, iMax = groups.length; i < iMax; i++) {
+1662             group = groups[i];
+1663             if (options.axisOnTop) {
+1664                 group.top = top + axisHeight;
+1665                 group.labelTop = top + axisHeight + (group.height - group.labelHeight) / 2;
+1666                 group.lineTop = top + axisHeight + group.height + eventMargin/2;
+1667                 top += group.height + eventMargin;
+1668             }
+1669             else {
+1670                 top -= group.height + eventMargin;
+1671                 group.top = top;
+1672                 group.labelTop = top + (group.height - group.labelHeight) / 2;
+1673                 group.lineTop = top - eventMargin/2;
+1674             }
+1675         }
+1676 
+1677         resized = true;
+1678     }
+1679 
+1680     if (actualHeight < options.minHeight) {
+1681         actualHeight = options.minHeight;
+1682     }
+1683     resized = resized || (actualHeight != size.actualHeight);
+1684     size.actualHeight = actualHeight;
+1685 
+1686     return resized;
+1687 };
+1688 
+1689 /**
+1690  * This method clears the (internal) array this.items in a safe way: neatly
+1691  * cleaning up the DOM, and accompanying arrays this.renderedItems and
+1692  * the created clusters.
+1693  */
+1694 links.Timeline.prototype.clearItems = function() {
+1695     // add all visible items to the list to be hidden
+1696     var hideItems = this.renderQueue.hide;
+1697     this.renderedItems.forEach(function (item) {
+1698         hideItems.push(item);
+1699     });
+1700 
+1701     // clear the cluster generator
+1702     this.clusterGenerator.clear();
+1703 
+1704     // actually clear the items
+1705     this.items = [];
+1706 };
+1707 
+1708 /**
+1709  * Repaint all items
+1710  * @return {boolean} needsReflow   Returns true if the DOM is changed such that
+1711  *                                 a reflow is needed.
+1712  */
+1713 links.Timeline.prototype.repaintItems = function() {
+1714     var i, iMax, item, index;
+1715 
+1716     var needsReflow = false,
+1717         dom = this.dom,
+1718         size = this.size,
+1719         timeline = this,
+1720         renderedItems = this.renderedItems;
+1721 
+1722     if (!dom.items) {
+1723         dom.items = {};
+1724     }
+1725 
+1726     // draw the frame containing the items
+1727     var frame = dom.items.frame;
+1728     if (!frame) {
+1729         frame = document.createElement("DIV");
+1730         frame.style.position = "relative";
+1731         dom.content.appendChild(frame);
+1732         dom.items.frame = frame;
+1733     }
+1734 
+1735     frame.style.left = "0px";
+1736     frame.style.top = size.items.top + "px";
+1737     frame.style.height = "0px";
+1738 
+1739     // Take frame offline (for faster manipulation of the DOM)
+1740     dom.content.removeChild(frame);
+1741 
+1742     // process the render queue with changes
+1743     var queue = this.renderQueue;
+1744     var newImageUrls = [];
+1745     needsReflow = needsReflow ||
+1746         (queue.show.length > 0) ||
+1747         (queue.update.length > 0) ||
+1748         (queue.hide.length > 0);   // TODO: reflow needed on hide of items?
+1749 
+1750     while (item = queue.show.shift()) {
+1751         item.showDOM(frame);
+1752         item.getImageUrls(newImageUrls);
+1753         renderedItems.push(item);
+1754     }
+1755     while (item = queue.update.shift()) {
+1756         item.updateDOM(frame);
+1757         item.getImageUrls(newImageUrls);
+1758         index = this.renderedItems.indexOf(item);
+1759         if (index == -1) {
+1760             renderedItems.push(item);
+1761         }
+1762     }
+1763     while (item = queue.hide.shift()) {
+1764         item.hideDOM(frame);
+1765         index = this.renderedItems.indexOf(item);
+1766         if (index != -1) {
+1767             renderedItems.splice(index, 1);
+1768         }
+1769     }
+1770 
+1771     // reposition all visible items
+1772     renderedItems.forEach(function (item) {
+1773         item.updatePosition(timeline);
+1774     });
+1775 
+1776     // redraw the delete button and dragareas of the selected item (if any)
+1777     this.repaintDeleteButton();
+1778     this.repaintDragAreas();
+1779 
+1780     // put frame online again
+1781     dom.content.appendChild(frame);
+1782 
+1783     if (newImageUrls.length) {
+1784         // retrieve all image sources from the items, and set a callback once
+1785         // all images are retrieved
+1786         var callback = function () {
+1787             timeline.render();
+1788         };
+1789         var sendCallbackWhenAlreadyLoaded = false;
+1790         links.imageloader.loadAll(newImageUrls, callback, sendCallbackWhenAlreadyLoaded);
+1791     }
+1792 
+1793     return needsReflow;
+1794 };
+1795 
+1796 /**
+1797  * Reflow the size of the groups
+1798  * @return {boolean} resized    Returns true if any of the frame elements
+1799  *                              have been resized.
+1800  */
+1801 links.Timeline.prototype.reflowGroups = function() {
+1802     var resized = false,
+1803         options = this.options,
+1804         size = this.size,
+1805         dom = this.dom;
+1806 
+1807     // calculate the groups width and height
+1808     // TODO: only update when data is changed! -> use an updateSeq
+1809     var groupsWidth = 0;
+1810 
+1811     // loop through all groups to get the labels width and height
+1812     var groups = this.groups;
+1813     var labels = this.dom.groups ? this.dom.groups.labels : [];
+1814     for (var i = 0, iMax = groups.length; i < iMax; i++) {
+1815         var group = groups[i];
+1816         var label = labels[i];
+1817         group.labelWidth  = label ? label.clientWidth : 0;
+1818         group.labelHeight = label ? label.clientHeight : 0;
+1819         group.width = group.labelWidth;  // TODO: group.width is redundant with labelWidth
+1820 
+1821         groupsWidth = Math.max(groupsWidth, group.width);
+1822     }
+1823 
+1824     // limit groupsWidth to the groups width in the options
+1825     if (options.groupsWidth !== undefined) {
+1826         groupsWidth = dom.groups && dom.groups.frame ? dom.groups.frame.clientWidth : 0;
+1827     }
+1828 
+1829     // compensate for the border width. TODO: calculate the real border width
+1830     groupsWidth += 1;
+1831 
+1832     var groupsLeft = options.groupsOnRight ? size.frameWidth - groupsWidth : 0;
+1833     resized = resized || (size.groupsWidth !== groupsWidth);
+1834     resized = resized || (size.groupsLeft !== groupsLeft);
+1835     size.groupsWidth = groupsWidth;
+1836     size.groupsLeft = groupsLeft;
+1837 
+1838     return resized;
+1839 };
+1840 
+1841 /**
+1842  * Redraw the group labels
+1843  */
+1844 links.Timeline.prototype.repaintGroups = function() {
+1845     var dom = this.dom,
+1846         timeline = this,
+1847         options = this.options,
+1848         size = this.size,
+1849         groups = this.groups;
+1850 
+1851     if (dom.groups === undefined) {
+1852         dom.groups = {};
+1853     }
+1854 
+1855     var labels = dom.groups.labels;
+1856     if (!labels) {
+1857         labels = [];
+1858         dom.groups.labels = labels;
+1859     }
+1860     var labelLines = dom.groups.labelLines;
+1861     if (!labelLines) {
+1862         labelLines = [];
+1863         dom.groups.labelLines = labelLines;
+1864     }
+1865     var itemLines = dom.groups.itemLines;
+1866     if (!itemLines) {
+1867         itemLines = [];
+1868         dom.groups.itemLines = itemLines;
+1869     }
+1870 
+1871     // create the frame for holding the groups
+1872     var frame = dom.groups.frame;
+1873     if (!frame) {
+1874         frame =  document.createElement("DIV");
+1875         frame.className = "timeline-groups-axis";
+1876         frame.style.position = "absolute";
+1877         frame.style.overflow = "hidden";
+1878         frame.style.top = "0px";
+1879         frame.style.height = "100%";
+1880 
+1881         dom.frame.appendChild(frame);
+1882         dom.groups.frame = frame;
+1883     }
+1884 
+1885     frame.style.left = size.groupsLeft + "px";
+1886     frame.style.width = (options.groupsWidth !== undefined) ?
+1887         options.groupsWidth :
+1888         size.groupsWidth + "px";
+1889 
+1890     // hide groups axis when there are no groups
+1891     if (groups.length == 0) {
+1892         frame.style.display = 'none';
+1893     }
+1894     else {
+1895         frame.style.display = '';
+1896     }
+1897 
+1898     // TODO: only create/update groups when data is changed.
+1899 
+1900     // create the items
+1901     var current = labels.length,
+1902         needed = groups.length;
+1903 
+1904     // overwrite existing group labels
+1905     for (var i = 0, iMax = Math.min(current, needed); i < iMax; i++) {
+1906         var group = groups[i];
+1907         var label = labels[i];
+1908         label.innerHTML = this.getGroupName(group);
+1909         label.style.display = '';
+1910     }
+1911 
+1912     // append new items when needed
+1913     for (var i = current; i < needed; i++) {
+1914         var group = groups[i];
+1915 
+1916         // create text label
+1917         var label = document.createElement("DIV");
+1918         label.className = "timeline-groups-text";
+1919         label.style.position = "absolute";
+1920         if (options.groupsWidth === undefined) {
+1921             label.style.whiteSpace = "nowrap";
+1922         }
+1923         label.innerHTML = this.getGroupName(group);
+1924         frame.appendChild(label);
+1925         labels[i] = label;
+1926 
+1927         // create the grid line between the group labels
+1928         var labelLine = document.createElement("DIV");
+1929         labelLine.className = "timeline-axis-grid timeline-axis-grid-minor";
+1930         labelLine.style.position = "absolute";
+1931         labelLine.style.left = "0px";
+1932         labelLine.style.width = "100%";
+1933         labelLine.style.height = "0px";
+1934         labelLine.style.borderTopStyle = "solid";
+1935         frame.appendChild(labelLine);
+1936         labelLines[i] = labelLine;
+1937 
+1938         // create the grid line between the items
+1939         var itemLine = document.createElement("DIV");
+1940         itemLine.className = "timeline-axis-grid timeline-axis-grid-minor";
+1941         itemLine.style.position = "absolute";
+1942         itemLine.style.left = "0px";
+1943         itemLine.style.width = "100%";
+1944         itemLine.style.height = "0px";
+1945         itemLine.style.borderTopStyle = "solid";
+1946         dom.content.insertBefore(itemLine, dom.content.firstChild);
+1947         itemLines[i] = itemLine;
+1948     }
+1949 
+1950     // remove redundant items from the DOM when needed
+1951     for (var i = needed; i < current; i++) {
+1952         var label = labels[i],
+1953             labelLine = labelLines[i],
+1954             itemLine = itemLines[i];
+1955 
+1956         frame.removeChild(label);
+1957         frame.removeChild(labelLine);
+1958         dom.content.removeChild(itemLine);
+1959     }
+1960     labels.splice(needed, current - needed);
+1961     labelLines.splice(needed, current - needed);
+1962     itemLines.splice(needed, current - needed);
+1963 
+1964     links.Timeline.addClassName(frame, options.groupsOnRight ? 'timeline-groups-axis-onright' : 'timeline-groups-axis-onleft');
+1965 
+1966     // position the groups
+1967     for (var i = 0, iMax = groups.length; i < iMax; i++) {
+1968         var group = groups[i],
+1969             label = labels[i],
+1970             labelLine = labelLines[i],
+1971             itemLine = itemLines[i];
+1972 
+1973         label.style.top = group.labelTop + "px";
+1974         labelLine.style.top = group.lineTop + "px";
+1975         itemLine.style.top = group.lineTop + "px";
+1976         itemLine.style.width = size.contentWidth + "px";
+1977     }
+1978 
+1979     if (!dom.groups.background) {
+1980         // create the axis grid line background
+1981         var background = document.createElement("DIV");
+1982         background.className = "timeline-axis";
+1983         background.style.position = "absolute";
+1984         background.style.left = "0px";
+1985         background.style.width = "100%";
+1986         background.style.border = "none";
+1987 
+1988         frame.appendChild(background);
+1989         dom.groups.background = background;
+1990     }
+1991     dom.groups.background.style.top = size.axis.top + 'px';
+1992     dom.groups.background.style.height = size.axis.height + 'px';
+1993 
+1994     if (!dom.groups.line) {
+1995         // create the axis grid line
+1996         var line = document.createElement("DIV");
+1997         line.className = "timeline-axis";
+1998         line.style.position = "absolute";
+1999         line.style.left = "0px";
+2000         line.style.width = "100%";
+2001         line.style.height = "0px";
+2002 
+2003         frame.appendChild(line);
+2004         dom.groups.line = line;
+2005     }
+2006     dom.groups.line.style.top = size.axis.line + 'px';
+2007 
+2008     // create a callback when there are images which are not yet loaded
+2009     // TODO: more efficiently load images in the groups
+2010     if (dom.groups.frame && groups.length) {
+2011         var imageUrls = [];
+2012         links.imageloader.filterImageUrls(dom.groups.frame, imageUrls);
+2013         if (imageUrls.length) {
+2014             // retrieve all image sources from the items, and set a callback once
+2015             // all images are retrieved
+2016             var callback = function () {
+2017                 timeline.render();
+2018             };
+2019             var sendCallbackWhenAlreadyLoaded = false;
+2020             links.imageloader.loadAll(imageUrls, callback, sendCallbackWhenAlreadyLoaded);
+2021         }
+2022     }
+2023 };
+2024 
+2025 
+2026 /**
+2027  * Redraw the current time bar
+2028  */
+2029 links.Timeline.prototype.repaintCurrentTime = function() {
+2030     var options = this.options,
+2031         dom = this.dom,
+2032         size = this.size;
+2033 
+2034     if (!options.showCurrentTime) {
+2035         if (dom.currentTime) {
+2036             dom.contentTimelines.removeChild(dom.currentTime);
+2037             delete dom.currentTime;
+2038         }
+2039 
+2040         return;
+2041     }
+2042 
+2043     if (!dom.currentTime) {
+2044         // create the current time bar
+2045         var currentTime = document.createElement("DIV");
+2046         currentTime.className = "timeline-currenttime";
+2047         currentTime.style.position = "absolute";
+2048         currentTime.style.top = "0px";
+2049         currentTime.style.height = "100%";
+2050 
+2051         dom.contentTimelines.appendChild(currentTime);
+2052         dom.currentTime = currentTime;
+2053     }
+2054 
+2055     var now = new Date();
+2056     var nowOffset = new Date(now.valueOf() + this.clientTimeOffset);
+2057     var x = this.timeToScreen(nowOffset);
+2058 
+2059     var visible = (x > -size.contentWidth && x < 2 * size.contentWidth);
+2060     dom.currentTime.style.display = visible ? '' : 'none';
+2061     dom.currentTime.style.left = x + "px";
+2062     dom.currentTime.title = "Current time: " + nowOffset;
+2063 
+2064     // start a timer to adjust for the new time
+2065     if (this.currentTimeTimer != undefined) {
+2066         clearTimeout(this.currentTimeTimer);
+2067         delete this.currentTimeTimer;
+2068     }
+2069     var timeline = this;
+2070     var onTimeout = function() {
+2071         timeline.repaintCurrentTime();
+2072     };
+2073     // the time equal to the width of one pixel, divided by 2 for more smoothness
+2074     var interval = 1 / this.conversion.factor / 2;
+2075     if (interval < 30) interval = 30;
+2076     this.currentTimeTimer = setTimeout(onTimeout, interval);
+2077 };
+2078 
+2079 /**
+2080  * Redraw the custom time bar
+2081  */
+2082 links.Timeline.prototype.repaintCustomTime = function() {
+2083     var options = this.options,
+2084         dom = this.dom,
+2085         size = this.size;
+2086 
+2087     if (!options.showCustomTime) {
+2088         if (dom.customTime) {
+2089             dom.contentTimelines.removeChild(dom.customTime);
+2090             delete dom.customTime;
+2091         }
+2092 
+2093         return;
+2094     }
+2095 
+2096     if (!dom.customTime) {
+2097         var customTime = document.createElement("DIV");
+2098         customTime.className = "timeline-customtime";
+2099         customTime.style.position = "absolute";
+2100         customTime.style.top = "0px";
+2101         customTime.style.height = "100%";
+2102 
+2103         var drag = document.createElement("DIV");
+2104         drag.style.position = "relative";
+2105         drag.style.top = "0px";
+2106         drag.style.left = "-10px";
+2107         drag.style.height = "100%";
+2108         drag.style.width = "20px";
+2109         customTime.appendChild(drag);
+2110 
+2111         dom.contentTimelines.appendChild(customTime);
+2112         dom.customTime = customTime;
+2113 
+2114         // initialize parameter
+2115         this.customTime = new Date();
+2116     }
+2117 
+2118     var x = this.timeToScreen(this.customTime),
+2119         visible = (x > -size.contentWidth && x < 2 * size.contentWidth);
+2120     dom.customTime.style.display = visible ? '' : 'none';
+2121     dom.customTime.style.left = x + "px";
+2122     dom.customTime.title = "Time: " + this.customTime;
+2123 };
+2124 
+2125 
+2126 /**
+2127  * Redraw the delete button, on the top right of the currently selected item
+2128  * if there is no item selected, the button is hidden.
+2129  */
+2130 links.Timeline.prototype.repaintDeleteButton = function () {
+2131     var timeline = this,
+2132         dom = this.dom,
+2133         frame = dom.items.frame;
+2134 
+2135     var deleteButton = dom.items.deleteButton;
+2136     if (!deleteButton) {
+2137         // create a delete button
+2138         deleteButton = document.createElement("DIV");
+2139         deleteButton.className = "timeline-navigation-delete";
+2140         deleteButton.style.position = "absolute";
+2141 
+2142         frame.appendChild(deleteButton);
+2143         dom.items.deleteButton = deleteButton;
+2144     }
+2145 
+2146     var index = (this.selection && this.selection.index !== undefined) ? this.selection.index : -1,
+2147         item = (this.selection && this.selection.index !== undefined) ? this.items[index] : undefined;
+2148     if (item && item.rendered && this.isEditable(item)) {
+2149         var right = item.getRight(this),
+2150             top = item.top;
+2151 
+2152         deleteButton.style.left = right + 'px';
+2153         deleteButton.style.top = top + 'px';
+2154         deleteButton.style.display = '';
+2155         frame.removeChild(deleteButton);
+2156         frame.appendChild(deleteButton);
+2157     }
+2158     else {
+2159         deleteButton.style.display = 'none';
+2160     }
+2161 };
+2162 
+2163 
+2164 /**
+2165  * Redraw the drag areas. When an item (ranges only) is selected,
+2166  * it gets a drag area on the left and right side, to change its width
+2167  */
+2168 links.Timeline.prototype.repaintDragAreas = function () {
+2169     var timeline = this,
+2170         options = this.options,
+2171         dom = this.dom,
+2172         frame = this.dom.items.frame;
+2173 
+2174     // create left drag area
+2175     var dragLeft = dom.items.dragLeft;
+2176     if (!dragLeft) {
+2177         dragLeft = document.createElement("DIV");
+2178         dragLeft.className="timeline-event-range-drag-left";
+2179         dragLeft.style.position = "absolute";
+2180 
+2181         frame.appendChild(dragLeft);
+2182         dom.items.dragLeft = dragLeft;
+2183     }
+2184 
+2185     // create right drag area
+2186     var dragRight = dom.items.dragRight;
+2187     if (!dragRight) {
+2188         dragRight = document.createElement("DIV");
+2189         dragRight.className="timeline-event-range-drag-right";
+2190         dragRight.style.position = "absolute";
+2191 
+2192         frame.appendChild(dragRight);
+2193         dom.items.dragRight = dragRight;
+2194     }
+2195 
+2196     // reposition left and right drag area
+2197     var index = (this.selection && this.selection.index !== undefined) ? this.selection.index : -1,
+2198         item = (this.selection && this.selection.index !== undefined) ? this.items[index] : undefined;
+2199     if (item && item.rendered && this.isEditable(item) &&
+2200         (item instanceof links.Timeline.ItemRange || item instanceof links.Timeline.ItemFloatingRange)) {
+2201         var left = item.getLeft(this), // NH change to getLeft
+2202             right = item.getRight(this), // NH change to getRight
+2203             top = item.top,
+2204             height = item.height;
+2205 
+2206         dragLeft.style.left = left + 'px';
+2207         dragLeft.style.top = top + 'px';
+2208         dragLeft.style.width = options.dragAreaWidth + "px";
+2209         dragLeft.style.height = height + 'px';
+2210         dragLeft.style.display = '';
+2211         frame.removeChild(dragLeft);
+2212         frame.appendChild(dragLeft);
+2213 
+2214         dragRight.style.left = (right - options.dragAreaWidth) + 'px';
+2215         dragRight.style.top = top + 'px';
+2216         dragRight.style.width = options.dragAreaWidth + "px";
+2217         dragRight.style.height = height + 'px';
+2218         dragRight.style.display = '';
+2219         frame.removeChild(dragRight);
+2220         frame.appendChild(dragRight);
+2221     }
+2222     else {
+2223         dragLeft.style.display = 'none';
+2224         dragRight.style.display = 'none';
+2225     }
+2226 };
+2227 
+2228 /**
+2229  * Create the navigation buttons for zooming and moving
+2230  */
+2231 links.Timeline.prototype.repaintNavigation = function () {
+2232     var timeline = this,
+2233         options = this.options,
+2234         dom = this.dom,
+2235         frame = dom.frame,
+2236         navBar = dom.navBar;
+2237 
+2238     if (!navBar) {
+2239         var showButtonNew = options.showButtonNew && options.editable;
+2240         var showNavigation = options.showNavigation && (options.zoomable || options.moveable);
+2241         if (showNavigation || showButtonNew) {
+2242             // create a navigation bar containing the navigation buttons
+2243             navBar = document.createElement("DIV");
+2244             navBar.style.position = "absolute";
+2245             navBar.className = "timeline-navigation ui-widget ui-state-highlight ui-corner-all";
+2246             if (options.groupsOnRight) {
+2247                 navBar.style.left = '10px';
+2248             }
+2249             else {
+2250                 navBar.style.right = '10px';
+2251             }
+2252             if (options.axisOnTop) {
+2253                 navBar.style.bottom = '10px';
+2254             }
+2255             else {
+2256                 navBar.style.top = '10px';
+2257             }
+2258             dom.navBar = navBar;
+2259             frame.appendChild(navBar);
+2260         }
+2261 
+2262         if (showButtonNew) {
+2263             // create a new in button
+2264             navBar.addButton = document.createElement("DIV");
+2265             navBar.addButton.className = "timeline-navigation-new";
+2266             navBar.addButton.title = options.CREATE_NEW_EVENT;
+2267             var addIconSpan = document.createElement("SPAN");
+2268             addIconSpan.className = "ui-icon ui-icon-circle-plus";
+2269             navBar.addButton.appendChild(addIconSpan);
+2270 
+2271             var onAdd = function(event) {
+2272                 links.Timeline.preventDefault(event);
+2273                 links.Timeline.stopPropagation(event);
+2274 
+2275                 // create a new event at the center of the frame
+2276                 var w = timeline.size.contentWidth;
+2277                 var x = w / 2;
+2278                 var xstart = timeline.screenToTime(x);
+2279                 if (options.snapEvents) {
+2280                     timeline.step.snap(xstart);
+2281                 }
+2282 
+2283                 var content = options.NEW;
+2284                 var group = timeline.groups.length ? timeline.groups[0].content : undefined;
+2285                 var preventRender = true;
+2286                 timeline.addItem({
+2287                     'start': xstart,
+2288                     'content': content,
+2289                     'group': group
+2290                 }, preventRender);
+2291                 var index = (timeline.items.length - 1);
+2292                 timeline.selectItem(index);
+2293 
+2294                 timeline.applyAdd = true;
+2295 
+2296                 // fire an add event.
+2297                 // Note that the change can be canceled from within an event listener if
+2298                 // this listener calls the method cancelAdd().
+2299                 timeline.trigger('add');
+2300 
+2301                 if (timeline.applyAdd) {
+2302                     // render and select the item
+2303                     timeline.render({animate: false});
+2304                     timeline.selectItem(index);
+2305                 }
+2306                 else {
+2307                     // undo an add
+2308                     timeline.deleteItem(index);
+2309                 }
+2310             };
+2311             links.Timeline.addEventListener(navBar.addButton, "mousedown", onAdd);
+2312             navBar.appendChild(navBar.addButton);
+2313         }
+2314 
+2315         if (showButtonNew && showNavigation) {
+2316             // create a separator line
+2317             links.Timeline.addClassName(navBar.addButton, 'timeline-navigation-new-line');
+2318         }
+2319 
+2320         if (showNavigation) {
+2321             if (options.zoomable) {
+2322                 // create a zoom in button
+2323                 navBar.zoomInButton = document.createElement("DIV");
+2324                 navBar.zoomInButton.className = "timeline-navigation-zoom-in";
+2325                 navBar.zoomInButton.title = this.options.ZOOM_IN;
+2326                 var ziIconSpan = document.createElement("SPAN");
+2327                 ziIconSpan.className = "ui-icon ui-icon-circle-zoomin";
+2328                 navBar.zoomInButton.appendChild(ziIconSpan);
+2329 
+2330                 var onZoomIn = function(event) {
+2331                     links.Timeline.preventDefault(event);
+2332                     links.Timeline.stopPropagation(event);
+2333                     timeline.zoom(0.4);
+2334                     timeline.trigger("rangechange");
+2335                     timeline.trigger("rangechanged");
+2336                 };
+2337                 links.Timeline.addEventListener(navBar.zoomInButton, "mousedown", onZoomIn);
+2338                 navBar.appendChild(navBar.zoomInButton);
+2339 
+2340                 // create a zoom out button
+2341                 navBar.zoomOutButton = document.createElement("DIV");
+2342                 navBar.zoomOutButton.className = "timeline-navigation-zoom-out";
+2343                 navBar.zoomOutButton.title = this.options.ZOOM_OUT;
+2344                 var zoIconSpan = document.createElement("SPAN");
+2345                 zoIconSpan.className = "ui-icon ui-icon-circle-zoomout";
+2346                 navBar.zoomOutButton.appendChild(zoIconSpan);
+2347 
+2348                 var onZoomOut = function(event) {
+2349                     links.Timeline.preventDefault(event);
+2350                     links.Timeline.stopPropagation(event);
+2351                     timeline.zoom(-0.4);
+2352                     timeline.trigger("rangechange");
+2353                     timeline.trigger("rangechanged");
+2354                 };
+2355                 links.Timeline.addEventListener(navBar.zoomOutButton, "mousedown", onZoomOut);
+2356                 navBar.appendChild(navBar.zoomOutButton);
+2357             }
+2358 
+2359             if (options.moveable) {
+2360                 // create a move left button
+2361                 navBar.moveLeftButton = document.createElement("DIV");
+2362                 navBar.moveLeftButton.className = "timeline-navigation-move-left";
+2363                 navBar.moveLeftButton.title = this.options.MOVE_LEFT;
+2364                 var mlIconSpan = document.createElement("SPAN");
+2365                 mlIconSpan.className = "ui-icon ui-icon-circle-arrow-w";
+2366                 navBar.moveLeftButton.appendChild(mlIconSpan);
+2367 
+2368                 var onMoveLeft = function(event) {
+2369                     links.Timeline.preventDefault(event);
+2370                     links.Timeline.stopPropagation(event);
+2371                     timeline.move(-0.2);
+2372                     timeline.trigger("rangechange");
+2373                     timeline.trigger("rangechanged");
+2374                 };
+2375                 links.Timeline.addEventListener(navBar.moveLeftButton, "mousedown", onMoveLeft);
+2376                 navBar.appendChild(navBar.moveLeftButton);
+2377 
+2378                 // create a move right button
+2379                 navBar.moveRightButton = document.createElement("DIV");
+2380                 navBar.moveRightButton.className = "timeline-navigation-move-right";
+2381                 navBar.moveRightButton.title = this.options.MOVE_RIGHT;
+2382                 var mrIconSpan = document.createElement("SPAN");
+2383                 mrIconSpan.className = "ui-icon ui-icon-circle-arrow-e";
+2384                 navBar.moveRightButton.appendChild(mrIconSpan);
+2385 
+2386                 var onMoveRight = function(event) {
+2387                     links.Timeline.preventDefault(event);
+2388                     links.Timeline.stopPropagation(event);
+2389                     timeline.move(0.2);
+2390                     timeline.trigger("rangechange");
+2391                     timeline.trigger("rangechanged");
+2392                 };
+2393                 links.Timeline.addEventListener(navBar.moveRightButton, "mousedown", onMoveRight);
+2394                 navBar.appendChild(navBar.moveRightButton);
+2395             }
+2396         }
+2397     }
+2398 };
+2399 
+2400 
+2401 /**
+2402  * Set current time. This function can be used to set the time in the client
+2403  * timeline equal with the time on a server.
+2404  * @param {Date} time
+2405  */
+2406 links.Timeline.prototype.setCurrentTime = function(time) {
+2407     var now = new Date();
+2408     this.clientTimeOffset = (time.valueOf() - now.valueOf());
+2409 
+2410     this.repaintCurrentTime();
+2411 };
+2412 
+2413 /**
+2414  * Get current time. The time can have an offset from the real time, when
+2415  * the current time has been changed via the method setCurrentTime.
+2416  * @return {Date} time
+2417  */
+2418 links.Timeline.prototype.getCurrentTime = function() {
+2419     var now = new Date();
+2420     return new Date(now.valueOf() + this.clientTimeOffset);
+2421 };
+2422 
+2423 
+2424 /**
+2425  * Set custom time.
+2426  * The custom time bar can be used to display events in past or future.
+2427  * @param {Date} time
+2428  */
+2429 links.Timeline.prototype.setCustomTime = function(time) {
+2430     this.customTime = new Date(time.valueOf());
+2431     this.repaintCustomTime();
+2432 };
+2433 
+2434 /**
+2435  * Retrieve the current custom time.
+2436  * @return {Date} customTime
+2437  */
+2438 links.Timeline.prototype.getCustomTime = function() {
+2439     return new Date(this.customTime.valueOf());
+2440 };
+2441 
+2442 /**
+2443  * Set a custom scale. Autoscaling will be disabled.
+2444  * For example setScale(SCALE.MINUTES, 5) will result
+2445  * in minor steps of 5 minutes, and major steps of an hour.
+2446  *
+2447  * @param {links.Timeline.StepDate.SCALE} scale
+2448  *                               A scale. Choose from SCALE.MILLISECOND,
+2449  *                               SCALE.SECOND, SCALE.MINUTE, SCALE.HOUR,
+2450  *                               SCALE.WEEKDAY, SCALE.DAY, SCALE.MONTH,
+2451  *                               SCALE.YEAR.
+2452  * @param {int}        step   A step size, by default 1. Choose for
+2453  *                               example 1, 2, 5, or 10.
+2454  */
+2455 links.Timeline.prototype.setScale = function(scale, step) {
+2456     this.step.setScale(scale, step);
+2457     this.render(); // TODO: optimize: only reflow/repaint axis
+2458 };
+2459 
+2460 /**
+2461  * Enable or disable autoscaling
+2462  * @param {boolean} enable  If true or not defined, autoscaling is enabled.
+2463  *                          If false, autoscaling is disabled.
+2464  */
+2465 links.Timeline.prototype.setAutoScale = function(enable) {
+2466     this.step.setAutoScale(enable);
+2467     this.render(); // TODO: optimize: only reflow/repaint axis
+2468 };
+2469 
+2470 /**
+2471  * Redraw the timeline
+2472  * Reloads the (linked) data table and redraws the timeline when resized.
+2473  * See also the method checkResize
+2474  */
+2475 links.Timeline.prototype.redraw = function() {
+2476     this.setData(this.data);
+2477 };
+2478 
+2479 
+2480 /**
+2481  * Check if the timeline is resized, and if so, redraw the timeline.
+2482  * Useful when the webpage is resized.
+2483  */
+2484 links.Timeline.prototype.checkResize = function() {
+2485     // TODO: re-implement the method checkResize, or better, make it redundant as this.render will be smarter
+2486     this.render();
+2487 };
+2488 
+2489 /**
+2490  * Check whether a given item is editable
+2491  * @param {links.Timeline.Item} item
+2492  * @return {boolean} editable
+2493  */
+2494 links.Timeline.prototype.isEditable = function (item) {
+2495     if (item) {
+2496         if (item.editable != undefined) {
+2497             return item.editable;
+2498         }
+2499         else {
+2500             return this.options.editable;
+2501         }
+2502     }
+2503     return false;
+2504 };
+2505 
+2506 /**
+2507  * Calculate the factor and offset to convert a position on screen to the
+2508  * corresponding date and vice versa.
+2509  * After the method calcConversionFactor is executed once, the methods screenToTime and
+2510  * timeToScreen can be used.
+2511  */
+2512 links.Timeline.prototype.recalcConversion = function() {
+2513     this.conversion.offset = this.start.valueOf();
+2514     this.conversion.factor = this.size.contentWidth /
+2515         (this.end.valueOf() - this.start.valueOf());
+2516 };
+2517 
+2518 
+2519 /**
+2520  * Convert a position on screen (pixels) to a datetime
+2521  * Before this method can be used, the method calcConversionFactor must be
+2522  * executed once.
+2523  * @param {int}     x    Position on the screen in pixels
+2524  * @return {Date}   time The datetime the corresponds with given position x
+2525  */
+2526 links.Timeline.prototype.screenToTime = function(x) {
+2527     var conversion = this.conversion;
+2528     return new Date(x / conversion.factor + conversion.offset);
+2529 };
+2530 
+2531 /**
+2532  * Convert a datetime (Date object) into a position on the screen
+2533  * Before this method can be used, the method calcConversionFactor must be
+2534  * executed once.
+2535  * @param {Date}   time A date
+2536  * @return {int}   x    The position on the screen in pixels which corresponds
+2537  *                      with the given date.
+2538  */
+2539 links.Timeline.prototype.timeToScreen = function(time) {
+2540     var conversion = this.conversion;
+2541     return (time.valueOf() - conversion.offset) * conversion.factor;
+2542 };
+2543 
+2544 
+2545 
+2546 /**
+2547  * Event handler for touchstart event on mobile devices
+2548  */
+2549 links.Timeline.prototype.onTouchStart = function(event) {
+2550     var params = this.eventParams,
+2551         me = this;
+2552 
+2553     if (params.touchDown) {
+2554         // if already moving, return
+2555         return;
+2556     }
+2557 
+2558     params.touchDown = true;
+2559     params.zoomed = false;
+2560 
+2561     this.onMouseDown(event);
+2562 
+2563     if (!params.onTouchMove) {
+2564         params.onTouchMove = function (event) {me.onTouchMove(event);};
+2565         links.Timeline.addEventListener(document, "touchmove", params.onTouchMove);
+2566     }
+2567     if (!params.onTouchEnd) {
+2568         params.onTouchEnd  = function (event) {me.onTouchEnd(event);};
+2569         links.Timeline.addEventListener(document, "touchend",  params.onTouchEnd);
+2570     }
+2571 
+2572     /* TODO
+2573      // check for double tap event
+2574      var delta = 500; // ms
+2575      var doubleTapStart = (new Date()).valueOf();
+2576      var target = links.Timeline.getTarget(event);
+2577      var doubleTapItem = this.getItemIndex(target);
+2578      if (params.doubleTapStart &&
+2579      (doubleTapStart - params.doubleTapStart) < delta &&
+2580      doubleTapItem == params.doubleTapItem) {
+2581      delete params.doubleTapStart;
+2582      delete params.doubleTapItem;
+2583      me.onDblClick(event);
+2584      params.touchDown = false;
+2585      }
+2586      params.doubleTapStart = doubleTapStart;
+2587      params.doubleTapItem = doubleTapItem;
+2588      */
+2589     // store timing for double taps
+2590     var target = links.Timeline.getTarget(event);
+2591     var item = this.getItemIndex(target);
+2592     params.doubleTapStartPrev = params.doubleTapStart;
+2593     params.doubleTapStart = (new Date()).valueOf();
+2594     params.doubleTapItemPrev = params.doubleTapItem;
+2595     params.doubleTapItem = item;
+2596 
+2597     links.Timeline.preventDefault(event);
+2598 };
+2599 
+2600 /**
+2601  * Event handler for touchmove event on mobile devices
+2602  */
+2603 links.Timeline.prototype.onTouchMove = function(event) {
+2604     var params = this.eventParams;
+2605 
+2606     if (event.scale && event.scale !== 1) {
+2607         params.zoomed = true;
+2608     }
+2609 
+2610     if (!params.zoomed) {
+2611         // move
+2612         this.onMouseMove(event);
+2613     }
+2614     else {
+2615         if (this.options.zoomable) {
+2616             // pinch
+2617             // TODO: pinch only supported on iPhone/iPad. Create something manually for Android?
+2618             params.zoomed = true;
+2619 
+2620             var scale = event.scale,
+2621                 oldWidth = (params.end.valueOf() - params.start.valueOf()),
+2622                 newWidth = oldWidth / scale,
+2623                 diff = newWidth - oldWidth,
+2624                 start = new Date(parseInt(params.start.valueOf() - diff/2)),
+2625                 end = new Date(parseInt(params.end.valueOf() + diff/2));
+2626 
+2627             // TODO: determine zoom-around-date from touch positions?
+2628 
+2629             this.setVisibleChartRange(start, end);
+2630             this.trigger("rangechange");
+2631         }
+2632     }
+2633 
+2634     links.Timeline.preventDefault(event);
+2635 };
+2636 
+2637 /**
+2638  * Event handler for touchend event on mobile devices
+2639  */
+2640 links.Timeline.prototype.onTouchEnd = function(event) {
+2641     var params = this.eventParams;
+2642     var me = this;
+2643     params.touchDown = false;
+2644 
+2645     if (params.zoomed) {
+2646         this.trigger("rangechanged");
+2647     }
+2648 
+2649     if (params.onTouchMove) {
+2650         links.Timeline.removeEventListener(document, "touchmove", params.onTouchMove);
+2651         delete params.onTouchMove;
+2652 
+2653     }
+2654     if (params.onTouchEnd) {
+2655         links.Timeline.removeEventListener(document, "touchend",  params.onTouchEnd);
+2656         delete params.onTouchEnd;
+2657     }
+2658 
+2659     this.onMouseUp(event);
+2660 
+2661     // check for double tap event
+2662     var delta = 500; // ms
+2663     var doubleTapEnd = (new Date()).valueOf();
+2664     var target = links.Timeline.getTarget(event);
+2665     var doubleTapItem = this.getItemIndex(target);
+2666     if (params.doubleTapStartPrev &&
+2667         (doubleTapEnd - params.doubleTapStartPrev) < delta &&
+2668         params.doubleTapItem == params.doubleTapItemPrev) {
+2669         params.touchDown = true;
+2670         me.onDblClick(event);
+2671         params.touchDown = false;
+2672     }
+2673 
+2674     links.Timeline.preventDefault(event);
+2675 };
+2676 
+2677 
+2678 /**
+2679  * Start a moving operation inside the provided parent element
+2680  * @param {Event} event       The event that occurred (required for
+2681  *                             retrieving the  mouse position)
+2682  */
+2683 links.Timeline.prototype.onMouseDown = function(event) {
+2684     event = event || window.event;
+2685 
+2686     var params = this.eventParams,
+2687         options = this.options,
+2688         dom = this.dom;
+2689 
+2690     // only react on left mouse button down
+2691     var leftButtonDown = event.which ? (event.which == 1) : (event.button == 1);
+2692     if (!leftButtonDown && !params.touchDown) {
+2693         return;
+2694     }
+2695 
+2696     // get mouse position
+2697     params.mouseX = links.Timeline.getPageX(event);
+2698     params.mouseY = links.Timeline.getPageY(event);
+2699     params.frameLeft = links.Timeline.getAbsoluteLeft(this.dom.content);
+2700     params.frameTop = links.Timeline.getAbsoluteTop(this.dom.content);
+2701     params.previousLeft = 0;
+2702     params.previousOffset = 0;
+2703 
+2704     params.moved = false;
+2705     params.start = new Date(this.start.valueOf());
+2706     params.end = new Date(this.end.valueOf());
+2707 
+2708     params.target = links.Timeline.getTarget(event);
+2709     var dragLeft = (dom.items && dom.items.dragLeft) ? dom.items.dragLeft : undefined;
+2710     var dragRight = (dom.items && dom.items.dragRight) ? dom.items.dragRight : undefined;
+2711     params.itemDragLeft = (params.target === dragLeft);
+2712     params.itemDragRight = (params.target === dragRight);
+2713 
+2714     if (params.itemDragLeft || params.itemDragRight) {
+2715         params.itemIndex = (this.selection && this.selection.index !== undefined) ? this.selection.index : undefined;
+2716         delete params.clusterIndex;
+2717     }
+2718     else {
+2719         params.itemIndex = this.getItemIndex(params.target);
+2720         params.clusterIndex = this.getClusterIndex(params.target);
+2721     }
+2722 
+2723     params.customTime = (params.target === dom.customTime ||
+2724         params.target.parentNode === dom.customTime) ?
+2725         this.customTime :
+2726         undefined;
+2727 
+2728     params.addItem = (options.editable && event.ctrlKey);
+2729     if (params.addItem) {
+2730         // create a new event at the current mouse position
+2731         var x = params.mouseX - params.frameLeft;
+2732         var y = params.mouseY - params.frameTop;
+2733 
+2734         var xstart = this.screenToTime(x);
+2735         if (options.snapEvents) {
+2736             this.step.snap(xstart);
+2737         }
+2738         var xend = new Date(xstart.valueOf());
+2739         var content = options.NEW;
+2740         var group = this.getGroupFromHeight(y);
+2741         this.addItem({
+2742             'start': xstart,
+2743             'end': xend,
+2744             'content': content,
+2745             'group': this.getGroupName(group)
+2746         });
+2747         params.itemIndex = (this.items.length - 1);
+2748         delete params.clusterIndex;
+2749         this.selectItem(params.itemIndex);
+2750         params.itemDragRight = true;
+2751     }
+2752 
+2753     var item = this.items[params.itemIndex];
+2754     var isSelected = this.isSelected(params.itemIndex);
+2755     params.editItem = isSelected && this.isEditable(item);
+2756     if (params.editItem) {
+2757         params.itemStart = item.start;
+2758         params.itemEnd = item.end;
+2759         params.itemGroup = item.group;
+2760         params.itemLeft = item.getLeft(this); // NH Use item.getLeft here
+2761         params.itemRight = item.getRight(this); // NH Use item.getRight here
+2762     }
+2763     else {
+2764         this.dom.frame.style.cursor = 'move';
+2765     }
+2766     if (!params.touchDown) {
+2767         // add event listeners to handle moving the contents
+2768         // we store the function onmousemove and onmouseup in the timeline, so we can
+2769         // remove the eventlisteners lateron in the function mouseUp()
+2770         var me = this;
+2771         if (!params.onMouseMove) {
+2772             params.onMouseMove = function (event) {me.onMouseMove(event);};
+2773             links.Timeline.addEventListener(document, "mousemove", params.onMouseMove);
+2774         }
+2775         if (!params.onMouseUp) {
+2776             params.onMouseUp = function (event) {me.onMouseUp(event);};
+2777             links.Timeline.addEventListener(document, "mouseup", params.onMouseUp);
+2778         }
+2779 
+2780         links.Timeline.preventDefault(event);
+2781     }
+2782 };
+2783 
+2784 
+2785 /**
+2786  * Perform moving operating.
+2787  * This function activated from within the funcion links.Timeline.onMouseDown().
+2788  * @param {Event}   event  Well, eehh, the event
+2789  */
+2790 links.Timeline.prototype.onMouseMove = function (event) {
+2791     event = event || window.event;
+2792 
+2793     var params = this.eventParams,
+2794         size = this.size,
+2795         dom = this.dom,
+2796         options = this.options;
+2797 
+2798     // calculate change in mouse position
+2799     var mouseX = links.Timeline.getPageX(event);
+2800     var mouseY = links.Timeline.getPageY(event);
+2801 
+2802     if (params.mouseX == undefined) {
+2803         params.mouseX = mouseX;
+2804     }
+2805     if (params.mouseY == undefined) {
+2806         params.mouseY = mouseY;
+2807     }
+2808 
+2809     var diffX = mouseX - params.mouseX;
+2810     var diffY = mouseY - params.mouseY;
+2811 
+2812     // if mouse movement is big enough, register it as a "moved" event
+2813     if (Math.abs(diffX) >= 1) {
+2814         params.moved = true;
+2815     }
+2816 
+2817     if (params.customTime) {
+2818         var x = this.timeToScreen(params.customTime);
+2819         var xnew = x + diffX;
+2820         this.customTime = this.screenToTime(xnew);
+2821         this.repaintCustomTime();
+2822 
+2823         // fire a timechange event
+2824         this.trigger('timechange');
+2825     }
+2826     else if (params.editItem) {
+2827         var item = this.items[params.itemIndex],
+2828             left,
+2829             right;
+2830 
+2831         if (params.itemDragLeft && options.timeChangeable) {
+2832             // move the start of the item
+2833             left = params.itemLeft + diffX;
+2834             right = params.itemRight;
+2835 
+2836             item.start = this.screenToTime(left);
+2837             if (options.snapEvents) {
+2838                 this.step.snap(item.start);
+2839                 left = this.timeToScreen(item.start);
+2840             }
+2841 
+2842             if (left > right) {
+2843                 left = right;
+2844                 item.start = this.screenToTime(left);
+2845             }
+2846           this.trigger('change');
+2847         }
+2848         else if (params.itemDragRight && options.timeChangeable) {
+2849             // move the end of the item
+2850             left = params.itemLeft;
+2851             right = params.itemRight + diffX;
+2852 
+2853             item.end = this.screenToTime(right);
+2854             if (options.snapEvents) {
+2855                 this.step.snap(item.end);
+2856                 right = this.timeToScreen(item.end);
+2857             }
+2858 
+2859             if (right < left) {
+2860                 right = left;
+2861                 item.end = this.screenToTime(right);
+2862             }
+2863           this.trigger('change');
+2864         }
+2865         else if (options.timeChangeable) {
+2866             // move the item
+2867             left = params.itemLeft + diffX;
+2868             item.start = this.screenToTime(left);
+2869             if (options.snapEvents) {
+2870                 this.step.snap(item.start);
+2871                 left = this.timeToScreen(item.start);
+2872             }
+2873 
+2874             if (item.end) {
+2875                 right = left + (params.itemRight - params.itemLeft);
+2876                 item.end = this.screenToTime(right);
+2877             }
+2878             this.trigger('change');
+2879         }
+2880 
+2881         item.setPosition(left, right);
+2882 
+2883         var dragging = params.itemDragLeft || params.itemDragRight;
+2884         if (this.groups.length && !dragging) {
+2885             // move item from one group to another when needed
+2886             var y = mouseY - params.frameTop;
+2887             var group = this.getGroupFromHeight(y);
+2888             if (options.groupsChangeable && item.group !== group) {
+2889                 // move item to the other group
+2890                 var index = this.items.indexOf(item);
+2891                 this.changeItem(index, {'group': this.getGroupName(group)});
+2892             }
+2893             else {
+2894                 this.repaintDeleteButton();
+2895                 this.repaintDragAreas();
+2896             }
+2897         }
+2898         else {
+2899             // TODO: does not work well in FF, forces redraw with every mouse move it seems
+2900             this.render(); // TODO: optimize, only redraw the items?
+2901             // Note: when animate==true, no redraw is needed here, its done by stackItems animation
+2902         }
+2903     }
+2904     else if (options.moveable) {
+2905         var interval = (params.end.valueOf() - params.start.valueOf());
+2906         var diffMillisecs = Math.round((-diffX) / size.contentWidth * interval);
+2907         var newStart = new Date(params.start.valueOf() + diffMillisecs);
+2908         var newEnd = new Date(params.end.valueOf() + diffMillisecs);
+2909         this.applyRange(newStart, newEnd);
+2910         // if the applied range is moved due to a fixed min or max,
+2911         // change the diffMillisecs accordingly
+2912         var appliedDiff = (this.start.valueOf() - newStart.valueOf());
+2913         if (appliedDiff) {
+2914             diffMillisecs += appliedDiff;
+2915         }
+2916 
+2917         this.recalcConversion();
+2918 
+2919         // move the items by changing the left position of their frame.
+2920         // this is much faster than repositioning all elements individually via the
+2921         // repaintFrame() function (which is done once at mouseup)
+2922         // note that we round diffX to prevent wrong positioning on millisecond scale
+2923         var previousLeft = params.previousLeft || 0;
+2924         var currentLeft = parseFloat(dom.items.frame.style.left) || 0;
+2925         var previousOffset = params.previousOffset || 0;
+2926         var frameOffset = previousOffset + (currentLeft - previousLeft);
+2927         var frameLeft = -diffMillisecs / interval * size.contentWidth + frameOffset;
+2928 
+2929         dom.items.frame.style.left = (frameLeft) + "px";
+2930 
+2931         // read the left again from DOM (IE8- rounds the value)
+2932         params.previousOffset = frameOffset;
+2933         params.previousLeft = parseFloat(dom.items.frame.style.left) || frameLeft;
+2934 
+2935         this.repaintCurrentTime();
+2936         this.repaintCustomTime();
+2937         this.repaintAxis();
+2938 
+2939         // fire a rangechange event
+2940         this.trigger('rangechange');
+2941     }
+2942 
+2943     links.Timeline.preventDefault(event);
+2944 };
+2945 
+2946 
+2947 /**
+2948  * Stop moving operating.
+2949  * This function activated from within the funcion links.Timeline.onMouseDown().
+2950  * @param {event}  event   The event
+2951  */
+2952 links.Timeline.prototype.onMouseUp = function (event) {
+2953     var params = this.eventParams,
+2954         options = this.options;
+2955 
+2956     event = event || window.event;
+2957 
+2958     this.dom.frame.style.cursor = 'auto';
+2959 
+2960     // remove event listeners here, important for Safari
+2961     if (params.onMouseMove) {
+2962         links.Timeline.removeEventListener(document, "mousemove", params.onMouseMove);
+2963         delete params.onMouseMove;
+2964     }
+2965     if (params.onMouseUp) {
+2966         links.Timeline.removeEventListener(document, "mouseup",   params.onMouseUp);
+2967         delete params.onMouseUp;
+2968     }
+2969     //links.Timeline.preventDefault(event);
+2970 
+2971     if (params.customTime) {
+2972         // fire a timechanged event
+2973         this.trigger('timechanged');
+2974     }
+2975     else if (params.editItem) {
+2976         var item = this.items[params.itemIndex];
+2977 
+2978         if (params.moved || params.addItem) {
+2979             this.applyChange = true;
+2980             this.applyAdd = true;
+2981 
+2982             this.updateData(params.itemIndex, {
+2983                 'start': item.start,
+2984                 'end': item.end
+2985             });
+2986 
+2987             // fire an add or changed event.
+2988             // Note that the change can be canceled from within an event listener if
+2989             // this listener calls the method cancelChange().
+2990             this.trigger(params.addItem ? 'add' : 'changed');
+2991             
+2992             //retrieve item data again to include changes made to it in the triggered event handlers
+2993             item = this.items[params.itemIndex];
+2994 
+2995             if (params.addItem) {
+2996                 if (this.applyAdd) {
+2997                     this.updateData(params.itemIndex, {
+2998                         'start': item.start,
+2999                         'end': item.end,
+3000                         'content': item.content,
+3001                         'group': this.getGroupName(item.group)
+3002                     });
+3003                 }
+3004                 else {
+3005                     // undo an add
+3006                     this.deleteItem(params.itemIndex);
+3007                 }
+3008             }
+3009             else {
+3010                 if (this.applyChange) {
+3011                     this.updateData(params.itemIndex, {
+3012                         'start': item.start,
+3013                         'end': item.end
+3014                     });
+3015                 }
+3016                 else {
+3017                     // undo a change
+3018                     delete this.applyChange;
+3019                     delete this.applyAdd;
+3020 
+3021                     var item = this.items[params.itemIndex],
+3022                         domItem = item.dom;
+3023 
+3024                     item.start = params.itemStart;
+3025                     item.end = params.itemEnd;
+3026                     item.group = params.itemGroup;
+3027                     // TODO: original group should be restored too
+3028                     item.setPosition(params.itemLeft, params.itemRight);
+3029 
+3030                     this.updateData(params.itemIndex, {
+3031                         'start': params.itemStart,
+3032                         'end': params.itemEnd
+3033                     });
+3034                 }
+3035             }
+3036 
+3037             // prepare data for clustering, by filtering and sorting by type
+3038             if (this.options.cluster) {
+3039                 this.clusterGenerator.updateData();
+3040             }
+3041 
+3042             this.render();
+3043         }
+3044     }
+3045     else {
+3046         if (!params.moved && !params.zoomed) {
+3047             // mouse did not move -> user has selected an item
+3048 
+3049             if (params.target === this.dom.items.deleteButton) {
+3050                 // delete item
+3051                 if (this.selection && this.selection.index !== undefined) {
+3052                     this.confirmDeleteItem(this.selection.index);
+3053                 }
+3054             }
+3055             else if (options.selectable) {
+3056                 // select/unselect item
+3057                 if (params.itemIndex != undefined) {
+3058                     if (!this.isSelected(params.itemIndex)) {
+3059                         this.selectItem(params.itemIndex);
+3060                         this.trigger('select');
+3061                     }
+3062                 }
+3063                 else if(params.clusterIndex != undefined) {
+3064                     this.selectCluster(params.clusterIndex);
+3065                     this.trigger('select');
+3066                 }
+3067                 else {
+3068                     if (options.unselectable) {
+3069                         this.unselectItem();
+3070                         this.trigger('select');
+3071                     }
+3072                 }
+3073             }
+3074         }
+3075         else {
+3076             // timeline is moved
+3077             // TODO: optimize: no need to reflow and cluster again?
+3078             this.render();
+3079 
+3080             if ((params.moved && options.moveable) || (params.zoomed && options.zoomable) ) {
+3081                 // fire a rangechanged event
+3082                 this.trigger('rangechanged');
+3083             }
+3084         }
+3085     }
+3086 };
+3087 
+3088 /**
+3089  * Double click event occurred for an item
+3090  * @param {Event}  event
+3091  */
+3092 links.Timeline.prototype.onDblClick = function (event) {
+3093     var params = this.eventParams,
+3094         options = this.options,
+3095         dom = this.dom,
+3096         size = this.size;
+3097     event = event || window.event;
+3098 
+3099     if (params.itemIndex != undefined) {
+3100         var item = this.items[params.itemIndex];
+3101         if (item && this.isEditable(item)) {
+3102             // fire the edit event
+3103             this.trigger('edit');
+3104         }
+3105     }
+3106     else {
+3107         if (options.editable) {
+3108             // create a new item
+3109 
+3110             // get mouse position
+3111             params.mouseX = links.Timeline.getPageX(event);
+3112             params.mouseY = links.Timeline.getPageY(event);
+3113             var x = params.mouseX - links.Timeline.getAbsoluteLeft(dom.content);
+3114             var y = params.mouseY - links.Timeline.getAbsoluteTop(dom.content);
+3115 
+3116             // create a new event at the current mouse position
+3117             var xstart = this.screenToTime(x);
+3118             if (options.snapEvents) {
+3119                 this.step.snap(xstart);
+3120             }
+3121 
+3122             var content = options.NEW;
+3123             var group = this.getGroupFromHeight(y);   // (group may be undefined)
+3124             var preventRender = true;
+3125             this.addItem({
+3126                 'start': xstart,
+3127                 'content': content,
+3128                 'group': this.getGroupName(group)
+3129             }, preventRender);
+3130             params.itemIndex = (this.items.length - 1);
+3131             this.selectItem(params.itemIndex);
+3132 
+3133             this.applyAdd = true;
+3134 
+3135             // fire an add event.
+3136             // Note that the change can be canceled from within an event listener if
+3137             // this listener calls the method cancelAdd().
+3138             this.trigger('add');
+3139 
+3140             if (this.applyAdd) {
+3141                 // render and select the item
+3142                 this.render({animate: false});
+3143                 this.selectItem(params.itemIndex);
+3144             }
+3145             else {
+3146                 // undo an add
+3147                 this.deleteItem(params.itemIndex);
+3148             }
+3149         }
+3150     }
+3151 
+3152     links.Timeline.preventDefault(event);
+3153 };
+3154 
+3155 
+3156 /**
+3157  * Event handler for mouse wheel event, used to zoom the timeline
+3158  * Code from http://adomas.org/javascript-mouse-wheel/
+3159  * @param {Event}  event   The event
+3160  */
+3161 links.Timeline.prototype.onMouseWheel = function(event) {
+3162     if (!this.options.zoomable)
+3163         return;
+3164 
+3165     if (!event) { /* For IE. */
+3166         event = window.event;
+3167     }
+3168 
+3169     // retrieve delta
+3170     var delta = 0;
+3171     if (event.wheelDelta) { /* IE/Opera. */
+3172         delta = event.wheelDelta/120;
+3173     } else if (event.detail) { /* Mozilla case. */
+3174         // In Mozilla, sign of delta is different than in IE.
+3175         // Also, delta is multiple of 3.
+3176         delta = -event.detail/3;
+3177     }
+3178 
+3179     // If delta is nonzero, handle it.
+3180     // Basically, delta is now positive if wheel was scrolled up,
+3181     // and negative, if wheel was scrolled down.
+3182     if (delta) {
+3183         // TODO: on FireFox, the window is not redrawn within repeated scroll-events
+3184         // -> use a delayed redraw? Make a zoom queue?
+3185 
+3186         var timeline = this;
+3187         var zoom = function () {
+3188             // perform the zoom action. Delta is normally 1 or -1
+3189             var zoomFactor = delta / 5.0;
+3190             var frameLeft = links.Timeline.getAbsoluteLeft(timeline.dom.content);
+3191             var mouseX = links.Timeline.getPageX(event);
+3192             var zoomAroundDate =
+3193                 (mouseX != undefined && frameLeft != undefined) ?
+3194                     timeline.screenToTime(mouseX - frameLeft) :
+3195                     undefined;
+3196 
+3197             timeline.zoom(zoomFactor, zoomAroundDate);
+3198 
+3199             // fire a rangechange and a rangechanged event
+3200             timeline.trigger("rangechange");
+3201             timeline.trigger("rangechanged");
+3202         };
+3203 
+3204         var scroll = function () {
+3205             // Scroll the timeline
+3206             timeline.move(delta * -0.2);
+3207             timeline.trigger("rangechange");
+3208             timeline.trigger("rangechanged");
+3209         };
+3210 
+3211         if (event.shiftKey) {
+3212             scroll();
+3213         }
+3214         else {
+3215             zoom();
+3216         }
+3217     }
+3218 
+3219     // Prevent default actions caused by mouse wheel.
+3220     // That might be ugly, but we handle scrolls somehow
+3221     // anyway, so don't bother here...
+3222     links.Timeline.preventDefault(event);
+3223 };
+3224 
+3225 
+3226 /**
+3227  * Zoom the timeline the given zoomfactor in or out. Start and end date will
+3228  * be adjusted, and the timeline will be redrawn. You can optionally give a
+3229  * date around which to zoom.
+3230  * For example, try zoomfactor = 0.1 or -0.1
+3231  * @param {Number} zoomFactor      Zooming amount. Positive value will zoom in,
+3232  *                                 negative value will zoom out
+3233  * @param {Date}   zoomAroundDate  Date around which will be zoomed. Optional
+3234  */
+3235 links.Timeline.prototype.zoom = function(zoomFactor, zoomAroundDate) {
+3236     // if zoomAroundDate is not provided, take it half between start Date and end Date
+3237     if (zoomAroundDate == undefined) {
+3238         zoomAroundDate = new Date((this.start.valueOf() + this.end.valueOf()) / 2);
+3239     }
+3240 
+3241     // prevent zoom factor larger than 1 or smaller than -1 (larger than 1 will
+3242     // result in a start>=end )
+3243     if (zoomFactor >= 1) {
+3244         zoomFactor = 0.9;
+3245     }
+3246     if (zoomFactor <= -1) {
+3247         zoomFactor = -0.9;
+3248     }
+3249 
+3250     // adjust a negative factor such that zooming in with 0.1 equals zooming
+3251     // out with a factor -0.1
+3252     if (zoomFactor < 0) {
+3253         zoomFactor = zoomFactor / (1 + zoomFactor);
+3254     }
+3255 
+3256     // zoom start Date and end Date relative to the zoomAroundDate
+3257     var startDiff = (this.start.valueOf() - zoomAroundDate);
+3258     var endDiff = (this.end.valueOf() - zoomAroundDate);
+3259 
+3260     // calculate new dates
+3261     var newStart = new Date(this.start.valueOf() - startDiff * zoomFactor);
+3262     var newEnd   = new Date(this.end.valueOf() - endDiff * zoomFactor);
+3263 
+3264     // only zoom in when interval is larger than minimum interval (to prevent
+3265     // sliding to left/right when having reached the minimum zoom level)
+3266     var interval = (newEnd.valueOf() - newStart.valueOf());
+3267     var zoomMin = Number(this.options.zoomMin) || 10;
+3268     if (zoomMin < 10) {
+3269         zoomMin = 10;
+3270     }
+3271     if (interval >= zoomMin) {
+3272         this.applyRange(newStart, newEnd, zoomAroundDate);
+3273         this.render({
+3274             animate: this.options.animate && this.options.animateZoom
+3275         });
+3276     }
+3277 };
+3278 
+3279 /**
+3280  * Move the timeline the given movefactor to the left or right. Start and end
+3281  * date will be adjusted, and the timeline will be redrawn.
+3282  * For example, try moveFactor = 0.1 or -0.1
+3283  * @param {Number}  moveFactor      Moving amount. Positive value will move right,
+3284  *                                 negative value will move left
+3285  */
+3286 links.Timeline.prototype.move = function(moveFactor) {
+3287     // zoom start Date and end Date relative to the zoomAroundDate
+3288     var diff = (this.end.valueOf() - this.start.valueOf());
+3289 
+3290     // apply new dates
+3291     var newStart = new Date(this.start.valueOf() + diff * moveFactor);
+3292     var newEnd   = new Date(this.end.valueOf() + diff * moveFactor);
+3293     this.applyRange(newStart, newEnd);
+3294 
+3295     this.render(); // TODO: optimize, no need to reflow, only to recalc conversion and repaint
+3296 };
+3297 
+3298 /**
+3299  * Apply a visible range. The range is limited to feasible maximum and minimum
+3300  * range.
+3301  * @param {Date} start
+3302  * @param {Date} end
+3303  * @param {Date}   zoomAroundDate  Optional. Date around which will be zoomed.
+3304  */
+3305 links.Timeline.prototype.applyRange = function (start, end, zoomAroundDate) {
+3306     // calculate new start and end value
+3307     var startValue = start.valueOf(); // number
+3308     var endValue = end.valueOf();     // number
+3309     var interval = (endValue - startValue);
+3310 
+3311     // determine maximum and minimum interval
+3312     var options = this.options;
+3313     var year = 1000 * 60 * 60 * 24 * 365;
+3314     var zoomMin = Number(options.zoomMin) || 10;
+3315     if (zoomMin < 10) {
+3316         zoomMin = 10;
+3317     }
+3318     var zoomMax = Number(options.zoomMax) || 10000 * year;
+3319     if (zoomMax > 10000 * year) {
+3320         zoomMax = 10000 * year;
+3321     }
+3322     if (zoomMax < zoomMin) {
+3323         zoomMax = zoomMin;
+3324     }
+3325 
+3326     // determine min and max date value
+3327     var min = options.min ? options.min.valueOf() : undefined; // number
+3328     var max = options.max ? options.max.valueOf() : undefined; // number
+3329     if (min != undefined && max != undefined) {
+3330         if (min >= max) {
+3331             // empty range
+3332             var day = 1000 * 60 * 60 * 24;
+3333             max = min + day;
+3334         }
+3335         if (zoomMax > (max - min)) {
+3336             zoomMax = (max - min);
+3337         }
+3338         if (zoomMin > (max - min)) {
+3339             zoomMin = (max - min);
+3340         }
+3341     }
+3342 
+3343     // prevent empty interval
+3344     if (startValue >= endValue) {
+3345         endValue += 1000 * 60 * 60 * 24;
+3346     }
+3347 
+3348     // prevent too small scale
+3349     // TODO: IE has problems with milliseconds
+3350     if (interval < zoomMin) {
+3351         var diff = (zoomMin - interval);
+3352         var f = zoomAroundDate ? (zoomAroundDate.valueOf() - startValue) / interval : 0.5;
+3353         startValue -= Math.round(diff * f);
+3354         endValue   += Math.round(diff * (1 - f));
+3355     }
+3356 
+3357     // prevent too large scale
+3358     if (interval > zoomMax) {
+3359         var diff = (interval - zoomMax);
+3360         var f = zoomAroundDate ? (zoomAroundDate.valueOf() - startValue) / interval : 0.5;
+3361         startValue += Math.round(diff * f);
+3362         endValue   -= Math.round(diff * (1 - f));
+3363     }
+3364 
+3365     // prevent to small start date
+3366     if (min != undefined) {
+3367         var diff = (startValue - min);
+3368         if (diff < 0) {
+3369             startValue -= diff;
+3370             endValue -= diff;
+3371         }
+3372     }
+3373 
+3374     // prevent to large end date
+3375     if (max != undefined) {
+3376         var diff = (max - endValue);
+3377         if (diff < 0) {
+3378             startValue += diff;
+3379             endValue += diff;
+3380         }
+3381     }
+3382 
+3383     // apply new dates
+3384     this.start = new Date(startValue);
+3385     this.end = new Date(endValue);
+3386 };
+3387 
+3388 /**
+3389  * Delete an item after a confirmation.
+3390  * The deletion can be cancelled by executing .cancelDelete() during the
+3391  * triggered event 'delete'.
+3392  * @param {int} index   Index of the item to be deleted
+3393  */
+3394 links.Timeline.prototype.confirmDeleteItem = function(index) {
+3395     this.applyDelete = true;
+3396 
+3397     // select the event to be deleted
+3398     if (!this.isSelected(index)) {
+3399         this.selectItem(index);
+3400     }
+3401 
+3402     // fire a delete event trigger.
+3403     // Note that the delete event can be canceled from within an event listener if
+3404     // this listener calls the method cancelChange().
+3405     this.trigger('delete');
+3406 
+3407     if (this.applyDelete) {
+3408         this.deleteItem(index);
+3409     }
+3410 
+3411     delete this.applyDelete;
+3412 };
+3413 
+3414 /**
+3415  * Delete an item
+3416  * @param {int} index   Index of the item to be deleted
+3417  * @param {boolean} [preventRender=false]   Do not re-render timeline if true
+3418  *                                          (optimization for multiple delete)
+3419  */
+3420 links.Timeline.prototype.deleteItem = function(index, preventRender) {
+3421     if (index >= this.items.length) {
+3422         throw "Cannot delete row, index out of range";
+3423     }
+3424 
+3425     if (this.selection && this.selection.index !== undefined) {
+3426         // adjust the selection
+3427         if (this.selection.index == index) {
+3428             // item to be deleted is selected
+3429             this.unselectItem();
+3430         }
+3431         else if (this.selection.index > index) {
+3432             // update selection index
+3433             this.selection.index--;
+3434         }
+3435     }
+3436 
+3437     // actually delete the item and remove it from the DOM
+3438     var item = this.items.splice(index, 1)[0];
+3439     this.renderQueue.hide.push(item);
+3440 
+3441     // delete the row in the original data table
+3442     if (this.data) {
+3443         if (google && google.visualization &&
+3444             this.data instanceof google.visualization.DataTable) {
+3445             this.data.removeRow(index);
+3446         }
+3447         else if (links.Timeline.isArray(this.data)) {
+3448             this.data.splice(index, 1);
+3449         }
+3450         else {
+3451             throw "Cannot delete row from data, unknown data type";
+3452         }
+3453     }
+3454 
+3455     // prepare data for clustering, by filtering and sorting by type
+3456     if (this.options.cluster) {
+3457         this.clusterGenerator.updateData();
+3458     }
+3459 
+3460     if (!preventRender) {
+3461         this.render();
+3462     }
+3463 };
+3464 
+3465 
+3466 /**
+3467  * Delete all items
+3468  */
+3469 links.Timeline.prototype.deleteAllItems = function() {
+3470     this.unselectItem();
+3471 
+3472     // delete the loaded items
+3473     this.clearItems();
+3474 
+3475     // delete the groups
+3476     this.deleteGroups();
+3477 
+3478     // empty original data table
+3479     if (this.data) {
+3480         if (google && google.visualization &&
+3481             this.data instanceof google.visualization.DataTable) {
+3482             this.data.removeRows(0, this.data.getNumberOfRows());
+3483         }
+3484         else if (links.Timeline.isArray(this.data)) {
+3485             this.data.splice(0, this.data.length);
+3486         }
+3487         else {
+3488             throw "Cannot delete row from data, unknown data type";
+3489         }
+3490     }
+3491 
+3492     // prepare data for clustering, by filtering and sorting by type
+3493     if (this.options.cluster) {
+3494         this.clusterGenerator.updateData();
+3495     }
+3496 
+3497     this.render();
+3498 };
+3499 
+3500 
+3501 /**
+3502  * Find the group from a given height in the timeline
+3503  * @param {Number} height   Height in the timeline
+3504  * @return {Object | undefined} group   The group object, or undefined if out
+3505  *                                      of range
+3506  */
+3507 links.Timeline.prototype.getGroupFromHeight = function(height) {
+3508     var i,
+3509         group,
+3510         groups = this.groups;
+3511 
+3512     if (groups.length) {
+3513         if (this.options.axisOnTop) {
+3514             for (i = groups.length - 1; i >= 0; i--) {
+3515                 group = groups[i];
+3516                 if (height > group.top) {
+3517                     return group;
+3518                 }
+3519             }
+3520         }
+3521         else {
+3522             for (i = 0; i < groups.length; i++) {
+3523                 group = groups[i];
+3524                 if (height > group.top) {
+3525                     return group;
+3526                 }
+3527             }
+3528         }
+3529 
+3530         return group; // return the last group
+3531     }
+3532 
+3533     return undefined;
+3534 };
+3535 
+3536 /**
+3537  * @constructor links.Timeline.Item
+3538  * @param {Object} data       Object containing parameters start, end
+3539  *                            content, group, type, editable.
+3540  * @param {Object} [options]  Options to set initial property values
+3541  *                                {Number} top
+3542  *                                {Number} left
+3543  *                                {Number} width
+3544  *                                {Number} height
+3545  */
+3546 links.Timeline.Item = function (data, options) {
+3547     if (data) {
+3548         /* TODO: use parseJSONDate as soon as it is tested and working (in two directions)
+3549          this.start = links.Timeline.parseJSONDate(data.start);
+3550          this.end = links.Timeline.parseJSONDate(data.end);
+3551          */
+3552         this.start = data.start;
+3553         this.end = data.end;
+3554         this.content = data.content;
+3555         this.className = data.className;
+3556         this.editable = data.editable;
+3557         this.group = data.group;
+3558         this.type = data.type;
+3559     }
+3560     this.top = 0;
+3561     this.left = 0;
+3562     this.width = 0;
+3563     this.height = 0;
+3564     this.lineWidth = 0;
+3565     this.dotWidth = 0;
+3566     this.dotHeight = 0;
+3567 
+3568     this.rendered = false; // true when the item is draw in the Timeline DOM
+3569 
+3570     if (options) {
+3571         // override the default properties
+3572         for (var option in options) {
+3573             if (options.hasOwnProperty(option)) {
+3574                 this[option] = options[option];
+3575             }
+3576         }
+3577     }
+3578 
+3579 };
+3580 
+3581 
+3582 
+3583 /**
+3584  * Reflow the Item: retrieve its actual size from the DOM
+3585  * @return {boolean} resized    returns true if the axis is resized
+3586  */
+3587 links.Timeline.Item.prototype.reflow = function () {
+3588     // Should be implemented by sub-prototype
+3589     return false;
+3590 };
+3591 
+3592 /**
+3593  * Append all image urls present in the items DOM to the provided array
+3594  * @param {String[]} imageUrls
+3595  */
+3596 links.Timeline.Item.prototype.getImageUrls = function (imageUrls) {
+3597     if (this.dom) {
+3598         links.imageloader.filterImageUrls(this.dom, imageUrls);
+3599     }
+3600 };
+3601 
+3602 /**
+3603  * Select the item
+3604  */
+3605 links.Timeline.Item.prototype.select = function () {
+3606     // Should be implemented by sub-prototype
+3607 };
+3608 
+3609 /**
+3610  * Unselect the item
+3611  */
+3612 links.Timeline.Item.prototype.unselect = function () {
+3613     // Should be implemented by sub-prototype
+3614 };
+3615 
+3616 /**
+3617  * Creates the DOM for the item, depending on its type
+3618  * @return {Element | undefined}
+3619  */
+3620 links.Timeline.Item.prototype.createDOM = function () {
+3621     // Should be implemented by sub-prototype
+3622 };
+3623 
+3624 /**
+3625  * Append the items DOM to the given HTML container. If items DOM does not yet
+3626  * exist, it will be created first.
+3627  * @param {Element} container
+3628  */
+3629 links.Timeline.Item.prototype.showDOM = function (container) {
+3630     // Should be implemented by sub-prototype
+3631 };
+3632 
+3633 /**
+3634  * Remove the items DOM from the current HTML container
+3635  * @param {Element} container
+3636  */
+3637 links.Timeline.Item.prototype.hideDOM = function (container) {
+3638     // Should be implemented by sub-prototype
+3639 };
+3640 
+3641 /**
+3642  * Update the DOM of the item. This will update the content and the classes
+3643  * of the item
+3644  */
+3645 links.Timeline.Item.prototype.updateDOM = function () {
+3646     // Should be implemented by sub-prototype
+3647 };
+3648 
+3649 /**
+3650  * Reposition the item, recalculate its left, top, and width, using the current
+3651  * range of the timeline and the timeline options.
+3652  * @param {links.Timeline} timeline
+3653  */
+3654 links.Timeline.Item.prototype.updatePosition = function (timeline) {
+3655     // Should be implemented by sub-prototype
+3656 };
+3657 
+3658 /**
+3659  * Check if the item is drawn in the timeline (i.e. the DOM of the item is
+3660  * attached to the frame. You may also just request the parameter item.rendered
+3661  * @return {boolean} rendered
+3662  */
+3663 links.Timeline.Item.prototype.isRendered = function () {
+3664     return this.rendered;
+3665 };
+3666 
+3667 /**
+3668  * Check if the item is located in the visible area of the timeline, and
+3669  * not part of a cluster
+3670  * @param {Date} start
+3671  * @param {Date} end
+3672  * @return {boolean} visible
+3673  */
+3674 links.Timeline.Item.prototype.isVisible = function (start, end) {
+3675     // Should be implemented by sub-prototype
+3676     return false;
+3677 };
+3678 
+3679 /**
+3680  * Reposition the item
+3681  * @param {Number} left
+3682  * @param {Number} right
+3683  */
+3684 links.Timeline.Item.prototype.setPosition = function (left, right) {
+3685     // Should be implemented by sub-prototype
+3686 };
+3687 
+3688 /**
+3689  * Calculate the left position of the item
+3690  * @param {links.Timeline} timeline
+3691  * @return {Number} left
+3692  */
+3693 links.Timeline.Item.prototype.getLeft = function (timeline) {
+3694     // Should be implemented by sub-prototype
+3695     return 0;
+3696 };
+3697 
+3698 /**
+3699  * Calculate the right position of the item
+3700  * @param {links.Timeline} timeline
+3701  * @return {Number} right
+3702  */
+3703 links.Timeline.Item.prototype.getRight = function (timeline) {
+3704     // Should be implemented by sub-prototype
+3705     return 0;
+3706 };
+3707 
+3708 /**
+3709  * Calculate the width of the item
+3710  * @param {links.Timeline} timeline
+3711  * @return {Number} width
+3712  */
+3713 links.Timeline.Item.prototype.getWidth = function (timeline) {
+3714     // Should be implemented by sub-prototype
+3715     return this.width || 0; // last rendered width
+3716 };
+3717 
+3718 
+3719 /**
+3720  * @constructor links.Timeline.ItemBox
+3721  * @extends links.Timeline.Item
+3722  * @param {Object} data       Object containing parameters start, end
+3723  *                            content, group, type, className, editable.
+3724  * @param {Object} [options]  Options to set initial property values
+3725  *                                {Number} top
+3726  *                                {Number} left
+3727  *                                {Number} width
+3728  *                                {Number} height
+3729  */
+3730 links.Timeline.ItemBox = function (data, options) {
+3731     links.Timeline.Item.call(this, data, options);
+3732 };
+3733 
+3734 links.Timeline.ItemBox.prototype = new links.Timeline.Item();
+3735 
+3736 /**
+3737  * Reflow the Item: retrieve its actual size from the DOM
+3738  * @return {boolean} resized    returns true if the axis is resized
+3739  * @override
+3740  */
+3741 links.Timeline.ItemBox.prototype.reflow = function () {
+3742     var dom = this.dom,
+3743         dotHeight = dom.dot.offsetHeight,
+3744         dotWidth = dom.dot.offsetWidth,
+3745         lineWidth = dom.line.offsetWidth,
+3746         resized = (
+3747             (this.dotHeight != dotHeight) ||
+3748                 (this.dotWidth != dotWidth) ||
+3749                 (this.lineWidth != lineWidth)
+3750             );
+3751 
+3752     this.dotHeight = dotHeight;
+3753     this.dotWidth = dotWidth;
+3754     this.lineWidth = lineWidth;
+3755 
+3756     return resized;
+3757 };
+3758 
+3759 /**
+3760  * Select the item
+3761  * @override
+3762  */
+3763 links.Timeline.ItemBox.prototype.select = function () {
+3764     var dom = this.dom;
+3765     links.Timeline.addClassName(dom, 'timeline-event-selected ui-state-active');
+3766     links.Timeline.addClassName(dom.line, 'timeline-event-selected ui-state-active');
+3767     links.Timeline.addClassName(dom.dot, 'timeline-event-selected ui-state-active');
+3768 };
+3769 
+3770 /**
+3771  * Unselect the item
+3772  * @override
+3773  */
+3774 links.Timeline.ItemBox.prototype.unselect = function () {
+3775     var dom = this.dom;
+3776     links.Timeline.removeClassName(dom, 'timeline-event-selected ui-state-active');
+3777     links.Timeline.removeClassName(dom.line, 'timeline-event-selected ui-state-active');
+3778     links.Timeline.removeClassName(dom.dot, 'timeline-event-selected ui-state-active');
+3779 };
+3780 
+3781 /**
+3782  * Creates the DOM for the item, depending on its type
+3783  * @return {Element | undefined}
+3784  * @override
+3785  */
+3786 links.Timeline.ItemBox.prototype.createDOM = function () {
+3787     // background box
+3788     var divBox = document.createElement("DIV");
+3789     divBox.style.position = "absolute";
+3790     divBox.style.left = this.left + "px";
+3791     divBox.style.top = this.top + "px";
+3792 
+3793     // contents box (inside the background box). used for making margins
+3794     var divContent = document.createElement("DIV");
+3795     divContent.className = "timeline-event-content";
+3796     divContent.innerHTML = this.content;
+3797     divBox.appendChild(divContent);
+3798 
+3799     // line to axis
+3800     var divLine = document.createElement("DIV");
+3801     divLine.style.position = "absolute";
+3802     divLine.style.width = "0px";
+3803     // important: the vertical line is added at the front of the list of elements,
+3804     // so it will be drawn behind all boxes and ranges
+3805     divBox.line = divLine;
+3806 
+3807     // dot on axis
+3808     var divDot = document.createElement("DIV");
+3809     divDot.style.position = "absolute";
+3810     divDot.style.width  = "0px";
+3811     divDot.style.height = "0px";
+3812     divBox.dot = divDot;
+3813 
+3814     this.dom = divBox;
+3815     this.updateDOM();
+3816 
+3817     return divBox;
+3818 };
+3819 
+3820 /**
+3821  * Append the items DOM to the given HTML container. If items DOM does not yet
+3822  * exist, it will be created first.
+3823  * @param {Element} container
+3824  * @override
+3825  */
+3826 links.Timeline.ItemBox.prototype.showDOM = function (container) {
+3827     var dom = this.dom;
+3828     if (!dom) {
+3829         dom = this.createDOM();
+3830     }
+3831 
+3832     if (dom.parentNode != container) {
+3833         if (dom.parentNode) {
+3834             // container is changed. remove from old container
+3835             this.hideDOM();
+3836         }
+3837 
+3838         // append to this container
+3839         container.appendChild(dom);
+3840         container.insertBefore(dom.line, container.firstChild);
+3841         // Note: line must be added in front of the this,
+3842         //       such that it stays below all this
+3843         container.appendChild(dom.dot);
+3844         this.rendered = true;
+3845     }
+3846 };
+3847 
+3848 /**
+3849  * Remove the items DOM from the current HTML container, but keep the DOM in
+3850  * memory
+3851  * @override
+3852  */
+3853 links.Timeline.ItemBox.prototype.hideDOM = function () {
+3854     var dom = this.dom;
+3855     if (dom) {
+3856         if (dom.parentNode) {
+3857             dom.parentNode.removeChild(dom);
+3858         }
+3859         if (dom.line && dom.line.parentNode) {
+3860             dom.line.parentNode.removeChild(dom.line);
+3861         }
+3862         if (dom.dot && dom.dot.parentNode) {
+3863             dom.dot.parentNode.removeChild(dom.dot);
+3864         }
+3865         this.rendered = false;
+3866     }
+3867 };
+3868 
+3869 /**
+3870  * Update the DOM of the item. This will update the content and the classes
+3871  * of the item
+3872  * @override
+3873  */
+3874 links.Timeline.ItemBox.prototype.updateDOM = function () {
+3875     var divBox = this.dom;
+3876     if (divBox) {
+3877         var divLine = divBox.line;
+3878         var divDot = divBox.dot;
+3879 
+3880         // update contents
+3881         divBox.firstChild.innerHTML = this.content;
+3882 
+3883         // update class
+3884         divBox.className = "timeline-event timeline-event-box ui-widget ui-state-default";
+3885         divLine.className = "timeline-event timeline-event-line ui-widget ui-state-default";
+3886         divDot.className  = "timeline-event timeline-event-dot ui-widget ui-state-default";
+3887 
+3888         if (this.isCluster) {
+3889             links.Timeline.addClassName(divBox, 'timeline-event-cluster ui-widget-header');
+3890             links.Timeline.addClassName(divLine, 'timeline-event-cluster ui-widget-header');
+3891             links.Timeline.addClassName(divDot, 'timeline-event-cluster ui-widget-header');
+3892         }
+3893 
+3894         // add item specific class name when provided
+3895         if (this.className) {
+3896             links.Timeline.addClassName(divBox, this.className);
+3897             links.Timeline.addClassName(divLine, this.className);
+3898             links.Timeline.addClassName(divDot, this.className);
+3899         }
+3900 
+3901         // TODO: apply selected className?
+3902     }
+3903 };
+3904 
+3905 /**
+3906  * Reposition the item, recalculate its left, top, and width, using the current
+3907  * range of the timeline and the timeline options.
+3908  * @param {links.Timeline} timeline
+3909  * @override
+3910  */
+3911 links.Timeline.ItemBox.prototype.updatePosition = function (timeline) {
+3912     var dom = this.dom;
+3913     if (dom) {
+3914         var left = timeline.timeToScreen(this.start),
+3915             axisOnTop = timeline.options.axisOnTop,
+3916             axisTop = timeline.size.axis.top,
+3917             axisHeight = timeline.size.axis.height,
+3918             boxAlign = (timeline.options.box && timeline.options.box.align) ?
+3919                 timeline.options.box.align : undefined;
+3920 
+3921         dom.style.top = this.top + "px";
+3922         if (boxAlign == 'right') {
+3923             dom.style.left = (left - this.width) + "px";
+3924         }
+3925         else if (boxAlign == 'left') {
+3926             dom.style.left = (left) + "px";
+3927         }
+3928         else { // default or 'center'
+3929             dom.style.left = (left - this.width/2) + "px";
+3930         }
+3931 
+3932         var line = dom.line;
+3933         var dot = dom.dot;
+3934         line.style.left = (left - this.lineWidth/2) + "px";
+3935         dot.style.left = (left - this.dotWidth/2) + "px";
+3936         if (axisOnTop) {
+3937             line.style.top = axisHeight + "px";
+3938             line.style.height = Math.max(this.top - axisHeight, 0) + "px";
+3939             dot.style.top = (axisHeight - this.dotHeight/2) + "px";
+3940         }
+3941         else {
+3942             line.style.top = (this.top + this.height) + "px";
+3943             line.style.height = Math.max(axisTop - this.top - this.height, 0) + "px";
+3944             dot.style.top = (axisTop - this.dotHeight/2) + "px";
+3945         }
+3946     }
+3947 };
+3948 
+3949 /**
+3950  * Check if the item is visible in the timeline, and not part of a cluster
+3951  * @param {Date} start
+3952  * @param {Date} end
+3953  * @return {Boolean} visible
+3954  * @override
+3955  */
+3956 links.Timeline.ItemBox.prototype.isVisible = function (start, end) {
+3957     if (this.cluster) {
+3958         return false;
+3959     }
+3960 
+3961     return (this.start > start) && (this.start < end);
+3962 };
+3963 
+3964 /**
+3965  * Reposition the item
+3966  * @param {Number} left
+3967  * @param {Number} right
+3968  * @override
+3969  */
+3970 links.Timeline.ItemBox.prototype.setPosition = function (left, right) {
+3971     var dom = this.dom;
+3972 
+3973     dom.style.left = (left - this.width / 2) + "px";
+3974     dom.line.style.left = (left - this.lineWidth / 2) + "px";
+3975     dom.dot.style.left = (left - this.dotWidth / 2) + "px";
+3976 
+3977     if (this.group) {
+3978         this.top = this.group.top;
+3979         dom.style.top = this.top + 'px';
+3980     }
+3981 };
+3982 
+3983 /**
+3984  * Calculate the left position of the item
+3985  * @param {links.Timeline} timeline
+3986  * @return {Number} left
+3987  * @override
+3988  */
+3989 links.Timeline.ItemBox.prototype.getLeft = function (timeline) {
+3990     var boxAlign = (timeline.options.box && timeline.options.box.align) ?
+3991         timeline.options.box.align : undefined;
+3992 
+3993     var left = timeline.timeToScreen(this.start);
+3994     if (boxAlign == 'right') {
+3995         left = left - width;
+3996     }
+3997     else { // default or 'center'
+3998         left = (left - this.width / 2);
+3999     }
+4000 
+4001     return left;
+4002 };
+4003 
+4004 /**
+4005  * Calculate the right position of the item
+4006  * @param {links.Timeline} timeline
+4007  * @return {Number} right
+4008  * @override
+4009  */
+4010 links.Timeline.ItemBox.prototype.getRight = function (timeline) {
+4011     var boxAlign = (timeline.options.box && timeline.options.box.align) ?
+4012         timeline.options.box.align : undefined;
+4013 
+4014     var left = timeline.timeToScreen(this.start);
+4015     var right;
+4016     if (boxAlign == 'right') {
+4017         right = left;
+4018     }
+4019     else if (boxAlign == 'left') {
+4020         right = (left + this.width);
+4021     }
+4022     else { // default or 'center'
+4023         right = (left + this.width / 2);
+4024     }
+4025 
+4026     return right;
+4027 };
+4028 
+4029 /**
+4030  * @constructor links.Timeline.ItemRange
+4031  * @extends links.Timeline.Item
+4032  * @param {Object} data       Object containing parameters start, end
+4033  *                            content, group, type, className, editable.
+4034  * @param {Object} [options]  Options to set initial property values
+4035  *                                {Number} top
+4036  *                                {Number} left
+4037  *                                {Number} width
+4038  *                                {Number} height
+4039  */
+4040 links.Timeline.ItemRange = function (data, options) {
+4041     links.Timeline.Item.call(this, data, options);
+4042 };
+4043 
+4044 links.Timeline.ItemRange.prototype = new links.Timeline.Item();
+4045 
+4046 /**
+4047  * Select the item
+4048  * @override
+4049  */
+4050 links.Timeline.ItemRange.prototype.select = function () {
+4051     var dom = this.dom;
+4052     links.Timeline.addClassName(dom, 'timeline-event-selected ui-state-active');
+4053 };
+4054 
+4055 /**
+4056  * Unselect the item
+4057  * @override
+4058  */
+4059 links.Timeline.ItemRange.prototype.unselect = function () {
+4060     var dom = this.dom;
+4061     links.Timeline.removeClassName(dom, 'timeline-event-selected ui-state-active');
+4062 };
+4063 
+4064 /**
+4065  * Creates the DOM for the item, depending on its type
+4066  * @return {Element | undefined}
+4067  * @override
+4068  */
+4069 links.Timeline.ItemRange.prototype.createDOM = function () {
+4070     // background box
+4071     var divBox = document.createElement("DIV");
+4072     divBox.style.position = "absolute";
+4073 
+4074     // contents box
+4075     var divContent = document.createElement("DIV");
+4076     divContent.className = "timeline-event-content";
+4077     divBox.appendChild(divContent);
+4078 
+4079     this.dom = divBox;
+4080     this.updateDOM();
+4081 
+4082     return divBox;
+4083 };
+4084 
+4085 /**
+4086  * Append the items DOM to the given HTML container. If items DOM does not yet
+4087  * exist, it will be created first.
+4088  * @param {Element} container
+4089  * @override
+4090  */
+4091 links.Timeline.ItemRange.prototype.showDOM = function (container) {
+4092     var dom = this.dom;
+4093     if (!dom) {
+4094         dom = this.createDOM();
+4095     }
+4096 
+4097     if (dom.parentNode != container) {
+4098         if (dom.parentNode) {
+4099             // container changed. remove the item from the old container
+4100             this.hideDOM();
+4101         }
+4102 
+4103         // append to the new container
+4104         container.appendChild(dom);
+4105         this.rendered = true;
+4106     }
+4107 };
+4108 
+4109 /**
+4110  * Remove the items DOM from the current HTML container
+4111  * The DOM will be kept in memory
+4112  * @override
+4113  */
+4114 links.Timeline.ItemRange.prototype.hideDOM = function () {
+4115     var dom = this.dom;
+4116     if (dom) {
+4117         if (dom.parentNode) {
+4118             dom.parentNode.removeChild(dom);
+4119         }
+4120         this.rendered = false;
+4121     }
+4122 };
+4123 
+4124 /**
+4125  * Update the DOM of the item. This will update the content and the classes
+4126  * of the item
+4127  * @override
+4128  */
+4129 links.Timeline.ItemRange.prototype.updateDOM = function () {
+4130     var divBox = this.dom;
+4131     if (divBox) {
+4132         // update contents
+4133         divBox.firstChild.innerHTML = this.content;
+4134 
+4135         // update class
+4136         divBox.className = "timeline-event timeline-event-range ui-widget ui-state-default";
+4137 
+4138         if (this.isCluster) {
+4139             links.Timeline.addClassName(divBox, 'timeline-event-cluster ui-widget-header');
+4140         }
+4141 
+4142         // add item specific class name when provided
+4143         if (this.className) {
+4144             links.Timeline.addClassName(divBox, this.className);
+4145         }
+4146 
+4147         // TODO: apply selected className?
+4148     }
+4149 };
+4150 
+4151 /**
+4152  * Reposition the item, recalculate its left, top, and width, using the current
+4153  * range of the timeline and the timeline options. *
+4154  * @param {links.Timeline} timeline
+4155  * @override
+4156  */
+4157 links.Timeline.ItemRange.prototype.updatePosition = function (timeline) {
+4158     var dom = this.dom;
+4159     if (dom) {
+4160         var contentWidth = timeline.size.contentWidth,
+4161             left = timeline.timeToScreen(this.start),
+4162             right = timeline.timeToScreen(this.end);
+4163 
+4164         // limit the width of the this, as browsers cannot draw very wide divs
+4165         if (left < -contentWidth) {
+4166             left = -contentWidth;
+4167         }
+4168         if (right > 2 * contentWidth) {
+4169             right = 2 * contentWidth;
+4170         }
+4171 
+4172         dom.style.top = this.top + "px";
+4173         dom.style.left = left + "px";
+4174         //dom.style.width = Math.max(right - left - 2 * this.borderWidth, 1) + "px"; // TODO: borderWidth
+4175         dom.style.width = Math.max(right - left, 1) + "px";
+4176     }
+4177 };
+4178 
+4179 /**
+4180  * Check if the item is visible in the timeline, and not part of a cluster
+4181  * @param {Number} start
+4182  * @param {Number} end
+4183  * @return {boolean} visible
+4184  * @override
+4185  */
+4186 links.Timeline.ItemRange.prototype.isVisible = function (start, end) {
+4187     if (this.cluster) {
+4188         return false;
+4189     }
+4190 
+4191     return (this.end > start)
+4192         && (this.start < end);
+4193 };
+4194 
+4195 /**
+4196  * Reposition the item
+4197  * @param {Number} left
+4198  * @param {Number} right
+4199  * @override
+4200  */
+4201 links.Timeline.ItemRange.prototype.setPosition = function (left, right) {
+4202     var dom = this.dom;
+4203 
+4204     dom.style.left = left + 'px';
+4205     dom.style.width = (right - left) + 'px';
+4206 
+4207     if (this.group) {
+4208         this.top = this.group.top;
+4209         dom.style.top = this.top + 'px';
+4210     }
+4211 };
+4212 
+4213 /**
+4214  * Calculate the left position of the item
+4215  * @param {links.Timeline} timeline
+4216  * @return {Number} left
+4217  * @override
+4218  */
+4219 links.Timeline.ItemRange.prototype.getLeft = function (timeline) {
+4220     return timeline.timeToScreen(this.start);
+4221 };
+4222 
+4223 /**
+4224  * Calculate the right position of the item
+4225  * @param {links.Timeline} timeline
+4226  * @return {Number} right
+4227  * @override
+4228  */
+4229 links.Timeline.ItemRange.prototype.getRight = function (timeline) {
+4230     return timeline.timeToScreen(this.end);
+4231 };
+4232 
+4233 /**
+4234  * Calculate the width of the item
+4235  * @param {links.Timeline} timeline
+4236  * @return {Number} width
+4237  * @override
+4238  */
+4239 links.Timeline.ItemRange.prototype.getWidth = function (timeline) {
+4240     return timeline.timeToScreen(this.end) - timeline.timeToScreen(this.start);
+4241 };
+4242 
+4243 /**
+4244  * @constructor links.Timeline.ItemFloatingRange
+4245  * @extends links.Timeline.Item
+4246  * @param {Object} data       Object containing parameters start, end
+4247  *                            content, group, type, className, editable.
+4248  * @param {Object} [options]  Options to set initial property values
+4249  *                                {Number} top
+4250  *                                {Number} left
+4251  *                                {Number} width
+4252  *                                {Number} height
+4253  */
+4254 links.Timeline.ItemFloatingRange = function (data, options) {
+4255     links.Timeline.Item.call(this, data, options);
+4256 };
+4257 
+4258 links.Timeline.ItemFloatingRange.prototype = new links.Timeline.Item();
+4259 
+4260 /**
+4261  * Select the item
+4262  * @override
+4263  */
+4264 links.Timeline.ItemFloatingRange.prototype.select = function () {
+4265     var dom = this.dom;
+4266     links.Timeline.addClassName(dom, 'timeline-event-selected ui-state-active');
+4267 };
+4268 
+4269 /**
+4270  * Unselect the item
+4271  * @override
+4272  */
+4273 links.Timeline.ItemFloatingRange.prototype.unselect = function () {
+4274     var dom = this.dom;
+4275     links.Timeline.removeClassName(dom, 'timeline-event-selected ui-state-active');
+4276 };
+4277 
+4278 /**
+4279  * Creates the DOM for the item, depending on its type
+4280  * @return {Element | undefined}
+4281  * @override
+4282  */
+4283 links.Timeline.ItemFloatingRange.prototype.createDOM = function () {
+4284     // background box
+4285     var divBox = document.createElement("DIV");
+4286     divBox.style.position = "absolute";
+4287 
+4288     // contents box
+4289     var divContent = document.createElement("DIV");
+4290     divContent.className = "timeline-event-content";
+4291     divBox.appendChild(divContent);
+4292 
+4293     this.dom = divBox;
+4294     this.updateDOM();
+4295 
+4296     return divBox;
+4297 };
+4298 
+4299 /**
+4300  * Append the items DOM to the given HTML container. If items DOM does not yet
+4301  * exist, it will be created first.
+4302  * @param {Element} container
+4303  * @override
+4304  */
+4305 links.Timeline.ItemFloatingRange.prototype.showDOM = function (container) {
+4306     var dom = this.dom;
+4307     if (!dom) {
+4308         dom = this.createDOM();
+4309     }
+4310 
+4311     if (dom.parentNode != container) {
+4312         if (dom.parentNode) {
+4313             // container changed. remove the item from the old container
+4314             this.hideDOM();
+4315         }
+4316 
+4317         // append to the new container
+4318         container.appendChild(dom);
+4319         this.rendered = true;
+4320     }
+4321 };
+4322 
+4323 /**
+4324  * Remove the items DOM from the current HTML container
+4325  * The DOM will be kept in memory
+4326  * @override
+4327  */
+4328 links.Timeline.ItemFloatingRange.prototype.hideDOM = function () {
+4329     var dom = this.dom;
+4330     if (dom) {
+4331         if (dom.parentNode) {
+4332             dom.parentNode.removeChild(dom);
+4333         }
+4334         this.rendered = false;
+4335     }
+4336 };
+4337 
+4338 /**
+4339  * Update the DOM of the item. This will update the content and the classes
+4340  * of the item
+4341  * @override
+4342  */
+4343 links.Timeline.ItemFloatingRange.prototype.updateDOM = function () {
+4344     var divBox = this.dom;
+4345     if (divBox) {
+4346         // update contents
+4347         divBox.firstChild.innerHTML = this.content;
+4348 
+4349         // update class
+4350         divBox.className = "timeline-event timeline-event-range ui-widget ui-state-default";
+4351 
+4352         if (this.isCluster) {
+4353             links.Timeline.addClassName(divBox, 'timeline-event-cluster ui-widget-header');
+4354         }
+4355 
+4356         // add item specific class name when provided
+4357         if (this.className) {
+4358             links.Timeline.addClassName(divBox, this.className);
+4359         }
+4360 
+4361         // TODO: apply selected className?
+4362     }
+4363 };
+4364 
+4365 /**
+4366  * Reposition the item, recalculate its left, top, and width, using the current
+4367  * range of the timeline and the timeline options. *
+4368  * @param {links.Timeline} timeline
+4369  * @override
+4370  */
+4371 links.Timeline.ItemFloatingRange.prototype.updatePosition = function (timeline) {
+4372     var dom = this.dom;
+4373     if (dom) {
+4374         var contentWidth = timeline.size.contentWidth,
+4375             left = this.getLeft(timeline), // NH use getLeft
+4376             right = this.getRight(timeline); // NH use getRight;
+4377 
+4378         // limit the width of the this, as browsers cannot draw very wide divs
+4379         if (left < -contentWidth) {
+4380             left = -contentWidth;
+4381         }
+4382         if (right > 2 * contentWidth) {
+4383             right = 2 * contentWidth;
+4384         }
+4385 
+4386         dom.style.top = this.top + "px";
+4387         dom.style.left = left + "px";
+4388         //dom.style.width = Math.max(right - left - 2 * this.borderWidth, 1) + "px"; // TODO: borderWidth
+4389         dom.style.width = Math.max(right - left, 1) + "px";
+4390     }
+4391 };
+4392 
+4393 /**
+4394  * Check if the item is visible in the timeline, and not part of a cluster
+4395  * @param {Number} start
+4396  * @param {Number} end
+4397  * @return {boolean} visible
+4398  * @override
+4399  */
+4400 links.Timeline.ItemFloatingRange.prototype.isVisible = function (start, end) {
+4401     if (this.cluster) {
+4402         return false;
+4403     }
+4404 
+4405 	// NH check for no end value
+4406 	if (this.end && this.start) {
+4407 		return (this.end > start)
+4408 			&& (this.start < end);
+4409 	} else if (this.start) {
+4410 		return (this.start < end);
+4411 	} else if (this.end) {
+4412         return (this.end > start);
+4413     } else {return true;}
+4414 };
+4415 
+4416 /**
+4417  * Reposition the item
+4418  * @param {Number} left
+4419  * @param {Number} right
+4420  * @override
+4421  */
+4422 links.Timeline.ItemFloatingRange.prototype.setPosition = function (left, right) {
+4423     var dom = this.dom;
+4424 
+4425     dom.style.left = left + 'px';
+4426     dom.style.width = (right - left) + 'px';
+4427 
+4428     if (this.group) {
+4429         this.top = this.group.top;
+4430         dom.style.top = this.top + 'px';
+4431     }
+4432 };
+4433 
+4434 /**
+4435  * Calculate the left position of the item
+4436  * @param {links.Timeline} timeline
+4437  * @return {Number} left
+4438  * @override
+4439  */
+4440 links.Timeline.ItemFloatingRange.prototype.getLeft = function (timeline) {
+4441     // NH check for no start value
+4442 	if (this.start) {
+4443 		return timeline.timeToScreen(this.start);
+4444 	} else {
+4445 		return 0;
+4446 	}
+4447 };
+4448 
+4449 /**
+4450  * Calculate the right position of the item
+4451  * @param {links.Timeline} timeline
+4452  * @return {Number} right
+4453  * @override
+4454  */
+4455 links.Timeline.ItemFloatingRange.prototype.getRight = function (timeline) {
+4456     // NH check for no end value
+4457 	if (this.end) {
+4458 		return timeline.timeToScreen(this.end);
+4459 	} else {
+4460 		return timeline.size.contentWidth;
+4461 	}
+4462 };
+4463 
+4464 /**
+4465  * Calculate the width of the item
+4466  * @param {links.Timeline} timeline
+4467  * @return {Number} width
+4468  * @override
+4469  */
+4470 links.Timeline.ItemFloatingRange.prototype.getWidth = function (timeline) {
+4471     return this.getRight(timeline) - this.getLeft(timeline);
+4472 };
+4473 
+4474 /**
+4475  * @constructor links.Timeline.ItemDot
+4476  * @extends links.Timeline.Item
+4477  * @param {Object} data       Object containing parameters start, end
+4478  *                            content, group, type, className, editable.
+4479  * @param {Object} [options]  Options to set initial property values
+4480  *                                {Number} top
+4481  *                                {Number} left
+4482  *                                {Number} width
+4483  *                                {Number} height
+4484  */
+4485 links.Timeline.ItemDot = function (data, options) {
+4486     links.Timeline.Item.call(this, data, options);
+4487 };
+4488 
+4489 links.Timeline.ItemDot.prototype = new links.Timeline.Item();
+4490 
+4491 /**
+4492  * Reflow the Item: retrieve its actual size from the DOM
+4493  * @return {boolean} resized    returns true if the axis is resized
+4494  * @override
+4495  */
+4496 links.Timeline.ItemDot.prototype.reflow = function () {
+4497     var dom = this.dom,
+4498         dotHeight = dom.dot.offsetHeight,
+4499         dotWidth = dom.dot.offsetWidth,
+4500         contentHeight = dom.content.offsetHeight,
+4501         resized = (
+4502             (this.dotHeight != dotHeight) ||
+4503                 (this.dotWidth != dotWidth) ||
+4504                 (this.contentHeight != contentHeight)
+4505             );
+4506 
+4507     this.dotHeight = dotHeight;
+4508     this.dotWidth = dotWidth;
+4509     this.contentHeight = contentHeight;
+4510 
+4511     return resized;
+4512 };
+4513 
+4514 /**
+4515  * Select the item
+4516  * @override
+4517  */
+4518 links.Timeline.ItemDot.prototype.select = function () {
+4519     var dom = this.dom;
+4520     links.Timeline.addClassName(dom, 'timeline-event-selected ui-state-active');
+4521 };
+4522 
+4523 /**
+4524  * Unselect the item
+4525  * @override
+4526  */
+4527 links.Timeline.ItemDot.prototype.unselect = function () {
+4528     var dom = this.dom;
+4529     links.Timeline.removeClassName(dom, 'timeline-event-selected ui-state-active');
+4530 };
+4531 
+4532 /**
+4533  * Creates the DOM for the item, depending on its type
+4534  * @return {Element | undefined}
+4535  * @override
+4536  */
+4537 links.Timeline.ItemDot.prototype.createDOM = function () {
+4538     // background box
+4539     var divBox = document.createElement("DIV");
+4540     divBox.style.position = "absolute";
+4541 
+4542     // contents box, right from the dot
+4543     var divContent = document.createElement("DIV");
+4544     divContent.className = "timeline-event-content";
+4545     divBox.appendChild(divContent);
+4546 
+4547     // dot at start
+4548     var divDot = document.createElement("DIV");
+4549     divDot.style.position = "absolute";
+4550     divDot.style.width = "0px";
+4551     divDot.style.height = "0px";
+4552     divBox.appendChild(divDot);
+4553 
+4554     divBox.content = divContent;
+4555     divBox.dot = divDot;
+4556 
+4557     this.dom = divBox;
+4558     this.updateDOM();
+4559 
+4560     return divBox;
+4561 };
+4562 
+4563 /**
+4564  * Append the items DOM to the given HTML container. If items DOM does not yet
+4565  * exist, it will be created first.
+4566  * @param {Element} container
+4567  * @override
+4568  */
+4569 links.Timeline.ItemDot.prototype.showDOM = function (container) {
+4570     var dom = this.dom;
+4571     if (!dom) {
+4572         dom = this.createDOM();
+4573     }
+4574 
+4575     if (dom.parentNode != container) {
+4576         if (dom.parentNode) {
+4577             // container changed. remove it from old container first
+4578             this.hideDOM();
+4579         }
+4580 
+4581         // append to container
+4582         container.appendChild(dom);
+4583         this.rendered = true;
+4584     }
+4585 };
+4586 
+4587 /**
+4588  * Remove the items DOM from the current HTML container
+4589  * @override
+4590  */
+4591 links.Timeline.ItemDot.prototype.hideDOM = function () {
+4592     var dom = this.dom;
+4593     if (dom) {
+4594         if (dom.parentNode) {
+4595             dom.parentNode.removeChild(dom);
+4596         }
+4597         this.rendered = false;
+4598     }
+4599 };
+4600 
+4601 /**
+4602  * Update the DOM of the item. This will update the content and the classes
+4603  * of the item
+4604  * @override
+4605  */
+4606 links.Timeline.ItemDot.prototype.updateDOM = function () {
+4607     if (this.dom) {
+4608         var divBox = this.dom;
+4609         var divDot = divBox.dot;
+4610 
+4611         // update contents
+4612         divBox.firstChild.innerHTML = this.content;
+4613 
+4614         // update classes
+4615         divBox.className = "timeline-event-dot-container";
+4616         divDot.className  = "timeline-event timeline-event-dot ui-widget ui-state-default";
+4617 
+4618         if (this.isCluster) {
+4619             links.Timeline.addClassName(divBox, 'timeline-event-cluster ui-widget-header');
+4620             links.Timeline.addClassName(divDot, 'timeline-event-cluster ui-widget-header');
+4621         }
+4622 
+4623         // add item specific class name when provided
+4624         if (this.className) {
+4625             links.Timeline.addClassName(divBox, this.className);
+4626             links.Timeline.addClassName(divDot, this.className);
+4627         }
+4628 
+4629         // TODO: apply selected className?
+4630     }
+4631 };
+4632 
+4633 /**
+4634  * Reposition the item, recalculate its left, top, and width, using the current
+4635  * range of the timeline and the timeline options. *
+4636  * @param {links.Timeline} timeline
+4637  * @override
+4638  */
+4639 links.Timeline.ItemDot.prototype.updatePosition = function (timeline) {
+4640     var dom = this.dom;
+4641     if (dom) {
+4642         var left = timeline.timeToScreen(this.start);
+4643 
+4644         dom.style.top = this.top + "px";
+4645         dom.style.left = (left - this.dotWidth / 2) + "px";
+4646 
+4647         dom.content.style.marginLeft = (1.5 * this.dotWidth) + "px";
+4648         //dom.content.style.marginRight = (0.5 * this.dotWidth) + "px"; // TODO
+4649         dom.dot.style.top = ((this.height - this.dotHeight) / 2) + "px";
+4650     }
+4651 };
+4652 
+4653 /**
+4654  * Check if the item is visible in the timeline, and not part of a cluster.
+4655  * @param {Date} start
+4656  * @param {Date} end
+4657  * @return {boolean} visible
+4658  * @override
+4659  */
+4660 links.Timeline.ItemDot.prototype.isVisible = function (start, end) {
+4661     if (this.cluster) {
+4662         return false;
+4663     }
+4664 
+4665     return (this.start > start)
+4666         && (this.start < end);
+4667 };
+4668 
+4669 /**
+4670  * Reposition the item
+4671  * @param {Number} left
+4672  * @param {Number} right
+4673  * @override
+4674  */
+4675 links.Timeline.ItemDot.prototype.setPosition = function (left, right) {
+4676     var dom = this.dom;
+4677 
+4678     dom.style.left = (left - this.dotWidth / 2) + "px";
+4679 
+4680     if (this.group) {
+4681         this.top = this.group.top;
+4682         dom.style.top = this.top + 'px';
+4683     }
+4684 };
+4685 
+4686 /**
+4687  * Calculate the left position of the item
+4688  * @param {links.Timeline} timeline
+4689  * @return {Number} left
+4690  * @override
+4691  */
+4692 links.Timeline.ItemDot.prototype.getLeft = function (timeline) {
+4693     return timeline.timeToScreen(this.start);
+4694 };
+4695 
+4696 /**
+4697  * Calculate the right position of the item
+4698  * @param {links.Timeline} timeline
+4699  * @return {Number} right
+4700  * @override
+4701  */
+4702 links.Timeline.ItemDot.prototype.getRight = function (timeline) {
+4703     return timeline.timeToScreen(this.start) + this.width;
+4704 };
+4705 
+4706 /**
+4707  * Retrieve the properties of an item.
+4708  * @param {Number} index
+4709  * @return {Object} itemData    Object containing item properties:<br>
+4710  *                              {Date} start (required),
+4711  *                              {Date} end (optional),
+4712  *                              {String} content (required),
+4713  *                              {String} group (optional),
+4714  *                              {String} className (optional)
+4715  *                              {boolean} editable (optional)
+4716  *                              {String} type (optional)
+4717  */
+4718 links.Timeline.prototype.getItem = function (index) {
+4719     if (index >= this.items.length) {
+4720         throw "Cannot get item, index out of range";
+4721     }
+4722 
+4723     // take the original data as start, includes foreign fields
+4724     var data = this.data,
+4725         itemData;
+4726     if (google && google.visualization &&
+4727         data instanceof google.visualization.DataTable) {
+4728         // map the datatable columns
+4729         var cols = links.Timeline.mapColumnIds(data);
+4730 
+4731         itemData = {};
+4732         for (var col in cols) {
+4733             if (cols.hasOwnProperty(col)) {
+4734                 itemData[col] = this.data.getValue(index, cols[col]);
+4735             }
+4736         }
+4737     }
+4738     else if (links.Timeline.isArray(this.data)) {
+4739         // read JSON array
+4740         itemData = links.Timeline.clone(this.data[index]);
+4741     }
+4742     else {
+4743         throw "Unknown data type. DataTable or Array expected.";
+4744     }
+4745 
+4746     // override the data with current settings of the item (should be the same)
+4747     var item = this.items[index];
+4748 
+4749     itemData.start = new Date(item.start.valueOf());
+4750     if (item.end) {
+4751         itemData.end = new Date(item.end.valueOf());
+4752     }
+4753     itemData.content = item.content;
+4754     if (item.group) {
+4755         itemData.group = this.getGroupName(item.group);
+4756     }
+4757     if (item.className) {
+4758         itemData.className = item.className;
+4759     }
+4760     if (typeof item.editable !== 'undefined') {
+4761         itemData.editable = item.editable;
+4762     }
+4763     if (item.type) {
+4764         itemData.type = item.type;
+4765     }
+4766 
+4767     return itemData;
+4768 };
+4769 
+4770 
+4771 /**
+4772  * Retrieve the properties of a cluster.
+4773  * @param {Number} index
+4774  * @return {Object} clusterdata    Object containing cluster properties:<br>
+4775  *                              {Date} start (required),
+4776  *                              {String} type (optional)
+4777  *                              {Array} array with item data as is in getItem()
+4778  */
+4779 links.Timeline.prototype.getCluster = function (index) {
+4780     if (index >= this.clusters.length) {
+4781         throw "Cannot get cluster, index out of range";
+4782     }
+4783 
+4784     var clusterData = {},
+4785         cluster = this.clusters[index],
+4786         clusterItems = cluster.items;
+4787     
+4788     clusterData.start = new Date(cluster.start.valueOf());
+4789     if (cluster.type) {
+4790         clusterData.type = cluster.type;
+4791     }
+4792 
+4793     // push cluster item data
+4794     clusterData.items = [];
+4795     for(var i = 0; i < clusterItems.length; i++){
+4796         for(var j = 0; j < this.items.length; j++){
+4797             // TODO could be nicer to be able to have the item index into the cluster
+4798             if(this.items[j] == clusterItems[i])
+4799             {
+4800                 clusterData.items.push(this.getItem(j));
+4801                 break;
+4802             }
+4803 
+4804         }
+4805     }
+4806 
+4807     return clusterData;
+4808 };
+4809 
+4810 /**
+4811  * Add a new item.
+4812  * @param {Object} itemData     Object containing item properties:<br>
+4813  *                              {Date} start (required),
+4814  *                              {Date} end (optional),
+4815  *                              {String} content (required),
+4816  *                              {String} group (optional)
+4817  *                              {String} className (optional)
+4818  *                              {Boolean} editable (optional)
+4819  *                              {String} type (optional)
+4820  * @param {boolean} [preventRender=false]   Do not re-render timeline if true
+4821  */
+4822 links.Timeline.prototype.addItem = function (itemData, preventRender) {
+4823     var itemsData = [
+4824         itemData
+4825     ];
+4826 
+4827     this.addItems(itemsData, preventRender);
+4828 };
+4829 
+4830 /**
+4831  * Add new items.
+4832  * @param {Array} itemsData An array containing Objects.
+4833  *                          The objects must have the following parameters:
+4834  *                            {Date} start,
+4835  *                            {Date} end,
+4836  *                            {String} content with text or HTML code,
+4837  *                            {String} group (optional)
+4838  *                            {String} className (optional)
+4839  *                            {String} editable (optional)
+4840  *                            {String} type (optional)
+4841  * @param {boolean} [preventRender=false]   Do not re-render timeline if true
+4842  */
+4843 links.Timeline.prototype.addItems = function (itemsData, preventRender) {
+4844     var timeline = this,
+4845         items = this.items;
+4846 
+4847     // append the items
+4848     itemsData.forEach(function (itemData) {
+4849         var index = items.length;
+4850         items.push(timeline.createItem(itemData));
+4851         timeline.updateData(index, itemData);
+4852 
+4853         // note: there is no need to add the item to the renderQueue, that
+4854         // will be done when this.render() is executed and all items are
+4855         // filtered again.
+4856     });
+4857 
+4858     // prepare data for clustering, by filtering and sorting by type
+4859     if (this.options.cluster) {
+4860         this.clusterGenerator.updateData();
+4861     }
+4862 
+4863     if (!preventRender) {
+4864         this.render({
+4865             animate: false
+4866         });
+4867     }
+4868 };
+4869 
+4870 /**
+4871  * Create an item object, containing all needed parameters
+4872  * @param {Object} itemData  Object containing parameters start, end
+4873  *                           content, group.
+4874  * @return {Object} item
+4875  */
+4876 links.Timeline.prototype.createItem = function(itemData) {
+4877     var type = itemData.type || (itemData.end ? 'range' : this.options.style);
+4878     var data = links.Timeline.clone(itemData);
+4879     data.type = type;
+4880     data.group = this.getGroup(itemData.group);
+4881     // TODO: optimize this, when creating an item, all data is copied twice...
+4882 
+4883     // TODO: is initialTop needed?
+4884     var initialTop,
+4885         options = this.options;
+4886     if (options.axisOnTop) {
+4887         initialTop = this.size.axis.height + options.eventMarginAxis + options.eventMargin / 2;
+4888     }
+4889     else {
+4890         initialTop = this.size.contentHeight - options.eventMarginAxis - options.eventMargin / 2;
+4891     }
+4892 
+4893     if (type in this.itemTypes) {
+4894         return new this.itemTypes[type](data, {'top': initialTop})
+4895     }
+4896 
+4897     console.log('ERROR: Unknown event type "' + type + '"');
+4898     return new links.Timeline.Item(data, {
+4899         'top': initialTop
+4900     });
+4901 };
+4902 
+4903 /**
+4904  * Edit an item
+4905  * @param {Number} index
+4906  * @param {Object} itemData     Object containing item properties:<br>
+4907  *                              {Date} start (required),
+4908  *                              {Date} end (optional),
+4909  *                              {String} content (required),
+4910  *                              {String} group (optional)
+4911  * @param {boolean} [preventRender=false]   Do not re-render timeline if true
+4912  */
+4913 links.Timeline.prototype.changeItem = function (index, itemData, preventRender) {
+4914     var oldItem = this.items[index];
+4915     if (!oldItem) {
+4916         throw "Cannot change item, index out of range";
+4917     }
+4918 
+4919     // replace item, merge the changes
+4920     var newItem = this.createItem({
+4921         'start':   itemData.hasOwnProperty('start') ?   itemData.start :   oldItem.start,
+4922         'end':     itemData.hasOwnProperty('end') ?     itemData.end :     oldItem.end,
+4923         'content': itemData.hasOwnProperty('content') ? itemData.content : oldItem.content,
+4924         'group':   itemData.hasOwnProperty('group') ?   itemData.group :   this.getGroupName(oldItem.group),
+4925         'className': itemData.hasOwnProperty('className') ? itemData.className : oldItem.className,
+4926         'editable':  itemData.hasOwnProperty('editable') ?  itemData.editable :  oldItem.editable,
+4927         'type':      itemData.hasOwnProperty('type') ?      itemData.type :      oldItem.type
+4928     });
+4929     this.items[index] = newItem;
+4930 
+4931     // append the changes to the render queue
+4932     this.renderQueue.hide.push(oldItem);
+4933     this.renderQueue.show.push(newItem);
+4934 
+4935     // update the original data table
+4936     this.updateData(index, itemData);
+4937 
+4938     // prepare data for clustering, by filtering and sorting by type
+4939     if (this.options.cluster) {
+4940         this.clusterGenerator.updateData();
+4941     }
+4942 
+4943     if (!preventRender) {
+4944         // redraw timeline
+4945         this.render({
+4946             animate: false
+4947         });
+4948 
+4949         if (this.selection && this.selection.index == index) {
+4950             newItem.select();
+4951         }
+4952     }
+4953 };
+4954 
+4955 /**
+4956  * Delete all groups
+4957  */
+4958 links.Timeline.prototype.deleteGroups = function () {
+4959     this.groups = [];
+4960     this.groupIndexes = {};
+4961 };
+4962 
+4963 
+4964 /**
+4965  * Get a group by the group name. When the group does not exist,
+4966  * it will be created.
+4967  * @param {String} groupName   the name of the group
+4968  * @return {Object} groupObject
+4969  */
+4970 links.Timeline.prototype.getGroup = function (groupName) {
+4971     var groups = this.groups,
+4972         groupIndexes = this.groupIndexes,
+4973         groupObj = undefined;
+4974 
+4975     var groupIndex = groupIndexes[groupName];
+4976     if (groupIndex == undefined && groupName != undefined) { // not null or undefined
+4977         groupObj = {
+4978             'content': groupName,
+4979             'labelTop': 0,
+4980             'lineTop': 0
+4981             // note: this object will lateron get addition information,
+4982             //       such as height and width of the group
+4983         };
+4984         groups.push(groupObj);
+4985         // sort the groups
+4986         if (this.options.groupsOrder == true) {
+4987             groups = groups.sort(function (a, b) {
+4988                 if (a.content > b.content) {
+4989                     return 1;
+4990 		        }
+4991 		        if (a.content < b.content) {
+4992 		            return -1;
+4993 		        }
+4994 		        return 0;
+4995         	});
+4996         } else if (typeof(this.options.groupsOrder) == "function") {
+4997         	groups = groups.sort(this.options.groupsOrder)
+4998         }
+4999 
+5000         // rebuilt the groupIndexes
+5001         for (var i = 0, iMax = groups.length; i < iMax; i++) {
+5002             groupIndexes[groups[i].content] = i;
+5003         }
+5004     }
+5005     else {
+5006         groupObj = groups[groupIndex];
+5007     }
+5008 
+5009     return groupObj;
+5010 };
+5011 
+5012 /**
+5013  * Get the group name from a group object.
+5014  * @param {Object} groupObj
+5015  * @return {String} groupName   the name of the group, or undefined when group
+5016  *                              was not provided
+5017  */
+5018 links.Timeline.prototype.getGroupName = function (groupObj) {
+5019     return groupObj ? groupObj.content : undefined;
+5020 };
+5021 
+5022 /**
+5023  * Cancel a change item
+5024  * This method can be called insed an event listener which catches the "change"
+5025  * event. The changed event position will be undone.
+5026  */
+5027 links.Timeline.prototype.cancelChange = function () {
+5028     this.applyChange = false;
+5029 };
+5030 
+5031 /**
+5032  * Cancel deletion of an item
+5033  * This method can be called insed an event listener which catches the "delete"
+5034  * event. Deletion of the event will be undone.
+5035  */
+5036 links.Timeline.prototype.cancelDelete = function () {
+5037     this.applyDelete = false;
+5038 };
+5039 
+5040 
+5041 /**
+5042  * Cancel creation of a new item
+5043  * This method can be called insed an event listener which catches the "new"
+5044  * event. Creation of the new the event will be undone.
+5045  */
+5046 links.Timeline.prototype.cancelAdd = function () {
+5047     this.applyAdd = false;
+5048 };
+5049 
+5050 
+5051 /**
+5052  * Select an event. The visible chart range will be moved such that the selected
+5053  * event is placed in the middle.
+5054  * For example selection = [{row: 5}];
+5055  * @param {Array} selection   An array with a column row, containing the row
+5056  *                           number (the id) of the event to be selected.
+5057  * @return {boolean}         true if selection is succesfully set, else false.
+5058  */
+5059 links.Timeline.prototype.setSelection = function(selection) {
+5060     if (selection != undefined && selection.length > 0) {
+5061         if (selection[0].row != undefined) {
+5062             var index = selection[0].row;
+5063             if (this.items[index]) {
+5064                 var item = this.items[index];
+5065                 this.selectItem(index);
+5066 
+5067                 // move the visible chart range to the selected event.
+5068                 var start = item.start;
+5069                 var end = item.end;
+5070                 var middle; // number
+5071                 if (end != undefined) {
+5072                     middle = (end.valueOf() + start.valueOf()) / 2;
+5073                 } else {
+5074                     middle = start.valueOf();
+5075                 }
+5076                 var diff = (this.end.valueOf() - this.start.valueOf()),
+5077                     newStart = new Date(middle - diff/2),
+5078                     newEnd = new Date(middle + diff/2);
+5079 
+5080                 this.setVisibleChartRange(newStart, newEnd);
+5081 
+5082                 return true;
+5083             }
+5084         }
+5085     }
+5086     else {
+5087         // unselect current selection
+5088         this.unselectItem();
+5089     }
+5090     return false;
+5091 };
+5092 
+5093 /**
+5094  * Retrieve the currently selected event
+5095  * @return {Array} sel  An array with a column row, containing the row number
+5096  *                      of the selected event. If there is no selection, an
+5097  *                      empty array is returned.
+5098  */
+5099 links.Timeline.prototype.getSelection = function() {
+5100     var sel = [];
+5101     if (this.selection) {
+5102         if(this.selection.index !== undefined)
+5103         {
+5104             sel.push({"row": this.selection.index});
+5105         } else {
+5106             sel.push({"cluster": this.selection.cluster});
+5107         }
+5108     }
+5109     return sel;
+5110 };
+5111 
+5112 
+5113 /**
+5114  * Select an item by its index
+5115  * @param {Number} index
+5116  */
+5117 links.Timeline.prototype.selectItem = function(index) {
+5118     this.unselectItem();
+5119 
+5120     this.selection = undefined;
+5121 
+5122     if (this.items[index] != undefined) {
+5123         var item = this.items[index],
+5124             domItem = item.dom;
+5125 
+5126         this.selection = {
+5127             'index': index
+5128         };
+5129 
+5130         if (item && item.dom) {
+5131             // TODO: move adjusting the domItem to the item itself
+5132             if (this.isEditable(item)) {
+5133                 item.dom.style.cursor = 'move';
+5134             }
+5135             item.select();
+5136         }
+5137         this.repaintDeleteButton();
+5138         this.repaintDragAreas();
+5139     }
+5140 };
+5141 
+5142 /**
+5143  * Select an cluster by its index
+5144  * @param {Number} index
+5145  */
+5146 links.Timeline.prototype.selectCluster = function(index) {
+5147     this.unselectItem();
+5148 
+5149     this.selection = undefined;
+5150 
+5151     if (this.clusters[index] != undefined) {
+5152         this.selection = {
+5153             'cluster': index
+5154         };
+5155         this.repaintDeleteButton();
+5156         this.repaintDragAreas();
+5157     }
+5158 };
+5159 
+5160 /**
+5161  * Check if an item is currently selected
+5162  * @param {Number} index
+5163  * @return {boolean} true if row is selected, else false
+5164  */
+5165 links.Timeline.prototype.isSelected = function (index) {
+5166     return (this.selection && this.selection.index == index);
+5167 };
+5168 
+5169 /**
+5170  * Unselect the currently selected event (if any)
+5171  */
+5172 links.Timeline.prototype.unselectItem = function() {
+5173     if (this.selection && this.selection.index !== undefined) {
+5174         var item = this.items[this.selection.index];
+5175 
+5176         if (item && item.dom) {
+5177             var domItem = item.dom;
+5178             domItem.style.cursor = '';
+5179             item.unselect();
+5180         }
+5181 
+5182         this.selection = undefined;
+5183         this.repaintDeleteButton();
+5184         this.repaintDragAreas();
+5185     }
+5186 };
+5187 
+5188 
+5189 /**
+5190  * Stack the items such that they don't overlap. The items will have a minimal
+5191  * distance equal to options.eventMargin.
+5192  * @param {boolean | undefined} animate    if animate is true, the items are
+5193  *                                         moved to their new position animated
+5194  *                                         defaults to false.
+5195  */
+5196 links.Timeline.prototype.stackItems = function(animate) {
+5197     if (animate == undefined) {
+5198         animate = false;
+5199     }
+5200 
+5201     // calculate the order and final stack position of the items
+5202     var stack = this.stack;
+5203     if (!stack) {
+5204         stack = {};
+5205         this.stack = stack;
+5206     }
+5207     stack.sortedItems = this.stackOrder(this.renderedItems);
+5208     stack.finalItems = this.stackCalculateFinal(stack.sortedItems);
+5209 
+5210     if (animate || stack.timer) {
+5211         // move animated to the final positions
+5212         var timeline = this;
+5213         var step = function () {
+5214             var arrived = timeline.stackMoveOneStep(stack.sortedItems,
+5215                 stack.finalItems);
+5216 
+5217             timeline.repaint();
+5218 
+5219             if (!arrived) {
+5220                 stack.timer = setTimeout(step, 30);
+5221             }
+5222             else {
+5223                 delete stack.timer;
+5224             }
+5225         };
+5226 
+5227         if (!stack.timer) {
+5228             stack.timer = setTimeout(step, 30);
+5229         }
+5230     }
+5231     else {
+5232         // move immediately to the final positions
+5233         this.stackMoveToFinal(stack.sortedItems, stack.finalItems);
+5234     }
+5235 };
+5236 
+5237 /**
+5238  * Cancel any running animation
+5239  */
+5240 links.Timeline.prototype.stackCancelAnimation = function() {
+5241     if (this.stack && this.stack.timer) {
+5242         clearTimeout(this.stack.timer);
+5243         delete this.stack.timer;
+5244     }
+5245 };
+5246 
+5247 links.Timeline.prototype.getItemsByGroup = function(items) {
+5248     var itemsByGroup = {};
+5249     for (var i = 0; i < items.length; ++i) {
+5250         var item = items[i];
+5251         var group = "undefined";
+5252 
+5253         if (item.group) {
+5254             if (item.group.content) {
+5255                 group = item.group.content;
+5256             } else {
+5257                 group = item.group;
+5258             }
+5259         }
+5260 
+5261         if (!itemsByGroup[group]) {
+5262             itemsByGroup[group] = [];
+5263         }
+5264 
+5265         itemsByGroup[group].push(item);
+5266     }
+5267 
+5268     return itemsByGroup;
+5269 };
+5270 
+5271 /**
+5272  * Order the items in the array this.items. The default order is determined via:
+5273  * - Ranges go before boxes and dots.
+5274  * - The item with the oldest start time goes first
+5275  * If a custom function has been provided via the stackorder option, then this will be used.
+5276  * @param {Array} items        Array with items
+5277  * @return {Array} sortedItems Array with sorted items
+5278  */
+5279 links.Timeline.prototype.stackOrder = function(items) {
+5280     // TODO: store the sorted items, to have less work later on
+5281     var sortedItems = items.concat([]);
+5282 
+5283     //if a customer stack order function exists, use it.
+5284     var f = this.options.customStackOrder && (typeof this.options.customStackOrder === 'function') ? this.options.customStackOrder : function (a, b)
+5285     {
+5286         if ((a instanceof links.Timeline.ItemRange || a instanceof links.Timeline.ItemFloatingRange) &&
+5287             !(b instanceof links.Timeline.ItemRange || b instanceof links.Timeline.ItemFloatingRange)) {
+5288             return -1;
+5289         }
+5290 
+5291         if (!(a instanceof links.Timeline.ItemRange || a instanceof links.Timeline.ItemFloatingRange) &&
+5292             (b instanceof links.Timeline.ItemRange || b instanceof links.Timeline.ItemFloatingRange)) {
+5293             return 1;
+5294         }
+5295 
+5296         return (a.left - b.left);
+5297     };
+5298 
+5299     sortedItems.sort(f);
+5300 
+5301     return sortedItems;
+5302 };
+5303 
+5304 /**
+5305  * Adjust vertical positions of the events such that they don't overlap each
+5306  * other.
+5307  * @param {timeline.Item[]} items
+5308  * @return {Object[]} finalItems
+5309  */
+5310 links.Timeline.prototype.stackCalculateFinal = function(items) {
+5311     var size = this.size,
+5312         options = this.options,
+5313         axisOnTop = options.axisOnTop,
+5314         eventMargin = options.eventMargin,
+5315         eventMarginAxis = options.eventMarginAxis,
+5316         groupBase = (axisOnTop)
+5317                   ? size.axis.height + eventMarginAxis + eventMargin/2
+5318                   : size.contentHeight - eventMarginAxis - eventMargin/2,
+5319         groupedItems, groupFinalItems, finalItems = [];
+5320 
+5321     groupedItems = this.getItemsByGroup(items);
+5322 
+5323     //
+5324     // groupedItems contains all items by group, plus it may contain an
+5325     // additional "undefined" group which contains all items with no group. We
+5326     // first process the grouped items, and then the ungrouped
+5327     //
+5328     for (j = 0; j<this.groups.length; ++j) {
+5329         var group = this.groups[j];
+5330 
+5331         if (!groupedItems[group.content]) {
+5332             if (axisOnTop) {
+5333                 groupBase += options.groupMinHeight + eventMargin;
+5334             } else {
+5335                 groupBase -= (options.groupMinHeight + eventMargin);
+5336             }
+5337             continue;
+5338         }
+5339 
+5340         // initialize final positions and fill finalItems
+5341         groupFinalItems = this.finalItemsPosition(groupedItems[group.content], groupBase, group);
+5342         groupFinalItems.forEach(function(item) {
+5343            finalItems.push(item);
+5344         });
+5345 
+5346         if (axisOnTop) {
+5347             groupBase += group.itemsHeight + eventMargin;
+5348         } else {
+5349             groupBase -= (group.itemsHeight + eventMargin);
+5350         }
+5351     }
+5352 
+5353     //
+5354     // Ungrouped items' turn now!
+5355     //
+5356     if (groupedItems["undefined"]) {
+5357         // initialize final positions and fill finalItems
+5358         groupFinalItems = this.finalItemsPosition(groupedItems["undefined"], groupBase);
+5359         groupFinalItems.forEach(function(item) {
+5360            finalItems.push(item);
+5361         });
+5362     }
+5363 
+5364     return finalItems;
+5365 };
+5366 
+5367 links.Timeline.prototype.finalItemsPosition = function(items, groupBase, group) {
+5368     var i,
+5369         iMax,
+5370         options = this.options,
+5371         axisOnTop = options.axisOnTop,
+5372         eventMargin = options.eventMargin,
+5373         groupFinalItems;
+5374 
+5375     // initialize final positions and fill finalItems
+5376     groupFinalItems = this.initialItemsPosition(items, groupBase);
+5377 
+5378     // calculate new, non-overlapping positions
+5379     for (i = 0, iMax = groupFinalItems.length; i < iMax; i++) {
+5380         var finalItem = groupFinalItems[i];
+5381         var collidingItem = null;
+5382 
+5383         if (this.options.stackEvents) {
+5384             do {
+5385                 // TODO: optimize checking for overlap. when there is a gap without items,
+5386                 //  you only need to check for items from the next item on, not from zero
+5387                 collidingItem = this.stackItemsCheckOverlap(groupFinalItems, i, 0, i-1);
+5388                 if (collidingItem != null) {
+5389                     // There is a collision. Reposition the event above the colliding element
+5390                     if (axisOnTop) {
+5391                         finalItem.top = collidingItem.top + collidingItem.height + eventMargin;
+5392                     }
+5393                     else {
+5394                         finalItem.top = collidingItem.top - finalItem.height - eventMargin;
+5395                     }
+5396                     finalItem.bottom = finalItem.top + finalItem.height;
+5397                 }
+5398             } while (collidingItem);
+5399         }
+5400 
+5401         if (group) {
+5402             if (axisOnTop) {
+5403                 group.itemsHeight = (group.itemsHeight)
+5404                                   ? Math.max(group.itemsHeight, finalItem.bottom - groupBase)
+5405                                   : finalItem.height + eventMargin;
+5406             } else {
+5407                 group.itemsHeight = (group.itemsHeight)
+5408                                   ? Math.max(group.itemsHeight, groupBase - finalItem.top)
+5409                                   : finalItem.height + eventMargin;
+5410             }
+5411         }
+5412     }
+5413 
+5414     return groupFinalItems;
+5415 };
+5416 
+5417 links.Timeline.prototype.initialItemsPosition = function(items, groupBase) {
+5418     var options = this.options,
+5419         axisOnTop = options.axisOnTop,
+5420         finalItems = [];
+5421 
+5422     for (var i = 0, iMax = items.length; i < iMax; ++i) {
+5423         var item = items[i],
+5424             top,
+5425             bottom,
+5426             height = item.height,
+5427             width = item.getWidth(this),
+5428             right = item.getRight(this),
+5429             left = right - width;
+5430 
+5431         top = (axisOnTop) ? groupBase
+5432                           : groupBase - height;
+5433 
+5434         bottom = top + height;
+5435 
+5436         finalItems.push({
+5437             'left': left,
+5438             'top': top,
+5439             'right': right,
+5440             'bottom': bottom,
+5441             'height': height,
+5442             'item': item
+5443         });
+5444     }
+5445 
+5446     return finalItems;
+5447 };
+5448 
+5449 /**
+5450  * Move the events one step in the direction of their final positions
+5451  * @param {Array} currentItems   Array with the real items and their current
+5452  *                               positions
+5453  * @param {Array} finalItems     Array with objects containing the final
+5454  *                               positions of the items
+5455  * @return {boolean} arrived     True if all items have reached their final
+5456  *                               location, else false
+5457  */
+5458 links.Timeline.prototype.stackMoveOneStep = function(currentItems, finalItems) {
+5459     var arrived = true;
+5460 
+5461     // apply new positions animated
+5462     for (var i = 0, iMax = finalItems.length; i < iMax; i++) {
+5463         var finalItem = finalItems[i],
+5464             item = finalItem.item;
+5465 
+5466         var topNow = parseInt(item.top);
+5467         var topFinal = parseInt(finalItem.top);
+5468         var diff = (topFinal - topNow);
+5469         if (diff) {
+5470             var step = (topFinal == topNow) ? 0 : ((topFinal > topNow) ? 1 : -1);
+5471             if (Math.abs(diff) > 4) step = diff / 4;
+5472             var topNew = parseInt(topNow + step);
+5473 
+5474             if (topNew != topFinal) {
+5475                 arrived = false;
+5476             }
+5477 
+5478             item.top = topNew;
+5479             item.bottom = item.top + item.height;
+5480         }
+5481         else {
+5482             item.top = finalItem.top;
+5483             item.bottom = finalItem.bottom;
+5484         }
+5485 
+5486         item.left = finalItem.left;
+5487         item.right = finalItem.right;
+5488     }
+5489 
+5490     return arrived;
+5491 };
+5492 
+5493 
+5494 
+5495 /**
+5496  * Move the events from their current position to the final position
+5497  * @param {Array} currentItems   Array with the real items and their current
+5498  *                               positions
+5499  * @param {Array} finalItems     Array with objects containing the final
+5500  *                               positions of the items
+5501  */
+5502 links.Timeline.prototype.stackMoveToFinal = function(currentItems, finalItems) {
+5503     // Put the events directly at there final position
+5504     for (var i = 0, iMax = finalItems.length; i < iMax; i++) {
+5505         var finalItem = finalItems[i],
+5506             current = finalItem.item;
+5507 
+5508         current.left = finalItem.left;
+5509         current.top = finalItem.top;
+5510         current.right = finalItem.right;
+5511         current.bottom = finalItem.bottom;
+5512     }
+5513 };
+5514 
+5515 
+5516 
+5517 /**
+5518  * Check if the destiny position of given item overlaps with any
+5519  * of the other items from index itemStart to itemEnd.
+5520  * @param {Array} items      Array with items
+5521  * @param {int}  itemIndex   Number of the item to be checked for overlap
+5522  * @param {int}  itemStart   First item to be checked.
+5523  * @param {int}  itemEnd     Last item to be checked.
+5524  * @return {Object}          colliding item, or undefined when no collisions
+5525  */
+5526 links.Timeline.prototype.stackItemsCheckOverlap = function(items, itemIndex,
+5527                                                            itemStart, itemEnd) {
+5528     var eventMargin = this.options.eventMargin,
+5529         collision = this.collision;
+5530 
+5531     // we loop from end to start, as we suppose that the chance of a
+5532     // collision is larger for items at the end, so check these first.
+5533     var item1 = items[itemIndex];
+5534     for (var i = itemEnd; i >= itemStart; i--) {
+5535         var item2 = items[i];
+5536         if (collision(item1, item2, eventMargin)) {
+5537             if (i != itemIndex) {
+5538                 return item2;
+5539             }
+5540         }
+5541     }
+5542 
+5543     return undefined;
+5544 };
+5545 
+5546 /**
+5547  * Test if the two provided items collide
+5548  * The items must have parameters left, right, top, and bottom.
+5549  * @param {Element} item1       The first item
+5550  * @param {Element} item2       The second item
+5551  * @param {Number}              margin  A minimum required margin. Optional.
+5552  *                              If margin is provided, the two items will be
+5553  *                              marked colliding when they overlap or
+5554  *                              when the margin between the two is smaller than
+5555  *                              the requested margin.
+5556  * @return {boolean}            true if item1 and item2 collide, else false
+5557  */
+5558 links.Timeline.prototype.collision = function(item1, item2, margin) {
+5559     // set margin if not specified
+5560     if (margin == undefined) {
+5561         margin = 0;
+5562     }
+5563 
+5564     // calculate if there is overlap (collision)
+5565     return (item1.left - margin < item2.right &&
+5566         item1.right + margin > item2.left &&
+5567         item1.top - margin < item2.bottom &&
+5568         item1.bottom + margin > item2.top);
+5569 };
+5570 
+5571 
+5572 /**
+5573  * fire an event
+5574  * @param {String} event   The name of an event, for example "rangechange" or "edit"
+5575  */
+5576 links.Timeline.prototype.trigger = function (event) {
+5577     // built up properties
+5578     var properties = null;
+5579     switch (event) {
+5580         case 'rangechange':
+5581         case 'rangechanged':
+5582             properties = {
+5583                 'start': new Date(this.start.valueOf()),
+5584                 'end': new Date(this.end.valueOf())
+5585             };
+5586             break;
+5587 
+5588         case 'timechange':
+5589         case 'timechanged':
+5590             properties = {
+5591                 'time': new Date(this.customTime.valueOf())
+5592             };
+5593             break;
+5594     }
+5595 
+5596     // trigger the links event bus
+5597     links.events.trigger(this, event, properties);
+5598 
+5599     // trigger the google event bus
+5600     if (google && google.visualization) {
+5601         google.visualization.events.trigger(this, event, properties);
+5602     }
+5603 };
+5604 
+5605 
+5606 /**
+5607  * Cluster the events
+5608  */
+5609 links.Timeline.prototype.clusterItems = function () {
+5610     if (!this.options.cluster) {
+5611         return;
+5612     }
+5613 
+5614     var clusters = this.clusterGenerator.getClusters(this.conversion.factor, this.options.clusterMaxItems);
+5615     if (this.clusters != clusters) {
+5616         // cluster level changed
+5617         var queue = this.renderQueue;
+5618 
+5619         // remove the old clusters from the scene
+5620         if (this.clusters) {
+5621             this.clusters.forEach(function (cluster) {
+5622                 queue.hide.push(cluster);
+5623 
+5624                 // unlink the items
+5625                 cluster.items.forEach(function (item) {
+5626                     item.cluster = undefined;
+5627                 });
+5628             });
+5629         }
+5630 
+5631         // append the new clusters
+5632         clusters.forEach(function (cluster) {
+5633             // don't add to the queue.show here, will be done in .filterItems()
+5634 
+5635             // link all items to the cluster
+5636             cluster.items.forEach(function (item) {
+5637                 item.cluster = cluster;
+5638             });
+5639         });
+5640 
+5641         this.clusters = clusters;
+5642     }
+5643 };
+5644 
+5645 /**
+5646  * Filter the visible events
+5647  */
+5648 links.Timeline.prototype.filterItems = function () {
+5649     var queue = this.renderQueue,
+5650         window = (this.end - this.start),
+5651         start = new Date(this.start.valueOf() - window),
+5652         end = new Date(this.end.valueOf() + window);
+5653 
+5654     function filter (arr) {
+5655         arr.forEach(function (item) {
+5656             var rendered = item.rendered;
+5657             var visible = item.isVisible(start, end);
+5658             if (rendered != visible) {
+5659                 if (rendered) {
+5660                     queue.hide.push(item); // item is rendered but no longer visible
+5661                 }
+5662                 if (visible && (queue.show.indexOf(item) == -1)) {
+5663                     queue.show.push(item); // item is visible but neither rendered nor queued up to be rendered
+5664                 }
+5665             }
+5666         });
+5667     }
+5668 
+5669     // filter all items and all clusters
+5670     filter(this.items);
+5671     if (this.clusters) {
+5672         filter(this.clusters);
+5673     }
+5674 };
+5675 
+5676 /** ------------------------------------------------------------------------ **/
+5677 
+5678 /**
+5679  * @constructor links.Timeline.ClusterGenerator
+5680  * Generator which creates clusters of items, based on the visible range in
+5681  * the Timeline. There is a set of cluster levels which is cached.
+5682  * @param {links.Timeline} timeline
+5683  */
+5684 links.Timeline.ClusterGenerator = function (timeline) {
+5685     this.timeline = timeline;
+5686     this.clear();
+5687 };
+5688 
+5689 /**
+5690  * Clear all cached clusters and data, and initialize all variables
+5691  */
+5692 links.Timeline.ClusterGenerator.prototype.clear = function () {
+5693     // cache containing created clusters for each cluster level
+5694     this.items = [];
+5695     this.groups = {};
+5696     this.clearCache();
+5697 };
+5698 
+5699 /**
+5700  * Clear the cached clusters
+5701  */
+5702 links.Timeline.ClusterGenerator.prototype.clearCache = function () {
+5703     // cache containing created clusters for each cluster level
+5704     this.cache = {};
+5705     this.cacheLevel = -1;
+5706     this.cache[this.cacheLevel] = [];
+5707 };
+5708 
+5709 /**
+5710  * Set the items to be clustered.
+5711  * This will clear cached clusters.
+5712  * @param {Item[]} items
+5713  * @param {Object} [options]  Available options:
+5714  *                            {boolean} applyOnChangedLevel
+5715  *                                If true (default), the changed data is applied
+5716  *                                as soon the cluster level changes. If false,
+5717  *                                The changed data is applied immediately
+5718  */
+5719 links.Timeline.ClusterGenerator.prototype.setData = function (items, options) {
+5720     this.items = items || [];
+5721     this.dataChanged = true;
+5722     this.applyOnChangedLevel = true;
+5723     if (options && options.applyOnChangedLevel) {
+5724         this.applyOnChangedLevel = options.applyOnChangedLevel;
+5725     }
+5726     // console.log('clustergenerator setData applyOnChangedLevel=' + this.applyOnChangedLevel); // TODO: cleanup
+5727 };
+5728 
+5729 /**
+5730  * Update the current data set: clear cache, and recalculate the clustering for
+5731  * the current level
+5732  */
+5733 links.Timeline.ClusterGenerator.prototype.updateData = function () {
+5734     this.dataChanged = true;
+5735     this.applyOnChangedLevel = false;
+5736 };
+5737 
+5738 /**
+5739  * Filter the items per group.
+5740  * @private
+5741  */
+5742 links.Timeline.ClusterGenerator.prototype.filterData = function () {
+5743     // filter per group
+5744     var items = this.items || [];
+5745     var groups = {};
+5746     this.groups = groups;
+5747 
+5748     // split the items per group
+5749     items.forEach(function (item) {
+5750         // put the item in the correct group
+5751         var groupName = item.group ? item.group.content : '';
+5752         var group = groups[groupName];
+5753         if (!group) {
+5754             group = [];
+5755             groups[groupName] = group;
+5756         }
+5757         group.push(item);
+5758 
+5759         // calculate the center of the item
+5760         if (item.start) {
+5761             if (item.end) {
+5762                 // range
+5763                 item.center = (item.start.valueOf() + item.end.valueOf()) / 2;
+5764             }
+5765             else {
+5766                 // box, dot
+5767                 item.center = item.start.valueOf();
+5768             }
+5769         }
+5770     });
+5771 
+5772     // sort the items per group
+5773     for (var groupName in groups) {
+5774         if (groups.hasOwnProperty(groupName)) {
+5775             groups[groupName].sort(function (a, b) {
+5776                 return (a.center - b.center);
+5777             });
+5778         }
+5779     }
+5780 
+5781     this.dataChanged = false;
+5782 };
+5783 
+5784 /**
+5785  * Cluster the events which are too close together
+5786  * @param {Number} scale     The scale of the current window,
+5787  *                           defined as (windowWidth / (endDate - startDate))
+5788  * @return {Item[]} clusters
+5789  */
+5790 links.Timeline.ClusterGenerator.prototype.getClusters = function (scale, maxItems) {
+5791     var level = -1,
+5792         granularity = 2, // TODO: what granularity is needed for the cluster levels?
+5793         timeWindow = 0;  // milliseconds
+5794 
+5795     if (scale > 0) {
+5796         level = Math.round(Math.log(100 / scale) / Math.log(granularity));
+5797         timeWindow = Math.pow(granularity, level);
+5798     }
+5799 
+5800     // clear the cache when and re-filter the data when needed.
+5801     if (this.dataChanged) {
+5802         var levelChanged = (level != this.cacheLevel);
+5803         var applyDataNow = this.applyOnChangedLevel ? levelChanged : true;
+5804         if (applyDataNow) {
+5805             // TODO: currently drawn clusters should be removed! mark them as invisible?
+5806             this.clearCache();
+5807             this.filterData();
+5808             // console.log('clustergenerator: cache cleared...'); // TODO: cleanup
+5809         }
+5810     }
+5811 
+5812     this.cacheLevel = level;
+5813     var clusters = this.cache[level];
+5814     if (!clusters) {
+5815         // console.log('clustergenerator: create cluster level ' + level); // TODO: cleanup
+5816         clusters = [];
+5817 
+5818         // TODO: spit this method, it is too large
+5819         for (var groupName in this.groups) {
+5820             if (this.groups.hasOwnProperty(groupName)) {
+5821                 var items = this.groups[groupName];
+5822                 var iMax = items.length;
+5823                 var i = 0;
+5824                 while (i < iMax) {
+5825                     // find all items around current item, within the timeWindow
+5826                     var item = items[i];
+5827                     var neighbors = 1;  // start at 1, to include itself)
+5828 
+5829                     // loop through items left from the current item
+5830                     var j = i - 1;
+5831                     while (j >= 0 && (item.center - items[j].center) < timeWindow / 2) {
+5832                         if (!items[j].cluster) {
+5833                             neighbors++;
+5834                         }
+5835                         j--;
+5836                     }
+5837 
+5838                     // loop through items right from the current item
+5839                     var k = i + 1;
+5840                     while (k < items.length && (items[k].center - item.center) < timeWindow / 2) {
+5841                         neighbors++;
+5842                         k++;
+5843                     }
+5844 
+5845                     // loop through the created clusters
+5846                     var l = clusters.length - 1;
+5847                     while (l >= 0 && (item.center - clusters[l].center) < timeWindow / 2) {
+5848                         if (item.group == clusters[l].group) {
+5849                             neighbors++;
+5850                         }
+5851                         l--;
+5852                     }
+5853 
+5854                     // aggregate until the number of items is within maxItems
+5855                     if (neighbors > maxItems) {
+5856                         // too busy in this window.
+5857                         var num = neighbors - maxItems + 1;
+5858                         var clusterItems = [];
+5859 
+5860                         // append the items to the cluster,
+5861                         // and calculate the average start for the cluster
+5862                         var avg = undefined;  // number. average of all start dates
+5863                         var min = undefined;  // number. minimum of all start dates
+5864                         var max = undefined;  // number. maximum of all start and end dates
+5865                         var containsRanges = false;
+5866                         var count = 0;
+5867                         var m = i;
+5868                         while (clusterItems.length < num && m < items.length) {
+5869                             var p = items[m];
+5870                             var start = p.start.valueOf();
+5871                             var end = p.end ? p.end.valueOf() : p.start.valueOf();
+5872                             clusterItems.push(p);
+5873                             if (count) {
+5874                                 // calculate new average (use fractions to prevent overflow)
+5875                                 avg = (count / (count + 1)) * avg + (1 / (count + 1)) * p.center;
+5876                             }
+5877                             else {
+5878                                 avg = p.center;
+5879                             }
+5880                             min = (min != undefined) ? Math.min(min, start) : start;
+5881                             max = (max != undefined) ? Math.max(max, end) : end;
+5882                             containsRanges = containsRanges || (p instanceof links.Timeline.ItemRange || p instanceof links.Timeline.ItemFloatingRange);
+5883                             count++;
+5884                             m++;
+5885                         }
+5886 
+5887                         var cluster;
+5888                         var title = 'Cluster containing ' + count +
+5889                             ' events. Zoom in to see the individual events.';
+5890                         var content = '<div title="' + title + '">' + count + ' events</div>';
+5891                         var group = item.group ? item.group.content : undefined;
+5892                         if (containsRanges) {
+5893                             // boxes and/or ranges
+5894                             cluster = this.timeline.createItem({
+5895                                 'start': new Date(min),
+5896                                 'end': new Date(max),
+5897                                 'content': content,
+5898                                 'group': group
+5899                             });
+5900                         }
+5901                         else {
+5902                             // boxes only
+5903                             cluster = this.timeline.createItem({
+5904                                 'start': new Date(avg),
+5905                                 'content': content,
+5906                                 'group': group
+5907                             });
+5908                         }
+5909                         cluster.isCluster = true;
+5910                         cluster.items = clusterItems;
+5911                         cluster.items.forEach(function (item) {
+5912                             item.cluster = cluster;
+5913                         });
+5914 
+5915                         clusters.push(cluster);
+5916                         i += num;
+5917                     }
+5918                     else {
+5919                         delete item.cluster;
+5920                         i += 1;
+5921                     }
+5922                 }
+5923             }
+5924         }
+5925 
+5926         this.cache[level] = clusters;
+5927     }
+5928 
+5929     return clusters;
+5930 };
+5931 
+5932 
+5933 /** ------------------------------------------------------------------------ **/
+5934 
+5935 
+5936 /**
+5937  * Event listener (singleton)
+5938  */
+5939 links.events = links.events || {
+5940     'listeners': [],
+5941 
+5942     /**
+5943      * Find a single listener by its object
+5944      * @param {Object} object
+5945      * @return {Number} index  -1 when not found
+5946      */
+5947     'indexOf': function (object) {
+5948         var listeners = this.listeners;
+5949         for (var i = 0, iMax = this.listeners.length; i < iMax; i++) {
+5950             var listener = listeners[i];
+5951             if (listener && listener.object == object) {
+5952                 return i;
+5953             }
+5954         }
+5955         return -1;
+5956     },
+5957 
+5958     /**
+5959      * Add an event listener
+5960      * @param {Object} object
+5961      * @param {String} event       The name of an event, for example 'select'
+5962      * @param {function} callback  The callback method, called when the
+5963      *                             event takes place
+5964      */
+5965     'addListener': function (object, event, callback) {
+5966         var index = this.indexOf(object);
+5967         var listener = this.listeners[index];
+5968         if (!listener) {
+5969             listener = {
+5970                 'object': object,
+5971                 'events': {}
+5972             };
+5973             this.listeners.push(listener);
+5974         }
+5975 
+5976         var callbacks = listener.events[event];
+5977         if (!callbacks) {
+5978             callbacks = [];
+5979             listener.events[event] = callbacks;
+5980         }
+5981 
+5982         // add the callback if it does not yet exist
+5983         if (callbacks.indexOf(callback) == -1) {
+5984             callbacks.push(callback);
+5985         }
+5986     },
+5987 
+5988     /**
+5989      * Remove an event listener
+5990      * @param {Object} object
+5991      * @param {String} event       The name of an event, for example 'select'
+5992      * @param {function} callback  The registered callback method
+5993      */
+5994     'removeListener': function (object, event, callback) {
+5995         var index = this.indexOf(object);
+5996         var listener = this.listeners[index];
+5997         if (listener) {
+5998             var callbacks = listener.events[event];
+5999             if (callbacks) {
+6000                 var index = callbacks.indexOf(callback);
+6001                 if (index != -1) {
+6002                     callbacks.splice(index, 1);
+6003                 }
+6004 
+6005                 // remove the array when empty
+6006                 if (callbacks.length == 0) {
+6007                     delete listener.events[event];
+6008                 }
+6009             }
+6010 
+6011             // count the number of registered events. remove listener when empty
+6012             var count = 0;
+6013             var events = listener.events;
+6014             for (var e in events) {
+6015                 if (events.hasOwnProperty(e)) {
+6016                     count++;
+6017                 }
+6018             }
+6019             if (count == 0) {
+6020                 delete this.listeners[index];
+6021             }
+6022         }
+6023     },
+6024 
+6025     /**
+6026      * Remove all registered event listeners
+6027      */
+6028     'removeAllListeners': function () {
+6029         this.listeners = [];
+6030     },
+6031 
+6032     /**
+6033      * Trigger an event. All registered event handlers will be called
+6034      * @param {Object} object
+6035      * @param {String} event
+6036      * @param {Object} properties (optional)
+6037      */
+6038     'trigger': function (object, event, properties) {
+6039         var index = this.indexOf(object);
+6040         var listener = this.listeners[index];
+6041         if (listener) {
+6042             var callbacks = listener.events[event];
+6043             if (callbacks) {
+6044                 for (var i = 0, iMax = callbacks.length; i < iMax; i++) {
+6045                     callbacks[i](properties);
+6046                 }
+6047             }
+6048         }
+6049     }
+6050 };
+6051 
+6052 
+6053 /** ------------------------------------------------------------------------ **/
+6054 
+6055 /**
+6056  * @constructor  links.Timeline.StepDate
+6057  * The class StepDate is an iterator for dates. You provide a start date and an
+6058  * end date. The class itself determines the best scale (step size) based on the
+6059  * provided start Date, end Date, and minimumStep.
+6060  *
+6061  * If minimumStep is provided, the step size is chosen as close as possible
+6062  * to the minimumStep but larger than minimumStep. If minimumStep is not
+6063  * provided, the scale is set to 1 DAY.
+6064  * The minimumStep should correspond with the onscreen size of about 6 characters
+6065  *
+6066  * Alternatively, you can set a scale by hand.
+6067  * After creation, you can initialize the class by executing start(). Then you
+6068  * can iterate from the start date to the end date via next(). You can check if
+6069  * the end date is reached with the function end(). After each step, you can
+6070  * retrieve the current date via get().
+6071  * The class step has scales ranging from milliseconds, seconds, minutes, hours,
+6072  * days, to years.
+6073  *
+6074  * Version: 1.2
+6075  *
+6076  * @param {Date} start          The start date, for example new Date(2010, 9, 21)
+6077  *                              or new Date(2010, 9, 21, 23, 45, 00)
+6078  * @param {Date} end            The end date
+6079  * @param {Number}  minimumStep Optional. Minimum step size in milliseconds
+6080  */
+6081 links.Timeline.StepDate = function(start, end, minimumStep) {
+6082 
+6083     // variables
+6084     this.current = new Date();
+6085     this._start = new Date();
+6086     this._end = new Date();
+6087 
+6088     this.autoScale  = true;
+6089     this.scale = links.Timeline.StepDate.SCALE.DAY;
+6090     this.step = 1;
+6091 
+6092     // initialize the range
+6093     this.setRange(start, end, minimumStep);
+6094 };
+6095 
+6096 /// enum scale
+6097 links.Timeline.StepDate.SCALE = {
+6098     MILLISECOND: 1,
+6099     SECOND: 2,
+6100     MINUTE: 3,
+6101     HOUR: 4,
+6102     DAY: 5,
+6103     WEEKDAY: 6,
+6104     MONTH: 7,
+6105     YEAR: 8
+6106 };
+6107 
+6108 
+6109 /**
+6110  * Set a new range
+6111  * If minimumStep is provided, the step size is chosen as close as possible
+6112  * to the minimumStep but larger than minimumStep. If minimumStep is not
+6113  * provided, the scale is set to 1 DAY.
+6114  * The minimumStep should correspond with the onscreen size of about 6 characters
+6115  * @param {Date} start        The start date and time.
+6116  * @param {Date} end          The end date and time.
+6117  * @param {int}  minimumStep  Optional. Minimum step size in milliseconds
+6118  */
+6119 links.Timeline.StepDate.prototype.setRange = function(start, end, minimumStep) {
+6120     if (!(start instanceof Date) || !(end instanceof Date)) {
+6121         //throw  "No legal start or end date in method setRange";
+6122         return;
+6123     }
+6124 
+6125     this._start = (start != undefined) ? new Date(start.valueOf()) : new Date();
+6126     this._end = (end != undefined) ? new Date(end.valueOf()) : new Date();
+6127 
+6128     if (this.autoScale) {
+6129         this.setMinimumStep(minimumStep);
+6130     }
+6131 };
+6132 
+6133 /**
+6134  * Set the step iterator to the start date.
+6135  */
+6136 links.Timeline.StepDate.prototype.start = function() {
+6137     this.current = new Date(this._start.valueOf());
+6138     this.roundToMinor();
+6139 };
+6140 
+6141 /**
+6142  * Round the current date to the first minor date value
+6143  * This must be executed once when the current date is set to start Date
+6144  */
+6145 links.Timeline.StepDate.prototype.roundToMinor = function() {
+6146     // round to floor
+6147     // IMPORTANT: we have no breaks in this switch! (this is no bug)
+6148     //noinspection FallthroughInSwitchStatementJS
+6149     switch (this.scale) {
+6150         case links.Timeline.StepDate.SCALE.YEAR:
+6151             this.current.setFullYear(this.step * Math.floor(this.current.getFullYear() / this.step));
+6152             this.current.setMonth(0);
+6153         case links.Timeline.StepDate.SCALE.MONTH:        this.current.setDate(1);
+6154         case links.Timeline.StepDate.SCALE.DAY:          // intentional fall through
+6155         case links.Timeline.StepDate.SCALE.WEEKDAY:      this.current.setHours(0);
+6156         case links.Timeline.StepDate.SCALE.HOUR:         this.current.setMinutes(0);
+6157         case links.Timeline.StepDate.SCALE.MINUTE:       this.current.setSeconds(0);
+6158         case links.Timeline.StepDate.SCALE.SECOND:       this.current.setMilliseconds(0);
+6159         //case links.Timeline.StepDate.SCALE.MILLISECOND: // nothing to do for milliseconds
+6160     }
+6161 
+6162     if (this.step != 1) {
+6163         // round down to the first minor value that is a multiple of the current step size
+6164         switch (this.scale) {
+6165             case links.Timeline.StepDate.SCALE.MILLISECOND:  this.current.setMilliseconds(this.current.getMilliseconds() - this.current.getMilliseconds() % this.step);  break;
+6166             case links.Timeline.StepDate.SCALE.SECOND:       this.current.setSeconds(this.current.getSeconds() - this.current.getSeconds() % this.step); break;
+6167             case links.Timeline.StepDate.SCALE.MINUTE:       this.current.setMinutes(this.current.getMinutes() - this.current.getMinutes() % this.step); break;
+6168             case links.Timeline.StepDate.SCALE.HOUR:         this.current.setHours(this.current.getHours() - this.current.getHours() % this.step); break;
+6169             case links.Timeline.StepDate.SCALE.WEEKDAY:      // intentional fall through
+6170             case links.Timeline.StepDate.SCALE.DAY:          this.current.setDate((this.current.getDate()-1) - (this.current.getDate()-1) % this.step + 1); break;
+6171             case links.Timeline.StepDate.SCALE.MONTH:        this.current.setMonth(this.current.getMonth() - this.current.getMonth() % this.step);  break;
+6172             case links.Timeline.StepDate.SCALE.YEAR:         this.current.setFullYear(this.current.getFullYear() - this.current.getFullYear() % this.step); break;
+6173             default: break;
+6174         }
+6175     }
+6176 };
+6177 
+6178 /**
+6179  * Check if the end date is reached
+6180  * @return {boolean}  true if the current date has passed the end date
+6181  */
+6182 links.Timeline.StepDate.prototype.end = function () {
+6183     return (this.current.valueOf() > this._end.valueOf());
+6184 };
+6185 
+6186 /**
+6187  * Do the next step
+6188  */
+6189 links.Timeline.StepDate.prototype.next = function() {
+6190     var prev = this.current.valueOf();
+6191 
+6192     // Two cases, needed to prevent issues with switching daylight savings
+6193     // (end of March and end of October)
+6194     if (this.current.getMonth() < 6)   {
+6195         switch (this.scale) {
+6196             case links.Timeline.StepDate.SCALE.MILLISECOND:
+6197 
+6198                 this.current = new Date(this.current.valueOf() + this.step); break;
+6199             case links.Timeline.StepDate.SCALE.SECOND:       this.current = new Date(this.current.valueOf() + this.step * 1000); break;
+6200             case links.Timeline.StepDate.SCALE.MINUTE:       this.current = new Date(this.current.valueOf() + this.step * 1000 * 60); break;
+6201             case links.Timeline.StepDate.SCALE.HOUR:
+6202                 this.current = new Date(this.current.valueOf() + this.step * 1000 * 60 * 60);
+6203                 // in case of skipping an hour for daylight savings, adjust the hour again (else you get: 0h 5h 9h ... instead of 0h 4h 8h ...)
+6204                 var h = this.current.getHours();
+6205                 this.current.setHours(h - (h % this.step));
+6206                 break;
+6207             case links.Timeline.StepDate.SCALE.WEEKDAY:      // intentional fall through
+6208             case links.Timeline.StepDate.SCALE.DAY:          this.current.setDate(this.current.getDate() + this.step); break;
+6209             case links.Timeline.StepDate.SCALE.MONTH:        this.current.setMonth(this.current.getMonth() + this.step); break;
+6210             case links.Timeline.StepDate.SCALE.YEAR:         this.current.setFullYear(this.current.getFullYear() + this.step); break;
+6211             default:                      break;
+6212         }
+6213     }
+6214     else {
+6215         switch (this.scale) {
+6216             case links.Timeline.StepDate.SCALE.MILLISECOND:  this.current = new Date(this.current.valueOf() + this.step); break;
+6217             case links.Timeline.StepDate.SCALE.SECOND:       this.current.setSeconds(this.current.getSeconds() + this.step); break;
+6218             case links.Timeline.StepDate.SCALE.MINUTE:       this.current.setMinutes(this.current.getMinutes() + this.step); break;
+6219             case links.Timeline.StepDate.SCALE.HOUR:         this.current.setHours(this.current.getHours() + this.step); break;
+6220             case links.Timeline.StepDate.SCALE.WEEKDAY:      // intentional fall through
+6221             case links.Timeline.StepDate.SCALE.DAY:          this.current.setDate(this.current.getDate() + this.step); break;
+6222             case links.Timeline.StepDate.SCALE.MONTH:        this.current.setMonth(this.current.getMonth() + this.step); break;
+6223             case links.Timeline.StepDate.SCALE.YEAR:         this.current.setFullYear(this.current.getFullYear() + this.step); break;
+6224             default:                      break;
+6225         }
+6226     }
+6227 
+6228     if (this.step != 1) {
+6229         // round down to the correct major value
+6230         switch (this.scale) {
+6231             case links.Timeline.StepDate.SCALE.MILLISECOND:  if(this.current.getMilliseconds() < this.step) this.current.setMilliseconds(0);  break;
+6232             case links.Timeline.StepDate.SCALE.SECOND:       if(this.current.getSeconds() < this.step) this.current.setSeconds(0);  break;
+6233             case links.Timeline.StepDate.SCALE.MINUTE:       if(this.current.getMinutes() < this.step) this.current.setMinutes(0);  break;
+6234             case links.Timeline.StepDate.SCALE.HOUR:         if(this.current.getHours() < this.step) this.current.setHours(0);  break;
+6235             case links.Timeline.StepDate.SCALE.WEEKDAY:      // intentional fall through
+6236             case links.Timeline.StepDate.SCALE.DAY:          if(this.current.getDate() < this.step+1) this.current.setDate(1); break;
+6237             case links.Timeline.StepDate.SCALE.MONTH:        if(this.current.getMonth() < this.step) this.current.setMonth(0);  break;
+6238             case links.Timeline.StepDate.SCALE.YEAR:         break; // nothing to do for year
+6239             default:                break;
+6240         }
+6241     }
+6242 
+6243     // safety mechanism: if current time is still unchanged, move to the end
+6244     if (this.current.valueOf() == prev) {
+6245         this.current = new Date(this._end.valueOf());
+6246     }
+6247 };
+6248 
+6249 
+6250 /**
+6251  * Get the current datetime
+6252  * @return {Date}  current The current date
+6253  */
+6254 links.Timeline.StepDate.prototype.getCurrent = function() {
+6255     return this.current;
+6256 };
+6257 
+6258 /**
+6259  * Set a custom scale. Autoscaling will be disabled.
+6260  * For example setScale(SCALE.MINUTES, 5) will result
+6261  * in minor steps of 5 minutes, and major steps of an hour.
+6262  *
+6263  * @param {links.Timeline.StepDate.SCALE} newScale
+6264  *                               A scale. Choose from SCALE.MILLISECOND,
+6265  *                               SCALE.SECOND, SCALE.MINUTE, SCALE.HOUR,
+6266  *                               SCALE.WEEKDAY, SCALE.DAY, SCALE.MONTH,
+6267  *                               SCALE.YEAR.
+6268  * @param {Number}     newStep   A step size, by default 1. Choose for
+6269  *                               example 1, 2, 5, or 10.
+6270  */
+6271 links.Timeline.StepDate.prototype.setScale = function(newScale, newStep) {
+6272     this.scale = newScale;
+6273 
+6274     if (newStep > 0) {
+6275         this.step = newStep;
+6276     }
+6277 
+6278     this.autoScale = false;
+6279 };
+6280 
+6281 /**
+6282  * Enable or disable autoscaling
+6283  * @param {boolean} enable  If true, autoascaling is set true
+6284  */
+6285 links.Timeline.StepDate.prototype.setAutoScale = function (enable) {
+6286     this.autoScale = enable;
+6287 };
+6288 
+6289 
+6290 /**
+6291  * Automatically determine the scale that bests fits the provided minimum step
+6292  * @param {Number} minimumStep  The minimum step size in milliseconds
+6293  */
+6294 links.Timeline.StepDate.prototype.setMinimumStep = function(minimumStep) {
+6295     if (minimumStep == undefined) {
+6296         return;
+6297     }
+6298 
+6299     var stepYear       = (1000 * 60 * 60 * 24 * 30 * 12);
+6300     var stepMonth      = (1000 * 60 * 60 * 24 * 30);
+6301     var stepDay        = (1000 * 60 * 60 * 24);
+6302     var stepHour       = (1000 * 60 * 60);
+6303     var stepMinute     = (1000 * 60);
+6304     var stepSecond     = (1000);
+6305     var stepMillisecond= (1);
+6306 
+6307     // find the smallest step that is larger than the provided minimumStep
+6308     if (stepYear*1000 > minimumStep)        {this.scale = links.Timeline.StepDate.SCALE.YEAR;        this.step = 1000;}
+6309     if (stepYear*500 > minimumStep)         {this.scale = links.Timeline.StepDate.SCALE.YEAR;        this.step = 500;}
+6310     if (stepYear*100 > minimumStep)         {this.scale = links.Timeline.StepDate.SCALE.YEAR;        this.step = 100;}
+6311     if (stepYear*50 > minimumStep)          {this.scale = links.Timeline.StepDate.SCALE.YEAR;        this.step = 50;}
+6312     if (stepYear*10 > minimumStep)          {this.scale = links.Timeline.StepDate.SCALE.YEAR;        this.step = 10;}
+6313     if (stepYear*5 > minimumStep)           {this.scale = links.Timeline.StepDate.SCALE.YEAR;        this.step = 5;}
+6314     if (stepYear > minimumStep)             {this.scale = links.Timeline.StepDate.SCALE.YEAR;        this.step = 1;}
+6315     if (stepMonth*3 > minimumStep)          {this.scale = links.Timeline.StepDate.SCALE.MONTH;       this.step = 3;}
+6316     if (stepMonth > minimumStep)            {this.scale = links.Timeline.StepDate.SCALE.MONTH;       this.step = 1;}
+6317     if (stepDay*5 > minimumStep)            {this.scale = links.Timeline.StepDate.SCALE.DAY;         this.step = 5;}
+6318     if (stepDay*2 > minimumStep)            {this.scale = links.Timeline.StepDate.SCALE.DAY;         this.step = 2;}
+6319     if (stepDay > minimumStep)              {this.scale = links.Timeline.StepDate.SCALE.DAY;         this.step = 1;}
+6320     if (stepDay/2 > minimumStep)            {this.scale = links.Timeline.StepDate.SCALE.WEEKDAY;     this.step = 1;}
+6321     if (stepHour*4 > minimumStep)           {this.scale = links.Timeline.StepDate.SCALE.HOUR;        this.step = 4;}
+6322     if (stepHour > minimumStep)             {this.scale = links.Timeline.StepDate.SCALE.HOUR;        this.step = 1;}
+6323     if (stepMinute*15 > minimumStep)        {this.scale = links.Timeline.StepDate.SCALE.MINUTE;      this.step = 15;}
+6324     if (stepMinute*10 > minimumStep)        {this.scale = links.Timeline.StepDate.SCALE.MINUTE;      this.step = 10;}
+6325     if (stepMinute*5 > minimumStep)         {this.scale = links.Timeline.StepDate.SCALE.MINUTE;      this.step = 5;}
+6326     if (stepMinute > minimumStep)           {this.scale = links.Timeline.StepDate.SCALE.MINUTE;      this.step = 1;}
+6327     if (stepSecond*15 > minimumStep)        {this.scale = links.Timeline.StepDate.SCALE.SECOND;      this.step = 15;}
+6328     if (stepSecond*10 > minimumStep)        {this.scale = links.Timeline.StepDate.SCALE.SECOND;      this.step = 10;}
+6329     if (stepSecond*5 > minimumStep)         {this.scale = links.Timeline.StepDate.SCALE.SECOND;      this.step = 5;}
+6330     if (stepSecond > minimumStep)           {this.scale = links.Timeline.StepDate.SCALE.SECOND;      this.step = 1;}
+6331     if (stepMillisecond*200 > minimumStep)  {this.scale = links.Timeline.StepDate.SCALE.MILLISECOND; this.step = 200;}
+6332     if (stepMillisecond*100 > minimumStep)  {this.scale = links.Timeline.StepDate.SCALE.MILLISECOND; this.step = 100;}
+6333     if (stepMillisecond*50 > minimumStep)   {this.scale = links.Timeline.StepDate.SCALE.MILLISECOND; this.step = 50;}
+6334     if (stepMillisecond*10 > minimumStep)   {this.scale = links.Timeline.StepDate.SCALE.MILLISECOND; this.step = 10;}
+6335     if (stepMillisecond*5 > minimumStep)    {this.scale = links.Timeline.StepDate.SCALE.MILLISECOND; this.step = 5;}
+6336     if (stepMillisecond > minimumStep)      {this.scale = links.Timeline.StepDate.SCALE.MILLISECOND; this.step = 1;}
+6337 };
+6338 
+6339 /**
+6340  * Snap a date to a rounded value. The snap intervals are dependent on the
+6341  * current scale and step.
+6342  * @param {Date} date   the date to be snapped
+6343  */
+6344 links.Timeline.StepDate.prototype.snap = function(date) {
+6345     if (this.scale == links.Timeline.StepDate.SCALE.YEAR) {
+6346         var year = date.getFullYear() + Math.round(date.getMonth() / 12);
+6347         date.setFullYear(Math.round(year / this.step) * this.step);
+6348         date.setMonth(0);
+6349         date.setDate(0);
+6350         date.setHours(0);
+6351         date.setMinutes(0);
+6352         date.setSeconds(0);
+6353         date.setMilliseconds(0);
+6354     }
+6355     else if (this.scale == links.Timeline.StepDate.SCALE.MONTH) {
+6356         if (date.getDate() > 15) {
+6357             date.setDate(1);
+6358             date.setMonth(date.getMonth() + 1);
+6359             // important: first set Date to 1, after that change the month.
+6360         }
+6361         else {
+6362             date.setDate(1);
+6363         }
+6364 
+6365         date.setHours(0);
+6366         date.setMinutes(0);
+6367         date.setSeconds(0);
+6368         date.setMilliseconds(0);
+6369     }
+6370     else if (this.scale == links.Timeline.StepDate.SCALE.DAY ||
+6371         this.scale == links.Timeline.StepDate.SCALE.WEEKDAY) {
+6372         switch (this.step) {
+6373             case 5:
+6374             case 2:
+6375                 date.setHours(Math.round(date.getHours() / 24) * 24); break;
+6376             default:
+6377                 date.setHours(Math.round(date.getHours() / 12) * 12); break;
+6378         }
+6379         date.setMinutes(0);
+6380         date.setSeconds(0);
+6381         date.setMilliseconds(0);
+6382     }
+6383     else if (this.scale == links.Timeline.StepDate.SCALE.HOUR) {
+6384         switch (this.step) {
+6385             case 4:
+6386                 date.setMinutes(Math.round(date.getMinutes() / 60) * 60); break;
+6387             default:
+6388                 date.setMinutes(Math.round(date.getMinutes() / 30) * 30); break;
+6389         }
+6390         date.setSeconds(0);
+6391         date.setMilliseconds(0);
+6392     } else if (this.scale == links.Timeline.StepDate.SCALE.MINUTE) {
+6393         switch (this.step) {
+6394             case 15:
+6395             case 10:
+6396                 date.setMinutes(Math.round(date.getMinutes() / 5) * 5);
+6397                 date.setSeconds(0);
+6398                 break;
+6399             case 5:
+6400                 date.setSeconds(Math.round(date.getSeconds() / 60) * 60); break;
+6401             default:
+6402                 date.setSeconds(Math.round(date.getSeconds() / 30) * 30); break;
+6403         }
+6404         date.setMilliseconds(0);
+6405     }
+6406     else if (this.scale == links.Timeline.StepDate.SCALE.SECOND) {
+6407         switch (this.step) {
+6408             case 15:
+6409             case 10:
+6410                 date.setSeconds(Math.round(date.getSeconds() / 5) * 5);
+6411                 date.setMilliseconds(0);
+6412                 break;
+6413             case 5:
+6414                 date.setMilliseconds(Math.round(date.getMilliseconds() / 1000) * 1000); break;
+6415             default:
+6416                 date.setMilliseconds(Math.round(date.getMilliseconds() / 500) * 500); break;
+6417         }
+6418     }
+6419     else if (this.scale == links.Timeline.StepDate.SCALE.MILLISECOND) {
+6420         var step = this.step > 5 ? this.step / 2 : 1;
+6421         date.setMilliseconds(Math.round(date.getMilliseconds() / step) * step);
+6422     }
+6423 };
+6424 
+6425 /**
+6426  * Check if the current step is a major step (for example when the step
+6427  * is DAY, a major step is each first day of the MONTH)
+6428  * @return {boolean} true if current date is major, else false.
+6429  */
+6430 links.Timeline.StepDate.prototype.isMajor = function() {
+6431     switch (this.scale) {
+6432         case links.Timeline.StepDate.SCALE.MILLISECOND:
+6433             return (this.current.getMilliseconds() == 0);
+6434         case links.Timeline.StepDate.SCALE.SECOND:
+6435             return (this.current.getSeconds() == 0);
+6436         case links.Timeline.StepDate.SCALE.MINUTE:
+6437             return (this.current.getHours() == 0) && (this.current.getMinutes() == 0);
+6438         // Note: this is no bug. Major label is equal for both minute and hour scale
+6439         case links.Timeline.StepDate.SCALE.HOUR:
+6440             return (this.current.getHours() == 0);
+6441         case links.Timeline.StepDate.SCALE.WEEKDAY: // intentional fall through
+6442         case links.Timeline.StepDate.SCALE.DAY:
+6443             return (this.current.getDate() == 1);
+6444         case links.Timeline.StepDate.SCALE.MONTH:
+6445             return (this.current.getMonth() == 0);
+6446         case links.Timeline.StepDate.SCALE.YEAR:
+6447             return false;
+6448         default:
+6449             return false;
+6450     }
+6451 };
+6452 
+6453 
+6454 /**
+6455  * Returns formatted text for the minor axislabel, depending on the current
+6456  * date and the scale. For example when scale is MINUTE, the current time is
+6457  * formatted as "hh:mm".
+6458  * @param {Object} options
+6459  * @param {Date} [date] custom date. if not provided, current date is taken
+6460  */
+6461 links.Timeline.StepDate.prototype.getLabelMinor = function(options, date) {
+6462     if (date == undefined) {
+6463         date = this.current;
+6464     }
+6465 
+6466     switch (this.scale) {
+6467         case links.Timeline.StepDate.SCALE.MILLISECOND:  return String(date.getMilliseconds());
+6468         case links.Timeline.StepDate.SCALE.SECOND:       return String(date.getSeconds());
+6469         case links.Timeline.StepDate.SCALE.MINUTE:
+6470             return this.addZeros(date.getHours(), 2) + ":" + this.addZeros(date.getMinutes(), 2);
+6471         case links.Timeline.StepDate.SCALE.HOUR:
+6472             return this.addZeros(date.getHours(), 2) + ":" + this.addZeros(date.getMinutes(), 2);
+6473         case links.Timeline.StepDate.SCALE.WEEKDAY:      return options.DAYS_SHORT[date.getDay()] + ' ' + date.getDate();
+6474         case links.Timeline.StepDate.SCALE.DAY:          return String(date.getDate());
+6475         case links.Timeline.StepDate.SCALE.MONTH:        return options.MONTHS_SHORT[date.getMonth()];   // month is zero based
+6476         case links.Timeline.StepDate.SCALE.YEAR:         return String(date.getFullYear());
+6477         default:                                         return "";
+6478     }
+6479 };
+6480 
+6481 
+6482 /**
+6483  * Returns formatted text for the major axislabel, depending on the current
+6484  * date and the scale. For example when scale is MINUTE, the major scale is
+6485  * hours, and the hour will be formatted as "hh".
+6486  * @param {Object} options
+6487  * @param {Date} [date] custom date. if not provided, current date is taken
+6488  */
+6489 links.Timeline.StepDate.prototype.getLabelMajor = function(options, date) {
+6490     if (date == undefined) {
+6491         date = this.current;
+6492     }
+6493 
+6494     switch (this.scale) {
+6495         case links.Timeline.StepDate.SCALE.MILLISECOND:
+6496             return  this.addZeros(date.getHours(), 2) + ":" +
+6497                 this.addZeros(date.getMinutes(), 2) + ":" +
+6498                 this.addZeros(date.getSeconds(), 2);
+6499         case links.Timeline.StepDate.SCALE.SECOND:
+6500             return  date.getDate() + " " +
+6501                 options.MONTHS[date.getMonth()] + " " +
+6502                 this.addZeros(date.getHours(), 2) + ":" +
+6503                 this.addZeros(date.getMinutes(), 2);
+6504         case links.Timeline.StepDate.SCALE.MINUTE:
+6505             return  options.DAYS[date.getDay()] + " " +
+6506                 date.getDate() + " " +
+6507                 options.MONTHS[date.getMonth()] + " " +
+6508                 date.getFullYear();
+6509         case links.Timeline.StepDate.SCALE.HOUR:
+6510             return  options.DAYS[date.getDay()] + " " +
+6511                 date.getDate() + " " +
+6512                 options.MONTHS[date.getMonth()] + " " +
+6513                 date.getFullYear();
+6514         case links.Timeline.StepDate.SCALE.WEEKDAY:
+6515         case links.Timeline.StepDate.SCALE.DAY:
+6516             return  options.MONTHS[date.getMonth()] + " " +
+6517                 date.getFullYear();
+6518         case links.Timeline.StepDate.SCALE.MONTH:
+6519             return String(date.getFullYear());
+6520         default:
+6521             return "";
+6522     }
+6523 };
+6524 
+6525 /**
+6526  * Add leading zeros to the given value to match the desired length.
+6527  * For example addZeros(123, 5) returns "00123"
+6528  * @param {int} value   A value
+6529  * @param {int} len     Desired final length
+6530  * @return {string}     value with leading zeros
+6531  */
+6532 links.Timeline.StepDate.prototype.addZeros = function(value, len) {
+6533     var str = "" + value;
+6534     while (str.length < len) {
+6535         str = "0" + str;
+6536     }
+6537     return str;
+6538 };
+6539 
+6540 
+6541 
+6542 /** ------------------------------------------------------------------------ **/
+6543 
+6544 /**
+6545  * Image Loader service.
+6546  * can be used to get a callback when a certain image is loaded
+6547  *
+6548  */
+6549 links.imageloader = (function () {
+6550     var urls = {};  // the loaded urls
+6551     var callbacks = {}; // the urls currently being loaded. Each key contains
+6552     // an array with callbacks
+6553 
+6554     /**
+6555      * Check if an image url is loaded
+6556      * @param {String} url
+6557      * @return {boolean} loaded   True when loaded, false when not loaded
+6558      *                            or when being loaded
+6559      */
+6560     function isLoaded (url) {
+6561         if (urls[url] == true) {
+6562             return true;
+6563         }
+6564 
+6565         var image = new Image();
+6566         image.src = url;
+6567         if (image.complete) {
+6568             return true;
+6569         }
+6570 
+6571         return false;
+6572     }
+6573 
+6574     /**
+6575      * Check if an image url is being loaded
+6576      * @param {String} url
+6577      * @return {boolean} loading   True when being loaded, false when not loading
+6578      *                             or when already loaded
+6579      */
+6580     function isLoading (url) {
+6581         return (callbacks[url] != undefined);
+6582     }
+6583 
+6584     /**
+6585      * Load given image url
+6586      * @param {String} url
+6587      * @param {function} callback
+6588      * @param {boolean} sendCallbackWhenAlreadyLoaded  optional
+6589      */
+6590     function load (url, callback, sendCallbackWhenAlreadyLoaded) {
+6591         if (sendCallbackWhenAlreadyLoaded == undefined) {
+6592             sendCallbackWhenAlreadyLoaded = true;
+6593         }
+6594 
+6595         if (isLoaded(url)) {
+6596             if (sendCallbackWhenAlreadyLoaded) {
+6597                 callback(url);
+6598             }
+6599             return;
+6600         }
+6601 
+6602         if (isLoading(url) && !sendCallbackWhenAlreadyLoaded) {
+6603             return;
+6604         }
+6605 
+6606         var c = callbacks[url];
+6607         if (!c) {
+6608             var image = new Image();
+6609             image.src = url;
+6610 
+6611             c = [];
+6612             callbacks[url] = c;
+6613 
+6614             image.onload = function (event) {
+6615                 urls[url] = true;
+6616                 delete callbacks[url];
+6617 
+6618                 for (var i = 0; i < c.length; i++) {
+6619                     c[i](url);
+6620                 }
+6621             }
+6622         }
+6623 
+6624         if (c.indexOf(callback) == -1) {
+6625             c.push(callback);
+6626         }
+6627     }
+6628 
+6629     /**
+6630      * Load a set of images, and send a callback as soon as all images are
+6631      * loaded
+6632      * @param {String[]} urls
+6633      * @param {function } callback
+6634      * @param {boolean} sendCallbackWhenAlreadyLoaded
+6635      */
+6636     function loadAll (urls, callback, sendCallbackWhenAlreadyLoaded) {
+6637         // list all urls which are not yet loaded
+6638         var urlsLeft = [];
+6639         urls.forEach(function (url) {
+6640             if (!isLoaded(url)) {
+6641                 urlsLeft.push(url);
+6642             }
+6643         });
+6644 
+6645         if (urlsLeft.length) {
+6646             // there are unloaded images
+6647             var countLeft = urlsLeft.length;
+6648             urlsLeft.forEach(function (url) {
+6649                 load(url, function () {
+6650                     countLeft--;
+6651                     if (countLeft == 0) {
+6652                         // done!
+6653                         callback();
+6654                     }
+6655                 }, sendCallbackWhenAlreadyLoaded);
+6656             });
+6657         }
+6658         else {
+6659             // we are already done!
+6660             if (sendCallbackWhenAlreadyLoaded) {
+6661                 callback();
+6662             }
+6663         }
+6664     }
+6665 
+6666     /**
+6667      * Recursively retrieve all image urls from the images located inside a given
+6668      * HTML element
+6669      * @param {Node} elem
+6670      * @param {String[]} urls   Urls will be added here (no duplicates)
+6671      */
+6672     function filterImageUrls (elem, urls) {
+6673         var child = elem.firstChild;
+6674         while (child) {
+6675             if (child.tagName == 'IMG') {
+6676                 var url = child.src;
+6677                 if (urls.indexOf(url) == -1) {
+6678                     urls.push(url);
+6679                 }
+6680             }
+6681 
+6682             filterImageUrls(child, urls);
+6683 
+6684             child = child.nextSibling;
+6685         }
+6686     }
+6687 
+6688     return {
+6689         'isLoaded': isLoaded,
+6690         'isLoading': isLoading,
+6691         'load': load,
+6692         'loadAll': loadAll,
+6693         'filterImageUrls': filterImageUrls
+6694     };
+6695 })();
+6696 
+6697 
+6698 /** ------------------------------------------------------------------------ **/
+6699 
+6700 
+6701 /**
+6702  * Add and event listener. Works for all browsers
+6703  * @param {Element} element    An html element
+6704  * @param {string}      action     The action, for example "click",
+6705  *                                 without the prefix "on"
+6706  * @param {function}    listener   The callback function to be executed
+6707  * @param {boolean}     useCapture
+6708  */
+6709 links.Timeline.addEventListener = function (element, action, listener, useCapture) {
+6710     if (element.addEventListener) {
+6711         if (useCapture === undefined)
+6712             useCapture = false;
+6713 
+6714         if (action === "mousewheel" && navigator.userAgent.indexOf("Firefox") >= 0) {
+6715             action = "DOMMouseScroll";  // For Firefox
+6716         }
+6717 
+6718         element.addEventListener(action, listener, useCapture);
+6719     } else {
+6720         element.attachEvent("on" + action, listener);  // IE browsers
+6721     }
+6722 };
+6723 
+6724 /**
+6725  * Remove an event listener from an element
+6726  * @param {Element}  element   An html dom element
+6727  * @param {string}       action    The name of the event, for example "mousedown"
+6728  * @param {function}     listener  The listener function
+6729  * @param {boolean}      useCapture
+6730  */
+6731 links.Timeline.removeEventListener = function(element, action, listener, useCapture) {
+6732     if (element.removeEventListener) {
+6733         // non-IE browsers
+6734         if (useCapture === undefined)
+6735             useCapture = false;
+6736 
+6737         if (action === "mousewheel" && navigator.userAgent.indexOf("Firefox") >= 0) {
+6738             action = "DOMMouseScroll";  // For Firefox
+6739         }
+6740 
+6741         element.removeEventListener(action, listener, useCapture);
+6742     } else {
+6743         // IE browsers
+6744         element.detachEvent("on" + action, listener);
+6745     }
+6746 };
+6747 
+6748 
+6749 /**
+6750  * Get HTML element which is the target of the event
+6751  * @param {Event} event
+6752  * @return {Element} target element
+6753  */
+6754 links.Timeline.getTarget = function (event) {
+6755     // code from http://www.quirksmode.org/js/events_properties.html
+6756     if (!event) {
+6757         event = window.event;
+6758     }
+6759 
+6760     var target;
+6761 
+6762     if (event.target) {
+6763         target = event.target;
+6764     }
+6765     else if (event.srcElement) {
+6766         target = event.srcElement;
+6767     }
+6768 
+6769     if (target.nodeType != undefined && target.nodeType == 3) {
+6770         // defeat Safari bug
+6771         target = target.parentNode;
+6772     }
+6773 
+6774     return target;
+6775 };
+6776 
+6777 /**
+6778  * Stop event propagation
+6779  */
+6780 links.Timeline.stopPropagation = function (event) {
+6781     if (!event)
+6782         event = window.event;
+6783 
+6784     if (event.stopPropagation) {
+6785         event.stopPropagation();  // non-IE browsers
+6786     }
+6787     else {
+6788         event.cancelBubble = true;  // IE browsers
+6789     }
+6790 };
+6791 
+6792 
+6793 /**
+6794  * Cancels the event if it is cancelable, without stopping further propagation of the event.
+6795  */
+6796 links.Timeline.preventDefault = function (event) {
+6797     if (!event)
+6798         event = window.event;
+6799 
+6800     if (event.preventDefault) {
+6801         event.preventDefault();  // non-IE browsers
+6802     }
+6803     else {
+6804         event.returnValue = false;  // IE browsers
+6805     }
+6806 };
+6807 
+6808 
+6809 /**
+6810  * Retrieve the absolute left value of a DOM element
+6811  * @param {Element} elem        A dom element, for example a div
+6812  * @return {number} left        The absolute left position of this element
+6813  *                              in the browser page.
+6814  */
+6815 links.Timeline.getAbsoluteLeft = function(elem) {
+6816     var doc = document.documentElement;
+6817     var body = document.body;
+6818 
+6819     var left = elem.offsetLeft;
+6820     var e = elem.offsetParent;
+6821     while (e != null && e != body && e != doc) {
+6822         left += e.offsetLeft;
+6823         left -= e.scrollLeft;
+6824         e = e.offsetParent;
+6825     }
+6826     return left;
+6827 };
+6828 
+6829 /**
+6830  * Retrieve the absolute top value of a DOM element
+6831  * @param {Element} elem        A dom element, for example a div
+6832  * @return {number} top        The absolute top position of this element
+6833  *                              in the browser page.
+6834  */
+6835 links.Timeline.getAbsoluteTop = function(elem) {
+6836     var doc = document.documentElement;
+6837     var body = document.body;
+6838 
+6839     var top = elem.offsetTop;
+6840     var e = elem.offsetParent;
+6841     while (e != null && e != body && e != doc) {
+6842         top += e.offsetTop;
+6843         top -= e.scrollTop;
+6844         e = e.offsetParent;
+6845     }
+6846     return top;
+6847 };
+6848 
+6849 /**
+6850  * Get the absolute, vertical mouse position from an event.
+6851  * @param {Event} event
+6852  * @return {Number} pageY
+6853  */
+6854 links.Timeline.getPageY = function (event) {
+6855     if (('targetTouches' in event) && event.targetTouches.length) {
+6856         event = event.targetTouches[0];
+6857     }
+6858 
+6859     if ('pageY' in event) {
+6860         return event.pageY;
+6861     }
+6862 
+6863     // calculate pageY from clientY
+6864     var clientY = event.clientY;
+6865     var doc = document.documentElement;
+6866     var body = document.body;
+6867     return clientY +
+6868         ( doc && doc.scrollTop || body && body.scrollTop || 0 ) -
+6869         ( doc && doc.clientTop || body && body.clientTop || 0 );
+6870 };
+6871 
+6872 /**
+6873  * Get the absolute, horizontal mouse position from an event.
+6874  * @param {Event} event
+6875  * @return {Number} pageX
+6876  */
+6877 links.Timeline.getPageX = function (event) {
+6878     if (('targetTouches' in event) && event.targetTouches.length) {
+6879         event = event.targetTouches[0];
+6880     }
+6881 
+6882     if ('pageX' in event) {
+6883         return event.pageX;
+6884     }
+6885 
+6886     // calculate pageX from clientX
+6887     var clientX = event.clientX;
+6888     var doc = document.documentElement;
+6889     var body = document.body;
+6890     return clientX +
+6891         ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) -
+6892         ( doc && doc.clientLeft || body && body.clientLeft || 0 );
+6893 };
+6894 
+6895 /**
+6896  * Adds one or more className's to the given elements style
+6897  * @param {Element} elem
+6898  * @param {String} className
+6899  */
+6900 links.Timeline.addClassName = function(elem, className) {
+6901     var classes = elem.className.split(' ');
+6902     var classesToAdd = className.split(' ');
+6903 
+6904     var added = false;
+6905     for (var i=0; i<classesToAdd.length; i++) {
+6906         if (classes.indexOf(classesToAdd[i]) == -1) {
+6907             classes.push(classesToAdd[i]); // add the class to the array
+6908             added = true;
+6909         }
+6910     }
+6911 
+6912     if (added) {
+6913         elem.className = classes.join(' ');
+6914     }
+6915 };
+6916 
+6917 /**
+6918  * Removes one or more className's from the given elements style
+6919  * @param {Element} elem
+6920  * @param {String} className
+6921  */
+6922 links.Timeline.removeClassName = function(elem, className) {
+6923     var classes = elem.className.split(' ');
+6924     var classesToRemove = className.split(' ');
+6925 
+6926     var removed = false;
+6927     for (var i=0; i<classesToRemove.length; i++) {
+6928         var index = classes.indexOf(classesToRemove[i]);
+6929         if (index != -1) {
+6930             classes.splice(index, 1); // remove the class from the array
+6931             removed = true;
+6932         }
+6933     }
+6934 
+6935     if (removed) {
+6936         elem.className = classes.join(' ');
+6937     }
+6938 };
+6939 
+6940 /**
+6941  * Check if given object is a Javascript Array
+6942  * @param {*} obj
+6943  * @return {Boolean} isArray    true if the given object is an array
+6944  */
+6945 // See http://stackoverflow.com/questions/2943805/javascript-instanceof-typeof-in-gwt-jsni
+6946 links.Timeline.isArray = function (obj) {
+6947     if (obj instanceof Array) {
+6948         return true;
+6949     }
+6950     return (Object.prototype.toString.call(obj) === '[object Array]');
+6951 };
+6952 
+6953 /**
+6954  * Shallow clone an object
+6955  * @param {Object} object
+6956  * @return {Object} clone
+6957  */
+6958 links.Timeline.clone = function (object) {
+6959     var clone = {};
+6960     for (var prop in object) {
+6961         if (object.hasOwnProperty(prop)) {
+6962             clone[prop] = object[prop];
+6963         }
+6964     }
+6965     return clone;
+6966 };
+6967 
+6968 /**
+6969  * parse a JSON date
+6970  * @param {Date | String | Number} date    Date object to be parsed. Can be:
+6971  *                                         - a Date object like new Date(),
+6972  *                                         - a long like 1356970529389,
+6973  *                                         an ISO String like "2012-12-31T16:16:07.213Z",
+6974  *                                         or a .Net Date string like
+6975  *                                         "\/Date(1356970529389)\/"
+6976  * @return {Date} parsedDate
+6977  */
+6978 links.Timeline.parseJSONDate = function (date) {
+6979     if (date == undefined) {
+6980         return undefined;
+6981     }
+6982 
+6983     //test for date
+6984     if (date instanceof Date) {
+6985         return date;
+6986     }
+6987 
+6988     // test for MS format.
+6989     // FIXME: will fail on a Number
+6990     var m = date.match(/\/Date\((-?\d+)([-\+]?\d{2})?(\d{2})?\)\//i);
+6991     if (m) {
+6992         var offset = m[2]
+6993             ? (3600000 * m[2]) // hrs offset
+6994             + (60000 * m[3] * (m[2] / Math.abs(m[2]))) // mins offset
+6995             : 0;
+6996 
+6997         return new Date(
+6998             (1 * m[1]) // ticks
+6999                 + offset
+7000         );
+7001     }
+7002 
+7003     // failing that, try to parse whatever we've got.
+7004     return Date.parse(date);
+7005 };
+7006 
\ No newline at end of file diff --git a/static/lib/timeline/doc/prettify/lang-apollo.js b/static/lib/timeline/doc/prettify/lang-apollo.js new file mode 100644 index 00000000..bfc0014c --- /dev/null +++ b/static/lib/timeline/doc/prettify/lang-apollo.js @@ -0,0 +1,2 @@ +PR.registerLangHandler(PR.createSimpleLexer([["com",/^#[^\r\n]*/,null,"#"],["pln",/^[\t\n\r \xA0]+/,null,"\t\n\r \u00a0"],["str",/^\"(?:[^\"\\]|\\[\s\S])*(?:\"|$)/,null,'"']],[["kwd",/^(?:ADS|AD|AUG|BZF|BZMF|CAE|CAF|CA|CCS|COM|CS|DAS|DCA|DCOM|DCS|DDOUBL|DIM|DOUBLE|DTCB|DTCF|DV|DXCH|EDRUPT|EXTEND|INCR|INDEX|NDX|INHINT|LXCH|MASK|MSK|MP|MSU|NOOP|OVSK|QXCH|RAND|READ|RELINT|RESUME|RETURN|ROR|RXOR|SQUARE|SU|TCR|TCAA|OVSK|TCF|TC|TS|WAND|WOR|WRITE|XCH|XLQ|XXALQ|ZL|ZQ|ADD|ADZ|SUB|SUZ|MPY|MPR|MPZ|DVP|COM|ABS|CLA|CLZ|LDQ|STO|STQ|ALS|LLS|LRS|TRA|TSQ|TMI|TOV|AXT|TIX|DLY|INP|OUT)\s/, +null],["typ",/^(?:-?GENADR|=MINUS|2BCADR|VN|BOF|MM|-?2CADR|-?[1-6]DNADR|ADRES|BBCON|[SE]?BANK\=?|BLOCK|BNKSUM|E?CADR|COUNT\*?|2?DEC\*?|-?DNCHAN|-?DNPTR|EQUALS|ERASE|MEMORY|2?OCT|REMADR|SETLOC|SUBRO|ORG|BSS|BES|SYN|EQU|DEFINE|END)\s/,null],["lit",/^\'(?:-*(?:\w|\\[\x21-\x7e])(?:[\w-]*|\\[\x21-\x7e])[=!?]?)?/],["pln",/^-*(?:[!-z_]|\\[\x21-\x7e])(?:[\w-]*|\\[\x21-\x7e])[=!?]?/i],["pun",/^[^\w\t\n\r \xA0()\"\\\';]+/]]),["apollo","agc","aea"]) \ No newline at end of file diff --git a/static/lib/timeline/doc/prettify/lang-css.js b/static/lib/timeline/doc/prettify/lang-css.js new file mode 100644 index 00000000..61157f38 --- /dev/null +++ b/static/lib/timeline/doc/prettify/lang-css.js @@ -0,0 +1,2 @@ +PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[ \t\r\n\f]+/,null," \t\r\n\u000c"]],[["str",/^\"(?:[^\n\r\f\\\"]|\\(?:\r\n?|\n|\f)|\\[\s\S])*\"/,null],["str",/^\'(?:[^\n\r\f\\\']|\\(?:\r\n?|\n|\f)|\\[\s\S])*\'/,null],["lang-css-str",/^url\(([^\)\"\']*)\)/i],["kwd",/^(?:url|rgb|\!important|@import|@page|@media|@charset|inherit)(?=[^\-\w]|$)/i,null],["lang-css-kw",/^(-?(?:[_a-z]|(?:\\[0-9a-f]+ ?))(?:[_a-z0-9\-]|\\(?:\\[0-9a-f]+ ?))*)\s*:/i],["com",/^\/\*[^*]*\*+(?:[^\/*][^*]*\*+)*\//], +["com",/^(?: +

+ Icons by DryIcons + and TpdkDesign.net +

+ + + diff --git a/static/lib/timeline/examples/example02_interactive.html b/static/lib/timeline/examples/example02_interactive.html new file mode 100644 index 00000000..4f4557fa --- /dev/null +++ b/static/lib/timeline/examples/example02_interactive.html @@ -0,0 +1,205 @@ + + + + Timeline demo + + + + + + + + + + + + +

This page demonstrates the timeline visualization.

+
    +
  • Click and drag on the time axis to move the timeline, scroll to zoom the timeline
  • +
  • Click and drag an item to change its date, double-click to change its text
  • +
  • Click or drag on an empty spot in the timeline to create a new item
  • +
+

+ Starttime: + Endtime: + + +

+ +
+ + +

+ Icons by DryIcons + and TpdkDesign.net +

+ +
+
+ + diff --git a/static/lib/timeline/examples/example03_performance.html b/static/lib/timeline/examples/example03_performance.html new file mode 100644 index 00000000..9c348572 --- /dev/null +++ b/static/lib/timeline/examples/example03_performance.html @@ -0,0 +1,125 @@ + + + Timeline demo + + + + + + + + + + + +

+ You can test the performance of the timeline visualization here. + Note that stacking events is relatively heavy. +

+ +
+ number of events: + +
+ +
+
+ +
+ + diff --git a/static/lib/timeline/examples/example04_format_dot.html b/static/lib/timeline/examples/example04_format_dot.html new file mode 100755 index 00000000..68c229e3 --- /dev/null +++ b/static/lib/timeline/examples/example04_format_dot.html @@ -0,0 +1,80 @@ + + + Timeline demo + + + + + + + + + + + +

World War II timeline

+

Source: http://www.onwar.com/chrono/index.htm

+
+ + + diff --git a/static/lib/timeline/examples/example05_format_custom_html.html b/static/lib/timeline/examples/example05_format_custom_html.html new file mode 100755 index 00000000..97513a99 --- /dev/null +++ b/static/lib/timeline/examples/example05_format_custom_html.html @@ -0,0 +1,174 @@ + + + Timeline demo + + + + + + + + + + +

This page demonstrates the timeline visualization.

+

Click and drag to move the timeline, scroll to zoom the timeline.

+

+ Starttime: + Endtime: + +

+ +
+ + +

+ Icons by DryIcons + and TpdkDesign.net +

+ +
+ + diff --git a/static/lib/timeline/examples/example06_format_custom_css.html b/static/lib/timeline/examples/example06_format_custom_css.html new file mode 100644 index 00000000..bfb213e6 --- /dev/null +++ b/static/lib/timeline/examples/example06_format_custom_css.html @@ -0,0 +1,138 @@ + + + Timeline demo + + + + + + + + + + + +

This page demonstrates the timeline visualization with custom css.

+ +
+ + +

+ Icons by DryIcons + and TpdkDesign.net +

+ + + diff --git a/static/lib/timeline/examples/example07_confirm_changes.html b/static/lib/timeline/examples/example07_confirm_changes.html new file mode 100644 index 00000000..7111f8ee --- /dev/null +++ b/static/lib/timeline/examples/example07_confirm_changes.html @@ -0,0 +1,166 @@ + + + Timeline demo + + + + + + + + + + + +

This page demonstrates the timeline visualization.

+

Click and drag to move the timeline, scroll to zoom the timeline. + Click and drag events to change there date. + You will be asked for confirmation before changes are actually applied.

+
+ + +

+ Icons by DryIcons + and TpdkDesign.net +

+ +
+ + diff --git a/static/lib/timeline/examples/example08_calendar.html b/static/lib/timeline/examples/example08_calendar.html new file mode 100644 index 00000000..3785d301 --- /dev/null +++ b/static/lib/timeline/examples/example08_calendar.html @@ -0,0 +1,99 @@ + + + + + Timeline demo + + + + + + + + + + + + + + + +

Google upcoming events

+
+ + diff --git a/static/lib/timeline/examples/example09_editable.html b/static/lib/timeline/examples/example09_editable.html new file mode 100644 index 00000000..7a2d0d7e --- /dev/null +++ b/static/lib/timeline/examples/example09_editable.html @@ -0,0 +1,196 @@ + + + Timeline demo + + + + + + + + + + + +

This page demonstrates the timeline visualization.

+

Click and drag to move the timeline, scroll to zoom the timeline. Click and drag events to change there date.

+ +

+ + + + +

+ +
+ + +

+ Icons by DryIcons + and TpdkDesign.net +

+ +
+ + diff --git a/static/lib/timeline/examples/example10_link_two_timelines.html b/static/lib/timeline/examples/example10_link_two_timelines.html new file mode 100644 index 00000000..123f5a5c --- /dev/null +++ b/static/lib/timeline/examples/example10_link_two_timelines.html @@ -0,0 +1,120 @@ + + + Timeline demo + + + + + + + + + + + +

When moving one timeline, the other moves along.

+
+
+
+ + +

+ Icons by DryIcons + and TpdkDesign.net +

+ + + diff --git a/static/lib/timeline/examples/example11_datasource.html b/static/lib/timeline/examples/example11_datasource.html new file mode 100644 index 00000000..98a13273 --- /dev/null +++ b/static/lib/timeline/examples/example11_datasource.html @@ -0,0 +1,106 @@ + + + Timeline demo + + + + + + + + + + + +

Enter a datasource and click the button "Go".

+

+ Datasource: + +

+

+ Examples: +

+

+ Open data.php (Works only if you run the example on a PHP server)
+ Open a Google spreadsheet + (or view this sheet)
+

+
+ + + diff --git a/static/lib/timeline/examples/example12_millisecondscale.html b/static/lib/timeline/examples/example12_millisecondscale.html new file mode 100644 index 00000000..cfeae2c4 --- /dev/null +++ b/static/lib/timeline/examples/example12_millisecondscale.html @@ -0,0 +1,72 @@ + + + Timeline demo + + + + + + + + + + + +
+ + +

+ Icons by DryIcons + and TpdkDesign.net +

+ + + diff --git a/static/lib/timeline/examples/example13_grouping.html b/static/lib/timeline/examples/example13_grouping.html new file mode 100755 index 00000000..d00d96c5 --- /dev/null +++ b/static/lib/timeline/examples/example13_grouping.html @@ -0,0 +1,144 @@ + + + Timeline demo + + + + + + + + + + + + + +

Grouping example

+ +
+ + +

+ Icons by DryIcons + and TpdkDesign.net +

+ + + diff --git a/static/lib/timeline/examples/example14_past_and_future.html b/static/lib/timeline/examples/example14_past_and_future.html new file mode 100644 index 00000000..c7592eb0 --- /dev/null +++ b/static/lib/timeline/examples/example14_past_and_future.html @@ -0,0 +1,91 @@ + + + Timeline demo + + + + + + + + + + + +

+ When the custom time bar is shown, the user can drag this bar to a specific + time. The Timeline sends an event that the custom time is changed, after + which the contents of the timeline can be changed according to the specified + time in past or future. +

+ +
 
+

+ +
+ + + diff --git a/static/lib/timeline/examples/example15_mobile.html b/static/lib/timeline/examples/example15_mobile.html new file mode 100644 index 00000000..1f8a0cf7 --- /dev/null +++ b/static/lib/timeline/examples/example15_mobile.html @@ -0,0 +1,201 @@ + + +Timeline mobile demo + + + + + + + + + + + + + + + +
+ ++ + + + diff --git a/static/lib/timeline/examples/example16_performance_grouping.html b/static/lib/timeline/examples/example16_performance_grouping.html new file mode 100644 index 00000000..05a5ff4a --- /dev/null +++ b/static/lib/timeline/examples/example16_performance_grouping.html @@ -0,0 +1,159 @@ + + + Timeline demo + + + + + + + + + + + + +

Timeline grouping performance

+ +

+ Choose a number of items: + 20, + 100, + 1000, + 10000 +

+

+ Current number of items: 100 +

+ +
+ +
+ + + + + diff --git a/static/lib/timeline/examples/example17_json_data.html b/static/lib/timeline/examples/example17_json_data.html new file mode 100644 index 00000000..a48ecf62 --- /dev/null +++ b/static/lib/timeline/examples/example17_json_data.html @@ -0,0 +1,103 @@ + + + Timeline JSON data + + + + + + + + + + +

Timeline JSON data

+

+ This demo shows how to feed the Timeline with JSON data. + No Google DataTable is used, and therefore the Google JSAPI is + not needed by the Timeline, which can thus be used offline. +

+ +
+ + +

+ Icons by DryIcons + and TpdkDesign.net +

+ +
+ + + diff --git a/static/lib/timeline/examples/example18_limit_range.html b/static/lib/timeline/examples/example18_limit_range.html new file mode 100644 index 00000000..bfc12142 --- /dev/null +++ b/static/lib/timeline/examples/example18_limit_range.html @@ -0,0 +1,49 @@ + + + Timeline demo + + + + + + + + +

+ The visible range is limited in this demo: +

+
    +
  • minimum visible date is limited to 2012-01-01 using option min
  • +
  • maximum visible date is limited to 2013-01-01 (excluded) using option max
  • +
  • visible interval is limited to a minimum of 24 hours using option zoomMin
  • +
  • visible interval is limited to a maximum of about 3 months using option zoomMax
  • +
+ +
+ + diff --git a/static/lib/timeline/examples/example19_bar_graph.html b/static/lib/timeline/examples/example19_bar_graph.html new file mode 100644 index 00000000..5099379c --- /dev/null +++ b/static/lib/timeline/examples/example19_bar_graph.html @@ -0,0 +1,145 @@ + + + Timeline demo + + + + + + + + + + +

Timeline - Bar Graph Example

+
+ + + diff --git a/static/lib/timeline/examples/example20_custom_class_names.html b/static/lib/timeline/examples/example20_custom_class_names.html new file mode 100755 index 00000000..2132795d --- /dev/null +++ b/static/lib/timeline/examples/example20_custom_class_names.html @@ -0,0 +1,127 @@ + + + Timeline demo + + + + + + + + + +

This page demonstrates the timeline visualization with custom css classes + for individual items.

+ +
+ + + diff --git a/static/lib/timeline/examples/example21_animate_visible_range.html b/static/lib/timeline/examples/example21_animate_visible_range.html new file mode 100644 index 00000000..aaedb45e --- /dev/null +++ b/static/lib/timeline/examples/example21_animate_visible_range.html @@ -0,0 +1,117 @@ + + + Timeline animate visible range + + + + + + + + + + +

Timeline - animate visible range

+

+ This demo shows how to to animate the timeline visible range to another date +

+ +
+ + +
+
+ +
+ + + diff --git a/static/lib/timeline/examples/example22_clustering.html b/static/lib/timeline/examples/example22_clustering.html new file mode 100644 index 00000000..fc195dc4 --- /dev/null +++ b/static/lib/timeline/examples/example22_clustering.html @@ -0,0 +1,106 @@ + + + Timeline clustering demo + + + + + + + + + + +

Timeline - clustering demo

+

+ When too much items are being displayed, Timeline will smartly cluster + the items together. This both: +

+ +
    +
  • keeps the amount of displayed information limited for the user,
  • +
  • and prevents the browser from getting overloaded
  • +
+ +
+ + + diff --git a/static/lib/timeline/examples/example24_individual_editable_events.html b/static/lib/timeline/examples/example24_individual_editable_events.html new file mode 100644 index 00000000..7a87cb2e --- /dev/null +++ b/static/lib/timeline/examples/example24_individual_editable_events.html @@ -0,0 +1,100 @@ + + + Timeline + + + + + + + + +

Timeline - editable/read-only events

+

+ In the demo below, events are made editable or read-only on an individual + basis. + To check whether an item is editable, the Timeline first checks + if the item has the field 'editable' defined, and if not, uses the global + options.editable. +

+ +
+ + + + + diff --git a/static/lib/timeline/examples/example25_new_item_type.html b/static/lib/timeline/examples/example25_new_item_type.html new file mode 100644 index 00000000..2a884ee4 --- /dev/null +++ b/static/lib/timeline/examples/example25_new_item_type.html @@ -0,0 +1,182 @@ + + + Timeline demo + + + + + + + + + + + + + +
+ + +

+ Icons by DryIcons + and TpdkDesign.net +

+ + + diff --git a/static/lib/timeline/examples/example26_localization.html b/static/lib/timeline/examples/example26_localization.html new file mode 100644 index 00000000..423e71b4 --- /dev/null +++ b/static/lib/timeline/examples/example26_localization.html @@ -0,0 +1,93 @@ + + + + Timeline localization demo + + + + + + + + + + + + + + +

This page demonstrates the timeline localization (i18n text).

+ +

German Timeline

+
+ +

Spanish Timeline

+
+ +

Russian Timeline

+
+ + +

+ Icons by DryIcons + and TpdkDesign.net +

+ + diff --git a/static/lib/timeline/examples/example27_jquery_themeroller.html b/static/lib/timeline/examples/example27_jquery_themeroller.html new file mode 100644 index 00000000..d5cb6d09 --- /dev/null +++ b/static/lib/timeline/examples/example27_jquery_themeroller.html @@ -0,0 +1,110 @@ + + + + Timeline jQuery Themeroller demo + + + + + + + + + + + + + + + +

This page demonstrates the timeline intergation with jQuery Themeroller CSS framework.

+ +

+ +

+

+ +
+ + +

+ Icons by DryIcons + and TpdkDesign.net +

+ + diff --git a/static/lib/timeline/examples/example28_custom_controls.html b/static/lib/timeline/examples/example28_custom_controls.html new file mode 100644 index 00000000..62410d78 --- /dev/null +++ b/static/lib/timeline/examples/example28_custom_controls.html @@ -0,0 +1,120 @@ + + + Timeline demo + + + + + + + + + + + +

This page demonstrates the timeline zoom and move functions

+ +
+

Zoom controls

+ + + +
+
+

Move controls

+ + + +
+ +
+ + +

+ Icons by DryIcons + and TpdkDesign.net +

+ + + diff --git a/static/lib/timeline/examples/example29_stacking_with_grouping.html b/static/lib/timeline/examples/example29_stacking_with_grouping.html new file mode 100755 index 00000000..dcf8140d --- /dev/null +++ b/static/lib/timeline/examples/example29_stacking_with_grouping.html @@ -0,0 +1,142 @@ + + + Timeline demo + + + + + + + + + + + + + +

Stacking with grouping example

+ +
+ + +

+ Icons by DryIcons + and TpdkDesign.net +

+ + + diff --git a/static/lib/timeline/examples/example30_floatingRange.html b/static/lib/timeline/examples/example30_floatingRange.html new file mode 100644 index 00000000..bc34e09d --- /dev/null +++ b/static/lib/timeline/examples/example30_floatingRange.html @@ -0,0 +1,73 @@ + + + Timeline demo + + + + + + + + + + + +

Timeline floatingRange demo

+

+ This demo shows how to use floatingRange items. + The start and end dates are optional in this type of range. +

+ +
+ + +

+ Icons by DryIcons + and TpdkDesign.net +

+ + + diff --git a/static/lib/timeline/examples/img/Hardware-Mobile-Phone-icon.png b/static/lib/timeline/examples/img/Hardware-Mobile-Phone-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..66a6d35fc329c86b12d57185fb82879b471c5546 GIT binary patch literal 3463 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 literal 0 HcmV?d00001 diff --git a/static/lib/timeline/examples/img/attachment-icon.png b/static/lib/timeline/examples/img/attachment-icon.png new file mode 100755 index 0000000000000000000000000000000000000000..fc82517762e5c83e8030e4947fd0b5ed62e73b4d GIT binary patch literal 2774 zcmV;{3Muu8P)968*hkWE>|ZCXOb?WKNdRQ4@^|Dk>^&C?X;v2n@0b0s_sd2*@HJJF@SqAPBM< zK>=}1j3%QK87D`RIGGt^7L}94I0xzO|L4~4uSZFP-OwEK&#CiX*MC*7ZoOBp>U|I~ z&-j^YY&KRYm#<}6g8nZ|$X)nooWc01V9Sr@-q?=)MiQ%d%{oytg;~N?X1B@o_U&TfQjO8&Qw7Fv8C+ zu~ z*)s*OXtN6$U=RA9RVocXtShb)Q z-S^#M>usyiw16I9znh({DQMS3C*-E0xdOV2xSo2Zy5RQk0kCzS&#_!HJXQe;Ia!(0 zBLMq7nvyTp+4}U&YmG|wi09a<{A;BcA=q?A<0f0^C zfoy)cm)dUMh9(zu8)N2Sh5n_fUdX^hVK=(Z4jUfNTX{8eYD;#!=#J2c5y5y~tjvhwqj< zcqOBefoL1dI8mO}qm6FJSD~>%5GQq%X9o6tuM+?(w|aY{Nn=#YJg2QR{ab-gXFUa= z6kfDxFHNu0Qtt#bpMhQiEri}*W#l0PSncGCt-)`R@gT2b#cA2ZU*+U0h4NZ-%|Wg3 z{<`BO`;}Vi_D7Qlx(2;d)QuT3025~!?P(tnZ6Tx9qSSi=-vkY1++NTU@ITc??;00B zeSoImodoiRe5TF;tabIDhUOgT57;6bS_+bz_{m-U^`ZC-y0gH~g(04;g(;jm9j0!9 zlQ8y&BYBBEeRO-G$pHNq^6$44rrgyz08HM5(!dPe_7C!tRzBiy3q(wC6cgRBdh*fy zq&w>5*SQCgm)oFYJc>8FBe@9|1icf$yU6e-7vlrn8U5KXXaHvJ!OPIJfqHNPEyv^^ z3r39`x5wp;HM0r!x2p(#&ttxL33{W7XqJTWZ-w<^jUNyFX1Ph0xid zfV3fgmNaGWb9(r0{q~(n;8XDZ17j96=fvOZM+X5UFaHU&2Rfnz`I(SEjqYfy!iJ`t z_{M>385DpGo*_<{ybxV%4bj}jtk|yw{tWQXqB{~~(U=u?q+cg^h9Ez1lpnr=_op{x z#rA*)d$<$eEdd>c{JN*vqBVexJ3_~zq3!Y}dG2t=-e}@m?AR@VA@%6eq(@nfwP?tU zmG`5Aj>JnK2>{#HXT;R1bc9;LplWn~!s;2-XU1I7IRHzaurM@{pl`50r_`lK|03|$ zq9Fic@ZSf&OP%~CpKv5K?qPm7jXz*wZ zz}i1j48{3mIKvlKjB!m$1b=pK_KVnoCS6#Sc{QmKH`VI!i+mp5r@TQmekvvps7{IC zHp?QW!4k?FV<2w}`GcC;r7-}TfT%e*6;9(^*F&jnaxf{pgXjB4O`y{RifDCY2b1@t z4WJ_!I^v+?HgrsZj&8v@jgViD?isvWTAjQ{qq~B}0PKTfr3lJac*ht&4}oke6GQpB z#x`hgCioucUIviGRf%Eu)#_m0 zczrtBOkBEr4#e-~G_grz08XKadMw9LpizLPm&OD=3ec^)6DSur!}!k9m|)}nbU214 z7;zj<9MycQpyQMvPbW=0=q4OwP#PP2OB>@g0^ky!?2F)~)cy^;Kc_f4@H^r=hb4{W zCsye&DT)p_sZQQ?Pl`Uvvh;2)MwVc(YhhFX3wipCNcrSNng;U4+8X~<0Pay~ufTYk zWFkE1mmeW}6rkH8QXO&0rb#d3odMpdO3lC?WD0A*n=`E(@MVFW^jGL9{=RByueJX&EjIzVzdF;{XSZ{~${)A!B%Myur zKMFYuXnKxkB5=^}LEKcp$l!fGTYuzrrk5FjPj>|@4r3nY?Qm?U#;XMoo?ST#4c(Nc zz=JEIJ#0@5q#!u01Q^6~ai=vEi$oJ)-7Og20QwY0@^KTET{#jH(Pu~c)?bIbV7=GN zUgLU4D*#dX)#KoytLTow%QwT_tp79ANuu(qUEmC=WV->(Ai~||D_t0`7C=l_v8@?FI z1o34J$vB4T?t25<>)lqwerZjFq$uqv30Bh z?AJFAR+q*A=t-|WiZfh9rEiJ1^%^HFb@ETvp=0_=mZj{CDwS(Sf1_;6x*;E%8UeuM zCRhdfb5J)<7K81UE5FoMaZX)ZFuYH-&yVo_A}_1eS9NWCzX0gTZ|K0?RkQ#D+9eW+ zsgv0fxu!}Bn>x23a4Bg$N8d%=ESBdChw%dfC~7)sAeM;f?8b2_!eK9w*_#;tJdm=g zrIhVFf@>?TJrN?ug$);j>065zl8Rv#S25Hq)$ literal 0 HcmV?d00001 diff --git a/static/lib/timeline/examples/img/blog-post-edit-icon.png b/static/lib/timeline/examples/img/blog-post-edit-icon.png new file mode 100755 index 0000000000000000000000000000000000000000..12ab23c64717a0b361a739661f5bdabf16df85a6 GIT binary patch literal 4225 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 X4%%syG(5Yu00000NkvXXu0mjfMVmS1 literal 0 HcmV?d00001 diff --git a/static/lib/timeline/examples/img/comments-icon.png b/static/lib/timeline/examples/img/comments-icon.png new file mode 100755 index 0000000000000000000000000000000000000000..736789edd6ffce59fd55e89948bd5ead588a8106 GIT binary patch literal 3173 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 LNkvXXu0mjfA!Y1$ literal 0 HcmV?d00001 diff --git a/static/lib/timeline/examples/img/community-users-icon.png b/static/lib/timeline/examples/img/community-users-icon.png new file mode 100755 index 0000000000000000000000000000000000000000..a77e239a3cb3df9cb8367d0beedbf1ab545fcaf0 GIT binary patch literal 4664 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 LNkvXXu0mjfwykOf literal 0 HcmV?d00001 diff --git a/static/lib/timeline/examples/img/product-icon.png b/static/lib/timeline/examples/img/product-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..fb12da43b3d7979fc6377f30398dbd12bcedded2 GIT binary patch literal 1594 zcmV-A2F3Y_P)3`Oy;0h7DOD~)MWi595e+d4w7XP@7D~Alfl#X$B8s5K5aT~F(O(*Y)F2@- zCQX%qs6e@xD0EAyn5IymQd)Ym+Z&~&H(Iys?#y`RTxMss3qLSXe|VacbLLFb_c`zP zeREDF{L4-HAK*U)Q1{aZ+wHDV?>ghBOp_#;yw$q|Iw!w6G}w!Q?l#D>4K~sxnXGFX zR8@hZsz^*qA&(mQUD7p`z9VnhNS*`zEsaXx_O3@?_#|%_K<$b5b~<7wd}wpUBRJ4b z#U)7>vC|Qx_uOnjYuy#t?GDoIkZm^l#}y@nP%wy;1zA)GnnFg>RW^c-Dx7f>KmZUJ zy!lb`(oc690M`rO8B2uPo$(L3LVtDw`tBqmEL#D(JDSmQ{Sp@^U6yox=0GTfIcclz z0T80kj**E7+-|$0siBFm;-Ec6Cp1X6+5>ZI~O3Gt&OO!EF;S@WSS!q zGyy!v`yEo^7NXU+s2Gm|YPpd$p)gc^U zVOY34mphPR=&o| zjze&Oa3XRD?!e5fFBm}ekv9y0u&@A;c^=4UYpO?8c?r#a_HBUSfZi8pZ)W0@N*9Y( z5hj2YdpW?5uSapfS^;_(S{rLoSypVsUwlObz>Dj*(5eWBf#t#79C&QyJ`V81W|D-$ zfrtc@!VWYyT*u|#in#q8K%)pyiSY7`Tlwxyd0-Y7a{;hwKLfb-{U)A-ChH^OuRGwY zuffIAGe{gi3EiC?R5&I!p27_F_hIF$+e{&d%mdZ*J)mozS*yQd09A)y3Fm;xb~cwG z&V{Dh8gzHv#MATBQE}djhU!XqmSrPu)EJyTdH_q;ZK6;bKL@NKP|X!U9hkM|YYuQI z$4!L1!@quE`*nccTU{8P@Blpn0z*T%cBve5pG~ECaHG|S@slQtvS1KUt%+!HLG{dD zo6i8Q9^Akk(5)5_R&n#`s0UyFVM!>l-Lk#&xoWsz{w!N7LiMD)^bG^}{lHo`5%os5 zpMQv`AU~eLAPfL1Yy~h}Fn^k@$>>R0e~Wk_s_gR5FD?h=#>O1IU*GUWN7Dj0rDtDZS87Ycw3HyJ2E%#?I=*yf?9 zr-xoVDlV2|*6bAc{eDbOo`L$hT8tZ)NX4&JT}Aeq73eSfSj50`B{Lk*T~Vz7WWh5h z_f!M`X)%vv;X=zOG&TJJhr@{zg-5Y4)s4QsUZg+21SMy^NP2iG6)QUZGxGNCM_=jt zMk0g(B0~@c;IPpFMoi5_dGl!ad^&&wCyy6m!NN2Ouqb^o&Xp900nYq_J$YZ^_OCl4 z$}l>BaEUhyKpGi}^|>=C0~ead5P&8MaO&i7%wLd-{=PoA7p0^0TnUnrlIUOX7M;Q8 zd-5=Neg_vv_(m+;7%nWDn*f}p0GIPKCXh)Bnc5`RI0VOMAf(9j+SPTd6Jy6F&@0!- z*f3#!4MvCV97t zbbU;eG-Zq({x~v^0V{ZYblj(AkaRy-Jp3WV3}}+Am(06JuO|IF9Y7Z$HxM{Y-Nn29 sE|#y|Pb2?mV2}gc;XNRFPEJnnFH4UWN> zrU6p1wW6qjsz{?D6*MGZ0?M{{sq4bR-fwf+o!PnU%$e&sGjn{;Fq?=j1&odV@Fj0% z<~x_?_rCA*ecv$nfd_LH;3~lP^`fVD?`10OwvHB0V`srIv~)J>OJ{PvoUZ$G`FwQq z-5ZPFJHYREzS!ur+1ANCdz+`euG48%>a129!*MJ)j)Nr0&~(knYWZ|K6Ubt*pvqZ^0|)*IgRY$~xeS2>6>5oSR)7G_ zFg+j$;-y>g$5#*B)8MYzHow-@Lat$W%2Y8kqB5ExnV*z-cshdav;BxAGZ^SS4Tf4I zlc1TkAW9`qm~G(7{Vx^^=DacJ^<5m`cROE_6`Om)D=e%@lCbDdV7KsaFhw-*27Xj6 zLyu1(98KWtWDf2M0g0Iq{G$WZYoXNh**2H}CWt`uR4xK@z?MJ%?VKzri-QFjzM_nAUBE~R z(8Wr+%Hqhac071=8VoPtm&~VVZEZm$rD1HKueA1AD);D20z>f>Qq;CKmlK?S7<_sL zr~dPA+<4O(V=x%5`s~<|nYm54{qKFW=G)A@JeSKrpf$hvnr1}e35-XwST^5@`%b2D zbDaY}Q@qgiJW_d}yZdttMq=onj>6@1qRFnnolhe^9VGMVxZ%b%c>nNwx&ATl{n4qw zdwMQwo(1`D0o=RkzCJ^0Y-?TMDJ?aR$Ah+}MX*^ESSZ8ZfngjzGmT|6EYj)Z`JGX+ zV%PrtCC9J-@p5!DHsIqA4N2OdH;rDBoWg{9I2y5jYyq=P0LnnKr!Xrs$!0ySs;XbuZB}D^eBz;0JoXVunFiF%g>eDE%3nRw zR_k{6wl>spHIh&|(I&h;h%PrcGGrjG;xX}G=&JcOqM;yO-L-?XvTE3XyuzJ<1O&iw!VJT(USIg7I*!1{~aE;g$K^{azTH`@@3cJn${)Q z_vXH#zSBMTmwTEl3nwVDvqt-0gPG$uK|rFADU@=^R7OQqtW^bFV_enlH$C<9?CtIC zIDGWz_ORdga#>g{gA^_$d@+D;UgIcu3gPQOJXOeQx38vuIN@k;@(t?mtZ?y?idO(I x*S+l5fXv_IW=1y;=_?ifE&%_RaTVYyz*l!zp+91aH)j9<002ovPDHLkV1m_RMTh_Z literal 0 HcmV?d00001 diff --git a/static/lib/timeline/examples/index.html b/static/lib/timeline/examples/index.html new file mode 100644 index 00000000..3f092a96 --- /dev/null +++ b/static/lib/timeline/examples/index.html @@ -0,0 +1,41 @@ + + + + + + + + diff --git a/static/lib/timeline/img/16/delete.png b/static/lib/timeline/img/16/delete.png new file mode 100644 index 0000000000000000000000000000000000000000..d54d0e06fc2047fb34cf420a6edaeefa52fde987 GIT binary patch literal 665 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Ea{HEjtmSN`?>!lvI6;x#X;^) z4C~IxyaaL-l0AZa85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP=YPV z+ueoXKL{?^yL>WGgtNdSvY3H^TNs2H8D`Cq011{AIHm(>utOMPj;%cmv@^uh#WBR< zbm`@TUebXgY!C92?nJxf7HQv47WvUWTvf7cP^tlX`(c^5al_?F77?z^hEw4tDn@4V^@0w-8rRM%jRv+ zj+riJ^ZmV$uG{m)H6f<+*?!2D#&7OCpL9h3()<-#K@Uv-J&^dvbhs@wc6x=<11Hv2m#DR)bL5fm(AhS~;3Rt5&&p1M9m(U6;;l9^VCTSNPfzfnL944$rjF6*2UngF*N B__6>1 literal 0 HcmV?d00001 diff --git a/static/lib/timeline/img/16/moveleft.png b/static/lib/timeline/img/16/moveleft.png new file mode 100644 index 0000000000000000000000000000000000000000..44c0d8216a9ba0ff824e817ed0a9fec5863a6c1c GIT binary patch literal 553 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!60wlNoGJgf6SkfJR9T^xl_H+M9WCijWi-X*q z7}lMWc?skwBzpw;GB8xBF)%c=FfjZA3N^f7U???UV0e|lz+g3lfkC`r&aOZkpafHr zx4R3&|Mvbf`++>p0*}aI1_o|n5N2eUHAey@SXSVe4y3`3V2C-k_Arq1!qdeuMB{wv zd0%Z8Mv1nEug_RsNtxv1BO#rd=((h(WJ7@1ri}qGGaMgrPiH*yW{EbgFEH0aK%c$-93U;x#t8RsO^sjv( z&*t?lRQGgw=(fco(_~jfnB4gsV7;pKnT*w@1dU`L?M-jbboH3ZD)!jhXli_)TK-Au znEkt}ceQ4TedW|oR1*BZEBJeY(@OU$KE;V0`|nzO&p5RtrvHO}?as1?XM2*gOb@-= z=c4qlKdAb7#dg^Sy~xd pY8x0?85sC3e6p0*}aI1_o|n5N2eUHAey@SXSVe4y3`3V2C-k_Arq1#?!?yMB{wv zMO$wtMv-G5=P!96cjZRZh11unZbwP|lB#WUIOH!V(K7XcfG*!fB~D2eA=e3xf;&_c zT~v|+tE89gx%PF<^ZI$k=RT_#MXx$nviXtr#Fev4-W=G;cT?iQHJP}%r?jhobNjML zFPmVNeRk8nv_X&3lHRE)x>CH4Ie2`_nJ zxKjRi?5RbpugxYOGGr^6@^-~h=J%_%&CU2+f3$tpoJrFgl^1ixuX`$!$@^A{$+o;q z)b_810IL)KCoZYQXBjVC4%qNK&R*~0l11Fps~$i4$9DKakpJHg5%xfTOP07slsM<- z=BDPAFgO>bCYGe8D3oWGWGJ|M`UZqI@`(c#se%-x0Hv&w!73Px3=9o*4NP?n%|Z+f utc)zJOiZ;6jI0a{4n6GKiJ~DlKP5A*61RrUd(1%b&EV literal 0 HcmV?d00001 diff --git a/static/lib/timeline/img/16/new.png b/static/lib/timeline/img/16/new.png new file mode 100644 index 0000000000000000000000000000000000000000..7eeba137b81d4ce1f5c58c9ce8ef77e1955c8c00 GIT binary patch literal 593 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Ea{HEjtmSN`?>!lvI6;x#X;^) z4C~IxyaaL-l0AZa85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP=YPV z+ueoXKL{?^yL>WGgtNdSvY3H^TNs2H8D`Cq011{AIHm(>utOMPj;%cmw3Elv#WBR< z^wNvAUe196tPk{`-SiZi{XyxSYxx5umfW{2%}=v+j@+8h8^NJ>aPJRc-7l(wyIs1^ zOwKmg)4|?W{ruj{!!s>;O;2!NILLVIW1I1mX1hpP#{}NpH;&lq1v*U=w+b}qPn@Is zl}*{gGbfh1Yt8d2h$pPQSSSHj?2l$uzQnxasiS(2gP z?&%v4-pD5oRHO=0lme8pN(QT7FfuSS)HN{GH8cw`G_*1?wlXl#HZTH`W|MSYqiD#@ gPsvQHMAu+sWoQo3u#n+kB~Sx{r>mdKI;Vst04uP|C;$Ke literal 0 HcmV?d00001 diff --git a/static/lib/timeline/img/16/zoomin.png b/static/lib/timeline/img/16/zoomin.png new file mode 100644 index 0000000000000000000000000000000000000000..b68dfadf770e06e59922ebd68ecbeebe07040662 GIT binary patch literal 441 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!60wlNoGJgf6SkfJR9T^xl_H+M9WCijWi-X*q z7}lMWc?skwBzpw;GB8xBF)%c=FfjZA3N^f7U???UV0e|lz+g3lfkC`r&aOZkpafHr zx4R3&|Mvbf`++>p0*}aI1_o|n5N2eUHAey@SXSVe4y3`3V2C-k_AroB;pyTSqH+H0 zg|nQ897I?ioX^SP(8*I?d8n_*!+oVv?;5U`iOthX18q9QPtK9+|C#Kkr8X(l$?R0| z-|~GA_*?3{zTR?WWVvV;nwg*bB!QvXHIwgBd$vIRONITeEF!nFkKFK@r>kTpetmhl z{d2R@@Y17q-+BbwGyL|FSXy+c!3gLE$r9Iy66gHf+|;}h2Ir#G#FEq$h4Rdj3nC} aQ!>*kackIP>(B($z~JfX=d#Wzp$PzM=!S9t literal 0 HcmV?d00001 diff --git a/static/lib/timeline/img/16/zoomout.png b/static/lib/timeline/img/16/zoomout.png new file mode 100644 index 0000000000000000000000000000000000000000..64e37275c8b6868ae69213ca52815ea61bbf67f5 GIT binary patch literal 361 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!60wlNoGJgf6SkfJR9T^xl_H+M9WCijWi-X*q z7}lMWc?skwBzpw;GB8xBF)%c=FfjZA3N^f7U???UV0e|lz+g3lfkC`r&aOZkpafHr zx4R3&|Mvbf`++>p0*}aI1_o|n5N2eUHAey@SXSVe4y3`3V2C-k_Arp6;pyTSqH#Vs zL4v7aqaWLTCb721Eg}L2jhz#uBP8Yt1SMDsBs!-uFtBZ5T6d6{vmdBOvcxr_#5q4V zH#M(>!MP|ku_QG`p**uBL&4qCHz2%`PaLR76{IKyC}oulR>5FoU}&goV5)0q7Gh{% uWn^w;WUOsqWMyDbIlXB+iiX_$l+3hB+!{DeS#bk3FnGH9xvX!lvI6;x#X;^) z4C~IxyaaL-l0AZa85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP=YPV z+ueoXKL{?^yL>WGgtNdSvY3H^TNs2H8D`A^SIZy6<#?hO1X7Bv}dH?e{zwOiKwQXqK^5#(Do}<&Zt&RNg z?jYlt1Js zwzcnQ^-ESuKn}%GTWaXEQMmuHw(r44Pp~S)U}=*dT6pP^z_t;@!V$u zj+R#!^odpUr$?+?>11rQJMNmP_UW${+1GyPvOoXbxN*uko4N-9zG}@D5-#hNZ_PGU zJ$rI_q5SGzou`R0M_9_PTdaFr`NluVoi~lM{3Anlu8CG@u9w#?m9H*W>yB7mQ2!+9 z={Pq?q*rF+h3W-`o{`Gi(&9I7Dk(lHYN^GyOYo@Al07qZQzw?MF49}|f?3-?|mK=v?kE81w4hT+=77ceGnisxklI_Uf7PKaqnIOfE}R zgeS=NeO1&yZPfgA+x^;2>#oO?KD{M5=Qmf)5gohhHn(*0R{vSOwK{dT>yHP$CXogGO1v1faLXN3pxJ3MvGqOd`q3^`%qJ6>anjf z`>yxC&b`s^AMxw>`Du4=bo1ZPsI6zbFmZ`-&XTuZfoV{(#5JPCIX^cyHLrxhxhOTU zBsE2$JhLQ2!QIn0AiR-J9H>YYq$mX_Wt9w8!C+)yXsByos%vN#VrXb(Y-(j>sBK_m lWnl2_sp~To4Y~O#nQ4`{HMH;e8wJ$B;OXk;vd$@?2>`WHi--UK literal 0 HcmV?d00001 diff --git a/static/lib/timeline/img/24/moveleft.png b/static/lib/timeline/img/24/moveleft.png new file mode 100644 index 0000000000000000000000000000000000000000..fce5907c624a14d8543f160cdd6d619735d34321 GIT binary patch literal 679 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM0wlfaz7_*1mUKs7M+SzC{oH>NS%G}U;vjb? zhIQv;UIIA^$sR$z3=CCj3=9n|3=F@3LJcn%7)lKo7+xhXFj&oCU=S~uvn$XBD8ZEE z?e4fM@Pm@@s8hxP1_uIaz5&i zcQ8KEdt=oiSEqNUo^9K)_{o{K=W3_F|84W!(&l}!pX*Am1!?C}mWoVC)b)P%Q)Vhd z|IF`Kn$*e`Gk$2BCYt*-&$yS%Z(a13C)+mGyUo=QkGZ(vMWy4Gi+P~Fqc-HQHj!z{gyjkJd?u5IItKHZI6gVDT2|rkU z_}K4nx4lnz7}nQ(JlE#ztGu(tzgF5e;fnA1>ZIvcU+-JX=J@CKx=`s?=T^>@$bWiF zq2p)j@#yNTS;rGSb4Begvgl=1KWvihT|;+&tGo0?a`;9QiNSdyBeP@Y+mq2TW68xY>eCk|Ak z3R08;l(I?&t6(rPFf`OPFx53Q3o$gXGP1NXwA3~*vNAC6UHEDxiiX_$l+3hB+!}2D S1c?GQFnGH9xvXNS%G}U;vjb? zhIQv;UIIA^$sR$z3=CCj3=9n|3=F@3LJcn%7)lKo7+xhXFj&oCU=S~uvn$XBD8ZEE z?e4YSi^wrb3_huxeeu)r=v%>4HouvWvHF(w6x|scA1&D0 zu$Jq0*cpwR`S-8&?ArApWtCRtI*IsqE0%VZ@=txE5`Vd8)`5+omj1Q9|BFKsuX0<) zTgm4MJbM%M`rE{Z`hFcH$Ayj-9RfyzWQl7;iF1B#Zfaf$gL6@8Vo7R>LV0FMhJw4N zZ$Nk>pEyvFDo9ZZP|7M9tb)PFz|c_Fz*N`JEX2^j%E;2n#8lhB$jZRr(8Io+C>nC} aQ!>*kackJT#|)I-7(8A5T-G@yGywpG0Sy=c literal 0 HcmV?d00001 diff --git a/static/lib/timeline/img/24/new.png b/static/lib/timeline/img/24/new.png new file mode 100644 index 0000000000000000000000000000000000000000..b5a0f077dc649f0a79a706966ee3882a3a2b62b0 GIT binary patch literal 667 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjEa{HEjtmSN`?>!lvI6;x#X;^) z4C~IxyaaL-l0AZa85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP=YPV z+ueoXKL{?^yL>WGgtNdSvY3H^TNs2H8D`A^SbW?IuswLc&UK-n%eHA1jQk2M)BKcgUJA}}-Z=Lbw*dbFQAMd%bB8O^SIxMZ zLf^!wJ$|=t_d0vao$3FopZ)oMX3oyZlES^)G}k0qEqZUI`@JxxHiq%cBbIK#a)C8M zj3=6SUG`p-v;OJL_YCX+NB-)=R66I zdGX(<=+1J-dchY-=^+8RCG(O>qT)|qJ5sqJZK~*#h+}CV^0ihg9Qw_$->7lnkMhPt zwi=c0Jo^hKee9|;pK|chhUqI0%z59pf@SA{{P)cpS@Jf<2JYKEkt#@03Q)=_8LWcA$iUE0 z*T7WQ&@9Bz(8|Qv%D_O|zz9g1P11Rdq9HdwB{QuOU4xO8p*cjuLWYBtKn)C@u6{1- HoD!MNS%G}U;vjb? zhIQv;UIIA^$sR$z3=CCj3=9n|3=F@3LJcn%7)lKo7+xhXFj&oCU=S~uvn$XBD8ZEE z?e4Eak-ar$ZC zY2F3}5$z+K7dEhJTS&3H7qf0VaGv9VYv&Z^he;ka>i4vBD_t8-Wm&w~{n4QNd|~IY zU#f{4Y&t8C|CnG@pH;Kd%SXVc;HYw_mG&AA)Al(wwey3j*L-Mg@iJme-?>HcP>1Q- zs-$Cq#U1)*8)T&g#dhU??icDQm&k5!;kK!k*fsTf;(MTjBuiW)N}Tg^b5rw57@Uhz z6H8K46v{J8G8EiBeFMT9`NV;WR6&YTfKpb;U=<8T28M>Z2Bx}(W+8?KRz_x4#)jGk mMpgy}XA^$dp=ij>PsvQH#I0eEtwR$~1B0ilpUXO@geCx#po*mc literal 0 HcmV?d00001 diff --git a/static/lib/timeline/img/24/zoomout.png b/static/lib/timeline/img/24/zoomout.png new file mode 100644 index 0000000000000000000000000000000000000000..73b7fcb233bbf723c832061b7875e9b55ecdee85 GIT binary patch literal 367 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM0wlfaz7_*1mUKs7M+SzC{oH>NS%G}U;vjb? zhIQv;UIIA^$sR$z3=CCj3=9n|3=F@3LJcn%7)lKo7+xhXFj&oCU=S~uvn$XBD8ZEE z?e4Eak-aXL9c zg4Kkfr&J{?AyGg%^l+-w?E@~WmS?VSY<(!YQmP~~=di{CP6h^p$;|Uad#qi7Iweb7 zBTAg}b8}PkN*J7rQWHy3QxwWGOEMJPJ$(bh8~Mb6ic~?0Qh-uc$zT->Mh1q4x(24Y zhGrp#23AJqRz}9!21Zr}29?vBwxejs%}>cptHiB=UftDnm{r-UW|wWD7D literal 0 HcmV?d00001 diff --git a/static/lib/timeline/img/32/delete.png b/static/lib/timeline/img/32/delete.png new file mode 100644 index 0000000000000000000000000000000000000000..320d9716b58f318ec1ec09e8f76acbbf03678111 GIT binary patch literal 725 zcmV;`0xJE9P)Px#32;bRa{vGf6951U69E94oEQKA00(qQO+^RW1rP}%74UI3rT_o{8FWQhbVF}# zZDnqB07G(RVRU6=Aa`kWXdp*PO;A^X4i^9b0zyedK~z}7t=HX76G0q?@n2U2QEtH) z4>T|WO2j~nA0g_ka0Pn64RE3f7o^7cff0kLL|j2bh~dyvF$x4ca2jFR-A+p<*|h1- zyw5ZLnYOc(w4A=2K|N|YgE@U=_p*}C188DBXQ&78A*`brvyZe!q4ODhK!_i0Aq0M& z0G{Lg|BqY`{5~cS;Y|z|a<(uM*zOR14qpzzTWt*!Es4gV&Yy6xBCjKf8hER1Vl1%T zC@FhYJ7Qh~uc~B8SJyM_;YY&6hOriBS2y#u1h~lDYb`+^p5bo7!0)(HT#g9;j0*`F zFL6J#1P)0&$DKrp5cn0xo{c3;!f&-GRiB zN;C@asZQX9>hm(L18#pK)$sXfjxA2lZv4m@dTTcRy>ITl| z9K@>`gSve#?2j3(y!q6Db2%#~ffpoJa^`eV!d^X|S7!YMH7&sGBtPrI00000NkvXX Hu0mjfQ*|Px#32;bRa{vGf6951U69E94oEQKA00(qQO+^RW1rP`w6Im7F*#H0l8FWQhbVF}# zZDnqB07G(RVRU6=Aa`kWXdp*PO;A^X4i^9b0lP^=K~z}7z1J~}3{e;d@ZauDHX^xe zL{8x(a-tC7PC`zFl13vDg+fIqL~EY6iEs@HIXTyA)s%GC5rwNICsZOdNbG2)SnFkJkMwHJYU97T+bvz z2w@g?aIK$jmZ0!F?&HE1;a=8Y;RQUxsbL+<8YsMkRU8@P@!Aw_z9MzMUi0-p5nOl=(X_~CvXUFQY+BEq&9F2i+G<> zfkC{*VVuOrlnVS6z&iHfTxq$DD9{?`m=!{p!X>O>M~wuQ$0E>2q=PGXT+?1~uad9F z7=M*}{xohjIRm5c0}nA%-fLY2Rq(x3Vi%sJRA3Naa2a!WnNop4Y{nSRmPB5sRA6ve zH)D*aOM8EpoIoFujTqz6(p5jCXu)Px#32;bRa{vGf6951U69E94oEQKA00(qQO+^RW1rP`wEtquwasU7T8FWQhbVF}# zZDnqB07G(RVRU6=Aa`kWXdp*PO;A^X4i^9b0l`T`K~z}7z1A^kR6!8N@n6ovLNsk` z6hyGFkgL>AEwvQEfVC(h2o^TN4tt%2SV_djMi3DTJ8g_s#wwCR5n>@INhL8N#Gszd z6T;&zcM13Q56gpn?9TAb?95E0l#XG(+wHC!ft1pw|GV9;t+yvGH+tH0f*75G|p*0=p^HJJk|ID`FF2ki~2UgK6^ z4Hxk!=REX@k242;<0>BHoYzM^G%f|MV+LzE=VI*`?qIU|u5Gu2ZAXEJ)j0pH#7wx6 z=T(AzDKQmq}L+P>nb7go=!_-5tRJF_lC5&%WU=`DNk#jEE ip4)ha+gqt#{XE)7O>#Hmd-qmY~`_&u>5>$r9Iy66gHf+|;}h2Ir#G#FEq$h4Rdj z3{XE)7O>#Hmd-Kl)U^S3sazwWQl7;iF1B#Zfaf$gL6@8Vo7R>LV0FM zhJw4NZ$Nk>pEyuagr|#RNW|f{*BrSV6ggZ2b02o)-LcONvFx(@?x^g^$Fa!EI4x{- zRa(~a`zy3w?up&?w=ISbsF5Lt{YBn(V@jmf UbKXra-~sVHUHx3vIVCg!07M2wivR!s literal 0 HcmV?d00001 diff --git a/static/lib/timeline/img/32/zoomout.png b/static/lib/timeline/img/32/zoomout.png new file mode 100644 index 0000000000000000000000000000000000000000..ddac687f2825303e51666c17526f5165fec55228 GIT binary patch literal 233 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz#^NA%Cx&(BWL^R}oCO|{#S9GG z!XV7ZFl&wkP>{XE)7O>#Hmd-Kv^a-SqZ?32vcxr_#5q4VH#M(>!MP|ku_QG`p**uB zL&4qCHz2%`PaLQy%+tj&B;xSfYld75h8!+|lbicr9KBn%S|u#;rhS6y31&x`YduR+ z?Tw>9r-eo?FMD}zc9|tmA47qxfr_X$1H*&+k44ofy`glX(f`uqAoBy8vk* z`02d69!PN(ctjR6FmMZlFeAgPITAoY_7YEDSN1!cGQ8rV_X_!YfI^Zbt`Q~9`MJ5N zc_j?aMX8A;sVNHOnI#zt?w-B@;f;LaKt(#9E{-7_*L{y~7n&J@A!3Ep*=j#-Iqn4u)%?|AG1#JYD@<);T3K0RVOUIH3Rl literal 0 HcmV?d00001 diff --git a/static/lib/timeline/img/deleteEvent.png b/static/lib/timeline/img/deleteEvent.png new file mode 100644 index 0000000000000000000000000000000000000000..e57c41c7153cc490d0c4c4717969d691bf244edc GIT binary patch literal 473 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 literal 0 HcmV?d00001 diff --git a/static/lib/timeline/img/themeswitcher/theme_90_black_matte.png b/static/lib/timeline/img/themeswitcher/theme_90_black_matte.png new file mode 100644 index 0000000000000000000000000000000000000000..182cc0e3815e774029770950d62cf5dbbfb9f5c0 GIT binary patch literal 3309 zcmVU30qM3Vy zlBce+Z+M2pwx*4nr-h4_hkbRVotDqSx|NKDN=iz!tfZr(qTbomw6U$4l8T6snVF%f ztg^Lxe0;dU#&2wE+~n!Ay1dHM*|)pENnmkUVQg$JW6$+)(%N;xd6s;RZKvZAT4kBEcJ%Eqv?xqWhPH9bd^l$3;t zj=;yve|U5tARxE5x7yOlOF=t_hlg}|eyygTC?g=%+ugjpymxMPadUUGv$K|*qBJWc zIx;I*O+=5Dp0cvCUtV9py}6yHtjxyCs-LSF85$iO9lW}^M@?0xr>4EMyU57LcXxNi z!N9`9!ouRAc~sCwyO-qRp`)8hZS11WyH3? z+@N0u3xq0Ry#4FDFA2fEoVDk)zkJUgBR-#d@8>z!@Okn{LUakv_YKg^cZpHdll%Ih z$Sy&Q$bOFcGUWb!E;rVO#HiK>R208VpEi#VA&NjSM|Yugj>=U#onHUF(e0#fV0_^SZ#f)k z$9E6F=k@Q`_kUl#3)t#)ym;hrUUwYN9;MTc+r^t%O?R(YTFB8JEM07-oNP)TkLMQ^ zD_hskf?KP*>1R)`-I+gszAIdVU0;`4`%7EtzaFK9m+9T>>&2VWMX*IS1$K$0=_0MT zQ_fs*{2u6{2dtsMVGK|nnkvq5F#SPNHj`5OMS6gx$Hj53|KXxy5&hz0JPXEiqs5OT zAt^(eGGx9Iickwn``Y8Lk75l-cSjoc4bUBqi0*Jmd;<(ePqXxHE~`l?~14ZGS%8#aspoU2!PbE2ztwHFN|fd6x2Xozq=laC1B z>paTF(v9_}=g&0`P1OUpL$_bsUL(E6!}~uUcR7^R*xL#Eo6n;!(AIvrm-^%U%?rHG zA2R33=xe+xlzIF-$`OY2uyIEX-}^QE0#4S~S08-We7cANFtfkm7ZGo~d$js!BUmE;f>UkhO86qBv-G6%P*=quQF~ed0VRQLmEQzEW zw!Jo)V1I1jl@H&5i9F)@M6LW&Xy+#s<$pMhWru3)*P)9oe zyk4(^aA-tuVuX3UQO`FTc@&NEbpp(pd}L6Z(121N1E?RIi%%UqT6)Ql9jJ0(VE++AqACw-;rJVYUU;S_;1#MN1D+ozS# zI4|t9FL_Qkf^bEZYAQ-t^DLEeQJh|g4>s8kr4=3G@o~s&NMG6h?#DT;hsJe2o(u?_ z!Xv)69qLFnwF-D4Y+EW(QIx*BQcE1N@1Kw>FH?mm?1Zdc2X?@&dsU2>KUCnV3Z%lm zEpb<}p%gw$%fVa}aeXnde24i!+Q}d&J14!_t~cUIP80CN!Lq!hbC@%1eBhL9C`Ad& zXGc^Nr?aPtOStQX{f0D)C&6NK*FfCnGo=|OTV)JsxKserEaF*~2hy0cte*X#LNW!x zfU}vm&EV5ib6n^NTyGYrgIdc>arUD#UQ(d+ycxJb+k`~cM_m)dsBOX3by=&ftQ4uH zNwWzVNY^=;G$2R2H4D)$IYVtYH(?vvtiY$uXIT8oP7o6puJabC`Mz26Fo^l)48UbD zZ2`-8v1M9r@N)}WCgX0+ECa{gZUO9iLZX@%&QJG(lv(p@%hJ8R&j_BBgDlsB^l{`O zEN}1{951Z=&C-{uWb5dBVeuq;Ja~Z9*YFK8L15KqJ?aud{bRpHNTmvM5#kVak*PAg6t z*L-z1oRBwwGz!-IH7Jdo6bYR6L%fD8^Z3`Gzv68}%P1@5ti0Z%PKd~OqSju2Zm*;Ph!U)152|A zRh9?Rn1dC1&Q~&nYLny5ai+=wX`BEo1Eh^Lj85V7D%?a9O3UtE38RyX&Uncy`euPs z;Z$?H2kRd!Ddsq*;q3DCM~-9a({mn5*mBTtNCXmu$dgo6nel zuhG|b8ED(OGwv$a<^po$vLFxT8E;=r=b+7HKxz3_r=u>kRA7i)^p=W(&VuTW`BEV0 zWB||bT&n|-Sx`GIr{-M%9N4C_kfNtnU!1~pbpa@K+y#3cTc)rm-CGQS;sf>17tSU2 zcwks&O}dPLOQeP^vtNmjgI#Qy_{q5(P>WO8dEZ5RhY|Y}T1JQ`PL}sJSuCw6e3%R- z6A!Ru_(d|dJvc&^(bwe4_TB}nAq?rY3VMC-JeEeq8ODRrU~C4o z%_rhFEV*3YrO~r&2};W;FMyzSye)V_a8T;CL>~-P!RzfURJ8>-uD&g)s<)(}MNUEO z_1ps+PVc-ewfbg;Q0nmLTz5c^@smsbB^6sn*iQ^j6G3DdVMjibz=a)Irf@FrZ6@y& zkY(0RPe3aGDF@;*NlHhQ4_YSnB(zdK!o>&boIg$k;{l_~@TUoJ zJFp8|L3KA?%Z-l>%jk=>bx$o+K$cnC9#C}R9_lg&$x!6X6{Mia3jT+O{`I$JT{F!7 z;G%f}y9})3Cj)xmfnA0LeMO?5NQYUCM~;z-o3R+SOm^VONfp>-K&g8M7yhLJjWQxq zPCV4HbP3lv%jkw>6dhh9uw@t??3OVt!z<7=*fP4p=w_Dz>A+-A8afXe3tPtBGoVt@ z8SjBElQFrI(Y&(>r=az$E+g5jE|Z(JSV#byEB6)p4|;PO8^!0*R7ybpnwinm$k+7Y;hxJyQ`xd5&q zASh)Yyk%9!xQ4Jt-k#GroO}+@jTv}eSeDyKboT^qqXfTPc9l0lT`Rf}C(o7>pcTLe z4q;K=6Uog2@%hrg4KaV4BsUGq#5}G6x_bg$hK<)kivhzjOt{vRgI^#GF8>F~y(eY) z5VwNI$wc2(J4AO+d_RUqxL82EZ1KWf>jbj47Z0H7@W43~&vZ@j|K3sb$H(E};r{AwR8&-y zl$2#(IrL&HX zj`HW&shEc6=jXJhlvrkTj+>?;A|h&eiO0Bwf`Wl{W>e4I=x13=IYm~w#?Ri~-c4I* z)55X)^13fOOPZ63zO}2PvA#t&EKWi>=HAnTlApGzqnL|=`ts$;%g%OdVe9nyN=r<~ z)7?i>UNR#YXK{QQBQR4;MrUemgo}~h;^lF1aNX9*tE;OhF*`RbAzx8OAuBqBhKV*c zHT3%Z>*?Pa85#Ne|NQvw_3Ga>IX|hMm=+o#Gc`FdFfcheIn&I+=IZSC_xFs7i0bX} zTTNAniHX+M*1o^K+1uRe>gte@lPW4ICnhEM{r@K?CtY4%;>xroB_;j)`A$ww_4V~X zGd?^sFt4z&;^EqSb8H?S9pLBeI5;?-prQT!_mG8p@9*#W`uhC*{Q3F$Gcz*)00960 z|3Y^8JOBU;JxN4CRCwC7nEhMg#umqeY!Y)52`>=}0u~pQtthT|r4bP<%j%kL+C>en zwu%^~d@#vKVdk8{qDWPCdZh73It!w8R|Lv5V}W&lHuAQ^@Lodz6gpdmY_!=W#7 zl3?W|NdRL~1xbUDQu)UCY)O_m*1niETap}QaA6%R5Udrf3$E3@s>I?r+hFA?l;#YH z#A^MD?pAOa3@gBpQ)EdpbV=gcZ?QeD0YqhmlQJG`HRD;o4tNUu%JLpJrc7PdYWtL7 zNplodt6~@>ITh`|`-S)E5|N%KLfy+0o{Cf>zc1udEJKtlsWdm+`zJbe{3&uValG<+ zGb)eWseKP~>8WzIwAxJRH4n}?6-waM+s*t>i^rS!)Pna@|9s=k=FC+7!t>8h`Gr@c zAQU%lHVX?I$K+!8;$l*E9}C-WlDy~4mKM4_Pqo*h+`q(F7GdVny4)& zmcz>n`SaSx4QyjhGD<(bzL`3{xIAwjuS{>|C0kiw^~gkuXjVB1NgHgV+H3YIuCk!x zsk1Z}j}*F>q3%vfC2^7@E0Kaxijb9ZLswG_Nf9BvMC?&Jr)AwyX7z5r*^GdPj-=rL zua2!*fXydyhAbPP33X29WH4w5oD3QVJr7P%IFMpN(@F~JTc;y+&>_0On$n=T3^4tF z^|SD0KkJ|OvzcQJ2{8h1$R(iBVbJ(GgO78hLOzB{>vVSp%`C;Mc`}mvk%h#J|)@T_g7e3OzA%7+@naECk*!TrS z`E)7EO#h6uM^Q5I&myV{ekfGKpEiCBTGFEsA6^gNPN7>f!{P6+in@XpF$zun8JG#9 z#4B|#LweG9*vWKxt7?)DPi8jJCBG}j7xLx6$ddjmfBJWbQ7!38_V*MMS~DlzO#NA` zCQ#znTxo9p`0pL(qOSsz3Cj=s6tafDJD4k0GjUt`Kl%NY*ZVs!(QkCTFgmz6*#F18 zrOTWDUO(IX1I?OQc(pRjM>eg@%h%0U8+O%b*&6<^9@zwP<_!rBhgK&Jp@B!>1|SNK z`DV_IEdMX?zdanZ$L~z(XEE=yO5fd&**K}gUtAkLVtDv1Kj`|w$I`=-^J&-oKe*-} z8=pQOkNg*|PcOQDEcTf+X})yf8<@Iy;oAGIV2w8#hT6jINatf!Yf3|Br!Nhss761Q zz9(e^88|?&i!c6V+l%)+XC}b;Lsn_riX@4ORjnxvK{zK&pF7gI-WSr64os-;6gbM3 zj!wc=8#>A?C9pD(w#pKFK$?TT5vUc6bHenC{et|ZG&s=!$i` zJq3j(%_;TSN#FUY=_d-9hJ7YI#C;;P!$5XRu~!`mfmJumgzxQ6HplxZD=MvWG->+a zs3o39knhV7H@?pw<4_fomT8jn7+-+L$ZFQO()Qs4-YU~XwpB6xjx2W0Bc`v(n)pSB zs9MLer1Yry*rc84XgJN=WywaYV)@{z(-F}rg3@CIjqW{I&9T-GPV@cnq34d*JcF@_ zZaP!2*o5m(17!T;UkMu%t_?Ok3r+OTGcgz&pV;s}s&d?B>%8gsi$I#D%)a6{nQvLm z2M;Q&mr?8l*>ai>L~5%m+YuG3D3&Wp(-Fs);SHgAcU=MY3?h_E;bdk(*Co zY0@k@3S{ev-X4$!-x+}@H+vv~cZj4L@q=8TR{+RBzm_ZYZV`<%rNBd+{I;K?XtD!+ zW!~f2JMuC~;J1s|PDrJBSfs?G#cVu;54vqm&P2D0Set59lbk$%kkbO8&iQ2$%&q0N z*PN#jzqo{i6$G%iJbZ!sT-Xx#2^#j!1u z#>4Oymx&@|1}12S)h!=8P))Sn?w{@|v8tJOvZQ@ob|=wr)dq+=$j|@;+JVt+5%0~G-_bcsA-yL#2AY?QB-M4GwFjFlSWMhKNgK(99&sJ zG@3OC8S7rdTS>Llj_Jy>tef{5_*_SAIYqME0W`MlDQv8gv@_gvB8o)TrpIA$ zgK7W9BV;zlk!d>Cx^Tz6kVee08r^dPtkvw>ZjY{wC3=Igh#ojbpG-J2`qMG{hREOt z+z_+*WbhdTZ%D^XC>_$iAuy9v>8?3NRup!ThG%1V5(@hLXJCd5ZdO}vJ2ciQK%h+{ z2ym5U5sh`qsH@jDjSY%bRo0|Yrwob|C@(z!j!s4=i=!)lgcA&&Wa}jB(0G(sZ^xH& zT|^@YmYUfzkOpi8W{wgEs}+mJwJ5dY2_YJVK(rCYLZAq5kpora?O=En$KHJPmCXMmzAr-c0oS%8ypS|f?G|ta}i4R>r z3o{2?zckrF(*I_De0>`pUG0PM`118mHESW`1DM_H`nsY?BM4aLMw1bZMJAU?ZP_$t z7z5u08yMUhGYp$aBint1tU<>!;DGbqKRmrlzrjiLx~v}hC|TbfBD@*Nssl!P>D zrVsW;@4(rkfHax`6DEzkd3piw(r(K<;^+eLCVMQUrbJ z_-Cy?;{+ETw`ihe(b(yLSBe6f558YO(CNqx^m=M{z)zC2-eDjDYyukF$X7ZY3ca3` zBzPey+%(tA$-f>fX0RZ1E!ZoG}cSuP{~t(dt(C}pqZ7q`0*;D zv0kk)iF_JJOO2ySBD;Mbl|g)5yf}l zeb!ZzkVZ|ERlJLhe5?p*)V6VzDi+!XUGZs$MYUY7?!vth z`A0cX9HS9JN6{9I&}#9Y&fuH_*0z}{N{R21fgYQPVO4?R!?K?hM z@e-=-pS9c~l1yEVf{qREzV6>aX-c-xQh1tda}pv@ky*4iDu_9f=4FdU0Ihm8y#K!j zKco?j`ze-5=@yNFTXr^dZPGYjMD!VU;r)2M%q2F<-Py_002ovPDHLkV1lX@3E6 z-El|W|Nis7c{AT{=I!q6&bRw!V~q{9Z&Tc(007{&u8xK&K|Uj}F*z~eT?k4*x1F(-^l?Go14Ly z6tU}QHNBY7Z+c#)jO3iAYVn~A$$Uaww`iZna1|~yn)K3XYLc)H7sL=JB!qrpG!dqX zqgW!_;VMdqD2|C6z1R#cc3! zDo6%6?>NS204`5}>PgEuO~6_lU~tmwmjjkW0C8O_CmrBt3(y0mrK|_YsQ_`4m`Fi@ zBp7%#%+37{_?!hWXq{LoARpG!?g|lRDyv?hjYm#1%$8ilhs?@KltTcl%lwc*8gv7c zts>g@KI`t|FiD!fsBr)&NMmptRiOWmMf&gs1Q$3AJ6HowKu|j$OKR23%No~u^(4C#7r~PWS zpi!%j*Uo)*Jyus9XCVrgSj^w^Cj;?E%2(P2yg;avZi){8ywuw9lfITG5;497LYqE6^Esi$ryp{0@j~C5Fg8&YC-coH;8J$JMJtLLbk=ITFKQ z@<1p?YD z)!@CKmes@^v6$DBzXD0ukW z>JPm}zIM8^eir-3kD{%0gt-^!6Yq%82FIxP%ka?0sz2s$OS+-^tHgYUenxBNjVU)w zxFSbV=N@{LTRCr zP*TUt$Ep^^*`{kh3eD-H5}&En6gHdInMD7%BN>n_Hxa?4t5;f6ls0?Mh1mt`TDRxl zPPdlEVVE&xH8Td&-pkk{Mh8;ej$(`$ig6aWo5MoJ;(Rxdr7lyy?Cxy*-63;vnMVhi zyIC|@UKZ9u%|ag-lSe7io~H4ou?mTqS5%f&u2)i8pe)AB6DwYteXP~8kTBb>xHXqv zWl@=Dd|<|E=3MdQM|7q04=;1&k`SA#SW=rm`hSenOH2xW*==_Ya#Fs&+we}9%l&p$ zR6v+iKi{v3!O zYqo5*R!&jQWS}UIsTHksFJ&$4&Nn*SC&X{1oYo1xothO_=bDLiTDkeTwFMLciLrFA;b#QIC zYv-vy#^=Rm&RmahaZ$;g&I@KVJEE zksIotxbY77ApA5?9?DDPOdK1g8fJUr0vGgw>vw{(JjC&|ei^R%rJzlfQ8h8VCLG#Z z!{su3m{h}s-OU6igI%d3jYIYprpQ45K=FSEJlsZ!KUVMV50vR!#l)X8Ri-a5}(*F%p@PE@E?`i)2T#w8pT zy_L5`xgE@$DK`AV`+Xs}4;@*~R3S<)ET68TA7d!{?O2so=m*mm-jh3lya^QV``G)O zABas$Psc2&KNsRKJkb#{2ue9j?v#4ZGayka3~l?&Uy;Nj_?oTn4Gl&il^)oZgOAJ4V)D54?$Q5#vZB8*y()s=jF>LeZ>NwrBoKU{Q#y z-r3R0>GwqJs9btg{=*6Qc*7_pNhbH`J04EoN57fUTpFckCBkm~udCWku3o|CJ%nPL z@#e!QOVVnE*0^RN&v~ONxK&1NNEcs_fqU4?-qG;hCL;F(N(%~T)9>4sPkSs2Va%{yM`UNm5pYhx>6xbzFp7d3{SKJX#p8R9E4 zZtCX6wz+xs8AWr`#D#|k+SEh$yRY+(0!401-?sRgJGjN|t?_;bhP}0c<+v@s^7cz` z^(NWu{kQDS>|$JY4ty;hd}RGwOVD@ z$=iAE`|m4Ur_LG;b>wzr*S0-(Z$kuiH3d6iVXXNw;5BsDdn6NnVLo3@ajgp#fUfK3~b?IpJlUq+<0cv_x8%r7)F?pSg zNu*J~nV6M07Ii!7AYWEVPHs!t_X>7du0H87$(PT3U35KG%giJef}1~B1W#v97iOGf zr2h8&PelZ5;o%{455~vGhiqvW=>8{GBPss-{m5Xkq&Vc+4Tea zhw#1q{p-u~E5ynf7IS=p!kuC+&(C~)ediuNJU&Jg6ck)uULGGI&_hEdZKJ_CO&2)C zG#gt(|IC7n%)mfD9C3`p;ZSJwnvKoz@yUv&Ci(<9Nk@k{#llijYHMrLYWupoyU)+h z4@*j5`-c|@!~`YfzlaDl`gDK)U|XV`x`khAl1_~9WQxwa2KuK5kV zL?ZX%xYy*Z_f6S7wV^M$pImINaIwDHeW&Y#E;a-ZUgF zEq!!+ba-$$y}F%T)pK@6Sg6wzBy#`YaB}%Ccyav%g+4k#!C?F01ua7WaD+U;Utb>` z9bvIpBocXgdWuG)F&NA>0X#+`j!%w{kFlqx*VlLgia-!D;^Y*Iy~g8@kCAx%)d}(# zLFf;Gz+z8PXbkfB7>+nPLZXh25EwKXevE|e@1J7OXNZl{Q|#5%72=4{ChGF~8jHi7 zUtDawdSxvpzmIv&tSK2C<6q^y^TOJc#)_5N=FP zbrf?iroSar%>2u%3IXH1g!EpwvC5CV3)y8Q@{OtT{u*Y8r7~<&}s$ikaHdCK(bW!IY_O6Nle=TDy$C;jqK6LS2!a@bW3@v|wOcbR+q z969(N-nAxAUsLaWJ5wD0{r5kEJl6+48tGFQYK~d*D7|VL@VGjS)$Og=+oiAa{hvz^s!Z-2F4=H-)*SVX%`drqrFK%QOTVqHho>_LG13;QB`t)X2_ zM~A44;9zccW=^}pBf-EmHmD`PqnCk{(Rcyo&Ryln>)FRwhwot-j=z1l`2=MIn?$7e z_@tzqoCm@CbD8~lvFH6#7UflztHUo-Tcos*Y(W^@T5;l^P9lf?`KnTJ!Z^zG$cT&-=-jN_YJ_gtFfM zARYm(Id@C;SSI^-7Zy<7@(*g^ST}6lu$8>KF>H(apk;B2O5Ex4;kH_oCN%MOFs^3O z%JFC}%UO?E;;1cScVN5#;(y-XxoBv0fNm(!d!F7d%GV_Fe-MIve2)l$1iW|C*Drdx z*zDm90cS$TR_x#Y1H+23IjQvxspHo+F250ob~pTUSk**G*RogbLe@l3*ULJYoGYh> zmq*xxiTQT7uHVnf@fS)VzeDWRj=pOtw>;m)UIbi|ap!@RBP@4d_Zb2yHcnSQDLoRD zWt?cabX_N27{lYNfeF-orB}#H$@5-!(lyAFJ8-CT?)tRNTd$+ssP$kT1G4hzz0n<5 z$jyqDgPyawN_V`T}J z@11ZArmp&X#5!Z}-?ZanmAawgmaa2L&3Bv`c4teY#5Q4@7Hl!s_4c;u*}L!a@7IJr z>}$BOM|@E)bYnR&+Nxh`2&@@BR7;b{`!0X?{YLjvn$70Jh=(biN(VjvLeD%GMt7=@ zhlpoQes7&izgHymnOMu_IZgrQ{jf0_SKVf}t-i{IADiwfme{{~DqZ?-89BWkywcUs z*QKm!r@y!qUL^7yxqg$9NqDK_RquM&#z$f5L1=U7#}{V0(mp}&Ic*K&1dM*}7VB+X z3kJ=74L2;Gg=y?FzJZ2s4Gbl)KY8nctO~}nwjcV-=Na-_*A>)>_ww8nD07{H`9HvL zf(m^IihLJlZLcl3&{Zr7l-VHY-y#6V4%CUh?8J$QUG7g#cHacCM1h`7nPw8J@Prfe z`Hfo%XNwp}{)kVRy0&JAh)Jsdl}(7)UH8J_bbzZP{H5bbgV%@*0W23l zFgV`mw=^$|XU$_;P3hE+V8r>A0 zGl6_%O9Y=Bc{nHegP)UT37>o}amZ~uHY4Thn>;r-$-`y8bm%9;q^ZL>sUyIf&Hk)p zJ|x{_ca}M`BMKO{%=jOjZZQPW5WbI5Sx@YjT!dqSR7uPQXn%d(I}Peuqlmm=FFSRB zdGI*$#$Co2Tph&CK8Kfgom90zDNSBB1J|c{V zHfZ;ltB({!5+?epVy)%|~KDge2qiv~XxJuO%{O=$df2p zZ;7FbKFXq2NAmjfQ-?@0Nf|3Chae^X4U4t}^7QITx#s}s6!RG6XSG6OfohBMY6tFz z3>1-St?sRs+jl{cY9Kgy)iZbG8NuQB@2hM~hgNbjBZWa3ds*Q#?zLfx4U4P~TE$Uq z-o^qB(bgNGQr3@|HBG;26;Hdo$`~=UQ6wU}S@J+-Z`wuj9&}bXwJ%fh-q)yrpRO+! zl#JR4ZnBcpiF}IX&l{LH^q+Xqt6N$YBYTbk;VYh2PME{-bAHb`$ZP*8z5y7_q32h; znNl)Y-`kwb#ww^P#BgjVHc@H+k9f^#UCl=-_L!AA{WPlE#tfPj$saVYS^Ogl1Y~Z8 zuNBJ*GShuyB~iWW8_5JUV}LGH9^^RM>*yPQV>NkIY)DDJ2)VGk)XcvRXPPE~zWGYb zh}nWoXmgVPkkuafVI(%q7Q{DGvoh&k9=B?M%?d9^d7c8o>Pq@`b*ZochkoUo3IT^`oC-K^0ikvMaWq#WR zZ`^8hzisDs#6Qiq@r!>2Jxd^xuQWToH9 zOFZGNa$uqv9e$(9r_mosB)YWeeMloBu?hxp3GRD)bKT0K%QN`sqkum_8P&>OH7JX_ zM@xUOv@*9cza!n@5XHu2bob3&<7YoUZxX!=Hrg~G24{ZzvuNaTB-gnHstV{8SKwT; zUn&Y>t``E~IzeMHy!_@mY?Jt)^|5#+CU@E`A7N*-Q0}0l259nXJ-Y$}RWH2k~TC7XI-@!*CTQZSuw7etf z*|4lbKQpSEUFOQF3-NgE1qsofmDHUnF-VAkN*c`Y=ysq)e6yRAd2|yD@;*4kSyow~ z;?6_d^m+DY-C~2f+p>m+_P!~>?Jjb1E)JkP8ZJ#MmrmVA3m$ipV=SxSM^?v=yQ^SM4y9Bv1&0kg4it_~Jy8yt)<&t)RtSq+sphNs zl7~OHT&*y-RwJUj^&q1ci!kOY%w+?VZ`~$R{{#%}d?Haj27BpQUFjGl-s`E8e<-ss z5IF487SZE#l=qc&a#i%3&D7<&INg2^x2WxK2S?6CoI zep&KC9f-GO%mpTWl)|owAIeDcw5+d?eGD0>0@yHSXCC2Q`*f|7hUu&9)EdA(o@N zEyL?vq@h+@#aC2PIPRS$SyAi05>Guud1^MxTWl(1tWYytQkJ^WD=Cg&=R2p1C^@ z#HlELQx}b~Qd0OX5v6*)>wg-3MnU0AO-&_~HhAJ&?6tF#RB0(F%);7cY;2rVY|ddW z^hX24tyOF?aPDRl75DZli%nWxx@V*4T0pOh1DO#=C#}52~S?z>`hWm_(KK^Tog$8C4SoRayo{W{voE07#mZG?*<3rpos1 zr{zf}+m>`FCISGLXNK{TUUrw|g2>B(yMFRPKKoL!e6%FV$g8W)z={}Rx)QO3qodu) zSSZ61*$DyE=Xl3Zf<<92e-s~eZ}fP`{zFrMS8ugp1ck_Gsm#6&S}}E_v=ercg8r8F zZKSj0N>l&&IaXgRHnJgDntY*^DiD1~d9IP4Au_+?#x@&5GB-` z`0Z)7p-qf!T(icinsS?0;{a3zS1#(ey{ v!hD@GqT8#iz;oq9D0t^8qS2FU8>GM|fqbP8K6#h_m*~2hh8neMufqQWno?Y# literal 0 HcmV?d00001 diff --git a/static/lib/timeline/img/themeswitcher/theme_90_cupertino.png b/static/lib/timeline/img/themeswitcher/theme_90_cupertino.png new file mode 100644 index 0000000000000000000000000000000000000000..0d9f11aa2cecaaabab29e7fc0305384a83c0dfef GIT binary patch literal 8530 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 M07*qoM6N<$g0+i_T>t<8 literal 0 HcmV?d00001 diff --git a/static/lib/timeline/img/themeswitcher/theme_90_dark_hive.png b/static/lib/timeline/img/themeswitcher/theme_90_dark_hive.png new file mode 100644 index 0000000000000000000000000000000000000000..66ab870bb81a6f12957dac0a4953f2e5062792f1 GIT binary patch literal 10481 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 nSe(G0VEm8Y$H>SXO?&X}?XS4R!?>#; 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دtnteyxrr>oTmN7?O3k*$1&bB$F_KGBgimxYdP6@-s!AWzp+TNvjNbU&>q2edzDb<3%zTX-%g>4DByMwbU6j;Y! zp05x?ES{ycM(`IplmN~=!~_&Y(5ks=Ar(EB_}O88X4vO^if}pp^POsyih2fkwSwOJ z$R4z_M+PbUq1kE?5x?zXoy|%F^OK`OxzUH0vSk?jO9lVodgFqEmrbJ;rFd^YXFR($ zC6l2ezWbWNODG++_ZVnpD>YcQ#L|%X-X`O$jY~qPs)X6ULtpHq zBSTzhIHZUy<%(^-{-{)|Azd8nv-`(HkuLa+{=S;xci;%ESg1?QQ&04hcFPns0GcCb zoy{Ea&|-}T2&4ELi(z>rw?DFW&P*GvoTr%t&#S`Wpwrr@1_{fu0i0tpbk8jsLpTt| z^E=hK%~}C6c~%H1xTBKT3ib_G&x?o;cpO0000S6 literal 0 HcmV?d00001 diff --git a/static/lib/timeline/img/themeswitcher/theme_90_hot_sneaks.png b/static/lib/timeline/img/themeswitcher/theme_90_hot_sneaks.png new file mode 100644 index 0000000000000000000000000000000000000000..cde01b30d78fedae934958f31419054a9890bc29 GIT binary patch literal 2961 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 Hu0mjf8kXZ~ literal 0 HcmV?d00001 diff --git a/static/lib/timeline/img/themeswitcher/theme_90_humanity.png b/static/lib/timeline/img/themeswitcher/theme_90_humanity.png new file mode 100644 index 0000000000000000000000000000000000000000..891b39efb0edd69a0fe60ae9df1099a1afbc7474 GIT binary patch literal 3259 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 literal 0 HcmV?d00001 diff --git a/static/lib/timeline/img/themeswitcher/theme_90_le_frog.png b/static/lib/timeline/img/themeswitcher/theme_90_le_frog.png new file mode 100644 index 0000000000000000000000000000000000000000..80d0d8b4fd8c9076eb70394ca96d814fefd0aa92 GIT binary patch literal 9124 zcmV;VBU{{wP)!DU|5w2a z<^NaTTG{+ADk9mT4o2^k%~K}GSSHNrdJ^}Z9hnx#%60X%JB_rP$)ybuBgWV}MHdhv zl!YSxh*UK2tpCihUTM|3=IWiXnRPPid zgmGrlDz6F!io!N=9M{4~4EZAPH(6s!5@q=IO)LOJ>k3E|5ng1sF5$}}2+6W2GfEt4 z34*AI3T2K+2#Vmm#B@5h5V(|nKFn2n#maD zM*^E9W~69kjS>k2Dm4A{`Q(6KiLI{Kq8kI<6P$d1>R zZ;4{<^w=qpk8o+SppvNEzx}Uww*Q$T`A-bI^zebd9ZK~mTq1rvmIG0UO+ikq>c1LE_Ud+KRn^AQaMgiRkAXL! zj+0FqAzyIXYr2du*928;uenOIG9Ufn&WCRP$NI8WtE)Et%=s!P@Fke3X{9!`-lm!p zEe&^6y?Wp;Z~alg&AH~8GZ}GPP2)>_9kP>i91XM&+|=p*pZBE_U#whR9J{t9?0)rk zpa1N;zHyc0eCJmmxnj$gZ)m^EvCnszrPs9H^oyf=9VA|Yf>@3Y+kr27#!r3aHy{7` z$43C?Pk+T{O0Imfp9}rxb(M&KKGmcBgMfoN%VueHmqDp$t~Z!`={s6{N$znSFs#x zDqCw=W5ZdkzG6d}KlED1KfKV}x3T*2;mNZmb1!X4@K>;%e1L@w!Zu;Eux0oacW~ZI zYy@MmbTy2a$TTY#P(oKW?%Lk=o`$kjhMoKNzW*|s>c0f#B*YE}8p{;@Yfpdr%v7?f zsH&xAOR0hn9{=YflY`?E9V3>B-Sj|uXmILC&s3tJ;@Y~fYY4ucz9-J>%C?5>dtdzI z6K4VpbhrfL1$)WtSbaxJ{4&@egovNM_?4Ht zpAj*p;LNfVj0NrbWPCI=7Kw`}fGFYdbyxfQ!Igps-hb*ba2$%HTv||LV15qqDXQaG zR4jYo+Rr}q;@=Dyh6K?Yi=qIbghxIIc#0@H#4;Q~!~#SSaA^`!9A@)4FQ}ASi2Ki= z<7NdBLY>6JEi!AFVI0-V@8g074#$_6)siJQavlY zV-nhF55!M@X3x?B9epQOHws?TBK-jl0^VL&rs_etck_}V;es$2ht9Zv5nm9KKO!%) zy5LYSPGQMmnbGnyip#n_h!V@}PFg%-Sv0QchdKGD*KKs=oi5~%mxCB8rl`|xH ziG#&R3aB9wk&Kar6P2VTFpevfM9PViP3Z;`7S6?22suke*Ye`GsrcddKl~TF?oEz& zk7jbJ>QfNpUUb%oxL!!LU;orocH;GQoB#Tb=9+!y&a}pBv)LrYbJN?luwl);pZmc7 zy7T%!Z!50o>N{qOQczYc*Pb29w1h32KYVNR*7fV|t&db}ZQDIKd^}tffyLkgsaaIM zeb@i|^q$Y(y5ZJ!ZM(Lv+|t=~M02zSc5T_h6<2=hf86=EO(oSm!zcZrQlOxaG8Uo? zOSpB{fBUcR`y942gBhbVD5p(r_7owA7X?BK6|1&-H8#36)cSY#fAKxn{r#S{wYsw) z1}ZD+uDECCM?P@%?bYS$9=hiTU;EfEK5^q+pf0l-t*XN7$AA2_r++Ea!M}Opk&oZ= z$etY^{m6|Ubgv{yf9UaFe*X8@H?udJ$+f!Z;|;bR_I4%%)bA>KRv2m_oaJ2T~pC`S<8m7BC+{{ijr^O z?4kN~cla|&$G2j0b;Z+14qUVT_5hl57M_VZrcJ>R4BIU$t>4hHxgr{&1w#QX9Uj~# zmbI%>r{k-(P9=J;Y`c7Xax4<5T`;3%TX4*b+DKGSo;h%A)M>9<>$(eVO2mq3CWkVK zvS`u6k3Do=v*h__?en3hfA@{Y&zoQW_|MlAhoaHi`e^wAkx7LH&k){z#e4P1lizx2 zZ*B9fwZX*k#E>k`4?QgVe8kV z%US0U5WxpNbCJh|i7c>049W{h2mdQ1E?gDzcIz-c zg<%S^ymWkli4;-FnJyN+l}pnwSQQpgO=-m<-hp6m6!ySo!ZKSFtbNKtMU|Go@$(OO zbXbuE=EZ^qC3?mwv-g!eeZl}(T*-hRDl;?APR$k(D%hLkf#*2*q8I3_!(6{_F2G-e zcc2+EhTa63xnzF+C*Xl|q2!{x<4?zq>BVw%#6?5tMdS!zxN?;$m@zOSeIIVj(W^_(3P%ck9KE}5;GSzRmI^yKWoj;V} z(p-1)H5V5b`@)8+Erro_JL&hWxuO33rK)P!84!9tsJ$K9!Rb7K&CvM_*(KSOIaTI& zP1mbWadDWSM+M%L0X@87*t7R6Z%%ceRbk0FGk)6fv}`d3yvf0HUpSfAc4Z`zc633YZ!7Nr zXXsk<#R0w|{i|c2fpy7}#7`apZMPs&&I`5nsV~29yMz@qO>&VZS#$nStaI$~^Ame> zZVG(r1u*=TNIkzd$z(;DmH6A#${{j};S|}D?3G{&04@kj=pz0E$psZ0?}o-J%Hc&r z@k_F_O&Jp5ch1t7S+WO;fowiqp*ScJ*m68Yz!ImDlwKrch+f@l85kc*6jJ?mHep|o zDMH?42(C#-I*jF7kr1b9$zCfna$(Z>#xRb~^4Gpnp0h+Ml~BY_FEBTp)6}r01f+2E z!WfSfObzAy5hV~-mqg8Cups(mmC*~*YQwT@fhv+uVCX_31B=s`4t&fTid`bctAi0_ z7c?0kWrY=VX!2>W-h{bfrissZd3dVS(XnUK74+BY|dB+ zfe=40@`09$*k9~#WHgyDhImzZ5hlL?D){T8YjQ?k%AE8#I5A9!YNQ~JFuz<;=8ITv z24J8ei!okkA>lxM5IGZOA}@5yGQp9s0&!64_|@t%MIFxdS`JS$V3Ve)yS$f%VeBiC zqggBAFts+^JfWR2VT1yVw_p@f$_Pms#4S?GEO*KPKTGD*FxV9k6|>--wI(ZL+wW}u zP^GWLbTZzt&;=ME2sy{tSa<)ns-0mu2=pl*L`^aerrDX0uX)Rg|MY?O2L+O2OJNKr z<)ZlRh6i`o-(QR&>hO~Ub(@dLIH-6>{oUK@?re$F!mu8}B?igCZ*?avD^2fR`JhCM z*7)r^8t%QiYP;p63o$T)PVhC&|9Mp?mLtmU*1xFthckAX74i;`7g0`B3QpdoX4)J{ zT4v6kG+o0p`-K>;-KcC`ygipW=f{!_G|>z4rlS?YVEhv!KZyjZO3CR7D+^k>7z5fZ zA|o8Ci;~{7o#j1aK*PYDLU^3x9kwd^{m7Ygab>u{v=8uPl)Cw$AQBBGpFNXa%LKKe zsNq*1?N5@|V!U4>6mX+ceeWq|+7SU(lE+gm1 zpL(jV5s?pb;AX{^B4OnR8i6_ zts%OWT2s1r1u=`UVEvSaebo`Qh%hngkB8N$!^JV5m2zG*pQwOWD-B=S5EP#1{=UZe z)yHCtr$j@0&pv)-#oDKOe`Z5U?GbR>H40&rLQEZh^4xbP90Ow&Ero&62PdEFic|;L z)RBo365^c?9xI(k!@TYW_Hy^P4-D+f_j%4RPRNFxXsC4{eH1d(gWccT-LPlh+3)J} zSSbud1YBY}edB@d zEW~gs%`*!sf`>+O&x^Teol?9)E!-+!5V#!%fzuCz_AZ6-qK{+4biDP!m+7~Y{dWD< z(Da4nywrxL7(513)O#pfy3z+MftS9y(%FV?j1fencsz*kOAaJ>4u3IO0A7kA%<(%mkE%o9m?3^h!GU~P2c`pE0yCM#%myeK z`#qgyiuVO<3RDoyT`Y_zup%Ilv1M{l$R5PyFtaeuUze-aT^!@F3q;`v)a6O3Kujd5 zNK`J!IN`^3j*1Fwmn}n-!Eu8@*OYk|3m~WB%3x(p`QnqGR%1lYpBM~A{Z(}r!gv-T zxZNFtvC2?+W$BWzH-gEZ{@BPwawONZu2vKzw$xsE5tLXx$46RQYQQ>{6dS*h@S(G3 z`hw+ZX?ba3M!R6Tk-@Qv9&MJS3*l(c<865d3ogSF!RHC!fh-veULZZ4gW*VE7K1!) z2kEmS`UvkPqdqBQ6Rqp`Kr|L^Z(HL`GfwcnmV{N2U(?&572s$VV7x@$DK#Q5_OxAyyh|Z)=~KjzK^Gj}BhIn@$R-fm}`-r`lYg1^WTcn=?{bBME$^A+km0 zc3X3G^#@B(Agw3CmcfJMG4M|7lY|zx6kTrU6XoG+wp82*X;8*U^Kd}i%=A!Gy2Y9! zTO>jzbE8No52Ij4PZeU|ozhdK{`GM=k~Z9y=nZS4n+zifK9zT@S=r3Ybc$48A8JeG zh83x4Yvt{Jin2x;cIQ&prUt|*)5$6R%4^$q39epUdF`I<4{Tq34Rs+IL5^$BtUQ@9 z%$o3)Fk?x>T3LKcYq%++Pt2wZGrR*VI?pM9{}HpHd{;bJqS+H^653JsUTRM=FVI*s zyaV{Ci~LtqUgx8F&dxNIU*8t3%Q;!ky^}nQQ%T~q#CI2~ibmu;YyYk-R-NTEaSj9j zH5{$DX!Y9SW*1f6-0(q>W;HiU^E8a}j{Hy=Nv>QU-^zsITUzdm$s(*1e#@Zp%pyrn(4H4aaa? zBcFOeBm)eb$&_~L52Hs@R_>aXPn1XwmWru&pD~Lu9n*0pI!2!Y`kU5{?i<)&7F|by zQd8nFNMmL?>(uBAeVIXq%EN-7qq6F74bKT+t1y(MgDgOKdk6Qu-gk-+y`%e}Zl!

(=nP*oE8K)_c9DuW;da*xAdhMN_|l2v7^ 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%0D&r^;iKqL7P>-h9s({R?EX!OsJL< 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 literal 0 HcmV?d00001 diff --git a/static/lib/timeline/img/themeswitcher/theme_90_pepper_grinder.png b/static/lib/timeline/img/themeswitcher/theme_90_pepper_grinder.png new file mode 100644 index 0000000000000000000000000000000000000000..97b5d73c0b5872205e69a5852b7ed7837c4db61a GIT binary patch literal 11553 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 T)8WWr00000NkvXXu0mjfUIH%1 literal 0 HcmV?d00001 diff --git a/static/lib/timeline/img/themeswitcher/theme_90_smoothness.png b/static/lib/timeline/img/themeswitcher/theme_90_smoothness.png new file mode 100644 index 0000000000000000000000000000000000000000..fa0f8fe934dc09aad51532de3b1b954616778321 GIT binary patch literal 3417 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 literal 0 HcmV?d00001 diff --git a/static/lib/timeline/img/themeswitcher/theme_90_south_street.png b/static/lib/timeline/img/themeswitcher/theme_90_south_street.png new file mode 100644 index 0000000000000000000000000000000000000000..1545fd00401b7d414b2d8dddf0fc9e44a0a12710 GIT binary patch literal 8417 zcmV<7ARga|P)lG^5C2gpkjd zg^&gij^kLCg(=Zg4I%yivk71rhU0lyb6wXpjoh!>likO zu^ngHPoHk*Sgx?B*y(b^x6XA5j0Ha>-MVe40{>xjI-SV!aq1*1cVERXTx z97h6jLcw5DV}qt^IXStR**Q9y5d^mnssLSZ@o3PC<3|r~+^{YX2nd1zUs!g{b$)-k zevUeVkgVx~z{8z0G(+wSLtjj9XQ!$&2r0hIOc=*NUk_qz>3(mpuUlhmey_8yyNec_ z9+%kL)x|s9BG2gX&41Lmu?*YO)4gu(8dz*akv$&o0u1J^L*Q|d2WOw9>rHen>^mY%OeeI&^ch|he zXOI8(+|ldb-6R%F{P7QOc5^V5IB_r|nL0XdU@XVO?bO%TPMtO*Ej?q$_APL;rDf#| z%f&=+(e+bxT~QTfV4&aU^Ub~Z;tlK9!Ab@Kz3>sz)r1~~_GrzKH7T_9&**|?P;mF2 z6D}8f;Il(}n?L^O)7s49@~LHM>o@EkTRv`7Rt|y{*EQCa`GebU`STzDxbK6_SrccJ zw4D0uOV3aH)(u?C_P5__5?$W5rkci%;FM8LSxeY5Bb$93|AM9l0{x(&JkMV;f8oK; z_QTC;x-JkyX#tri98_3`J?r!PdwY7`dHbzMI1F$5e14b<*vNwoLDPmeGHYhjp($pg z8LF-3;J!nr{0{!(?OSTQ!&7HpB6T+$KGj(HttDk?TuXZw*d{U`k?#Nd=n9-!Ijg*& zr>nC!qKTrjzxzyAw{qd-R}|&=1HF<<gIQaQzJjaz!m{3t!rK%dn$u;83%{WE1wx6zEboI5DSH1D-n>DSC z^>v+d=UrTsMh9$J84*PhvEtzbhVE=U)!L=l`F3{N9P#AFKw8;tS1)m zziid2$HKv0hbs+i99UDBj=sJ=mSxg2GQpsNLpmq7!mvEYXgcM#q1DekTQq&if~tau ztioDh3I;Zn z^8zD`1bb`__ucnAz!@N3*I<0c$aLN1c6)q2_!ZO`zDCpM##1p;Rifd62=$%s{tL}= z!LStlOdni3jA8XGLl#w7(y?ys4pmjpbtE8JM_@Se3kpFrGH#DHy4Ezs!SZCYfYGqo zU4q>?5a_Vmoy5QVlgKbdl!5g8|5hM?B`E~AFW6m_$va?1d>Nxcfi6`E|5Jym zEJ#Y~(sl*Gur5f?&4(Zg3o1(r^e$tCto)mWAzqaEheL5>7lJUDRX zOs9@%CWRL3x*7=ds|d43G?Xl6;j~DoFA#$JgewW4a$@aJx8gm+=^IF;uAQsXsiG2odfaoiJ&2&vEpF3}KZt%xT#Jn0!%T)EUwo&G;7|JR!JdwJeIOdWAo zd%N9LaCqy6`+xIr5F+D5CBmdr+}$5Z^XDGl_4?iSEZ=>+9oXiu&4RJfAjVZEOuv-r z*!%XzEp_|%?mm1}HW?d^HKa)4qM7rh<|9Fft_mE-Kd;Hp&1h&iDT5N@cqHKsSkpP4 zuQ_q_!w>g_O%fIR6igNEnpEK5{^7~*FT3dDJx6k!Y-3%U%jET@wY$OMck`ts*b8~xm~e|me{=Ux4M^{w3| z<%vq5Oh>Dmp($ptB8R8W`|h0C)hG7vI-@vBa$Pzh=_pELFlYB)am5ujW(jY%tFq#A z(K~kSyZx#~4q8s+ue7dFilr)M4uq3I8{X|l+D=88(T#=G0AlEd>NYKFx!qD|d ze<}wlMaaOkh&DoOZ*`|c)D!^d#q4N!7Jvln)@C8w7*pTu3mde{m<|ekr5$6;v%J7N zzbxERG^7c<<14@b0UFRGb2?0;`qgQN!1DE7Uu>`0$R{I07SlthG-F)8uXuaSdjiM) zvoS^f(U+7iP9W)D*~PQ=Qys@vANsE}kC2L$hgJ2W-euLJ7Op<>U+Hc>De638ruY_I zTE6t_nGSOB#qwS!G~bZv0H!YMGRN2iLADDHjum`P)_^5qG>N9keoKX+FqmkGW;kI4 z3<;(b6_XUdgLjxCVZJWY1++>>s*bc+({!2TGH2#rJK9yE=#sgA2?I&MNHm+fu=M^5 zbLWGL!$~nnqL{49O7ESPIa^C12b!t{MccUPS&MX}3`-q<<(H9z*5aFr!VFh@bM>P$ zb1EYchZ)NSp-Cbp;;@a%bQIh&{n0{!R}6PB1fwAt)868&D{q_rppznb?co?5%VETS zciO63CVgKfhhAUzbO8G|v}3Tr&Ta2{|L+akbec5|56o4i5;1Ih@3szY;N(vfwi1sR)oZ*{aojYS@ z!8Jv8K_NG9-o_v%qRM0PZun8v?E>uiXtretM$uKD=c2LBi~%)5V=IS}h*2R5>ghYU zsqRe#;Udt}DAnM;uIa!;d-WlfG%S6x;{9p}tvfZX%!nH>l>lRCs=4E>Th?x7X=VV& zP687!5Zd+xK3a3=7lFv}HjS!ChGA*yROf~hof}@WIl98(d^`7bP6tF^5`<+sj?Y>c z>4kxQX#if!x~ba)CdR=aOp)b*-bf6iB*DPV>wzO(djYH>Xh|?83|fyA28^Q1gVO;D zW#ep|ahjhh=?1=yr8$n}Mo1b0&M^L(owwuE2|SABePa3~?+nq-q+)-PhKju9>8^}Q z&kSb@*jZwV&jK^XKhcbj$#lR(oM=DT9qeIJSQ6NHW!dHZk)Dn~2g8i8=9J&*&vxhS ztv|}psWA?JN#?j8&3J%GeV&I9&h%t@MBk66Kfut*VdoK(=1Nly1tHU6;~cB^JhZ?2 zeFrZlUCy3hgSNFvG1fHekt+ZEr4w$wf9s8YmzY#POw6(gxBh})9I1kX zuoAgA@4MB73s&sB4MhF3G1D>@J$ltEvGfnN2{ymiA@Z*Ht%b0nB8_8s#Hb9-3j9z^ z%mnI422UYUoG94A$a&p@&*O>h7ekb)5l_L`DHbq{g>ettQ(!P8isl5JvGD?Q>h*9w zw>uFPaMEJLCVX^KAJ_szR+?%EkyvsA2FoCoGD0VDaHlje=R z_koN4;%9WtFj_+}I*CO3vofyw*_@}AS3jQ1aVj<$XF{iv)?bo${qmWQ-g&_va(G@v z@fb=D7mQT6OWvhJf(v9;AW`=>sMtO&+9V82@ zTS0`?Fh*U$GU7N4=<1Qy7e8p< zQ{VYPeOP9rHg$+74Qv|H1lGOjvBglez>x>#EYFA050Y6tyQqFeIm^gJVipRoL@h zFK^R~nH>tF>875Oy_&}-*VP4j#%C~b7+u9_GxM&SkWtL!G(qB$%;T zmGj5kF)?$7$IY%g_L>^KDK5?&5*izSr`?egJ5T=cSjRgmL$nCv;TVczsl(0BtU{+L zx%PyFF0hf)8Y3Qwn+^)|wD$7;o9epu+8Bd155pM#o;uR_{3^9smzs|a3|#DFqDnLf z1D%(Y#_cu#`>#EJZ&US&#*#)cn4#s*8vj(&#+>eN`n2OcT|RyyEERf^U{1Eu19IrK z{kQNGIM~4)G#8B^NCsDrb9(@3>)p}VP4S$076B`dhG3%5$eyOPCd)&F2onv_sRVC; zP|v5Q_wX#)qlm0h5)6D@*1LApuYngj=@BJ?(NtJ&++6=0Sg?sQ0H)rmC?621(CyZyr_Ex zg&s0*Hlw_S9uWhV-O5m5=#F%%C4t$E%?uckbpcW46elau=DmtTGhJ9<#36EQ!!RQ2 zw(Q3Z*Io6@>L=R!Tl+%;BT&hLjDnCf&>QS$=#f~d$Kmoh)0(@Q=ySkW?z+!nrO)pD{b!xq#bF1ZrortG zhyG*EqX$|({IGR>QjB@Yno^m5;pOEwuGs!#ufvIxG0wBWkdqr#nwx*+w1T;h?D}^D zmK-xJYr!urTIm(ic$-KiW5L8&=<4>y&41bRs}bZ($(;9_%bpmt9Wn}0Vu0pR)cBF= zUWV8dm1THc?^QHKM&WpjRV70qnqt5l0KKDiS;1jdQ+1(_cF^YdObkP@hD<6cCJKXn zNF!q88H$sjJLpum^%}7F?l?>l>qBue3>zWj^kv&cPi$t5DqtL~bH$;~CPkHp%Yh*Q zSH>`GE<$cUJ{tzE1Gpk_{D#3t$i`EGj(DF?0>8tXq zFsqT{LZdDvD$2wNlo$Rdr`MDN4aHb6;JqB>q!8z1^F3T9Ce<{gW*f(e0t|GA^e~0J z>9#_0I%(uY5E-y$)U&Ea1)QR(;gHm?sFG3QgsH)i$K<#*UA1$gM9L1-m>HZ0iXZ-K(o%#Sml1Twgj3Esa!FThlckY>Tms6;`@1ob2mflQb z+01kytJ5fE>T;gRx^vdcOUHhXLQ1su$T}xtX!N%|x2^i@sX*}PEBpU*#r8YSsE9Kw zkP_uApL}Pgd-l)fzIN}d$Fo>kjUH}CSt;QiBx^=trh8!L;oe5S&Aq?ziG#hzJoYrR z?AhQQnne&XR^{eTTHbSt*R0DOC%@GQ!yGg|qUeq}j9GtX(%)AGR*gVcYcF z%M>Y)?w@g4@x?rwoo=(6DX<}OY&@_Lp}<>|sQB;yX zZ{hf#-&B6%r!8BR=$11vnlULFWlMLI<@+Yj%w3?X{j`uK5Za1N#u<;v@m#R5@L!PD zo1ZbKK=dd^p4P+|O;xciLmXS+yRgJFYJ1~*(@U<;gm}c5*=UazCf_$}w0nG8pshG- zUcTL_4pL-OLG<28dt={`GokKnwd*DoEwMAmv?)X61#73uVkfdY8Fnl=j`G%T94!cX08(;nOg&vI>MVVyG zV8qD89NbcO>{#o%w@&?KdPY%gsBfZ&9mJR$g65UT$@TShtlds);b->VSrbtTymah9 zz*u>Ld9SIVrej~f9&~E;2m5=bq?ri{WO6p7OJUA7CBL#Oc)Gk`$(Z~px+cZEX}p|G zP4!K^^&3wG8M&@D7_9Iy3DaQ(Oki&rpnV5l`1Bx*m^Bz1uu?$9J*9!7=DYXZ!HA7B9uQ7;e#6X)m6=Z>NnQoPZ= z1-e7D)g8^S48vlhs(WtPzs)sH;i&8iOtLW1M@@#w;Yqmg8j%y1B;(9fsG=$Z1C-7u zRzsLS6>19nJ-v6rKmJ_+UT?~QYeH|Ny4Ngs88vy>!=+` zj>})1Hsb5O4>yCErvvESwFN9?2htvP#=;;Id+dfEzF(P!eJblXCl5anE z;9;lD_77uB@_IquB^5c-p8xa_r_G)UGd*u!cd%;J-ru?H_N1v~7*uS0-EfMuf+TytSQ(!E zMQC?A=fzR7Vq#30a#Bo!C@}Jjq=vHt1v#$5FT#7$IZu>cB*A36MztuPr`tU^QI2`~ zCZW*j(Ae(am=toz{sKA9J`ZCsI?H774A0SE@5oP(q-YvL3&b^0cJMVkSSp6&pqUs0 z#sZPW@KXSKM`0V#VxZO_hou>w=7wN&T~P@6vvD+^fFX^*C=4$+O;;G;ri4b4?ntLJ zGXw+FL7?4mBTQyxJ8&5oQk*F@GhM(nNrq5ziq*GO-+lDdqxICd z>q@WP-}w0J$JblV*uWSYPD4z_vdTxsdZ_nnUaTH_Hy!@yiO(L4vQmHypFZ%PC>ds)*ZtqU_?w4&0BEVM@LH_EVdu6)x)!9eC;R3Y2() zKgdd-om1#$epR{qAr2XZsMHP&Xg z^1T)-H8HE*-l|;Q#9Pcz5&5oa2I0hp@fr^@({)yey-e8D@)3 zS{T+brPSl^$F4b}7IMUw;NcirET55o?KKnbsmL5lsBtn3BUV&pUNR|fmWUx_NybVI z)=ZwWl9cX_a9@^l!sm^fbz2cf1r^<}BUBV)ut`}BPA&PqPdl@_qlRZWL^!L8%q+f< ziHl*?xhp|{fpLhbz#MH1hJF%D5hg~ z+rEf=T0?fx$aD?Ed_M=Z1gXMtuCz3FRk1TmLCSDB#Z2$ky1#Cydwp)%5A%6JMf#BX z4vTTBy5ezE`j{TgQQ)^{HFtmX!l6fkuu%>6q(_TJz+MPKMy|ux96nXs{z{+hXl{S= zcu3{rC}0%h{UUI5QuYNrSI=-+**rC*{sbnG<+6&M&J+Dd%X1fFwKkwd+$^QXmAedL z0>^Uw7v_tuJkQCq$sX-k1iz!*f3lI5nATfdEsl<$tVx5*07)-$w- zsIeZ80lK-dVXc{j$cw{R34N{pkq@pgMZI!_uv=J6>->Q>V2PNmjZcsVRk5|0NiZxK z?$Og5jEA!6RG4jzPr}|+sX?M_vC^;->J3s#BBfBQ2iPe12$njcgok5dFq#~NQ(=1u z_DEkC$Z&EhIRYjg7E&na4m#}%T1E5;-C+c8j*K}wIoOmFc7{w=${9Q)a(&eubNa5} zQlt~XAXVf~Nq1*fGRuE;;lrt5XM-_e#pxwEo`PS^ewb%diW;3h zCe4|7_q1PvJ54ciRGL{{;42;(Q=DcN=NZ!h45T~U(LT^1u*s@lXdo(}8q<2i-6=6v zy{c~G`8>6#Ezn@&xuj{(v%whTRr88ouif7^P;ck?q%egPk_fZME-cTRMx`z%F{+N$ z+w-Q5fWf*tAoa%TJA@r|?;H$laR~OL1r6N+sXViCZ}XOqy53BRiEadGLf<7mTjm?5 zo=EqKNh@B?24fT%NWGEo0ONYIc2&A3IROVuRo{ZEC*KlQ`@Xc^NYlRrL&pv!!A9CS z(P3zPO*-Cnd|c*i zq;+quS*e+MP(o119~v+*qwLDA#`Tq>uG6KX@76w#;xOivY1n!3n0t$zXj}b;$wfCQ z!QJa?U&hfYG83jDZuaQAM~lqgYu}hT<}OA$u=eCLh{EUhQP=ovm}X?dRF)PxrM_k3 z?jM!)z3S|-&wa92kL5}Yj9J@2vqC6RKWW^3F744%n)toaE8jh_!VHRx5?U41!Ng1` z{b_--xF~lqtDM+b_ktdWF;D3+#Sh4>g(Y|0ox22-mZ#?)Z`)`VQbw~_@DF%k#=LRY zWID>yJ!KB2`f%$y6LTIfi=-PTx`c7Ui|+7or>nfa?Mv~_0hRe=(!7FE+h|$2rf{JCM&8NZ)&JB$149k#gB8kT|DTcAC zSd4Tk9Zm5{I$?AWH3HA$Rr8@C6QjYW1Iih*re!F`O3)#b+V?@~2&`_1TTdmPn zQ&sZ+|Bk;{fyw2t)@cEEt&hXptj5@(th1Dzq%4-jSF+g3?fOQj(j|+z-1h!tveWq5 zO?$=U{{Hk|GVb*t>OKX)$ZBq^Z5V&8;H3(pvzCC%=p$j9D}s~ z^tSu?>KPRnK8&|}r^Ls?yL4)3ZouN>_58r<`<|kw#F#G(fwrN{;L_yoXS361yWaoi zav+7Z7k8_`vZDX%h@;!^;pEw0xZTX+zNeXqV6V~i^YZB2%np9B;qCGghPi>v^MbL= zA(F!vg}3+Z;U<2riOuNX&%Y^#w4K=R{QLF*a;m}J>|va~BZ;_iw$&z&zyJUH`1}3M z@B6r;ly0rf@%sHLfv?xLL6d=enwgo&<%3YJ)gFkrE{nS7?(ZCny|&KX{r>*^{r&&{ z|EYZ|U;qFL(n&-?RCwCFSo>Sr$Qn)zmr{b|5?CZL1j17BNT8xgIW2f=4Y=5CX>n;6 z-MVYJRx5k#K^G|h`k6~IiFz*X^Q`B6_~D)TzImBU=H;7#dY*W6FK|7l5}&ej_khBw zi+YjOoc92&kf0v1&T6$9iA1V@5wMh&2GVmtIwDE^TjGsIBXWI=6^TU9=SBuff>PD0 z6H7-TY$w}cBR6t9X&s7yZ*WE$&W1CpJE4}d5jjpv(RAOF?jP&@o1^Bilp)=avRO9U z0rS3woyB09)%$b0q)T&YU7vfe_gP&^vyHiICks&NRNm{2Yh!>^2T7UIY(Z~iD-xO^ z27D8p*6|;O_uyNDe*mRQHlFQt3h(0uNgILTQh1TgW(y3Z*+EH_4wbG{H3~^nS|nRx zD;+1uqHM@7R`kMRy254)dPk3^J3t+@7wJ&&54KZ@gHJZ=Q|&`2wNdG?g^otiP@1JF zO3D^Ged-3P(Y{)hG)am`jVgR@Nz(QJr9zTaZLnIE)%vVG=)F6fTf5ug+}}}z*2rFomKtxUk<fr zq1(2Aorj@ihQ}TgtHYCH3uk9P6YPX-fz{z_lX_CyR{v{pmGBcN?N)1s{fZ;E&5h$! zY8{)a$E}|PZEjSF8+%1h*nesAJ&~@N9IdrGge?>kxPUug+Ds4z`TW430{1$I-N=EK z=|;p2Hv%5JG~5VcLN8#GrrC*O5i(dU}>r+K+x$DSP;xPy0chHlegj75 z1THq00iinhc>-MTY8@Fbh#y&~O*3uPbYpvvp43t)?7v-UWq&ouW0RI8nZa%ZoM+lm zWj{5M@%oNSlY`2cpHv3<)#ql`7z5BQz^_pNaglPa2L`f%bfd4hro?I zf5bAHUfRly0bieMvFvYk@zBeA$9gNn{*K(}rkkeELT=*5WO6r^+QqEaF$O5B*_4L3HE#Ugg2TRmFGNCN5Px`_{|)Ca;(f@3pl{RnJ6GcD-}AClo<^AV1u z*HQ%eVcu$_!eNV_ZQBB=;SQm};S++Lp-l=}W-U*!Gu*Kn`R#3shiyEc9|j3Md-gXA zLz@(KBR9YpkHpb_)&T zNin3C9xN>ZY3N3p&1lROkrt?Uw_X8m#L~{Vnk{okT4+qP#a7RhPPgcES;f+N*;6@> zV(B+aZ{IEqC5gP4C5Nb)o zjYl!zQs$#r8shth$c^g)cUkg|t{FXPH+r*a8NHco5~IWBHKQYGjE6Zt`OU!6q<}?N zhpSOi&7#2|X+(FzR={&SJTY6*CyyTz{8O|^LCbv0Sva-v+;I5s`SmnVYIEUS4wYSd zKb*BVB7X-2#DMKzhE&S>qu_PW_P4=E+%nVr$6=KuZHXbm>sFP4MYTt&40w+{E}!QN z&h=iO4RHAZC8Y-})5E-XiK+}7F7#^P9D+G0&6XSKb6J*&(baRs*)_^8b*^M&AdSne zv&+c}F1t#@A!ig1D!af1j# zL;JdU$m)v@U>VS8`k9PR2FFP_oMz&aZXNAwUS)QD`ysRJ0t-2`$-Yr`+x^K^r|d;# zx4k#HasoG=p|U&flrwST5IkP&Ua{~H43c75nKcfbxD^@^!g1Rx^XJHO^Bx!ce{r}8$Y!LMElj#evAF)Ce)2)y+`hsVAdn+O1iT{ z8Y3`kE3hZpj^qpffg5f_2VIV_(xQW^^As1Ox7jx6-~V>_$alebVGlNUO!m z^&+LGE2WTo1n-*b$%xMfjeZ2~rgR)sFvrQ+xQH*F3R_g~EDhZ_m~?g4K^tz=CdI}| z?Fl*rUrFh6=A+?8Uh@s~{lmLU15>Dy)@T*gwU8HGFZ=R&mq%^{S5QUDKsUn1x|E@$ zlK;-qrW>1fH#Tii@0#|Dr)axj=B{5! u7w#mTSh%0Ruh(4E^ThnUVDtIE1Q-D8w_mI!m<;Ct0000RCwCte0h*u$9Z4(yWiZ`?#}Fq z#qMGk7eN37K#%}Qk>DYU)>R=DQBtDFQn{FN$*~;Aar}qlN~~B#I!@$@T`HACOO#D9 zp(xT6X+k0?QY1kT(1JMkz~1-H?%dbAyVL#N%DbY#z-oqzJDkHeEM|DYr0*|Gbkr=NQI>gZLD;~<2M#=k*3>pO=xb$YXqMjhQS z)Xk#;*BboRdTi8rjIm{!JNkEg`g5PYdgbEWQh{5T8M*6@N5B8Qr^m;}w{P#Zb>XN3 z({~V(?*RLa^Zn|Za!WR#3R~;JI@tQV&gWH8o4>XGlPb7I9h<&b?ZbLZ-Okv^^3bYC zGH^2dhadUG>C^wfnb=%iNsNqM?dk3&8_7cS3p`8ZnHFRiz}QXKZLGE#y!qFZ)MFEk~pKdbIvdgJZyaf*l+cODZJhftU!Q z1fmMg(KrJcdli901KN)5dM3k>t{&N=mNaH`jwg$yp=rj~GToNxi*yh4w_iN_Zb4B= zuNa0SbE0Zy|INp}qUrTVE}!~wf%o5X^r(yrmo8rD+H+Jkl9z_Zciny*Wv51_;x`>U ztgKF585#z^gySR2p}$iUjrS#t$QrRt1O{Yv&>1oPE$ZuG8aNRF;3}59#`j27Z?!C9}+uNI(n^fH$eO;~T#qp&a z>f63e7Nkre9f`&`hO9uGOsw2=^PywS?JU`)Vl2{e6AN>w%!#ej?sFkm&qzBeR%>h4l&*y1?449d$25_Q=B>YApMO4QIAoLd5Zmu8Wz#W0#? zlnR<9G;E`)npz!IECsR{SG21=l1XPedIxkqY8uIofrI|MF2j6Q!Lle4+ioGGP;_ES z$ZAD&W7u70Y+>|&Vl_<*3{P7O4?cD`+uO;QB``LN$k!lj__Du?Z9A}bS>?;rG_`g6 zZo$gDf9~hOSg+sX4uzvg%@s<@^33pJA_vKwA*+;2yPLM(_mTU3Zn>DvM0yT)hvoC< z-`&3Fo~TUFRhrSPFAt=A_m2IQH7djwRK#5t-I_2;>ktURAF~3y6>pY z@?dBGgoj?0qrf+tPW41nPp7Y=C$|F0UqMriQf4 zV$NVRT}doVWQ!WhFxOnC^*^!SkIev0MFZPNn_zwgk4zKokrl$JN{NEWW+9r5M8Yh~ z615WpOLTf}#2Or?5{M#*)%|5CFlnQZUM34s6uDGGC@a=H8npju*QCoV(sF9c&l35F%EhH115?4Rg*x-_)_#^;cuAC6201B*qC zEDWLqvcfpBESni-c}TSaVh@sPkx*zfjB{GN-b48 z@xXm9m;A<0-^dq>#OZFuoPTkB)Ve$C8q9q2=Zyk^52lYAUxP^e_ULCnecK(!Emfhc zr~Dp+yx=+gg8PwyfYhaF33{DO{Eh|eMQsA1XzgrFdDxQYl#|&;;6}` zMir8U-DuXzFw<;2ucY%Fo%TB2E^ij%Wo+|COgh8prToO?e59?tDdKf_97eUGv9&ap z_J*58E0@S=(P$IV4((#?NFd8(mzEO65=LxWN1H6O#DCO?f)JT{YPlE;d-Ay=G314! z5pD|u62F->9)zfUX?{^r4WcluWNhEnD{}~&XtT>m#aC96*|zR&Uat$QYCUCurHQGW z#r5@VBQu3{y)sX9D#+N_2Ol_g=)iu)=9iE|-+KIsS1+x0#eBpgmR8b)cnCcC9&(ls zVF5s0{o?2TNNMg_IraSG-+lMQiGAnKTo61ykIc~-t}HY%?W^OXfA-bCy*!!e?udx2 zt{6ZT*)>sQb*Z_(`JYd!toqge@qJ!IXD-HDyjHqk1buQ9MtjP`D}$&1^W)zxah`Lp zypdz2j%Y~a;W~^1Grs=#H?J&YJ7WHo*+rM%BeKkT3?V-g=U)HgzkD{@9(A+E%+z8q z>TKrnYc2uFfpgP zcXpG>H_HIhoL8D2zV!Op5te6X7gDW0{GD$;^Zt19t~>Yh&{`9PKu1@2@bdJh{^iG$ zmj}-bUP)@gfdk#Z(8~b&A`@V~{o{8SU#mJl`s~j}?)}gKfey6_KxE8}r4J8J2%fMO zANu;Yo)2!@-P`H2GarsR-e>I1V$v5dfuXRHALQr9XX2^L=ii%L;sj8>TX|W!65X}i zYbl;!tTQA+i)<4@X9>qQ!N!+L7!50mi*pNazCA4P8$=P`#_s6~jL(!F{qX+Tg-l;p zgbb=@pq&E-y}KT)t0d&cY95Ng4&K_3bjaq5gd1Dy02u!DU;X>XzVI2sh$$Upz})2YavtsN@0_2S&RN2) z9qkfLjjiQ6$>8J3BB8FtIuMfLcCo`F^W6hIVV|_od@vxskdXbp%<|GoUhnVk_R9Q* zq@Jc07gyExCf746RRs}*+(6zzp5zDCL(w9c&+qyeBEx(jjw{>>}JOY8)sW0nqzy0?_9e?oHzxkA- z4todkw)HjvjbsTKF*Xr9;trS^!beT1S=T8*jw7A6T?_=eQODpzhDx)Y3pOk$^3>uQ zR$U)NSUO~#5S%jh`psD;q4YFRw(2<-;x~zBp`nNE776=8<%A@@yCV+w-$8vtoVNjl{@p!JUuV*{}^H{a0`?4Dpn{0OM(jP|LUR zWX?&l>Zz54QS=5vf*cGJQn2Y@??z$>i=vKoLkRb)+AGwtL5A!X9&E_yF%Zf;Pz`Jl zPKas9gB=)CgCV|*e6Q3P11lJ%F@|hef+2TQ;@7xx!uX$&H6syIzVP(7PG24`Fg(); zqvZ?FeDB>KzIfFjPP*QS9QoK()ffKvnU{Vti5V6&NN+-sTbf*a@u$;vs;#1G0RQvFHyDgiTZGfN1{$x+D2d|#J4SJZ%IuEDH=%`X|cvlu8c*6GvJeMkDEE}YC^ zW;2FHR>&U|+_IwSCafn13jD~av593x6%&i8l3eDM_}7&CqBJlE%oJQlv$1j#R!6!* zfAQ7hz(m+oOVk}~!dRv|D1H7j0}P3_v=RoMIv9)und#mY>E0d2s#3zNbC>%y*bWkG zA!I07Q<2c-oSWhdiG;8|NMRXH;OnO5u8mQyR}L~br<9;#J2(m2+pysPEDbtT@*2hl zVPq1bwIu~)rC@iVbXU&c8(J1*%FWw&cdVctHx1$cHO3Wf2X@TI*=Cl{jK5?Q7Ra0W zLo`)y$DMk9LC;M!!Z>m{S5yuU|wL_NJhOirmsq~Js_Z6e1 zhJwvJWQ5xDBIqOpmCUk|p0NrO{*VP3t3d@Fje^oEqkwgb?4l>!fz}x3`uZ}8DY0%I zUG@0ZW5D{lJB+k!GG%B*5l+b7*d{g!ZY(CfGVgA?gPKx1bi)kKbCSQJj>^R{P+&=< z$0-F`hQkS*#BannA_be(={mzx#>q(@R`N3yXGxpp7>XfVS8IT&dK{6Xrc_ZF&Y*2d zUeYmp7_}G+VXY2^cu*RG85WRuTCJdNfk8m#fNml~WB9D22X2k0)CRSXWm3zj!Sl=A zeH~p*kcPhi*A09j2S*0Se{a+2pIo&3;oENt*2QSN zYfrEL^jq_teQlkwGAkvjU~nDNXoqtmGj?hA#W&|MnOKPHvp=$x1a4(y<{RG~OcgDr z5e#Eq;yFY4;g2RQrmi%*MWVIE#54bR>4lfCzpXF2Gi1K{)`Z14eM5j^REj|c!B7~BmS)o|7KYv$UCNsdj>rM)V8}E) zZ9bM~_8;r=%FxLo5;*`Vl@@JLgo^5>Pv96AXPD)3oDHIYsfStvU9Il;Qb9Kmtih0< z=+@hMn*8GOd?wl+jroPVV%Eh3WsV8BkKNJ&O_Oe6Co$^S4u{`BBM%vI&E{dYm`|$M z>W)~fk+fB20wYy}Ax#yz?j2IsIm7Z`FPoxAL*z2kK$l^~ZqahglsPoKeAmNGpcF5c zOPU#=yI|QUI2?&1+|lo6q1%AwD!^WP!%P8#hYpvghM1KEg@x9>-LWojHk)+8^%xA_ zd28t6<$PavPil4whJxLJyqzA(4M_|b2I%u&*eM7WFjR;o zunFU2LtA%>Dn_k09!B6noB zmoRz}6jdxSn=ud3sl55i`{_o8#SC)SkaR+9k)^^~Gs$uw$U|%>$kc#R}|2ZVobNNCFyQnvF5lvRqqEdA2#bA{lYs-gI`Rt`ntS&;?IR6ksKtH5y?Yip99w zByV#r*`;M%^)qn<}ytXEmpP>MwEOVjOSW%yj}Dx z!j5REHl^SWl?%WIMXU@mc~=AyHw0ag?<=>y=hm7C8U&lP!1x=HA&tPHvi&B74guo$Mk`l;u!hjid{-#Dl)!8QY3Mg(koy zIaJGBc{^KA45eU~X_#h7O_482{uU|JUQXdS7{e~&U_gBg-L=F7+e}fk>n~JAF*V3Q zIT(`yZNSl56~j3>PQ^?VSeck3lU4Dl+=u!I)@IiRjN`ADXI2d;w6(YPl z@$Lcd=J0xUwWKp_n*`4;lw2-;XN#Mu?1&mUQ0R!c$ImYSm%FD!s><24DvWA;yfyhvtmWIFvHe=waPixSq6^VD-Asd)06Po4VCKMbZcTy2e6D+{Bv&m;^| z2>Tzndk68CvEHUgvv!;!2o3181BT0 zzSf{Hb9U_Qi$$PY`J&0dD#l^JCLzZs?%UPulLVKvf4l$6rRj`@Dlii`eALFYhFy!( zE1F_WP0r0{D(BwyWQd~P163}K${2*Tt`leUm`@9CoGp%;J^*FVbEr! zD-cOED<9Y2K0Q{5WSHf#XI@_T-QSC1v*=)ek)f>ANzY>N-s#bcBZa|t-AT>hHH5Sz zt+@a;D>Y>2!J_xx8-4#$VPMaW58dW}Z!%-5DM*%L>% zt*yXXIp;3sW1&(YC~B;tDhW5PsT_pmgKIKiM22cT^4S5*va-PJ+aHlUhNb6l*?^if zkK&xzA$;_B+kvCV<3<5KboT=u38ssd#6tV{m*|CVSBlwx#0s{!eYg1T$s2Aio3uo> zd_-)PkK_$-;I`PV!%>e1HSyj%?r!rj*(8Y_%P_mB$j0nE)Dnug_jGmZtPph-a#^2U zTwh)t37`kFNVJNJ< zEGpb20$NIhsIA2at{2r_5#^{S zs2Xl?)XaMVvP(L1`nB=V0IJ6+OcGa^svrk5D_h9{Vk>=C&VIay=+5+YoKW(s5Z32* zGC*>uk9W1G`Tj;2$9IbEu;7kZ9gj44>hroV4ovd45OpB*aHEq`D$3ikNAkAGS1?#= z#5jH74nf{6BVh|UvbTxaT5QuW$nfd$XJtvP&q^Vq=Htk?U(b$8TxtteO6+JhF38Qd zYD+(q1Fdx#=k;Lhovvk*A;I5oCQcH))PFd`#)$rYn0!TUfFX=CKNIG!B_|!1nh*Ym zG7TdjPH_2R?Q4vag=Kq5)P*3Qk`)X&LH4!u*09oYRtT5zmSrp?$%6DmI$cfM%8av$ zVVo!l)xkJ0`!EsMj}u`-Gvf-;p0|118k?-aAZ+LaL+FjCxw{UgTww2F!uotFfWhs*PYNGxaEY%uypgWesy7KXu9;f|L$0&MsRISQ_T6rTOYVNKQexCiTUHN z9NtvVKr!!}o4@}vcfhN|FV3+4^|6})&^KdFUs&3Id++&oM)w`r`;iYts~xGdNgtmh z{tY416eGd=j`bk27!hJwG<NO zZs9+D^>t6!Lt3=!r=1+9gIRszYcG!^bRWpXi@J>Rs+xoKFvF{A*sZt4T=ChJY%asX zI+&pqr8R`RIz5v^ld4u=fE~WWa(xH1D=szXsKC^v2Ly zZ)3`=RJT6-&^FZsqM$wY#Q|2ZEG-Fe*q$eyMDnyfis@2JEWmtoGyA!lx&tto#9?L= zrlg~7eeQ!d4cr%3qpnOkT?a$u;9MXAe)|hM!(1wX*Rp5ktDr@L$ea3k`7^ld94{;2aO=MIB zHeizuhRv+3ibbmt#u5V8#xUEUeH!MlQX|m!h>}}r#5koULKAw-V2_eJvNbF9dm@56 z1mM5LxWOMIxeiPj=4;_ZFXX%cz(%5czGlG{mIA#E2`)|axfxE_8pBI2dLm_)yU?1( z%*69N%rs)9S}_5v2es@~&RV)gu5{HaHyQlh$!Psmvn~sV89qQ7{qC3)v zab{Nh(ObSEajq?^&?xzn{O#8$RWo&JO6}TwT5lL^>se!*O!=8~yE=_gQ=($&3=4y; zJvFS<+5664_^_X!N-QLhsd<~C?xyZC<6OhoX#|YwV9MukuuNX*<7iqkt{_YIx3o#Y z_A;BSin6;$La){Nq@D6JuA`O}ZC$G7I9hHkn6PM8%DJbO43_73k=08oqTUBNac>pl z!02Bo0W9GNs%i=%pVV5{!Wv+0E-k9dN9`R8Ao)n2IRVKv4D&mVv;E@b1a;1z*eW zJi3Ruv4w58rp(q(mRpuPRbE&*xO^(jbtra3v zpVx;SeZfqsH2BtxFV^Y-rJ1D0-B^88NIDHJu#v<@8ls$PDse^qm(2%-`MCYc0X&EIxgQ`n#1x1+^?R`1>>QC}@^PA0tw?Pq}? zrcX{0@)xn#)XMzsy}{l62$YrqqKp$F1)u_?F*wCEA>7o#9Y5k1L+&Oak1t2&`A;Q`&b#ay)Q(WqN1$X{K}!r zkrO=*=0hJHpmkqL=|<{;Y;0n~U6M?b=(?JV&o^SFYCg%e;w>Om8su%VO-=Cp*F$>e#BznTWFVUv_yQE1OJT zxU%}>_g~Hqz0J#Kf%I%AlKtTWVD>o{3dLFB3f}4mv6lRY@vpVn0kr zG$SDwQb{dWOf6GKDpp7)l#5-#t$?F`Mo&W}9uWYXf=nhE2Q(%RZe2TNN+8F{u|q5k z#=4k{m1s{wBuzRRIx7^8g;QTvIt&X7XIM4Enp#UgA(V<$QAQ_IN-JDPCsacuRY@os z4FFX_B0Mb7he38)jH9ZBi&R9S}Gk z1g@{18zvyfzMhkeTuVPC%g3d@x0pF64m2wneSUJp(2_ebBzo74{r~_GeMv+?RCwC7 zmk(SN<+{f~TuCw49Y&3ds}6>+e=^8Lq)~KS8{5J4V2Z3o%c2V%#?#QEyUMzWiW#WW zb&FulB|Ujc4vG2i7A>sBQU)KilOdXC^B6}?Na)$?z1<@Bbi2}-KtrKG1uv5QSST}MmOg++U z9x;E!h#$pWPyRoJBcDh|!qgkg<>6;;`-Tf~$H`wL1dphvz|`O7ov~UA+YN@4q7-W( zgte$>APTK1Li_@u&5%-PwNiOc!qm?kDJpC~Q(m89O(_h0g-;>sGI;8C;V$2hWDS%n zttnP~HgY}XNMT`4(mnTVPXXUW;6e;=@UP8d3ftNY?FI;Fq!`-T+S{#$loYF>FvVbK zPib#U2~Qau(T+SfWZ#p$JjL2QBILU5z&-CikzH>UuRh?Q(D3j_{S7&L&R)s8(tz)| zlDz!vi0gTU`LPeA%v*V5f9%cD*azUhFB+uyMb@I&q=ux}CWC7r*X`Gn5)u}Kht^0ab17$zkHISsA6`}b zK*PGjs}3BlT7~6)RA`ObULh;lZoc^L&7x=iS~zS3S|f&ngoK1*$o1@(Q9_P{w_EGC zH8dFpt}X;51a6?At-TFy9=d@B!{2|1yP1bhtHa>GOXnLZf*B#S0pZ0>w`V{Lc!SBW_{p#`@W_p{fWm zTZs8X@#};mIUaFpy+=l-dt{z;62dK$)yZWtd7TzwxPbox!L1iuPid56Icm8%$1GRp zU=Vt_TCZ2D^*L(w&k63I9U&$psK(T?Mz!9oM&WL(lQm+{5rxOnXfX={CT}F&vPQWm zcp5DhOccy=i^bwmW0)v-JaV;JuNJ5N(30b}fBVRdU?XyXUEKWf{>?XnBwSsOMScEx zRb!(p3zN%B-zdIx^!V&>IS6&9KEJTx{*S{k!E@y!2R;tUkZ-wq|F;Kj$UKmS&~4NQ zw`9M(x$=>#acAepCF#Z3%~czYfq%8+mEi{mzzY#sssL@3v8dG5(&k1bvHF`0vTByTPXTMB%$^xpq^__1*)-&kYxqBUZVV#>+WB=>;~jlZTU3YcK;tfLAl19OOKyCxhU4HHoMVAzXrM9bFJ8ZylREo zt=1g3sj-RN<-0B?aQr4-fJs0L$B25q2A)vjyFLxULy<%RFw2$Kt`vW;15?Sj?ZuEEt%B zw%iRJ-I&^J*2^qzk3|OS1x9=#Q_HldH~c@KTZI0C>u-Z#PYoBsQ0Bme-YtifDn}=O zy&z1DTw`i|C`5x`LHPBn1#BSK=t5@UV#tA7aG;lm9Na~~^m30`pYDO3-a3zB*_A)r(`DW#HfDk%~djwn+Z4974=V^@!ZQQ|dSLYv_krAJ6eqiD}OXiYEH12y&&0#5LD zhPK)HR=<|gXzX^Hu5IQCrPdE^8}0S#{3_Yw!*eZKgU}D;T7P$e^cs1dG1`vp>mZ#z zqr>6l5;Lj`0@~glhr?*xJ*~Rf=@D`rRGXn1LYUP#LXlGs`M#T=r@RcUu``nR_4O{L z5BxJNiCdqpV98AI&lnT8?%XcsdP7i-4cLR)IbcnWD%stIfQ`3%dEOSk@Ssb{@k|d- z&z<_o1-eryD477FdE`w zM8r0y*3Uy*vH01v1+LK4f<3cbv?hdl!1G-N-0rp6>4yaQkf3B)*6G9p0jH~uqHx>^5ugHOIu&pQluokS z6>x=aqn2e!Esi2RT}!gK*2Ur^$ztdvuElW(jMb7jt99Wx=}N~!y+N!?$6ndqqLB|2I&aaU_EL9}KPL`RE6D?vvHf3HNVY-uHk-Wr0a>BU_&HgqH; zL^2u3tm!~)7({9N;b^NtgDElBL5a>Tb!ZqVVZ(77&q#H)9!AmO*Q#{T)^r&!UXqZK zT{pja zG%Dgcg%dj1Fj3{vCAyI7@Ls8gW~7q%2OC(Hk@B=x+P`G#J2|doX)o>dmCjnYk02#d zFU|XmyLar|r)6QAYkVE?qu++9rFK{?x|r{Fyy_xbd^Xef3y+;kgDrzxUkE1G@;Xkl zc*erzeI(cA;B>~!$>+9H774?1m$~LwW{yADq+)cO!>IE~A1Z)OoX%k+mQ+tIXmT=~ zPRG%U7tT1{t*tTY=(%a5!oGgOJi&rbp_a zJJ#-q%ONEiUJ72h#c?kvVaxbnCC68XUFlY8G(IRvEz@5c^Hm>|CocEg$c*acPMMhN z4#wDJWE68Jt_TFUS|h_5o1wxeaX%DH`1bmAep~`A=w(YSuu)J{yNq2Q(7TPTP*kC9 zH11maP8TYwsEfu|Yg7uZuZ2rWC93{piIPeV;BZ83oa$GRO7Xl(QmVqK(tedBxnH96 zC$nrnYJ))ZlL0uQwo;kwB%!keP2?{XU0<-IYb|&kX(8)KkDSFV+B#eY8-;Y&;iLtQ z7T85@ZD-S&U}tCWOlPOZje3hC%rdeLM&NZa8J;e;3<~LTA=g1l1>8{~4zaj!6r(O6 z9F+lRlX(-DIJ;}{*I99$uck2hr+J34T*LSVIUEj@le zsnU3TI+de^G5MP+CcG3m;iU;{0@q13eu08Am##XOlu2>{cWTD%>EQgD4C z*lLHmK0Pctqrs(ZfxXzgb>y*g+m+pZ*unpp9Cz&2JNh#ft0%nl(o4%@f8Vh8W)ti` zV(rY_Z}wexA%M{rGb;abdJlyF#`mtBxiu~9yjENxH9if^NB=QqX9Jt=_3?Dg#;~=A zo=}qgurpgH&sm!mrtdtArk+s0a?JlEEbjw=DZYRG*v@x4NCYr?_w&>KxFd`d0LFh` zwrOja+#*ix*Li*Yi^oSyEpP>F4x_z)>+4^S-lxJP9A}qIo^*E9X?;`0eJCN=rH|j= zyu1%;SjY5*&uyJ_RR9?G-hWJdcE%HZI0Be|`uKy#jSMKo(xt zLZ9+0^^^!OvYW+20Aq&(%tZz$S7_=Gj!3Nw69EQ6YDIt{9Ki`a+0@VD{bw(x=1BlxI&W^}^_b)3k^lmjt~nwK_(TD~xWv@6 z@Z-l}@fl&YNOLPc5CE1L6Oq>%wZ|DMsx?xLKX-iUYY(n+2>@%JHF4C8(+FVn+!;IL zz8MvkBLK`lJ?-u1#xG|9V5<1C^;^@{!@8E*iNsqw_ubk#h6RAp?~U5IVD5tl@F9Th zdhgKIXJ2`>NdTBBe$I}Jw_oV=_h_1zyuGz7e$sgh0vMhD{Q8TBmb(C8^x{`eN52(z zT?+u?n>Q|8HGS#>EC7tpoV@V4jZ@#jhXCfyKQ}XDVnJUWDo>e{Pe=VF34`*)#~dnq za@x7WN*n>qHvQ@K$7WQx0ARg;etJ&E({suZz_|S9%c`F|w5AWrQ%~Zovg#S5!^mL( z^Ezm$^fDy?%-E&Kow-7S0MwdKtnSAEd*f#S<{S>N^ngl$mJ>P!>VEPKOf~cd7RogM4BkN) z#{j@MuGZfb0+`X^+f^&%+TO+KYFp{cR5}6}#{tAb0CO0-YQ;CO9=IW#eK^4E#u`Ph z*GAwtS|Nl@k@(OyB?6d~CUh;m3V<0rmT?5V`=OchSrQ&`dV3W%DdE?mM;z4l(V;gm zf?zKDZK}|^ZiQ-{F>%|di486n04({~xlKzZ6{su#Fgkx!*vRLr8-gk+N6*cem^$^X z?Va!jMohmI7dbjX zTG)5DCe;JLdQCCY%3d8=eFcZzsF*vgEOqLG+g(mCW14@pCXRJSu0Hy<>ICm3;Lk-d8zcxPO z^-*ya)&_51qhEh$#`q&z^bmY8e$uq+Lt|VBU|xIfTbpLBamk(v0jy5bmkj`nr-_c{lCvRz5wuC+xBI&RV7$#{YToZ7v?{5wmxgj}O185u zcx&``_!Fb9HzR=2yCcpLrVgn9FpWJoO5<-)g?1w@0F3SIb5fKm;6!+W2mrtWYyc17 zE|%2?&CCZDL^>@g2R^{lM=>-AY#UqD=? zv$E(fg!m=GRZ&Dj*45*S?+v^6{fNh>JU(U0?eVx6zgpOk`x#9An|*%6ssB%a0RWTd VX+#1GteXG;002ovPDHLkV1mX%`Aq-- literal 0 HcmV?d00001 diff --git a/static/lib/timeline/img/themeswitcher/theme_90_trontastic.png b/static/lib/timeline/img/themeswitcher/theme_90_trontastic.png new file mode 100644 index 0000000000000000000000000000000000000000..f77b455fecfa7f6f7a07388f20ba00c5bd8f3804 GIT binary patch literal 4191 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 literal 0 HcmV?d00001 diff --git a/static/lib/timeline/img/themeswitcher/theme_90_windoze.png b/static/lib/timeline/img/themeswitcher/theme_90_windoze.png new file mode 100644 index 0000000000000000000000000000000000000000..2b8c3bd3ab5ce8893a23661f3b18fcdca5e52174 GIT binary patch literal 3370 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 A4gdfE literal 0 HcmV?d00001 diff --git a/static/lib/timeline/lib/jquery-1.9.1.js b/static/lib/timeline/lib/jquery-1.9.1.js new file mode 100644 index 00000000..e2c203fe --- /dev/null +++ b/static/lib/timeline/lib/jquery-1.9.1.js @@ -0,0 +1,9597 @@ +/*! + * jQuery JavaScript Library v1.9.1 + * http://jquery.com/ + * + * Includes Sizzle.js + * http://sizzlejs.com/ + * + * Copyright 2005, 2012 jQuery Foundation, Inc. and other contributors + * Released under the MIT license + * http://jquery.org/license + * + * Date: 2013-2-4 + */ +(function( window, undefined ) { + +// Can't do this because several apps including ASP.NET trace +// the stack via arguments.caller.callee and Firefox dies if +// you try to trace through "use strict" call chains. (#13335) +// Support: Firefox 18+ +//"use strict"; +var + // The deferred used on DOM ready + readyList, + + // A central reference to the root jQuery(document) + rootjQuery, + + // Support: IE<9 + // For `typeof node.method` instead of `node.method !== undefined` + core_strundefined = typeof undefined, + + // Use the correct document accordingly with window argument (sandbox) + document = window.document, + location = window.location, + + // Map over jQuery in case of overwrite + _jQuery = window.jQuery, + + // Map over the $ in case of overwrite + _$ = window.$, + + // [[Class]] -> type pairs + class2type = {}, + + // List of deleted data cache ids, so we can reuse them + core_deletedIds = [], + + core_version = "1.9.1", + + // Save a reference to some core methods + core_concat = core_deletedIds.concat, + core_push = core_deletedIds.push, + core_slice = core_deletedIds.slice, + core_indexOf = core_deletedIds.indexOf, + core_toString = class2type.toString, + core_hasOwn = class2type.hasOwnProperty, + core_trim = core_version.trim, + + // Define a local copy of jQuery + jQuery = function( selector, context ) { + // The jQuery object is actually just the init constructor 'enhanced' + return new jQuery.fn.init( selector, context, rootjQuery ); + }, + + // Used for matching numbers + core_pnum = /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source, + + // Used for splitting on whitespace + core_rnotwhite = /\S+/g, + + // Make sure we trim BOM and NBSP (here's looking at you, Safari 5.0 and IE) + rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, + + // A simple way to check for HTML strings + // Prioritize #id over to avoid XSS via location.hash (#9521) + // Strict HTML recognition (#11290: must start with <) + rquickExpr = /^(?:(<[\w\W]+>)[^>]*|#([\w-]*))$/, + + // Match a standalone tag + rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>|)$/, + + // JSON RegExp + rvalidchars = /^[\],:{}\s]*$/, + rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g, + rvalidescape = /\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g, + rvalidtokens = /"[^"\\\r\n]*"|true|false|null|-?(?:\d+\.|)\d+(?:[eE][+-]?\d+|)/g, + + // Matches dashed string for camelizing + rmsPrefix = /^-ms-/, + rdashAlpha = /-([\da-z])/gi, + + // Used by jQuery.camelCase as callback to replace() + fcamelCase = function( all, letter ) { + return letter.toUpperCase(); + }, + + // The ready event handler + completed = function( event ) { + + // readyState === "complete" is good enough for us to call the dom ready in oldIE + if ( document.addEventListener || event.type === "load" || document.readyState === "complete" ) { + detach(); + jQuery.ready(); + } + }, + // Clean-up method for dom ready events + detach = function() { + if ( document.addEventListener ) { + document.removeEventListener( "DOMContentLoaded", completed, false ); + window.removeEventListener( "load", completed, false ); + + } else { + document.detachEvent( "onreadystatechange", completed ); + window.detachEvent( "onload", completed ); + } + }; + +jQuery.fn = jQuery.prototype = { + // The current version of jQuery being used + jquery: core_version, + + constructor: jQuery, + init: function( selector, context, rootjQuery ) { + var match, elem; + + // HANDLE: $(""), $(null), $(undefined), $(false) + if ( !selector ) { + return this; + } + + // Handle HTML strings + if ( typeof selector === "string" ) { + if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) { + // Assume that strings that start and end with <> are HTML and skip the regex check + match = [ null, selector, null ]; + + } else { + match = rquickExpr.exec( selector ); + } + + // Match html or make sure no context is specified for #id + if ( match && (match[1] || !context) ) { + + // HANDLE: $(html) -> $(array) + if ( match[1] ) { + context = context instanceof jQuery ? context[0] : context; + + // scripts is true for back-compat + jQuery.merge( this, jQuery.parseHTML( + match[1], + context && context.nodeType ? context.ownerDocument || context : document, + true + ) ); + + // HANDLE: $(html, props) + if ( rsingleTag.test( match[1] ) && jQuery.isPlainObject( context ) ) { + for ( match in context ) { + // Properties of context are called as methods if possible + if ( jQuery.isFunction( this[ match ] ) ) { + this[ match ]( context[ match ] ); + + // ...and otherwise set as attributes + } else { + this.attr( match, context[ match ] ); + } + } + } + + return this; + + // HANDLE: $(#id) + } else { + elem = document.getElementById( match[2] ); + + // Check parentNode to catch when Blackberry 4.6 returns + // nodes that are no longer in the document #6963 + if ( elem && elem.parentNode ) { + // Handle the case where IE and Opera return items + // by name instead of ID + if ( elem.id !== match[2] ) { + return rootjQuery.find( selector ); + } + + // Otherwise, we inject the element directly into the jQuery object + this.length = 1; + this[0] = elem; + } + + this.context = document; + this.selector = selector; + return this; + } + + // HANDLE: $(expr, $(...)) + } else if ( !context || context.jquery ) { + return ( context || rootjQuery ).find( selector ); + + // HANDLE: $(expr, context) + // (which is just equivalent to: $(context).find(expr) + } else { + return this.constructor( context ).find( selector ); + } + + // HANDLE: $(DOMElement) + } else if ( selector.nodeType ) { + this.context = this[0] = selector; + this.length = 1; + return this; + + // HANDLE: $(function) + // Shortcut for document ready + } else if ( jQuery.isFunction( selector ) ) { + return rootjQuery.ready( selector ); + } + + if ( selector.selector !== undefined ) { + this.selector = selector.selector; + this.context = selector.context; + } + + return jQuery.makeArray( selector, this ); + }, + + // Start with an empty selector + selector: "", + + // The default length of a jQuery object is 0 + length: 0, + + // The number of elements contained in the matched element set + size: function() { + return this.length; + }, + + toArray: function() { + return core_slice.call( this ); + }, + + // Get the Nth element in the matched element set OR + // Get the whole matched element set as a clean array + get: function( num ) { + return num == null ? + + // Return a 'clean' array + this.toArray() : + + // Return just the object + ( num < 0 ? this[ this.length + num ] : this[ num ] ); + }, + + // Take an array of elements and push it onto the stack + // (returning the new matched element set) + pushStack: function( elems ) { + + // Build a new jQuery matched element set + var ret = jQuery.merge( this.constructor(), elems ); + + // Add the old object onto the stack (as a reference) + ret.prevObject = this; + ret.context = this.context; + + // Return the newly-formed element set + return ret; + }, + + // Execute a callback for every element in the matched set. + // (You can seed the arguments with an array of args, but this is + // only used internally.) + each: function( callback, args ) { + return jQuery.each( this, callback, args ); + }, + + ready: function( fn ) { + // Add the callback + jQuery.ready.promise().done( fn ); + + return this; + }, + + slice: function() { + return this.pushStack( core_slice.apply( this, arguments ) ); + }, + + first: function() { + return this.eq( 0 ); + }, + + last: function() { + return this.eq( -1 ); + }, + + eq: function( i ) { + var len = this.length, + j = +i + ( i < 0 ? len : 0 ); + return this.pushStack( j >= 0 && j < len ? [ this[j] ] : [] ); + }, + + map: function( callback ) { + return this.pushStack( jQuery.map(this, function( elem, i ) { + return callback.call( elem, i, elem ); + })); + }, + + end: function() { + return this.prevObject || this.constructor(null); + }, + + // For internal use only. + // Behaves like an Array's method, not like a jQuery method. + push: core_push, + sort: [].sort, + splice: [].splice +}; + +// Give the init function the jQuery prototype for later instantiation +jQuery.fn.init.prototype = jQuery.fn; + +jQuery.extend = jQuery.fn.extend = function() { + var src, copyIsArray, copy, name, options, clone, + target = arguments[0] || {}, + i = 1, + length = arguments.length, + deep = false; + + // Handle a deep copy situation + if ( typeof target === "boolean" ) { + deep = target; + 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" && !jQuery.isFunction(target) ) { + target = {}; + } + + // extend jQuery itself if only one argument is passed + if ( length === i ) { + target = this; + --i; + } + + for ( ; i < length; i++ ) { + // Only deal with non-null/undefined values + if ( (options = arguments[ i ]) != null ) { + // Extend the base object + for ( name in options ) { + src = target[ name ]; + copy = options[ name ]; + + // Prevent never-ending loop + if ( target === copy ) { + continue; + } + + // Recurse if we're merging plain objects or arrays + if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) { + if ( copyIsArray ) { + copyIsArray = false; + clone = src && jQuery.isArray(src) ? src : []; + + } else { + clone = src && jQuery.isPlainObject(src) ? src : {}; + } + + // Never move original objects, clone them + target[ name ] = jQuery.extend( deep, clone, copy ); + + // Don't bring in undefined values + } else if ( copy !== undefined ) { + target[ name ] = copy; + } + } + } + } + + // Return the modified object + return target; +}; + +jQuery.extend({ + noConflict: function( deep ) { + if ( window.$ === jQuery ) { + window.$ = _$; + } + + if ( deep && window.jQuery === jQuery ) { + window.jQuery = _jQuery; + } + + return jQuery; + }, + + // Is the DOM ready to be used? Set to true once it occurs. + isReady: false, + + // A counter to track how many items to wait for before + // the ready event fires. See #6781 + readyWait: 1, + + // Hold (or release) the ready event + holdReady: function( hold ) { + if ( hold ) { + jQuery.readyWait++; + } else { + jQuery.ready( true ); + } + }, + + // Handle when the DOM is ready + ready: function( wait ) { + + // Abort if there are pending holds or we're already ready + if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) { + return; + } + + // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). + if ( !document.body ) { + return setTimeout( jQuery.ready ); + } + + // Remember that the DOM is ready + jQuery.isReady = true; + + // If a normal DOM Ready event fired, decrement, and wait if need be + if ( wait !== true && --jQuery.readyWait > 0 ) { + return; + } + + // If there are functions bound, to execute + readyList.resolveWith( document, [ jQuery ] ); + + // Trigger any bound ready events + if ( jQuery.fn.trigger ) { + jQuery( document ).trigger("ready").off("ready"); + } + }, + + // See test/unit/core.js for details concerning isFunction. + // Since version 1.3, DOM methods and functions like alert + // aren't supported. They return false on IE (#2968). + isFunction: function( obj ) { + return jQuery.type(obj) === "function"; + }, + + isArray: Array.isArray || function( obj ) { + return jQuery.type(obj) === "array"; + }, + + isWindow: function( obj ) { + return obj != null && obj == obj.window; + }, + + isNumeric: function( obj ) { + return !isNaN( parseFloat(obj) ) && isFinite( obj ); + }, + + type: function( obj ) { + if ( obj == null ) { + return String( obj ); + } + return typeof obj === "object" || typeof obj === "function" ? + class2type[ core_toString.call(obj) ] || "object" : + typeof obj; + }, + + isPlainObject: function( obj ) { + // Must be an Object. + // Because of IE, we also have to check the presence of the constructor property. + // Make sure that DOM nodes and window objects don't pass through, as well + if ( !obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) { + return false; + } + + try { + // Not own constructor property must be Object + if ( obj.constructor && + !core_hasOwn.call(obj, "constructor") && + !core_hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) { + return false; + } + } catch ( e ) { + // IE8,9 Will throw exceptions on certain host objects #9897 + return false; + } + + // Own properties are enumerated firstly, so to speed up, + // if last one is own, then all properties are own. + + var key; + for ( key in obj ) {} + + return key === undefined || core_hasOwn.call( obj, key ); + }, + + isEmptyObject: function( obj ) { + var name; + for ( name in obj ) { + return false; + } + return true; + }, + + error: function( msg ) { + throw new Error( msg ); + }, + + // data: string of html + // context (optional): If specified, the fragment will be created in this context, defaults to document + // keepScripts (optional): If true, will include scripts passed in the html string + parseHTML: function( data, context, keepScripts ) { + if ( !data || typeof data !== "string" ) { + return null; + } + if ( typeof context === "boolean" ) { + keepScripts = context; + context = false; + } + context = context || document; + + var parsed = rsingleTag.exec( data ), + scripts = !keepScripts && []; + + // Single tag + if ( parsed ) { + return [ context.createElement( parsed[1] ) ]; + } + + parsed = jQuery.buildFragment( [ data ], context, scripts ); + if ( scripts ) { + jQuery( scripts ).remove(); + } + return jQuery.merge( [], parsed.childNodes ); + }, + + parseJSON: function( data ) { + // Attempt to parse using the native JSON parser first + if ( window.JSON && window.JSON.parse ) { + return window.JSON.parse( data ); + } + + if ( data === null ) { + return data; + } + + if ( typeof data === "string" ) { + + // Make sure leading/trailing whitespace is removed (IE can't handle it) + data = jQuery.trim( data ); + + if ( data ) { + // Make sure the incoming data is actual JSON + // Logic borrowed from http://json.org/json2.js + if ( rvalidchars.test( data.replace( rvalidescape, "@" ) + .replace( rvalidtokens, "]" ) + .replace( rvalidbraces, "")) ) { + + return ( new Function( "return " + data ) )(); + } + } + } + + jQuery.error( "Invalid JSON: " + data ); + }, + + // Cross-browser xml parsing + parseXML: function( data ) { + var xml, tmp; + if ( !data || typeof data !== "string" ) { + return null; + } + try { + if ( window.DOMParser ) { // Standard + tmp = new DOMParser(); + xml = tmp.parseFromString( data , "text/xml" ); + } else { // IE + xml = new ActiveXObject( "Microsoft.XMLDOM" ); + xml.async = "false"; + xml.loadXML( data ); + } + } catch( e ) { + xml = undefined; + } + if ( !xml || !xml.documentElement || xml.getElementsByTagName( "parsererror" ).length ) { + jQuery.error( "Invalid XML: " + data ); + } + return xml; + }, + + noop: function() {}, + + // Evaluates a script in a global context + // Workarounds based on findings by Jim Driscoll + // http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context + globalEval: function( data ) { + if ( data && jQuery.trim( data ) ) { + // We use execScript on Internet Explorer + // We use an anonymous function so that context is window + // rather than jQuery in Firefox + ( window.execScript || function( data ) { + window[ "eval" ].call( window, data ); + } )( data ); + } + }, + + // Convert dashed to camelCase; used by the css and data modules + // Microsoft forgot to hump their vendor prefix (#9572) + camelCase: function( string ) { + return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); + }, + + nodeName: function( elem, name ) { + return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase(); + }, + + // args is for internal usage only + each: function( obj, callback, args ) { + var value, + i = 0, + length = obj.length, + isArray = isArraylike( obj ); + + if ( args ) { + if ( isArray ) { + for ( ; i < length; i++ ) { + value = callback.apply( obj[ i ], args ); + + if ( value === false ) { + break; + } + } + } else { + for ( i in obj ) { + value = callback.apply( obj[ i ], args ); + + if ( value === false ) { + break; + } + } + } + + // A special, fast, case for the most common use of each + } else { + if ( isArray ) { + for ( ; i < length; i++ ) { + value = callback.call( obj[ i ], i, obj[ i ] ); + + if ( value === false ) { + break; + } + } + } else { + for ( i in obj ) { + value = callback.call( obj[ i ], i, obj[ i ] ); + + if ( value === false ) { + break; + } + } + } + } + + return obj; + }, + + // Use native String.trim function wherever possible + trim: core_trim && !core_trim.call("\uFEFF\xA0") ? + function( text ) { + return text == null ? + "" : + core_trim.call( text ); + } : + + // Otherwise use our own trimming functionality + function( text ) { + return text == null ? + "" : + ( text + "" ).replace( rtrim, "" ); + }, + + // results is for internal usage only + makeArray: function( arr, results ) { + var ret = results || []; + + if ( arr != null ) { + if ( isArraylike( Object(arr) ) ) { + jQuery.merge( ret, + typeof arr === "string" ? + [ arr ] : arr + ); + } else { + core_push.call( ret, arr ); + } + } + + return ret; + }, + + inArray: function( elem, arr, i ) { + var len; + + if ( arr ) { + if ( core_indexOf ) { + return core_indexOf.call( arr, elem, i ); + } + + len = arr.length; + i = i ? i < 0 ? Math.max( 0, len + i ) : i : 0; + + for ( ; i < len; i++ ) { + // Skip accessing in sparse arrays + if ( i in arr && arr[ i ] === elem ) { + return i; + } + } + } + + return -1; + }, + + merge: function( first, second ) { + var l = second.length, + i = first.length, + j = 0; + + if ( typeof l === "number" ) { + for ( ; j < l; j++ ) { + first[ i++ ] = second[ j ]; + } + } else { + while ( second[j] !== undefined ) { + first[ i++ ] = second[ j++ ]; + } + } + + first.length = i; + + return first; + }, + + grep: function( elems, callback, inv ) { + var retVal, + ret = [], + i = 0, + length = elems.length; + inv = !!inv; + + // Go through the array, only saving the items + // that pass the validator function + for ( ; i < length; i++ ) { + retVal = !!callback( elems[ i ], i ); + if ( inv !== retVal ) { + ret.push( elems[ i ] ); + } + } + + return ret; + }, + + // arg is for internal usage only + map: function( elems, callback, arg ) { + var value, + i = 0, + length = elems.length, + isArray = isArraylike( elems ), + ret = []; + + // Go through the array, translating each of the items to their + if ( isArray ) { + for ( ; i < length; i++ ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret[ ret.length ] = value; + } + } + + // Go through every key on the object, + } else { + for ( i in elems ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret[ ret.length ] = value; + } + } + } + + // Flatten any nested arrays + return core_concat.apply( [], ret ); + }, + + // A global GUID counter for objects + guid: 1, + + // Bind a function to a context, optionally partially applying any + // arguments. + proxy: function( fn, context ) { + var args, proxy, tmp; + + if ( typeof context === "string" ) { + tmp = fn[ context ]; + context = fn; + fn = tmp; + } + + // Quick check to determine if target is callable, in the spec + // this throws a TypeError, but we will just return undefined. + if ( !jQuery.isFunction( fn ) ) { + return undefined; + } + + // Simulated bind + args = core_slice.call( arguments, 2 ); + proxy = function() { + return fn.apply( context || this, args.concat( core_slice.call( arguments ) ) ); + }; + + // Set the guid of unique handler to the same of original handler, so it can be removed + proxy.guid = fn.guid = fn.guid || jQuery.guid++; + + return proxy; + }, + + // Multifunctional method to get and set values of a collection + // The value/s can optionally be executed if it's a function + access: function( elems, fn, key, value, chainable, emptyGet, raw ) { + var i = 0, + length = elems.length, + bulk = key == null; + + // Sets many values + if ( jQuery.type( key ) === "object" ) { + chainable = true; + for ( i in key ) { + jQuery.access( elems, fn, i, key[i], true, emptyGet, raw ); + } + + // Sets one value + } else if ( value !== undefined ) { + chainable = true; + + if ( !jQuery.isFunction( value ) ) { + raw = true; + } + + if ( bulk ) { + // Bulk operations run against the entire set + if ( raw ) { + fn.call( elems, value ); + fn = null; + + // ...except when executing function values + } else { + bulk = fn; + fn = function( elem, key, value ) { + return bulk.call( jQuery( elem ), value ); + }; + } + } + + if ( fn ) { + for ( ; i < length; i++ ) { + fn( elems[i], key, raw ? value : value.call( elems[i], i, fn( elems[i], key ) ) ); + } + } + } + + return chainable ? + elems : + + // Gets + bulk ? + fn.call( elems ) : + length ? fn( elems[0], key ) : emptyGet; + }, + + now: function() { + return ( new Date() ).getTime(); + } +}); + +jQuery.ready.promise = function( obj ) { + if ( !readyList ) { + + readyList = jQuery.Deferred(); + + // Catch cases where $(document).ready() is called after the browser event has already occurred. + // we once tried to use readyState "interactive" here, but it caused issues like the one + // discovered by ChrisS here: http://bugs.jquery.com/ticket/12282#comment:15 + if ( document.readyState === "complete" ) { + // Handle it asynchronously to allow scripts the opportunity to delay ready + setTimeout( jQuery.ready ); + + // Standards-based browsers support DOMContentLoaded + } else if ( document.addEventListener ) { + // Use the handy event callback + document.addEventListener( "DOMContentLoaded", completed, false ); + + // A fallback to window.onload, that will always work + window.addEventListener( "load", completed, false ); + + // If IE event model is used + } else { + // Ensure firing before onload, maybe late but safe also for iframes + document.attachEvent( "onreadystatechange", completed ); + + // A fallback to window.onload, that will always work + window.attachEvent( "onload", completed ); + + // If IE and not a frame + // continually check to see if the document is ready + var top = false; + + try { + top = window.frameElement == null && document.documentElement; + } catch(e) {} + + if ( top && top.doScroll ) { + (function doScrollCheck() { + if ( !jQuery.isReady ) { + + try { + // Use the trick by Diego Perini + // http://javascript.nwbox.com/IEContentLoaded/ + top.doScroll("left"); + } catch(e) { + return setTimeout( doScrollCheck, 50 ); + } + + // detach all dom ready events + detach(); + + // and execute any waiting functions + jQuery.ready(); + } + })(); + } + } + } + return readyList.promise( obj ); +}; + +// Populate the class2type map +jQuery.each("Boolean Number String Function Array Date RegExp Object Error".split(" "), function(i, name) { + class2type[ "[object " + name + "]" ] = name.toLowerCase(); +}); + +function isArraylike( obj ) { + var length = obj.length, + type = jQuery.type( obj ); + + if ( jQuery.isWindow( obj ) ) { + return false; + } + + if ( obj.nodeType === 1 && length ) { + return true; + } + + return type === "array" || type !== "function" && + ( length === 0 || + typeof length === "number" && length > 0 && ( length - 1 ) in obj ); +} + +// All jQuery objects should point back to these +rootjQuery = jQuery(document); +// String to Object options format cache +var optionsCache = {}; + +// Convert String-formatted options into Object-formatted ones and store in cache +function createOptions( options ) { + var object = optionsCache[ options ] = {}; + jQuery.each( options.match( core_rnotwhite ) || [], function( _, flag ) { + object[ flag ] = true; + }); + return object; +} + +/* + * Create a callback list using the following parameters: + * + * options: an optional list of space-separated options that will change how + * the callback list behaves or a more traditional option object + * + * By default a callback list will act like an event callback list and can be + * "fired" multiple times. + * + * Possible options: + * + * once: will ensure the callback list can only be fired once (like a Deferred) + * + * memory: will keep track of previous values and will call any callback added + * after the list has been fired right away with the latest "memorized" + * values (like a Deferred) + * + * unique: will ensure a callback can only be added once (no duplicate in the list) + * + * stopOnFalse: interrupt callings when a callback returns false + * + */ +jQuery.Callbacks = function( options ) { + + // Convert options from String-formatted to Object-formatted if needed + // (we check in cache first) + options = typeof options === "string" ? + ( optionsCache[ options ] || createOptions( options ) ) : + jQuery.extend( {}, options ); + + var // Flag to know if list is currently firing + firing, + // Last fire value (for non-forgettable lists) + memory, + // Flag to know if list was already fired + fired, + // End of the loop when firing + firingLength, + // Index of currently firing callback (modified by remove if needed) + firingIndex, + // First callback to fire (used internally by add and fireWith) + firingStart, + // Actual callback list + list = [], + // Stack of fire calls for repeatable lists + stack = !options.once && [], + // Fire callbacks + fire = function( data ) { + memory = options.memory && data; + fired = true; + firingIndex = firingStart || 0; + firingStart = 0; + firingLength = list.length; + firing = true; + for ( ; list && firingIndex < firingLength; firingIndex++ ) { + if ( list[ firingIndex ].apply( data[ 0 ], data[ 1 ] ) === false && options.stopOnFalse ) { + memory = false; // To prevent further calls using add + break; + } + } + firing = false; + if ( list ) { + if ( stack ) { + if ( stack.length ) { + fire( stack.shift() ); + } + } else if ( memory ) { + list = []; + } else { + self.disable(); + } + } + }, + // Actual Callbacks object + self = { + // Add a callback or a collection of callbacks to the list + add: function() { + if ( list ) { + // First, we save the current length + var start = list.length; + (function add( args ) { + jQuery.each( args, function( _, arg ) { + var type = jQuery.type( arg ); + if ( type === "function" ) { + if ( !options.unique || !self.has( arg ) ) { + list.push( arg ); + } + } else if ( arg && arg.length && type !== "string" ) { + // Inspect recursively + add( arg ); + } + }); + })( arguments ); + // Do we need to add the callbacks to the + // current firing batch? + if ( firing ) { + firingLength = list.length; + // With memory, if we're not firing then + // we should call right away + } else if ( memory ) { + firingStart = start; + fire( memory ); + } + } + return this; + }, + // Remove a callback from the list + remove: function() { + if ( list ) { + jQuery.each( arguments, function( _, arg ) { + var index; + while( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) { + list.splice( index, 1 ); + // Handle firing indexes + if ( firing ) { + if ( index <= firingLength ) { + firingLength--; + } + if ( index <= firingIndex ) { + firingIndex--; + } + } + } + }); + } + return this; + }, + // Check if a given callback is in the list. + // If no argument is given, return whether or not list has callbacks attached. + has: function( fn ) { + return fn ? jQuery.inArray( fn, list ) > -1 : !!( list && list.length ); + }, + // Remove all callbacks from the list + empty: function() { + list = []; + return this; + }, + // Have the list do nothing anymore + disable: function() { + list = stack = memory = undefined; + return this; + }, + // Is it disabled? + disabled: function() { + return !list; + }, + // Lock the list in its current state + lock: function() { + stack = undefined; + if ( !memory ) { + self.disable(); + } + return this; + }, + // Is it locked? + locked: function() { + return !stack; + }, + // Call all callbacks with the given context and arguments + fireWith: function( context, args ) { + args = args || []; + args = [ context, args.slice ? args.slice() : args ]; + if ( list && ( !fired || stack ) ) { + if ( firing ) { + stack.push( args ); + } else { + fire( args ); + } + } + return this; + }, + // Call all the callbacks with the given arguments + fire: function() { + self.fireWith( this, arguments ); + return this; + }, + // To know if the callbacks have already been called at least once + fired: function() { + return !!fired; + } + }; + + return self; +}; +jQuery.extend({ + + Deferred: function( func ) { + var tuples = [ + // action, add listener, listener list, final state + [ "resolve", "done", jQuery.Callbacks("once memory"), "resolved" ], + [ "reject", "fail", jQuery.Callbacks("once memory"), "rejected" ], + [ "notify", "progress", jQuery.Callbacks("memory") ] + ], + state = "pending", + promise = { + state: function() { + return state; + }, + always: function() { + deferred.done( arguments ).fail( arguments ); + return this; + }, + then: function( /* fnDone, fnFail, fnProgress */ ) { + var fns = arguments; + return jQuery.Deferred(function( newDefer ) { + jQuery.each( tuples, function( i, tuple ) { + var action = tuple[ 0 ], + fn = jQuery.isFunction( fns[ i ] ) && fns[ i ]; + // deferred[ done | fail | progress ] for forwarding actions to newDefer + deferred[ tuple[1] ](function() { + var returned = fn && fn.apply( this, arguments ); + if ( returned && jQuery.isFunction( returned.promise ) ) { + returned.promise() + .done( newDefer.resolve ) + .fail( newDefer.reject ) + .progress( newDefer.notify ); + } else { + newDefer[ action + "With" ]( this === promise ? newDefer.promise() : this, fn ? [ returned ] : arguments ); + } + }); + }); + fns = null; + }).promise(); + }, + // Get a promise for this deferred + // If obj is provided, the promise aspect is added to the object + promise: function( obj ) { + return obj != null ? jQuery.extend( obj, promise ) : promise; + } + }, + deferred = {}; + + // Keep pipe for back-compat + promise.pipe = promise.then; + + // Add list-specific methods + jQuery.each( tuples, function( i, tuple ) { + var list = tuple[ 2 ], + stateString = tuple[ 3 ]; + + // promise[ done | fail | progress ] = list.add + promise[ tuple[1] ] = list.add; + + // Handle state + if ( stateString ) { + list.add(function() { + // state = [ resolved | rejected ] + state = stateString; + + // [ reject_list | resolve_list ].disable; progress_list.lock + }, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock ); + } + + // deferred[ resolve | reject | notify ] + deferred[ tuple[0] ] = function() { + deferred[ tuple[0] + "With" ]( this === deferred ? promise : this, arguments ); + return this; + }; + deferred[ tuple[0] + "With" ] = list.fireWith; + }); + + // Make the deferred a promise + promise.promise( deferred ); + + // Call given func if any + if ( func ) { + func.call( deferred, deferred ); + } + + // All done! + return deferred; + }, + + // Deferred helper + when: function( subordinate /* , ..., subordinateN */ ) { + var i = 0, + resolveValues = core_slice.call( arguments ), + length = resolveValues.length, + + // the count of uncompleted subordinates + remaining = length !== 1 || ( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0, + + // the master Deferred. If resolveValues consist of only a single Deferred, just use that. + deferred = remaining === 1 ? subordinate : jQuery.Deferred(), + + // Update function for both resolve and progress values + updateFunc = function( i, contexts, values ) { + return function( value ) { + contexts[ i ] = this; + values[ i ] = arguments.length > 1 ? core_slice.call( arguments ) : value; + if( values === progressValues ) { + deferred.notifyWith( contexts, values ); + } else if ( !( --remaining ) ) { + deferred.resolveWith( contexts, values ); + } + }; + }, + + progressValues, progressContexts, resolveContexts; + + // add listeners to Deferred subordinates; treat others as resolved + if ( length > 1 ) { + progressValues = new Array( length ); + progressContexts = new Array( length ); + resolveContexts = new Array( length ); + for ( ; i < length; i++ ) { + if ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) { + resolveValues[ i ].promise() + .done( updateFunc( i, resolveContexts, resolveValues ) ) + .fail( deferred.reject ) + .progress( updateFunc( i, progressContexts, progressValues ) ); + } else { + --remaining; + } + } + } + + // if we're not waiting on anything, resolve the master + if ( !remaining ) { + deferred.resolveWith( resolveContexts, resolveValues ); + } + + return deferred.promise(); + } +}); +jQuery.support = (function() { + + var support, all, a, + input, select, fragment, + opt, eventName, isSupported, i, + div = document.createElement("div"); + + // Setup + div.setAttribute( "className", "t" ); + div.innerHTML = "
a"; + + // Support tests won't run in some limited or non-browser environments + all = div.getElementsByTagName("*"); + a = div.getElementsByTagName("a")[ 0 ]; + if ( !all || !a || !all.length ) { + return {}; + } + + // First batch of tests + select = document.createElement("select"); + opt = select.appendChild( document.createElement("option") ); + input = div.getElementsByTagName("input")[ 0 ]; + + a.style.cssText = "top:1px;float:left;opacity:.5"; + support = { + // Test setAttribute on camelCase class. If it works, we need attrFixes when doing get/setAttribute (ie6/7) + getSetAttribute: div.className !== "t", + + // IE strips leading whitespace when .innerHTML is used + leadingWhitespace: div.firstChild.nodeType === 3, + + // Make sure that tbody elements aren't automatically inserted + // IE will insert them into empty tables + tbody: !div.getElementsByTagName("tbody").length, + + // Make sure that link elements get serialized correctly by innerHTML + // This requires a wrapper element in IE + htmlSerialize: !!div.getElementsByTagName("link").length, + + // Get the style information from getAttribute + // (IE uses .cssText instead) + style: /top/.test( a.getAttribute("style") ), + + // Make sure that URLs aren't manipulated + // (IE normalizes it by default) + hrefNormalized: a.getAttribute("href") === "/a", + + // Make sure that element opacity exists + // (IE uses filter instead) + // Use a regex to work around a WebKit issue. See #5145 + opacity: /^0.5/.test( a.style.opacity ), + + // Verify style float existence + // (IE uses styleFloat instead of cssFloat) + cssFloat: !!a.style.cssFloat, + + // Check the default checkbox/radio value ("" on WebKit; "on" elsewhere) + checkOn: !!input.value, + + // Make sure that a selected-by-default option has a working selected property. + // (WebKit defaults to false instead of true, IE too, if it's in an optgroup) + optSelected: opt.selected, + + // Tests for enctype support on a form (#6743) + enctype: !!document.createElement("form").enctype, + + // Makes sure cloning an html5 element does not cause problems + // Where outerHTML is undefined, this still works + html5Clone: document.createElement("nav").cloneNode( true ).outerHTML !== "<:nav>", + + // jQuery.support.boxModel DEPRECATED in 1.8 since we don't support Quirks Mode + boxModel: document.compatMode === "CSS1Compat", + + // Will be defined later + deleteExpando: true, + noCloneEvent: true, + inlineBlockNeedsLayout: false, + shrinkWrapBlocks: false, + reliableMarginRight: true, + boxSizingReliable: true, + pixelPosition: false + }; + + // Make sure checked status is properly cloned + input.checked = true; + support.noCloneChecked = input.cloneNode( true ).checked; + + // Make sure that the options inside disabled selects aren't marked as disabled + // (WebKit marks them as disabled) + select.disabled = true; + support.optDisabled = !opt.disabled; + + // Support: IE<9 + try { + delete div.test; + } catch( e ) { + support.deleteExpando = false; + } + + // Check if we can trust getAttribute("value") + input = document.createElement("input"); + input.setAttribute( "value", "" ); + support.input = input.getAttribute( "value" ) === ""; + + // Check if an input maintains its value after becoming a radio + input.value = "t"; + input.setAttribute( "type", "radio" ); + support.radioValue = input.value === "t"; + + // #11217 - WebKit loses check when the name is after the checked attribute + input.setAttribute( "checked", "t" ); + input.setAttribute( "name", "t" ); + + fragment = document.createDocumentFragment(); + fragment.appendChild( input ); + + // Check if a disconnected checkbox will retain its checked + // value of true after appended to the DOM (IE6/7) + support.appendChecked = input.checked; + + // WebKit doesn't clone checked state correctly in fragments + support.checkClone = fragment.cloneNode( true ).cloneNode( true ).lastChild.checked; + + // Support: IE<9 + // Opera does not clone events (and typeof div.attachEvent === undefined). + // IE9-10 clones events bound via attachEvent, but they don't trigger with .click() + if ( div.attachEvent ) { + div.attachEvent( "onclick", function() { + support.noCloneEvent = false; + }); + + div.cloneNode( true ).click(); + } + + // Support: IE<9 (lack submit/change bubble), Firefox 17+ (lack focusin event) + // Beware of CSP restrictions (https://developer.mozilla.org/en/Security/CSP), test/csp.php + for ( i in { submit: true, change: true, focusin: true }) { + div.setAttribute( eventName = "on" + i, "t" ); + + support[ i + "Bubbles" ] = eventName in window || div.attributes[ eventName ].expando === false; + } + + div.style.backgroundClip = "content-box"; + div.cloneNode( true ).style.backgroundClip = ""; + support.clearCloneStyle = div.style.backgroundClip === "content-box"; + + // Run tests that need a body at doc ready + jQuery(function() { + var container, marginDiv, tds, + divReset = "padding:0;margin:0;border:0;display:block;box-sizing:content-box;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;", + body = document.getElementsByTagName("body")[0]; + + if ( !body ) { + // Return for frameset docs that don't have a body + return; + } + + container = document.createElement("div"); + container.style.cssText = "border:0;width:0;height:0;position:absolute;top:0;left:-9999px;margin-top:1px"; + + body.appendChild( container ).appendChild( div ); + + // Support: IE8 + // Check if table cells still have offsetWidth/Height when they are set + // to display:none and there are still other visible table cells in a + // table row; if so, offsetWidth/Height are not reliable for use when + // determining if an element has been hidden directly using + // display:none (it is still safe to use offsets if a parent element is + // hidden; don safety goggles and see bug #4512 for more information). + div.innerHTML = "
t
"; + tds = div.getElementsByTagName("td"); + tds[ 0 ].style.cssText = "padding:0;margin:0;border:0;display:none"; + isSupported = ( tds[ 0 ].offsetHeight === 0 ); + + tds[ 0 ].style.display = ""; + tds[ 1 ].style.display = "none"; + + // Support: IE8 + // Check if empty table cells still have offsetWidth/Height + support.reliableHiddenOffsets = isSupported && ( tds[ 0 ].offsetHeight === 0 ); + + // Check box-sizing and margin behavior + div.innerHTML = ""; + div.style.cssText = "box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;"; + support.boxSizing = ( div.offsetWidth === 4 ); + support.doesNotIncludeMarginInBodyOffset = ( body.offsetTop !== 1 ); + + // Use window.getComputedStyle because jsdom on node.js will break without it. + if ( window.getComputedStyle ) { + support.pixelPosition = ( window.getComputedStyle( div, null ) || {} ).top !== "1%"; + support.boxSizingReliable = ( window.getComputedStyle( div, null ) || { width: "4px" } ).width === "4px"; + + // Check if div with explicit width and no margin-right incorrectly + // gets computed margin-right based on width of container. (#3333) + // Fails in WebKit before Feb 2011 nightlies + // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right + marginDiv = div.appendChild( document.createElement("div") ); + marginDiv.style.cssText = div.style.cssText = divReset; + marginDiv.style.marginRight = marginDiv.style.width = "0"; + div.style.width = "1px"; + + support.reliableMarginRight = + !parseFloat( ( window.getComputedStyle( marginDiv, null ) || {} ).marginRight ); + } + + if ( typeof div.style.zoom !== core_strundefined ) { + // Support: IE<8 + // Check if natively block-level elements act like inline-block + // elements when setting their display to 'inline' and giving + // them layout + div.innerHTML = ""; + div.style.cssText = divReset + "width:1px;padding:1px;display:inline;zoom:1"; + support.inlineBlockNeedsLayout = ( div.offsetWidth === 3 ); + + // Support: IE6 + // Check if elements with layout shrink-wrap their children + div.style.display = "block"; + div.innerHTML = "

"; + div.firstChild.style.width = "5px"; + support.shrinkWrapBlocks = ( div.offsetWidth !== 3 ); + + if ( support.inlineBlockNeedsLayout ) { + // Prevent IE 6 from affecting layout for positioned elements #11048 + // Prevent IE from shrinking the body in IE 7 mode #12869 + // Support: IE<8 + body.style.zoom = 1; + } + } + + body.removeChild( container ); + + // Null elements to avoid leaks in IE + container = div = tds = marginDiv = null; + }); + + // Null elements to avoid leaks in IE + all = select = fragment = opt = a = input = null; + + return support; +})(); + +var rbrace = /(?:\{[\s\S]*\}|\[[\s\S]*\])$/, + rmultiDash = /([A-Z])/g; + +function internalData( elem, name, data, pvt /* Internal Use Only */ ){ + if ( !jQuery.acceptData( elem ) ) { + return; + } + + var thisCache, ret, + internalKey = jQuery.expando, + getByName = typeof name === "string", + + // We have to handle DOM nodes and JS objects differently because IE6-7 + // can't GC object references properly across the DOM-JS boundary + isNode = elem.nodeType, + + // Only DOM nodes need the global jQuery cache; JS object data is + // attached directly to the object so GC can occur automatically + cache = isNode ? jQuery.cache : elem, + + // Only defining an ID for JS objects if its cache already exists allows + // the code to shortcut on the same path as a DOM node with no cache + id = isNode ? elem[ internalKey ] : elem[ internalKey ] && internalKey; + + // Avoid doing any more work than we need to when trying to get data on an + // object that has no data at all + if ( (!id || !cache[id] || (!pvt && !cache[id].data)) && getByName && data === undefined ) { + return; + } + + if ( !id ) { + // Only DOM nodes need a new unique ID for each element since their data + // ends up in the global cache + if ( isNode ) { + elem[ internalKey ] = id = core_deletedIds.pop() || jQuery.guid++; + } else { + id = internalKey; + } + } + + if ( !cache[ id ] ) { + cache[ id ] = {}; + + // Avoids exposing jQuery metadata on plain JS objects when the object + // is serialized using JSON.stringify + if ( !isNode ) { + cache[ id ].toJSON = jQuery.noop; + } + } + + // An object can be passed to jQuery.data instead of a key/value pair; this gets + // shallow copied over onto the existing cache + if ( typeof name === "object" || typeof name === "function" ) { + if ( pvt ) { + cache[ id ] = jQuery.extend( cache[ id ], name ); + } else { + cache[ id ].data = jQuery.extend( cache[ id ].data, name ); + } + } + + thisCache = cache[ id ]; + + // jQuery data() is stored in a separate object inside the object's internal data + // cache in order to avoid key collisions between internal data and user-defined + // data. + if ( !pvt ) { + if ( !thisCache.data ) { + thisCache.data = {}; + } + + thisCache = thisCache.data; + } + + if ( data !== undefined ) { + thisCache[ jQuery.camelCase( name ) ] = data; + } + + // Check for both converted-to-camel and non-converted data property names + // If a data property was specified + if ( getByName ) { + + // First Try to find as-is property data + ret = thisCache[ name ]; + + // Test for null|undefined property data + if ( ret == null ) { + + // Try to find the camelCased property + ret = thisCache[ jQuery.camelCase( name ) ]; + } + } else { + ret = thisCache; + } + + return ret; +} + +function internalRemoveData( elem, name, pvt ) { + if ( !jQuery.acceptData( elem ) ) { + return; + } + + var i, l, thisCache, + isNode = elem.nodeType, + + // See jQuery.data for more information + cache = isNode ? jQuery.cache : elem, + id = isNode ? elem[ jQuery.expando ] : jQuery.expando; + + // If there is already no cache entry for this object, there is no + // purpose in continuing + if ( !cache[ id ] ) { + return; + } + + if ( name ) { + + thisCache = pvt ? cache[ id ] : cache[ id ].data; + + if ( thisCache ) { + + // Support array or space separated string names for data keys + if ( !jQuery.isArray( name ) ) { + + // try the string as a key before any manipulation + if ( name in thisCache ) { + name = [ name ]; + } else { + + // split the camel cased version by spaces unless a key with the spaces exists + name = jQuery.camelCase( name ); + if ( name in thisCache ) { + name = [ name ]; + } else { + name = name.split(" "); + } + } + } else { + // If "name" is an array of keys... + // When data is initially created, via ("key", "val") signature, + // keys will be converted to camelCase. + // Since there is no way to tell _how_ a key was added, remove + // both plain key and camelCase key. #12786 + // This will only penalize the array argument path. + name = name.concat( jQuery.map( name, jQuery.camelCase ) ); + } + + for ( i = 0, l = name.length; i < l; i++ ) { + delete thisCache[ name[i] ]; + } + + // If there is no data left in the cache, we want to continue + // and let the cache object itself get destroyed + if ( !( pvt ? isEmptyDataObject : jQuery.isEmptyObject )( thisCache ) ) { + return; + } + } + } + + // See jQuery.data for more information + if ( !pvt ) { + delete cache[ id ].data; + + // Don't destroy the parent cache unless the internal data object + // had been the only thing left in it + if ( !isEmptyDataObject( cache[ id ] ) ) { + return; + } + } + + // Destroy the cache + if ( isNode ) { + jQuery.cleanData( [ elem ], true ); + + // Use delete when supported for expandos or `cache` is not a window per isWindow (#10080) + } else if ( jQuery.support.deleteExpando || cache != cache.window ) { + delete cache[ id ]; + + // When all else fails, null + } else { + cache[ id ] = null; + } +} + +jQuery.extend({ + cache: {}, + + // Unique for each copy of jQuery on the page + // Non-digits removed to match rinlinejQuery + expando: "jQuery" + ( core_version + Math.random() ).replace( /\D/g, "" ), + + // The following elements throw uncatchable exceptions if you + // attempt to add expando properties to them. + noData: { + "embed": true, + // Ban all objects except for Flash (which handle expandos) + "object": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000", + "applet": true + }, + + hasData: function( elem ) { + elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ]; + return !!elem && !isEmptyDataObject( elem ); + }, + + data: function( elem, name, data ) { + return internalData( elem, name, data ); + }, + + removeData: function( elem, name ) { + return internalRemoveData( elem, name ); + }, + + // For internal use only. + _data: function( elem, name, data ) { + return internalData( elem, name, data, true ); + }, + + _removeData: function( elem, name ) { + return internalRemoveData( elem, name, true ); + }, + + // A method for determining if a DOM node can handle the data expando + acceptData: function( elem ) { + // Do not set data on non-element because it will not be cleared (#8335). + if ( elem.nodeType && elem.nodeType !== 1 && elem.nodeType !== 9 ) { + return false; + } + + var noData = elem.nodeName && jQuery.noData[ elem.nodeName.toLowerCase() ]; + + // nodes accept data unless otherwise specified; rejection can be conditional + return !noData || noData !== true && elem.getAttribute("classid") === noData; + } +}); + +jQuery.fn.extend({ + data: function( key, value ) { + var attrs, name, + elem = this[0], + i = 0, + data = null; + + // Gets all values + if ( key === undefined ) { + if ( this.length ) { + data = jQuery.data( elem ); + + if ( elem.nodeType === 1 && !jQuery._data( elem, "parsedAttrs" ) ) { + attrs = elem.attributes; + for ( ; i < attrs.length; i++ ) { + name = attrs[i].name; + + if ( !name.indexOf( "data-" ) ) { + name = jQuery.camelCase( name.slice(5) ); + + dataAttr( elem, name, data[ name ] ); + } + } + jQuery._data( elem, "parsedAttrs", true ); + } + } + + return data; + } + + // Sets multiple values + if ( typeof key === "object" ) { + return this.each(function() { + jQuery.data( this, key ); + }); + } + + return jQuery.access( this, function( value ) { + + if ( value === undefined ) { + // Try to fetch any internally stored data first + return elem ? dataAttr( elem, key, jQuery.data( elem, key ) ) : null; + } + + this.each(function() { + jQuery.data( this, key, value ); + }); + }, null, value, arguments.length > 1, null, true ); + }, + + removeData: function( key ) { + return this.each(function() { + jQuery.removeData( this, key ); + }); + } +}); + +function dataAttr( elem, key, data ) { + // If nothing was found internally, try to fetch any + // data from the HTML5 data-* attribute + if ( data === undefined && elem.nodeType === 1 ) { + + var name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase(); + + data = elem.getAttribute( name ); + + if ( typeof data === "string" ) { + try { + data = data === "true" ? true : + data === "false" ? false : + data === "null" ? null : + // Only convert to a number if it doesn't change the string + +data + "" === data ? +data : + rbrace.test( data ) ? jQuery.parseJSON( data ) : + data; + } catch( e ) {} + + // Make sure we set the data so it isn't changed later + jQuery.data( elem, key, data ); + + } else { + data = undefined; + } + } + + return data; +} + +// checks a cache object for emptiness +function isEmptyDataObject( obj ) { + var name; + for ( name in obj ) { + + // if the public data object is empty, the private is still empty + if ( name === "data" && jQuery.isEmptyObject( obj[name] ) ) { + continue; + } + if ( name !== "toJSON" ) { + return false; + } + } + + return true; +} +jQuery.extend({ + queue: function( elem, type, data ) { + var queue; + + if ( elem ) { + type = ( type || "fx" ) + "queue"; + queue = jQuery._data( elem, type ); + + // Speed up dequeue by getting out quickly if this is just a lookup + if ( data ) { + if ( !queue || jQuery.isArray(data) ) { + queue = jQuery._data( elem, type, jQuery.makeArray(data) ); + } else { + queue.push( data ); + } + } + return queue || []; + } + }, + + dequeue: function( elem, type ) { + type = type || "fx"; + + var queue = jQuery.queue( elem, type ), + startLength = queue.length, + fn = queue.shift(), + hooks = jQuery._queueHooks( elem, type ), + next = function() { + jQuery.dequeue( elem, type ); + }; + + // If the fx queue is dequeued, always remove the progress sentinel + if ( fn === "inprogress" ) { + fn = queue.shift(); + startLength--; + } + + hooks.cur = fn; + if ( fn ) { + + // Add a progress sentinel to prevent the fx queue from being + // automatically dequeued + if ( type === "fx" ) { + queue.unshift( "inprogress" ); + } + + // clear up the last queue stop function + delete hooks.stop; + fn.call( elem, next, hooks ); + } + + if ( !startLength && hooks ) { + hooks.empty.fire(); + } + }, + + // not intended for public consumption - generates a queueHooks object, or returns the current one + _queueHooks: function( elem, type ) { + var key = type + "queueHooks"; + return jQuery._data( elem, key ) || jQuery._data( elem, key, { + empty: jQuery.Callbacks("once memory").add(function() { + jQuery._removeData( elem, type + "queue" ); + jQuery._removeData( elem, key ); + }) + }); + } +}); + +jQuery.fn.extend({ + queue: function( type, data ) { + var setter = 2; + + if ( typeof type !== "string" ) { + data = type; + type = "fx"; + setter--; + } + + if ( arguments.length < setter ) { + return jQuery.queue( this[0], type ); + } + + return data === undefined ? + this : + this.each(function() { + var queue = jQuery.queue( this, type, data ); + + // ensure a hooks for this queue + jQuery._queueHooks( this, type ); + + if ( type === "fx" && queue[0] !== "inprogress" ) { + jQuery.dequeue( this, type ); + } + }); + }, + dequeue: function( type ) { + return this.each(function() { + jQuery.dequeue( this, type ); + }); + }, + // Based off of the plugin by Clint Helfers, with permission. + // http://blindsignals.com/index.php/2009/07/jquery-delay/ + delay: function( time, type ) { + time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time; + type = type || "fx"; + + return this.queue( type, function( next, hooks ) { + var timeout = setTimeout( next, time ); + hooks.stop = function() { + clearTimeout( timeout ); + }; + }); + }, + clearQueue: function( type ) { + return this.queue( type || "fx", [] ); + }, + // Get a promise resolved when queues of a certain type + // are emptied (fx is the type by default) + promise: function( type, obj ) { + var tmp, + count = 1, + defer = jQuery.Deferred(), + elements = this, + i = this.length, + resolve = function() { + if ( !( --count ) ) { + defer.resolveWith( elements, [ elements ] ); + } + }; + + if ( typeof type !== "string" ) { + obj = type; + type = undefined; + } + type = type || "fx"; + + while( i-- ) { + tmp = jQuery._data( elements[ i ], type + "queueHooks" ); + if ( tmp && tmp.empty ) { + count++; + tmp.empty.add( resolve ); + } + } + resolve(); + return defer.promise( obj ); + } +}); +var nodeHook, boolHook, + rclass = /[\t\r\n]/g, + rreturn = /\r/g, + rfocusable = /^(?:input|select|textarea|button|object)$/i, + rclickable = /^(?:a|area)$/i, + rboolean = /^(?:checked|selected|autofocus|autoplay|async|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped)$/i, + ruseDefault = /^(?:checked|selected)$/i, + getSetAttribute = jQuery.support.getSetAttribute, + getSetInput = jQuery.support.input; + +jQuery.fn.extend({ + attr: function( name, value ) { + return jQuery.access( this, jQuery.attr, name, value, arguments.length > 1 ); + }, + + removeAttr: function( name ) { + return this.each(function() { + jQuery.removeAttr( this, name ); + }); + }, + + prop: function( name, value ) { + return jQuery.access( this, jQuery.prop, name, value, arguments.length > 1 ); + }, + + removeProp: function( name ) { + name = jQuery.propFix[ name ] || name; + return this.each(function() { + // try/catch handles cases where IE balks (such as removing a property on window) + try { + this[ name ] = undefined; + delete this[ name ]; + } catch( e ) {} + }); + }, + + addClass: function( value ) { + var classes, elem, cur, clazz, j, + i = 0, + len = this.length, + proceed = typeof value === "string" && value; + + if ( jQuery.isFunction( value ) ) { + return this.each(function( j ) { + jQuery( this ).addClass( value.call( this, j, this.className ) ); + }); + } + + if ( proceed ) { + // The disjunction here is for better compressibility (see removeClass) + classes = ( value || "" ).match( core_rnotwhite ) || []; + + for ( ; i < len; i++ ) { + elem = this[ i ]; + cur = elem.nodeType === 1 && ( elem.className ? + ( " " + elem.className + " " ).replace( rclass, " " ) : + " " + ); + + if ( cur ) { + j = 0; + while ( (clazz = classes[j++]) ) { + if ( cur.indexOf( " " + clazz + " " ) < 0 ) { + cur += clazz + " "; + } + } + elem.className = jQuery.trim( cur ); + + } + } + } + + return this; + }, + + removeClass: function( value ) { + var classes, elem, cur, clazz, j, + i = 0, + len = this.length, + proceed = arguments.length === 0 || typeof value === "string" && value; + + if ( jQuery.isFunction( value ) ) { + return this.each(function( j ) { + jQuery( this ).removeClass( value.call( this, j, this.className ) ); + }); + } + if ( proceed ) { + classes = ( value || "" ).match( core_rnotwhite ) || []; + + for ( ; i < len; i++ ) { + elem = this[ i ]; + // This expression is here for better compressibility (see addClass) + cur = elem.nodeType === 1 && ( elem.className ? + ( " " + elem.className + " " ).replace( rclass, " " ) : + "" + ); + + if ( cur ) { + j = 0; + while ( (clazz = classes[j++]) ) { + // Remove *all* instances + while ( cur.indexOf( " " + clazz + " " ) >= 0 ) { + cur = cur.replace( " " + clazz + " ", " " ); + } + } + elem.className = value ? jQuery.trim( cur ) : ""; + } + } + } + + return this; + }, + + toggleClass: function( value, stateVal ) { + var type = typeof value, + isBool = typeof stateVal === "boolean"; + + if ( jQuery.isFunction( value ) ) { + return this.each(function( i ) { + jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal ); + }); + } + + return this.each(function() { + if ( type === "string" ) { + // toggle individual class names + var className, + i = 0, + self = jQuery( this ), + state = stateVal, + classNames = value.match( core_rnotwhite ) || []; + + while ( (className = classNames[ i++ ]) ) { + // check each className given, space separated list + state = isBool ? state : !self.hasClass( className ); + self[ state ? "addClass" : "removeClass" ]( className ); + } + + // Toggle whole class name + } else if ( type === core_strundefined || type === "boolean" ) { + if ( this.className ) { + // store className if set + jQuery._data( this, "__className__", this.className ); + } + + // If the element has a class name or if we're passed "false", + // then remove the whole classname (if there was one, the above saved it). + // Otherwise bring back whatever was previously saved (if anything), + // falling back to the empty string if nothing was stored. + this.className = this.className || value === false ? "" : jQuery._data( this, "__className__" ) || ""; + } + }); + }, + + hasClass: function( selector ) { + var className = " " + selector + " ", + i = 0, + l = this.length; + for ( ; i < l; i++ ) { + if ( this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) >= 0 ) { + return true; + } + } + + return false; + }, + + val: function( value ) { + var ret, hooks, isFunction, + elem = this[0]; + + if ( !arguments.length ) { + if ( elem ) { + hooks = jQuery.valHooks[ elem.type ] || jQuery.valHooks[ elem.nodeName.toLowerCase() ]; + + if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) { + return ret; + } + + ret = elem.value; + + return typeof ret === "string" ? + // handle most common string cases + ret.replace(rreturn, "") : + // handle cases where value is null/undef or number + ret == null ? "" : ret; + } + + return; + } + + isFunction = jQuery.isFunction( value ); + + return this.each(function( i ) { + var val, + self = jQuery(this); + + if ( this.nodeType !== 1 ) { + return; + } + + if ( isFunction ) { + val = value.call( this, i, self.val() ); + } else { + val = value; + } + + // Treat null/undefined as ""; convert numbers to string + if ( val == null ) { + val = ""; + } else if ( typeof val === "number" ) { + val += ""; + } else if ( jQuery.isArray( val ) ) { + val = jQuery.map(val, function ( value ) { + return value == null ? "" : value + ""; + }); + } + + hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ]; + + // If set returns undefined, fall back to normal setting + if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) { + this.value = val; + } + }); + } +}); + +jQuery.extend({ + valHooks: { + option: { + get: function( elem ) { + // attributes.value is undefined in Blackberry 4.7 but + // uses .value. See #6932 + var val = elem.attributes.value; + return !val || val.specified ? elem.value : elem.text; + } + }, + select: { + get: function( elem ) { + var value, option, + options = elem.options, + index = elem.selectedIndex, + one = elem.type === "select-one" || index < 0, + values = one ? null : [], + max = one ? index + 1 : options.length, + i = index < 0 ? + max : + one ? index : 0; + + // Loop through all the selected options + for ( ; i < max; i++ ) { + option = options[ i ]; + + // oldIE doesn't update selected after form reset (#2551) + if ( ( option.selected || i === index ) && + // Don't return options that are disabled or in a disabled optgroup + ( jQuery.support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null ) && + ( !option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" ) ) ) { + + // Get the specific value for the option + value = jQuery( option ).val(); + + // We don't need an array for one selects + if ( one ) { + return value; + } + + // Multi-Selects return an array + values.push( value ); + } + } + + return values; + }, + + set: function( elem, value ) { + var values = jQuery.makeArray( value ); + + jQuery(elem).find("option").each(function() { + this.selected = jQuery.inArray( jQuery(this).val(), values ) >= 0; + }); + + if ( !values.length ) { + elem.selectedIndex = -1; + } + return values; + } + } + }, + + attr: function( elem, name, value ) { + var hooks, notxml, ret, + nType = elem.nodeType; + + // don't get/set attributes on text, comment and attribute nodes + if ( !elem || nType === 3 || nType === 8 || nType === 2 ) { + return; + } + + // Fallback to prop when attributes are not supported + if ( typeof elem.getAttribute === core_strundefined ) { + return jQuery.prop( elem, name, value ); + } + + notxml = nType !== 1 || !jQuery.isXMLDoc( elem ); + + // All attributes are lowercase + // Grab necessary hook if one is defined + if ( notxml ) { + name = name.toLowerCase(); + hooks = jQuery.attrHooks[ name ] || ( rboolean.test( name ) ? boolHook : nodeHook ); + } + + if ( value !== undefined ) { + + if ( value === null ) { + jQuery.removeAttr( elem, name ); + + } else if ( hooks && notxml && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) { + return ret; + + } else { + elem.setAttribute( name, value + "" ); + return value; + } + + } else if ( hooks && notxml && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) { + return ret; + + } else { + + // In IE9+, Flash objects don't have .getAttribute (#12945) + // Support: IE9+ + if ( typeof elem.getAttribute !== core_strundefined ) { + ret = elem.getAttribute( name ); + } + + // Non-existent attributes return null, we normalize to undefined + return ret == null ? + undefined : + ret; + } + }, + + removeAttr: function( elem, value ) { + var name, propName, + i = 0, + attrNames = value && value.match( core_rnotwhite ); + + if ( attrNames && elem.nodeType === 1 ) { + while ( (name = attrNames[i++]) ) { + propName = jQuery.propFix[ name ] || name; + + // Boolean attributes get special treatment (#10870) + if ( rboolean.test( name ) ) { + // Set corresponding property to false for boolean attributes + // Also clear defaultChecked/defaultSelected (if appropriate) for IE<8 + if ( !getSetAttribute && ruseDefault.test( name ) ) { + elem[ jQuery.camelCase( "default-" + name ) ] = + elem[ propName ] = false; + } else { + elem[ propName ] = false; + } + + // See #9699 for explanation of this approach (setting first, then removal) + } else { + jQuery.attr( elem, name, "" ); + } + + elem.removeAttribute( getSetAttribute ? name : propName ); + } + } + }, + + attrHooks: { + type: { + set: function( elem, value ) { + if ( !jQuery.support.radioValue && value === "radio" && jQuery.nodeName(elem, "input") ) { + // Setting the type on a radio button after the value resets the value in IE6-9 + // Reset value to default in case type is set after value during creation + var val = elem.value; + elem.setAttribute( "type", value ); + if ( val ) { + elem.value = val; + } + return value; + } + } + } + }, + + propFix: { + tabindex: "tabIndex", + readonly: "readOnly", + "for": "htmlFor", + "class": "className", + maxlength: "maxLength", + cellspacing: "cellSpacing", + cellpadding: "cellPadding", + rowspan: "rowSpan", + colspan: "colSpan", + usemap: "useMap", + frameborder: "frameBorder", + contenteditable: "contentEditable" + }, + + prop: function( elem, name, value ) { + var ret, hooks, notxml, + nType = elem.nodeType; + + // don't get/set properties on text, comment and attribute nodes + if ( !elem || nType === 3 || nType === 8 || nType === 2 ) { + return; + } + + notxml = nType !== 1 || !jQuery.isXMLDoc( elem ); + + if ( notxml ) { + // Fix name and attach hooks + name = jQuery.propFix[ name ] || name; + hooks = jQuery.propHooks[ name ]; + } + + if ( value !== undefined ) { + if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) { + return ret; + + } else { + return ( elem[ name ] = value ); + } + + } else { + if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) { + return ret; + + } else { + return elem[ name ]; + } + } + }, + + propHooks: { + tabIndex: { + get: function( elem ) { + // elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set + // http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ + var attributeNode = elem.getAttributeNode("tabindex"); + + return attributeNode && attributeNode.specified ? + parseInt( attributeNode.value, 10 ) : + rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ? + 0 : + undefined; + } + } + } +}); + +// Hook for boolean attributes +boolHook = { + get: function( elem, name ) { + var + // Use .prop to determine if this attribute is understood as boolean + prop = jQuery.prop( elem, name ), + + // Fetch it accordingly + attr = typeof prop === "boolean" && elem.getAttribute( name ), + detail = typeof prop === "boolean" ? + + getSetInput && getSetAttribute ? + attr != null : + // oldIE fabricates an empty string for missing boolean attributes + // and conflates checked/selected into attroperties + ruseDefault.test( name ) ? + elem[ jQuery.camelCase( "default-" + name ) ] : + !!attr : + + // fetch an attribute node for properties not recognized as boolean + elem.getAttributeNode( name ); + + return detail && detail.value !== false ? + name.toLowerCase() : + undefined; + }, + set: function( elem, value, name ) { + if ( value === false ) { + // Remove boolean attributes when set to false + jQuery.removeAttr( elem, name ); + } else if ( getSetInput && getSetAttribute || !ruseDefault.test( name ) ) { + // IE<8 needs the *property* name + elem.setAttribute( !getSetAttribute && jQuery.propFix[ name ] || name, name ); + + // Use defaultChecked and defaultSelected for oldIE + } else { + elem[ jQuery.camelCase( "default-" + name ) ] = elem[ name ] = true; + } + + return name; + } +}; + +// fix oldIE value attroperty +if ( !getSetInput || !getSetAttribute ) { + jQuery.attrHooks.value = { + get: function( elem, name ) { + var ret = elem.getAttributeNode( name ); + return jQuery.nodeName( elem, "input" ) ? + + // Ignore the value *property* by using defaultValue + elem.defaultValue : + + ret && ret.specified ? ret.value : undefined; + }, + set: function( elem, value, name ) { + if ( jQuery.nodeName( elem, "input" ) ) { + // Does not return so that setAttribute is also used + elem.defaultValue = value; + } else { + // Use nodeHook if defined (#1954); otherwise setAttribute is fine + return nodeHook && nodeHook.set( elem, value, name ); + } + } + }; +} + +// IE6/7 do not support getting/setting some attributes with get/setAttribute +if ( !getSetAttribute ) { + + // Use this for any attribute in IE6/7 + // This fixes almost every IE6/7 issue + nodeHook = jQuery.valHooks.button = { + get: function( elem, name ) { + var ret = elem.getAttributeNode( name ); + return ret && ( name === "id" || name === "name" || name === "coords" ? ret.value !== "" : ret.specified ) ? + ret.value : + undefined; + }, + set: function( elem, value, name ) { + // Set the existing or create a new attribute node + var ret = elem.getAttributeNode( name ); + if ( !ret ) { + elem.setAttributeNode( + (ret = elem.ownerDocument.createAttribute( name )) + ); + } + + ret.value = value += ""; + + // Break association with cloned elements by also using setAttribute (#9646) + return name === "value" || value === elem.getAttribute( name ) ? + value : + undefined; + } + }; + + // Set contenteditable to false on removals(#10429) + // Setting to empty string throws an error as an invalid value + jQuery.attrHooks.contenteditable = { + get: nodeHook.get, + set: function( elem, value, name ) { + nodeHook.set( elem, value === "" ? false : value, name ); + } + }; + + // Set width and height to auto instead of 0 on empty string( Bug #8150 ) + // This is for removals + jQuery.each([ "width", "height" ], function( i, name ) { + jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], { + set: function( elem, value ) { + if ( value === "" ) { + elem.setAttribute( name, "auto" ); + return value; + } + } + }); + }); +} + + +// Some attributes require a special call on IE +// http://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx +if ( !jQuery.support.hrefNormalized ) { + jQuery.each([ "href", "src", "width", "height" ], function( i, name ) { + jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], { + get: function( elem ) { + var ret = elem.getAttribute( name, 2 ); + return ret == null ? undefined : ret; + } + }); + }); + + // href/src property should get the full normalized URL (#10299/#12915) + jQuery.each([ "href", "src" ], function( i, name ) { + jQuery.propHooks[ name ] = { + get: function( elem ) { + return elem.getAttribute( name, 4 ); + } + }; + }); +} + +if ( !jQuery.support.style ) { + jQuery.attrHooks.style = { + get: function( elem ) { + // Return undefined in the case of empty string + // Note: IE uppercases css property names, but if we were to .toLowerCase() + // .cssText, that would destroy case senstitivity in URL's, like in "background" + return elem.style.cssText || undefined; + }, + set: function( elem, value ) { + return ( elem.style.cssText = value + "" ); + } + }; +} + +// Safari mis-reports the default selected property of an option +// Accessing the parent's selectedIndex property fixes it +if ( !jQuery.support.optSelected ) { + jQuery.propHooks.selected = jQuery.extend( jQuery.propHooks.selected, { + get: function( elem ) { + var parent = elem.parentNode; + + if ( parent ) { + parent.selectedIndex; + + // Make sure that it also works with optgroups, see #5701 + if ( parent.parentNode ) { + parent.parentNode.selectedIndex; + } + } + return null; + } + }); +} + +// IE6/7 call enctype encoding +if ( !jQuery.support.enctype ) { + jQuery.propFix.enctype = "encoding"; +} + +// Radios and checkboxes getter/setter +if ( !jQuery.support.checkOn ) { + jQuery.each([ "radio", "checkbox" ], function() { + jQuery.valHooks[ this ] = { + get: function( elem ) { + // Handle the case where in Webkit "" is returned instead of "on" if a value isn't specified + return elem.getAttribute("value") === null ? "on" : elem.value; + } + }; + }); +} +jQuery.each([ "radio", "checkbox" ], function() { + jQuery.valHooks[ this ] = jQuery.extend( jQuery.valHooks[ this ], { + set: function( elem, value ) { + if ( jQuery.isArray( value ) ) { + return ( elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0 ); + } + } + }); +}); +var rformElems = /^(?:input|select|textarea)$/i, + rkeyEvent = /^key/, + rmouseEvent = /^(?:mouse|contextmenu)|click/, + rfocusMorph = /^(?:focusinfocus|focusoutblur)$/, + rtypenamespace = /^([^.]*)(?:\.(.+)|)$/; + +function returnTrue() { + return true; +} + +function returnFalse() { + return false; +} + +/* + * Helper functions for managing events -- not part of the public interface. + * Props to Dean Edwards' addEvent library for many of the ideas. + */ +jQuery.event = { + + global: {}, + + add: function( elem, types, handler, data, selector ) { + var tmp, events, t, handleObjIn, + special, eventHandle, handleObj, + handlers, type, namespaces, origType, + elemData = jQuery._data( elem ); + + // Don't attach events to noData or text/comment nodes (but allow plain objects) + if ( !elemData ) { + return; + } + + // Caller can pass in an object of custom data in lieu of the handler + if ( handler.handler ) { + handleObjIn = handler; + handler = handleObjIn.handler; + selector = handleObjIn.selector; + } + + // Make sure that the handler has a unique ID, used to find/remove it later + if ( !handler.guid ) { + handler.guid = jQuery.guid++; + } + + // Init the element's event structure and main handler, if this is the first + if ( !(events = elemData.events) ) { + events = elemData.events = {}; + } + if ( !(eventHandle = elemData.handle) ) { + eventHandle = elemData.handle = function( e ) { + // Discard the second event of a jQuery.event.trigger() and + // when an event is called after a page has unloaded + return typeof jQuery !== core_strundefined && (!e || jQuery.event.triggered !== e.type) ? + jQuery.event.dispatch.apply( eventHandle.elem, arguments ) : + undefined; + }; + // Add elem as a property of the handle fn to prevent a memory leak with IE non-native events + eventHandle.elem = elem; + } + + // Handle multiple events separated by a space + // jQuery(...).bind("mouseover mouseout", fn); + types = ( types || "" ).match( core_rnotwhite ) || [""]; + t = types.length; + while ( t-- ) { + tmp = rtypenamespace.exec( types[t] ) || []; + type = origType = tmp[1]; + namespaces = ( tmp[2] || "" ).split( "." ).sort(); + + // If event changes its type, use the special event handlers for the changed type + special = jQuery.event.special[ type ] || {}; + + // If selector defined, determine special event api type, otherwise given type + type = ( selector ? special.delegateType : special.bindType ) || type; + + // Update special based on newly reset type + special = jQuery.event.special[ type ] || {}; + + // handleObj is passed to all event handlers + handleObj = jQuery.extend({ + type: type, + origType: origType, + data: data, + handler: handler, + guid: handler.guid, + selector: selector, + needsContext: selector && jQuery.expr.match.needsContext.test( selector ), + namespace: namespaces.join(".") + }, handleObjIn ); + + // Init the event handler queue if we're the first + if ( !(handlers = events[ type ]) ) { + handlers = events[ type ] = []; + handlers.delegateCount = 0; + + // Only use addEventListener/attachEvent if the special events handler returns false + if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) { + // Bind the global event handler to the element + if ( elem.addEventListener ) { + elem.addEventListener( type, eventHandle, false ); + + } else if ( elem.attachEvent ) { + elem.attachEvent( "on" + type, eventHandle ); + } + } + } + + if ( special.add ) { + special.add.call( elem, handleObj ); + + if ( !handleObj.handler.guid ) { + handleObj.handler.guid = handler.guid; + } + } + + // Add to the element's handler list, delegates in front + if ( selector ) { + handlers.splice( handlers.delegateCount++, 0, handleObj ); + } else { + handlers.push( handleObj ); + } + + // Keep track of which events have ever been used, for event optimization + jQuery.event.global[ type ] = true; + } + + // Nullify elem to prevent memory leaks in IE + elem = null; + }, + + // Detach an event or set of events from an element + remove: function( elem, types, handler, selector, mappedTypes ) { + var j, handleObj, tmp, + origCount, t, events, + special, handlers, type, + namespaces, origType, + elemData = jQuery.hasData( elem ) && jQuery._data( elem ); + + if ( !elemData || !(events = elemData.events) ) { + return; + } + + // Once for each type.namespace in types; type may be omitted + types = ( types || "" ).match( core_rnotwhite ) || [""]; + t = types.length; + while ( t-- ) { + tmp = rtypenamespace.exec( types[t] ) || []; + type = origType = tmp[1]; + namespaces = ( tmp[2] || "" ).split( "." ).sort(); + + // Unbind all events (on this namespace, if provided) for the element + if ( !type ) { + for ( type in events ) { + jQuery.event.remove( elem, type + types[ t ], handler, selector, true ); + } + continue; + } + + special = jQuery.event.special[ type ] || {}; + type = ( selector ? special.delegateType : special.bindType ) || type; + handlers = events[ type ] || []; + tmp = tmp[2] && new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" ); + + // Remove matching events + origCount = j = handlers.length; + while ( j-- ) { + handleObj = handlers[ j ]; + + if ( ( mappedTypes || origType === handleObj.origType ) && + ( !handler || handler.guid === handleObj.guid ) && + ( !tmp || tmp.test( handleObj.namespace ) ) && + ( !selector || selector === handleObj.selector || selector === "**" && handleObj.selector ) ) { + handlers.splice( j, 1 ); + + if ( handleObj.selector ) { + handlers.delegateCount--; + } + if ( special.remove ) { + special.remove.call( elem, handleObj ); + } + } + } + + // Remove generic event handler if we removed something and no more handlers exist + // (avoids potential for endless recursion during removal of special event handlers) + if ( origCount && !handlers.length ) { + if ( !special.teardown || special.teardown.call( elem, namespaces, elemData.handle ) === false ) { + jQuery.removeEvent( elem, type, elemData.handle ); + } + + delete events[ type ]; + } + } + + // Remove the expando if it's no longer used + if ( jQuery.isEmptyObject( events ) ) { + delete elemData.handle; + + // removeData also checks for emptiness and clears the expando if empty + // so use it instead of delete + jQuery._removeData( elem, "events" ); + } + }, + + trigger: function( event, data, elem, onlyHandlers ) { + var handle, ontype, cur, + bubbleType, special, tmp, i, + eventPath = [ elem || document ], + type = core_hasOwn.call( event, "type" ) ? event.type : event, + namespaces = core_hasOwn.call( event, "namespace" ) ? event.namespace.split(".") : []; + + cur = tmp = elem = elem || document; + + // Don't do events on text and comment nodes + if ( elem.nodeType === 3 || elem.nodeType === 8 ) { + return; + } + + // focus/blur morphs to focusin/out; ensure we're not firing them right now + if ( rfocusMorph.test( type + jQuery.event.triggered ) ) { + return; + } + + if ( type.indexOf(".") >= 0 ) { + // Namespaced trigger; create a regexp to match event type in handle() + namespaces = type.split("."); + type = namespaces.shift(); + namespaces.sort(); + } + ontype = type.indexOf(":") < 0 && "on" + type; + + // Caller can pass in a jQuery.Event object, Object, or just an event type string + event = event[ jQuery.expando ] ? + event : + new jQuery.Event( type, typeof event === "object" && event ); + + event.isTrigger = true; + event.namespace = namespaces.join("."); + event.namespace_re = event.namespace ? + new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" ) : + null; + + // Clean up the event in case it is being reused + event.result = undefined; + if ( !event.target ) { + event.target = elem; + } + + // Clone any incoming data and prepend the event, creating the handler arg list + data = data == null ? + [ event ] : + jQuery.makeArray( data, [ event ] ); + + // Allow special events to draw outside the lines + special = jQuery.event.special[ type ] || {}; + if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) { + return; + } + + // Determine event propagation path in advance, per W3C events spec (#9951) + // Bubble up to document, then to window; watch for a global ownerDocument var (#9724) + if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) { + + bubbleType = special.delegateType || type; + if ( !rfocusMorph.test( bubbleType + type ) ) { + cur = cur.parentNode; + } + for ( ; cur; cur = cur.parentNode ) { + eventPath.push( cur ); + tmp = cur; + } + + // Only add window if we got to document (e.g., not plain obj or detached DOM) + if ( tmp === (elem.ownerDocument || document) ) { + eventPath.push( tmp.defaultView || tmp.parentWindow || window ); + } + } + + // Fire handlers on the event path + i = 0; + while ( (cur = eventPath[i++]) && !event.isPropagationStopped() ) { + + event.type = i > 1 ? + bubbleType : + special.bindType || type; + + // jQuery handler + handle = ( jQuery._data( cur, "events" ) || {} )[ event.type ] && jQuery._data( cur, "handle" ); + if ( handle ) { + handle.apply( cur, data ); + } + + // Native handler + handle = ontype && cur[ ontype ]; + if ( handle && jQuery.acceptData( cur ) && handle.apply && handle.apply( cur, data ) === false ) { + event.preventDefault(); + } + } + event.type = type; + + // If nobody prevented the default action, do it now + if ( !onlyHandlers && !event.isDefaultPrevented() ) { + + if ( (!special._default || special._default.apply( elem.ownerDocument, data ) === false) && + !(type === "click" && jQuery.nodeName( elem, "a" )) && jQuery.acceptData( elem ) ) { + + // Call a native DOM method on the target with the same name name as the event. + // Can't use an .isFunction() check here because IE6/7 fails that test. + // Don't do default actions on window, that's where global variables be (#6170) + if ( ontype && elem[ type ] && !jQuery.isWindow( elem ) ) { + + // Don't re-trigger an onFOO event when we call its FOO() method + tmp = elem[ ontype ]; + + if ( tmp ) { + elem[ ontype ] = null; + } + + // Prevent re-triggering of the same event, since we already bubbled it above + jQuery.event.triggered = type; + try { + elem[ type ](); + } catch ( e ) { + // IE<9 dies on focus/blur to hidden element (#1486,#12518) + // only reproducible on winXP IE8 native, not IE9 in IE8 mode + } + jQuery.event.triggered = undefined; + + if ( tmp ) { + elem[ ontype ] = tmp; + } + } + } + } + + return event.result; + }, + + dispatch: function( event ) { + + // Make a writable jQuery.Event from the native event object + event = jQuery.event.fix( event ); + + var i, ret, handleObj, matched, j, + handlerQueue = [], + args = core_slice.call( arguments ), + handlers = ( jQuery._data( this, "events" ) || {} )[ event.type ] || [], + special = jQuery.event.special[ event.type ] || {}; + + // Use the fix-ed jQuery.Event rather than the (read-only) native event + args[0] = event; + event.delegateTarget = this; + + // Call the preDispatch hook for the mapped type, and let it bail if desired + if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) { + return; + } + + // Determine handlers + handlerQueue = jQuery.event.handlers.call( this, event, handlers ); + + // Run delegates first; they may want to stop propagation beneath us + i = 0; + while ( (matched = handlerQueue[ i++ ]) && !event.isPropagationStopped() ) { + event.currentTarget = matched.elem; + + j = 0; + while ( (handleObj = matched.handlers[ j++ ]) && !event.isImmediatePropagationStopped() ) { + + // Triggered event must either 1) have no namespace, or + // 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace). + if ( !event.namespace_re || event.namespace_re.test( handleObj.namespace ) ) { + + event.handleObj = handleObj; + event.data = handleObj.data; + + ret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler ) + .apply( matched.elem, args ); + + if ( ret !== undefined ) { + if ( (event.result = ret) === false ) { + event.preventDefault(); + event.stopPropagation(); + } + } + } + } + } + + // Call the postDispatch hook for the mapped type + if ( special.postDispatch ) { + special.postDispatch.call( this, event ); + } + + return event.result; + }, + + handlers: function( event, handlers ) { + var sel, handleObj, matches, i, + handlerQueue = [], + delegateCount = handlers.delegateCount, + cur = event.target; + + // Find delegate handlers + // Black-hole SVG instance trees (#13180) + // Avoid non-left-click bubbling in Firefox (#3861) + if ( delegateCount && cur.nodeType && (!event.button || event.type !== "click") ) { + + for ( ; cur != this; cur = cur.parentNode || this ) { + + // Don't check non-elements (#13208) + // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764) + if ( cur.nodeType === 1 && (cur.disabled !== true || event.type !== "click") ) { + matches = []; + for ( i = 0; i < delegateCount; i++ ) { + handleObj = handlers[ i ]; + + // Don't conflict with Object.prototype properties (#13203) + sel = handleObj.selector + " "; + + if ( matches[ sel ] === undefined ) { + matches[ sel ] = handleObj.needsContext ? + jQuery( sel, this ).index( cur ) >= 0 : + jQuery.find( sel, this, null, [ cur ] ).length; + } + if ( matches[ sel ] ) { + matches.push( handleObj ); + } + } + if ( matches.length ) { + handlerQueue.push({ elem: cur, handlers: matches }); + } + } + } + } + + // Add the remaining (directly-bound) handlers + if ( delegateCount < handlers.length ) { + handlerQueue.push({ elem: this, handlers: handlers.slice( delegateCount ) }); + } + + return handlerQueue; + }, + + fix: function( event ) { + if ( event[ jQuery.expando ] ) { + return event; + } + + // Create a writable copy of the event object and normalize some properties + var i, prop, copy, + type = event.type, + originalEvent = event, + fixHook = this.fixHooks[ type ]; + + if ( !fixHook ) { + this.fixHooks[ type ] = fixHook = + rmouseEvent.test( type ) ? this.mouseHooks : + rkeyEvent.test( type ) ? this.keyHooks : + {}; + } + copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props; + + event = new jQuery.Event( originalEvent ); + + i = copy.length; + while ( i-- ) { + prop = copy[ i ]; + event[ prop ] = originalEvent[ prop ]; + } + + // Support: IE<9 + // Fix target property (#1925) + if ( !event.target ) { + event.target = originalEvent.srcElement || document; + } + + // Support: Chrome 23+, Safari? + // Target should not be a text node (#504, #13143) + if ( event.target.nodeType === 3 ) { + event.target = event.target.parentNode; + } + + // Support: IE<9 + // For mouse/key events, metaKey==false if it's undefined (#3368, #11328) + event.metaKey = !!event.metaKey; + + return fixHook.filter ? fixHook.filter( event, originalEvent ) : event; + }, + + // Includes some event props shared by KeyEvent and MouseEvent + props: "altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "), + + fixHooks: {}, + + keyHooks: { + props: "char charCode key keyCode".split(" "), + filter: function( event, original ) { + + // Add which for key events + if ( event.which == null ) { + event.which = original.charCode != null ? original.charCode : original.keyCode; + } + + return event; + } + }, + + mouseHooks: { + props: "button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "), + filter: function( event, original ) { + var body, eventDoc, doc, + button = original.button, + fromElement = original.fromElement; + + // Calculate pageX/Y if missing and clientX/Y available + if ( event.pageX == null && original.clientX != null ) { + eventDoc = event.target.ownerDocument || document; + doc = eventDoc.documentElement; + body = eventDoc.body; + + event.pageX = original.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && body.clientLeft || 0 ); + event.pageY = original.clientY + ( doc && doc.scrollTop || body && body.scrollTop || 0 ) - ( doc && doc.clientTop || body && body.clientTop || 0 ); + } + + // Add relatedTarget, if necessary + if ( !event.relatedTarget && fromElement ) { + event.relatedTarget = fromElement === event.target ? original.toElement : fromElement; + } + + // Add which for click: 1 === left; 2 === middle; 3 === right + // Note: button is not normalized, so don't use it + if ( !event.which && button !== undefined ) { + event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) ); + } + + return event; + } + }, + + special: { + load: { + // Prevent triggered image.load events from bubbling to window.load + noBubble: true + }, + click: { + // For checkbox, fire native event so checked state will be right + trigger: function() { + if ( jQuery.nodeName( this, "input" ) && this.type === "checkbox" && this.click ) { + this.click(); + return false; + } + } + }, + focus: { + // Fire native event if possible so blur/focus sequence is correct + trigger: function() { + if ( this !== document.activeElement && this.focus ) { + try { + this.focus(); + return false; + } catch ( e ) { + // Support: IE<9 + // If we error on focus to hidden element (#1486, #12518), + // let .trigger() run the handlers + } + } + }, + delegateType: "focusin" + }, + blur: { + trigger: function() { + if ( this === document.activeElement && this.blur ) { + this.blur(); + return false; + } + }, + delegateType: "focusout" + }, + + beforeunload: { + postDispatch: function( event ) { + + // Even when returnValue equals to undefined Firefox will still show alert + if ( event.result !== undefined ) { + event.originalEvent.returnValue = event.result; + } + } + } + }, + + simulate: function( type, elem, event, bubble ) { + // Piggyback on a donor event to simulate a different one. + // Fake originalEvent to avoid donor's stopPropagation, but if the + // simulated event prevents default then we do the same on the donor. + var e = jQuery.extend( + new jQuery.Event(), + event, + { type: type, + isSimulated: true, + originalEvent: {} + } + ); + if ( bubble ) { + jQuery.event.trigger( e, null, elem ); + } else { + jQuery.event.dispatch.call( elem, e ); + } + if ( e.isDefaultPrevented() ) { + event.preventDefault(); + } + } +}; + +jQuery.removeEvent = document.removeEventListener ? + function( elem, type, handle ) { + if ( elem.removeEventListener ) { + elem.removeEventListener( type, handle, false ); + } + } : + function( elem, type, handle ) { + var name = "on" + type; + + if ( elem.detachEvent ) { + + // #8545, #7054, preventing memory leaks for custom events in IE6-8 + // detachEvent needed property on element, by name of that event, to properly expose it to GC + if ( typeof elem[ name ] === core_strundefined ) { + elem[ name ] = null; + } + + elem.detachEvent( name, handle ); + } + }; + +jQuery.Event = function( src, props ) { + // Allow instantiation without the 'new' keyword + if ( !(this instanceof jQuery.Event) ) { + return new jQuery.Event( src, props ); + } + + // Event object + if ( src && src.type ) { + this.originalEvent = src; + this.type = src.type; + + // Events bubbling up the document may have been marked as prevented + // by a handler lower down the tree; reflect the correct value. + this.isDefaultPrevented = ( src.defaultPrevented || src.returnValue === false || + src.getPreventDefault && src.getPreventDefault() ) ? returnTrue : returnFalse; + + // Event type + } else { + this.type = src; + } + + // Put explicitly provided properties onto the event object + if ( props ) { + jQuery.extend( this, props ); + } + + // Create a timestamp if incoming event doesn't have one + this.timeStamp = src && src.timeStamp || jQuery.now(); + + // Mark it as fixed + this[ jQuery.expando ] = true; +}; + +// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding +// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html +jQuery.Event.prototype = { + isDefaultPrevented: returnFalse, + isPropagationStopped: returnFalse, + isImmediatePropagationStopped: returnFalse, + + preventDefault: function() { + var e = this.originalEvent; + + this.isDefaultPrevented = returnTrue; + if ( !e ) { + return; + } + + // If preventDefault exists, run it on the original event + if ( e.preventDefault ) { + e.preventDefault(); + + // Support: IE + // Otherwise set the returnValue property of the original event to false + } else { + e.returnValue = false; + } + }, + stopPropagation: function() { + var e = this.originalEvent; + + this.isPropagationStopped = returnTrue; + if ( !e ) { + return; + } + // If stopPropagation exists, run it on the original event + if ( e.stopPropagation ) { + e.stopPropagation(); + } + + // Support: IE + // Set the cancelBubble property of the original event to true + e.cancelBubble = true; + }, + stopImmediatePropagation: function() { + this.isImmediatePropagationStopped = returnTrue; + this.stopPropagation(); + } +}; + +// Create mouseenter/leave events using mouseover/out and event-time checks +jQuery.each({ + mouseenter: "mouseover", + mouseleave: "mouseout" +}, function( orig, fix ) { + jQuery.event.special[ orig ] = { + delegateType: fix, + bindType: fix, + + handle: function( event ) { + var ret, + target = this, + related = event.relatedTarget, + handleObj = event.handleObj; + + // For mousenter/leave call the handler if related is outside the target. + // NB: No relatedTarget if the mouse left/entered the browser window + if ( !related || (related !== target && !jQuery.contains( target, related )) ) { + event.type = handleObj.origType; + ret = handleObj.handler.apply( this, arguments ); + event.type = fix; + } + return ret; + } + }; +}); + +// IE submit delegation +if ( !jQuery.support.submitBubbles ) { + + jQuery.event.special.submit = { + setup: function() { + // Only need this for delegated form submit events + if ( jQuery.nodeName( this, "form" ) ) { + return false; + } + + // Lazy-add a submit handler when a descendant form may potentially be submitted + jQuery.event.add( this, "click._submit keypress._submit", function( e ) { + // Node name check avoids a VML-related crash in IE (#9807) + var elem = e.target, + form = jQuery.nodeName( elem, "input" ) || jQuery.nodeName( elem, "button" ) ? elem.form : undefined; + if ( form && !jQuery._data( form, "submitBubbles" ) ) { + jQuery.event.add( form, "submit._submit", function( event ) { + event._submit_bubble = true; + }); + jQuery._data( form, "submitBubbles", true ); + } + }); + // return undefined since we don't need an event listener + }, + + postDispatch: function( event ) { + // If form was submitted by the user, bubble the event up the tree + if ( event._submit_bubble ) { + delete event._submit_bubble; + if ( this.parentNode && !event.isTrigger ) { + jQuery.event.simulate( "submit", this.parentNode, event, true ); + } + } + }, + + teardown: function() { + // Only need this for delegated form submit events + if ( jQuery.nodeName( this, "form" ) ) { + return false; + } + + // Remove delegated handlers; cleanData eventually reaps submit handlers attached above + jQuery.event.remove( this, "._submit" ); + } + }; +} + +// IE change delegation and checkbox/radio fix +if ( !jQuery.support.changeBubbles ) { + + jQuery.event.special.change = { + + setup: function() { + + if ( rformElems.test( this.nodeName ) ) { + // IE doesn't fire change on a check/radio until blur; trigger it on click + // after a propertychange. Eat the blur-change in special.change.handle. + // This still fires onchange a second time for check/radio after blur. + if ( this.type === "checkbox" || this.type === "radio" ) { + jQuery.event.add( this, "propertychange._change", function( event ) { + if ( event.originalEvent.propertyName === "checked" ) { + this._just_changed = true; + } + }); + jQuery.event.add( this, "click._change", function( event ) { + if ( this._just_changed && !event.isTrigger ) { + this._just_changed = false; + } + // Allow triggered, simulated change events (#11500) + jQuery.event.simulate( "change", this, event, true ); + }); + } + return false; + } + // Delegated event; lazy-add a change handler on descendant inputs + jQuery.event.add( this, "beforeactivate._change", function( e ) { + var elem = e.target; + + if ( rformElems.test( elem.nodeName ) && !jQuery._data( elem, "changeBubbles" ) ) { + jQuery.event.add( elem, "change._change", function( event ) { + if ( this.parentNode && !event.isSimulated && !event.isTrigger ) { + jQuery.event.simulate( "change", this.parentNode, event, true ); + } + }); + jQuery._data( elem, "changeBubbles", true ); + } + }); + }, + + handle: function( event ) { + var elem = event.target; + + // Swallow native change events from checkbox/radio, we already triggered them above + if ( this !== elem || event.isSimulated || event.isTrigger || (elem.type !== "radio" && elem.type !== "checkbox") ) { + return event.handleObj.handler.apply( this, arguments ); + } + }, + + teardown: function() { + jQuery.event.remove( this, "._change" ); + + return !rformElems.test( this.nodeName ); + } + }; +} + +// Create "bubbling" focus and blur events +if ( !jQuery.support.focusinBubbles ) { + jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) { + + // Attach a single capturing handler while someone wants focusin/focusout + var attaches = 0, + handler = function( event ) { + jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true ); + }; + + jQuery.event.special[ fix ] = { + setup: function() { + if ( attaches++ === 0 ) { + document.addEventListener( orig, handler, true ); + } + }, + teardown: function() { + if ( --attaches === 0 ) { + document.removeEventListener( orig, handler, true ); + } + } + }; + }); +} + +jQuery.fn.extend({ + + on: function( types, selector, data, fn, /*INTERNAL*/ one ) { + var type, origFn; + + // Types can be a map of types/handlers + if ( typeof types === "object" ) { + // ( types-Object, selector, data ) + if ( typeof selector !== "string" ) { + // ( types-Object, data ) + data = data || selector; + selector = undefined; + } + for ( type in types ) { + this.on( type, selector, data, types[ type ], one ); + } + return this; + } + + if ( data == null && fn == null ) { + // ( types, fn ) + fn = selector; + data = selector = undefined; + } else if ( fn == null ) { + if ( typeof selector === "string" ) { + // ( types, selector, fn ) + fn = data; + data = undefined; + } else { + // ( types, data, fn ) + fn = data; + data = selector; + selector = undefined; + } + } + if ( fn === false ) { + fn = returnFalse; + } else if ( !fn ) { + return this; + } + + if ( one === 1 ) { + origFn = fn; + fn = function( event ) { + // Can use an empty set, since event contains the info + jQuery().off( event ); + return origFn.apply( this, arguments ); + }; + // Use same guid so caller can remove using origFn + fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); + } + return this.each( function() { + jQuery.event.add( this, types, fn, data, selector ); + }); + }, + one: function( types, selector, data, fn ) { + return this.on( types, selector, data, fn, 1 ); + }, + off: function( types, selector, fn ) { + var handleObj, type; + if ( types && types.preventDefault && types.handleObj ) { + // ( event ) dispatched jQuery.Event + handleObj = types.handleObj; + jQuery( types.delegateTarget ).off( + handleObj.namespace ? handleObj.origType + "." + handleObj.namespace : handleObj.origType, + handleObj.selector, + handleObj.handler + ); + return this; + } + if ( typeof types === "object" ) { + // ( types-object [, selector] ) + for ( type in types ) { + this.off( type, selector, types[ type ] ); + } + return this; + } + if ( selector === false || typeof selector === "function" ) { + // ( types [, fn] ) + fn = selector; + selector = undefined; + } + if ( fn === false ) { + fn = returnFalse; + } + return this.each(function() { + jQuery.event.remove( this, types, fn, selector ); + }); + }, + + bind: function( types, data, fn ) { + return this.on( types, null, data, fn ); + }, + unbind: function( types, fn ) { + return this.off( types, null, fn ); + }, + + delegate: function( selector, types, data, fn ) { + return this.on( types, selector, data, fn ); + }, + undelegate: function( selector, types, fn ) { + // ( namespace ) or ( selector, types [, fn] ) + return arguments.length === 1 ? this.off( selector, "**" ) : this.off( types, selector || "**", fn ); + }, + + trigger: function( type, data ) { + return this.each(function() { + jQuery.event.trigger( type, data, this ); + }); + }, + triggerHandler: function( type, data ) { + var elem = this[0]; + if ( elem ) { + return jQuery.event.trigger( type, data, elem, true ); + } + } +}); +/*! + * Sizzle CSS Selector Engine + * Copyright 2012 jQuery Foundation and other contributors + * Released under the MIT license + * http://sizzlejs.com/ + */ +(function( window, undefined ) { + +var i, + cachedruns, + Expr, + getText, + isXML, + compile, + hasDuplicate, + outermostContext, + + // Local document vars + setDocument, + document, + docElem, + documentIsXML, + rbuggyQSA, + rbuggyMatches, + matches, + contains, + sortOrder, + + // Instance-specific data + expando = "sizzle" + -(new Date()), + preferredDoc = window.document, + support = {}, + dirruns = 0, + done = 0, + classCache = createCache(), + tokenCache = createCache(), + compilerCache = createCache(), + + // General-purpose constants + strundefined = typeof undefined, + MAX_NEGATIVE = 1 << 31, + + // Array methods + arr = [], + pop = arr.pop, + push = arr.push, + slice = arr.slice, + // Use a stripped-down indexOf if we can't use a native one + indexOf = arr.indexOf || function( elem ) { + var i = 0, + len = this.length; + for ( ; i < len; i++ ) { + if ( this[i] === elem ) { + return i; + } + } + return -1; + }, + + + // Regular expressions + + // Whitespace characters http://www.w3.org/TR/css3-selectors/#whitespace + whitespace = "[\\x20\\t\\r\\n\\f]", + // http://www.w3.org/TR/css3-syntax/#characters + characterEncoding = "(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+", + + // Loosely modeled on CSS identifier characters + // An unquoted value should be a CSS identifier http://www.w3.org/TR/css3-selectors/#attribute-selectors + // Proper syntax: http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier + identifier = characterEncoding.replace( "w", "w#" ), + + // Acceptable operators http://www.w3.org/TR/selectors/#attribute-selectors + operators = "([*^$|!~]?=)", + attributes = "\\[" + whitespace + "*(" + characterEncoding + ")" + whitespace + + "*(?:" + operators + whitespace + "*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|(" + identifier + ")|)|)" + whitespace + "*\\]", + + // Prefer arguments quoted, + // then not containing pseudos/brackets, + // then attribute selectors/non-parenthetical expressions, + // then anything else + // These preferences are here to reduce the number of selectors + // needing tokenize in the PSEUDO preFilter + pseudos = ":(" + characterEncoding + ")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|" + attributes.replace( 3, 8 ) + ")*)|.*)\\)|)", + + // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter + rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ), + + rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ), + rcombinators = new RegExp( "^" + whitespace + "*([\\x20\\t\\r\\n\\f>+~])" + whitespace + "*" ), + rpseudo = new RegExp( pseudos ), + ridentifier = new RegExp( "^" + identifier + "$" ), + + matchExpr = { + "ID": new RegExp( "^#(" + characterEncoding + ")" ), + "CLASS": new RegExp( "^\\.(" + characterEncoding + ")" ), + "NAME": new RegExp( "^\\[name=['\"]?(" + characterEncoding + ")['\"]?\\]" ), + "TAG": new RegExp( "^(" + characterEncoding.replace( "w", "w*" ) + ")" ), + "ATTR": new RegExp( "^" + attributes ), + "PSEUDO": new RegExp( "^" + pseudos ), + "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace + + "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace + + "*(\\d+)|))" + whitespace + "*\\)|)", "i" ), + // For use in libraries implementing .is() + // We use this for POS matching in `select` + "needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + + whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" ) + }, + + rsibling = /[\x20\t\r\n\f]*[+~]/, + + rnative = /^[^{]+\{\s*\[native code/, + + // Easily-parseable/retrievable ID or TAG or CLASS selectors + rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/, + + rinputs = /^(?:input|select|textarea|button)$/i, + rheader = /^h\d$/i, + + rescape = /'|\\/g, + rattributeQuotes = /\=[\x20\t\r\n\f]*([^'"\]]*)[\x20\t\r\n\f]*\]/g, + + // CSS escapes http://www.w3.org/TR/CSS21/syndata.html#escaped-characters + runescape = /\\([\da-fA-F]{1,6}[\x20\t\r\n\f]?|.)/g, + funescape = function( _, escaped ) { + var high = "0x" + escaped - 0x10000; + // NaN means non-codepoint + return high !== high ? + escaped : + // BMP codepoint + high < 0 ? + String.fromCharCode( high + 0x10000 ) : + // Supplemental Plane codepoint (surrogate pair) + String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 ); + }; + +// Use a stripped-down slice if we can't use a native one +try { + slice.call( preferredDoc.documentElement.childNodes, 0 )[0].nodeType; +} catch ( e ) { + slice = function( i ) { + var elem, + results = []; + while ( (elem = this[i++]) ) { + results.push( elem ); + } + return results; + }; +} + +/** + * For feature detection + * @param {Function} fn The function to test for native support + */ +function isNative( fn ) { + return rnative.test( fn + "" ); +} + +/** + * Create key-value caches of limited size + * @returns {Function(string, Object)} Returns the Object data after storing it on itself with + * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength) + * deleting the oldest entry + */ +function createCache() { + var cache, + keys = []; + + return (cache = function( key, value ) { + // Use (key + " ") to avoid collision with native prototype properties (see Issue #157) + if ( keys.push( key += " " ) > Expr.cacheLength ) { + // Only keep the most recent entries + delete cache[ keys.shift() ]; + } + return (cache[ key ] = value); + }); +} + +/** + * Mark a function for special use by Sizzle + * @param {Function} fn The function to mark + */ +function markFunction( fn ) { + fn[ expando ] = true; + return fn; +} + +/** + * Support testing using an element + * @param {Function} fn Passed the created div and expects a boolean result + */ +function assert( fn ) { + var div = document.createElement("div"); + + try { + return fn( div ); + } catch (e) { + return false; + } finally { + // release memory in IE + div = null; + } +} + +function Sizzle( selector, context, results, seed ) { + var match, elem, m, nodeType, + // QSA vars + i, groups, old, nid, newContext, newSelector; + + if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) { + setDocument( context ); + } + + context = context || document; + results = results || []; + + if ( !selector || typeof selector !== "string" ) { + return results; + } + + if ( (nodeType = context.nodeType) !== 1 && nodeType !== 9 ) { + return []; + } + + if ( !documentIsXML && !seed ) { + + // Shortcuts + if ( (match = rquickExpr.exec( selector )) ) { + // Speed-up: Sizzle("#ID") + if ( (m = match[1]) ) { + if ( nodeType === 9 ) { + elem = context.getElementById( m ); + // Check parentNode to catch when Blackberry 4.6 returns + // nodes that are no longer in the document #6963 + if ( elem && elem.parentNode ) { + // Handle the case where IE, Opera, and Webkit return items + // by name instead of ID + if ( elem.id === m ) { + results.push( elem ); + return results; + } + } else { + return results; + } + } else { + // Context is not a document + if ( context.ownerDocument && (elem = context.ownerDocument.getElementById( m )) && + contains( context, elem ) && elem.id === m ) { + results.push( elem ); + return results; + } + } + + // Speed-up: Sizzle("TAG") + } else if ( match[2] ) { + push.apply( results, slice.call(context.getElementsByTagName( selector ), 0) ); + return results; + + // Speed-up: Sizzle(".CLASS") + } else if ( (m = match[3]) && support.getByClassName && context.getElementsByClassName ) { + push.apply( results, slice.call(context.getElementsByClassName( m ), 0) ); + return results; + } + } + + // QSA path + if ( support.qsa && !rbuggyQSA.test(selector) ) { + old = true; + nid = expando; + newContext = context; + newSelector = nodeType === 9 && selector; + + // qSA works strangely on Element-rooted queries + // We can work around this by specifying an extra ID on the root + // and working up from there (Thanks to Andrew Dupont for the technique) + // IE 8 doesn't work on object elements + if ( nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) { + groups = tokenize( selector ); + + if ( (old = context.getAttribute("id")) ) { + nid = old.replace( rescape, "\\$&" ); + } else { + context.setAttribute( "id", nid ); + } + nid = "[id='" + nid + "'] "; + + i = groups.length; + while ( i-- ) { + groups[i] = nid + toSelector( groups[i] ); + } + newContext = rsibling.test( selector ) && context.parentNode || context; + newSelector = groups.join(","); + } + + if ( newSelector ) { + try { + push.apply( results, slice.call( newContext.querySelectorAll( + newSelector + ), 0 ) ); + return results; + } catch(qsaError) { + } finally { + if ( !old ) { + context.removeAttribute("id"); + } + } + } + } + } + + // All others + return select( selector.replace( rtrim, "$1" ), context, results, seed ); +} + +/** + * Detect xml + * @param {Element|Object} elem An element or a document + */ +isXML = Sizzle.isXML = function( elem ) { + // documentElement is verified for cases where it doesn't yet exist + // (such as loading iframes in IE - #4833) + var documentElement = elem && (elem.ownerDocument || elem).documentElement; + return documentElement ? documentElement.nodeName !== "HTML" : false; +}; + +/** + * Sets document-related variables once based on the current document + * @param {Element|Object} [doc] An element or document object to use to set the document + * @returns {Object} Returns the current document + */ +setDocument = Sizzle.setDocument = function( node ) { + var doc = node ? node.ownerDocument || node : preferredDoc; + + // If no document and documentElement is available, return + if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) { + return document; + } + + // Set our document + document = doc; + docElem = doc.documentElement; + + // Support tests + documentIsXML = isXML( doc ); + + // Check if getElementsByTagName("*") returns only elements + support.tagNameNoComments = assert(function( div ) { + div.appendChild( doc.createComment("") ); + return !div.getElementsByTagName("*").length; + }); + + // Check if attributes should be retrieved by attribute nodes + support.attributes = assert(function( div ) { + div.innerHTML = ""; + var type = typeof div.lastChild.getAttribute("multiple"); + // IE8 returns a string for some attributes even when not present + return type !== "boolean" && type !== "string"; + }); + + // Check if getElementsByClassName can be trusted + support.getByClassName = assert(function( div ) { + // Opera can't find a second classname (in 9.6) + div.innerHTML = ""; + if ( !div.getElementsByClassName || !div.getElementsByClassName("e").length ) { + return false; + } + + // Safari 3.2 caches class attributes and doesn't catch changes + div.lastChild.className = "e"; + return div.getElementsByClassName("e").length === 2; + }); + + // Check if getElementById returns elements by name + // Check if getElementsByName privileges form controls or returns elements by ID + support.getByName = assert(function( div ) { + // Inject content + div.id = expando + 0; + div.innerHTML = "
"; + docElem.insertBefore( div, docElem.firstChild ); + + // Test + var pass = doc.getElementsByName && + // buggy browsers will return fewer than the correct 2 + doc.getElementsByName( expando ).length === 2 + + // buggy browsers will return more than the correct 0 + doc.getElementsByName( expando + 0 ).length; + support.getIdNotName = !doc.getElementById( expando ); + + // Cleanup + docElem.removeChild( div ); + + return pass; + }); + + // IE6/7 return modified attributes + Expr.attrHandle = assert(function( div ) { + div.innerHTML = ""; + return div.firstChild && typeof div.firstChild.getAttribute !== strundefined && + div.firstChild.getAttribute("href") === "#"; + }) ? + {} : + { + "href": function( elem ) { + return elem.getAttribute( "href", 2 ); + }, + "type": function( elem ) { + return elem.getAttribute("type"); + } + }; + + // ID find and filter + if ( support.getIdNotName ) { + Expr.find["ID"] = function( id, context ) { + if ( typeof context.getElementById !== strundefined && !documentIsXML ) { + var m = context.getElementById( id ); + // Check parentNode to catch when Blackberry 4.6 returns + // nodes that are no longer in the document #6963 + return m && m.parentNode ? [m] : []; + } + }; + Expr.filter["ID"] = function( id ) { + var attrId = id.replace( runescape, funescape ); + return function( elem ) { + return elem.getAttribute("id") === attrId; + }; + }; + } else { + Expr.find["ID"] = function( id, context ) { + if ( typeof context.getElementById !== strundefined && !documentIsXML ) { + var m = context.getElementById( id ); + + return m ? + m.id === id || typeof m.getAttributeNode !== strundefined && m.getAttributeNode("id").value === id ? + [m] : + undefined : + []; + } + }; + Expr.filter["ID"] = function( id ) { + var attrId = id.replace( runescape, funescape ); + return function( elem ) { + var node = typeof elem.getAttributeNode !== strundefined && elem.getAttributeNode("id"); + return node && node.value === attrId; + }; + }; + } + + // Tag + Expr.find["TAG"] = support.tagNameNoComments ? + function( tag, context ) { + if ( typeof context.getElementsByTagName !== strundefined ) { + return context.getElementsByTagName( tag ); + } + } : + function( tag, context ) { + var elem, + tmp = [], + i = 0, + results = context.getElementsByTagName( tag ); + + // Filter out possible comments + if ( tag === "*" ) { + while ( (elem = results[i++]) ) { + if ( elem.nodeType === 1 ) { + tmp.push( elem ); + } + } + + return tmp; + } + return results; + }; + + // Name + Expr.find["NAME"] = support.getByName && function( tag, context ) { + if ( typeof context.getElementsByName !== strundefined ) { + return context.getElementsByName( name ); + } + }; + + // Class + Expr.find["CLASS"] = support.getByClassName && function( className, context ) { + if ( typeof context.getElementsByClassName !== strundefined && !documentIsXML ) { + return context.getElementsByClassName( className ); + } + }; + + // QSA and matchesSelector support + + // matchesSelector(:active) reports false when true (IE9/Opera 11.5) + rbuggyMatches = []; + + // qSa(:focus) reports false when true (Chrome 21), + // no need to also add to buggyMatches since matches checks buggyQSA + // A support test would require too much code (would include document ready) + rbuggyQSA = [ ":focus" ]; + + if ( (support.qsa = isNative(doc.querySelectorAll)) ) { + // Build QSA regex + // Regex strategy adopted from Diego Perini + assert(function( div ) { + // Select is set to empty string on purpose + // This is to test IE's treatment of not explictly + // setting a boolean content attribute, + // since its presence should be enough + // http://bugs.jquery.com/ticket/12359 + div.innerHTML = ""; + + // IE8 - Some boolean attributes are not treated correctly + if ( !div.querySelectorAll("[selected]").length ) { + rbuggyQSA.push( "\\[" + whitespace + "*(?:checked|disabled|ismap|multiple|readonly|selected|value)" ); + } + + // Webkit/Opera - :checked should return selected option elements + // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + // IE8 throws error here and will not see later tests + if ( !div.querySelectorAll(":checked").length ) { + rbuggyQSA.push(":checked"); + } + }); + + assert(function( div ) { + + // Opera 10-12/IE8 - ^= $= *= and empty values + // Should not select anything + div.innerHTML = ""; + if ( div.querySelectorAll("[i^='']").length ) { + rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:\"\"|'')" ); + } + + // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled) + // IE8 throws error here and will not see later tests + if ( !div.querySelectorAll(":enabled").length ) { + rbuggyQSA.push( ":enabled", ":disabled" ); + } + + // Opera 10-11 does not throw on post-comma invalid pseudos + div.querySelectorAll("*,:x"); + rbuggyQSA.push(",.*:"); + }); + } + + if ( (support.matchesSelector = isNative( (matches = docElem.matchesSelector || + docElem.mozMatchesSelector || + docElem.webkitMatchesSelector || + docElem.oMatchesSelector || + docElem.msMatchesSelector) )) ) { + + assert(function( div ) { + // Check to see if it's possible to do matchesSelector + // on a disconnected node (IE 9) + support.disconnectedMatch = matches.call( div, "div" ); + + // This should fail with an exception + // Gecko does not error, returns false instead + matches.call( div, "[s!='']:x" ); + rbuggyMatches.push( "!=", pseudos ); + }); + } + + rbuggyQSA = new RegExp( rbuggyQSA.join("|") ); + rbuggyMatches = new RegExp( rbuggyMatches.join("|") ); + + // Element contains another + // Purposefully does not implement inclusive descendent + // As in, an element does not contain itself + contains = isNative(docElem.contains) || docElem.compareDocumentPosition ? + function( a, b ) { + var adown = a.nodeType === 9 ? a.documentElement : a, + bup = b && b.parentNode; + return a === bup || !!( bup && bup.nodeType === 1 && ( + adown.contains ? + adown.contains( bup ) : + a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16 + )); + } : + function( a, b ) { + if ( b ) { + while ( (b = b.parentNode) ) { + if ( b === a ) { + return true; + } + } + } + return false; + }; + + // Document order sorting + sortOrder = docElem.compareDocumentPosition ? + function( a, b ) { + var compare; + + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + if ( (compare = b.compareDocumentPosition && a.compareDocumentPosition && a.compareDocumentPosition( b )) ) { + if ( compare & 1 || a.parentNode && a.parentNode.nodeType === 11 ) { + if ( a === doc || contains( preferredDoc, a ) ) { + return -1; + } + if ( b === doc || contains( preferredDoc, b ) ) { + return 1; + } + return 0; + } + return compare & 4 ? -1 : 1; + } + + return a.compareDocumentPosition ? -1 : 1; + } : + function( a, b ) { + var cur, + i = 0, + aup = a.parentNode, + bup = b.parentNode, + ap = [ a ], + bp = [ b ]; + + // Exit early if the nodes are identical + if ( a === b ) { + hasDuplicate = true; + return 0; + + // Parentless nodes are either documents or disconnected + } else if ( !aup || !bup ) { + return a === doc ? -1 : + b === doc ? 1 : + aup ? -1 : + bup ? 1 : + 0; + + // If the nodes are siblings, we can do a quick check + } else if ( aup === bup ) { + return siblingCheck( a, b ); + } + + // Otherwise we need full lists of their ancestors for comparison + cur = a; + while ( (cur = cur.parentNode) ) { + ap.unshift( cur ); + } + cur = b; + while ( (cur = cur.parentNode) ) { + bp.unshift( cur ); + } + + // Walk down the tree looking for a discrepancy + while ( ap[i] === bp[i] ) { + i++; + } + + return i ? + // Do a sibling check if the nodes have a common ancestor + siblingCheck( ap[i], bp[i] ) : + + // Otherwise nodes in our document sort first + ap[i] === preferredDoc ? -1 : + bp[i] === preferredDoc ? 1 : + 0; + }; + + // Always assume the presence of duplicates if sort doesn't + // pass them to our comparison function (as in Google Chrome). + hasDuplicate = false; + [0, 0].sort( sortOrder ); + support.detectDuplicates = hasDuplicate; + + return document; +}; + +Sizzle.matches = function( expr, elements ) { + return Sizzle( expr, null, null, elements ); +}; + +Sizzle.matchesSelector = function( elem, expr ) { + // Set document vars if needed + if ( ( elem.ownerDocument || elem ) !== document ) { + setDocument( elem ); + } + + // Make sure that attribute selectors are quoted + expr = expr.replace( rattributeQuotes, "='$1']" ); + + // rbuggyQSA always contains :focus, so no need for an existence check + if ( support.matchesSelector && !documentIsXML && (!rbuggyMatches || !rbuggyMatches.test(expr)) && !rbuggyQSA.test(expr) ) { + try { + var ret = matches.call( elem, expr ); + + // IE 9's matchesSelector returns false on disconnected nodes + if ( ret || support.disconnectedMatch || + // As well, disconnected nodes are said to be in a document + // fragment in IE 9 + elem.document && elem.document.nodeType !== 11 ) { + return ret; + } + } catch(e) {} + } + + return Sizzle( expr, document, null, [elem] ).length > 0; +}; + +Sizzle.contains = function( context, elem ) { + // Set document vars if needed + if ( ( context.ownerDocument || context ) !== document ) { + setDocument( context ); + } + return contains( context, elem ); +}; + +Sizzle.attr = function( elem, name ) { + var val; + + // Set document vars if needed + if ( ( elem.ownerDocument || elem ) !== document ) { + setDocument( elem ); + } + + if ( !documentIsXML ) { + name = name.toLowerCase(); + } + if ( (val = Expr.attrHandle[ name ]) ) { + return val( elem ); + } + if ( documentIsXML || support.attributes ) { + return elem.getAttribute( name ); + } + return ( (val = elem.getAttributeNode( name )) || elem.getAttribute( name ) ) && elem[ name ] === true ? + name : + val && val.specified ? val.value : null; +}; + +Sizzle.error = function( msg ) { + throw new Error( "Syntax error, unrecognized expression: " + msg ); +}; + +// Document sorting and removing duplicates +Sizzle.uniqueSort = function( results ) { + var elem, + duplicates = [], + i = 1, + j = 0; + + // Unless we *know* we can detect duplicates, assume their presence + hasDuplicate = !support.detectDuplicates; + results.sort( sortOrder ); + + if ( hasDuplicate ) { + for ( ; (elem = results[i]); i++ ) { + if ( elem === results[ i - 1 ] ) { + j = duplicates.push( i ); + } + } + while ( j-- ) { + results.splice( duplicates[ j ], 1 ); + } + } + + return results; +}; + +function siblingCheck( a, b ) { + var cur = b && a, + diff = cur && ( ~b.sourceIndex || MAX_NEGATIVE ) - ( ~a.sourceIndex || MAX_NEGATIVE ); + + // Use IE sourceIndex if available on both nodes + if ( diff ) { + return diff; + } + + // Check if b follows a + if ( cur ) { + while ( (cur = cur.nextSibling) ) { + if ( cur === b ) { + return -1; + } + } + } + + return a ? 1 : -1; +} + +// Returns a function to use in pseudos for input types +function createInputPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && elem.type === type; + }; +} + +// Returns a function to use in pseudos for buttons +function createButtonPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return (name === "input" || name === "button") && elem.type === type; + }; +} + +// Returns a function to use in pseudos for positionals +function createPositionalPseudo( fn ) { + return markFunction(function( argument ) { + argument = +argument; + return markFunction(function( seed, matches ) { + var j, + matchIndexes = fn( [], seed.length, argument ), + i = matchIndexes.length; + + // Match elements found at the specified indexes + while ( i-- ) { + if ( seed[ (j = matchIndexes[i]) ] ) { + seed[j] = !(matches[j] = seed[j]); + } + } + }); + }); +} + +/** + * Utility function for retrieving the text value of an array of DOM nodes + * @param {Array|Element} elem + */ +getText = Sizzle.getText = function( elem ) { + var node, + ret = "", + i = 0, + nodeType = elem.nodeType; + + if ( !nodeType ) { + // If no nodeType, this is expected to be an array + for ( ; (node = elem[i]); i++ ) { + // Do not traverse comment nodes + ret += getText( node ); + } + } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) { + // Use textContent for elements + // innerText usage removed for consistency of new lines (see #11153) + if ( typeof elem.textContent === "string" ) { + return elem.textContent; + } else { + // Traverse its children + for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { + ret += getText( elem ); + } + } + } else if ( nodeType === 3 || nodeType === 4 ) { + return elem.nodeValue; + } + // Do not include comment or processing instruction nodes + + return ret; +}; + +Expr = Sizzle.selectors = { + + // Can be adjusted by the user + cacheLength: 50, + + createPseudo: markFunction, + + match: matchExpr, + + find: {}, + + relative: { + ">": { dir: "parentNode", first: true }, + " ": { dir: "parentNode" }, + "+": { dir: "previousSibling", first: true }, + "~": { dir: "previousSibling" } + }, + + preFilter: { + "ATTR": function( match ) { + match[1] = match[1].replace( runescape, funescape ); + + // Move the given value to match[3] whether quoted or unquoted + match[3] = ( match[4] || match[5] || "" ).replace( runescape, funescape ); + + if ( match[2] === "~=" ) { + match[3] = " " + match[3] + " "; + } + + return match.slice( 0, 4 ); + }, + + "CHILD": function( match ) { + /* matches from matchExpr["CHILD"] + 1 type (only|nth|...) + 2 what (child|of-type) + 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...) + 4 xn-component of xn+y argument ([+-]?\d*n|) + 5 sign of xn-component + 6 x of xn-component + 7 sign of y-component + 8 y of y-component + */ + match[1] = match[1].toLowerCase(); + + if ( match[1].slice( 0, 3 ) === "nth" ) { + // nth-* requires argument + if ( !match[3] ) { + Sizzle.error( match[0] ); + } + + // numeric x and y parameters for Expr.filter.CHILD + // remember that false/true cast respectively to 0/1 + match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === "even" || match[3] === "odd" ) ); + match[5] = +( ( match[7] + match[8] ) || match[3] === "odd" ); + + // other types prohibit arguments + } else if ( match[3] ) { + Sizzle.error( match[0] ); + } + + return match; + }, + + "PSEUDO": function( match ) { + var excess, + unquoted = !match[5] && match[2]; + + if ( matchExpr["CHILD"].test( match[0] ) ) { + return null; + } + + // Accept quoted arguments as-is + if ( match[4] ) { + match[2] = match[4]; + + // Strip excess characters from unquoted arguments + } else if ( unquoted && rpseudo.test( unquoted ) && + // Get excess from tokenize (recursively) + (excess = tokenize( unquoted, true )) && + // advance to the next closing parenthesis + (excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) { + + // excess is a negative index + match[0] = match[0].slice( 0, excess ); + match[2] = unquoted.slice( 0, excess ); + } + + // Return only captures needed by the pseudo filter method (type and argument) + return match.slice( 0, 3 ); + } + }, + + filter: { + + "TAG": function( nodeName ) { + if ( nodeName === "*" ) { + return function() { return true; }; + } + + nodeName = nodeName.replace( runescape, funescape ).toLowerCase(); + return function( elem ) { + return elem.nodeName && elem.nodeName.toLowerCase() === nodeName; + }; + }, + + "CLASS": function( className ) { + var pattern = classCache[ className + " " ]; + + return pattern || + (pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) && + classCache( className, function( elem ) { + return pattern.test( elem.className || (typeof elem.getAttribute !== strundefined && elem.getAttribute("class")) || "" ); + }); + }, + + "ATTR": function( name, operator, check ) { + return function( elem ) { + var result = Sizzle.attr( elem, name ); + + if ( result == null ) { + return operator === "!="; + } + if ( !operator ) { + return true; + } + + result += ""; + + return operator === "=" ? result === check : + operator === "!=" ? result !== check : + operator === "^=" ? check && result.indexOf( check ) === 0 : + operator === "*=" ? check && result.indexOf( check ) > -1 : + operator === "$=" ? check && result.slice( -check.length ) === check : + operator === "~=" ? ( " " + result + " " ).indexOf( check ) > -1 : + operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" : + false; + }; + }, + + "CHILD": function( type, what, argument, first, last ) { + var simple = type.slice( 0, 3 ) !== "nth", + forward = type.slice( -4 ) !== "last", + ofType = what === "of-type"; + + return first === 1 && last === 0 ? + + // Shortcut for :nth-*(n) + function( elem ) { + return !!elem.parentNode; + } : + + function( elem, context, xml ) { + var cache, outerCache, node, diff, nodeIndex, start, + dir = simple !== forward ? "nextSibling" : "previousSibling", + parent = elem.parentNode, + name = ofType && elem.nodeName.toLowerCase(), + useCache = !xml && !ofType; + + if ( parent ) { + + // :(first|last|only)-(child|of-type) + if ( simple ) { + while ( dir ) { + node = elem; + while ( (node = node[ dir ]) ) { + if ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) { + return false; + } + } + // Reverse direction for :only-* (if we haven't yet done so) + start = dir = type === "only" && !start && "nextSibling"; + } + return true; + } + + start = [ forward ? parent.firstChild : parent.lastChild ]; + + // non-xml :nth-child(...) stores cache data on `parent` + if ( forward && useCache ) { + // Seek `elem` from a previously-cached index + outerCache = parent[ expando ] || (parent[ expando ] = {}); + cache = outerCache[ type ] || []; + nodeIndex = cache[0] === dirruns && cache[1]; + diff = cache[0] === dirruns && cache[2]; + node = nodeIndex && parent.childNodes[ nodeIndex ]; + + while ( (node = ++nodeIndex && node && node[ dir ] || + + // Fallback to seeking `elem` from the start + (diff = nodeIndex = 0) || start.pop()) ) { + + // When found, cache indexes on `parent` and break + if ( node.nodeType === 1 && ++diff && node === elem ) { + outerCache[ type ] = [ dirruns, nodeIndex, diff ]; + break; + } + } + + // Use previously-cached element index if available + } else if ( useCache && (cache = (elem[ expando ] || (elem[ expando ] = {}))[ type ]) && cache[0] === dirruns ) { + diff = cache[1]; + + // xml :nth-child(...) or :nth-last-child(...) or :nth(-last)?-of-type(...) + } else { + // Use the same loop as above to seek `elem` from the start + while ( (node = ++nodeIndex && node && node[ dir ] || + (diff = nodeIndex = 0) || start.pop()) ) { + + if ( ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) && ++diff ) { + // Cache the index of each encountered element + if ( useCache ) { + (node[ expando ] || (node[ expando ] = {}))[ type ] = [ dirruns, diff ]; + } + + if ( node === elem ) { + break; + } + } + } + } + + // Incorporate the offset, then check against cycle size + diff -= last; + return diff === first || ( diff % first === 0 && diff / first >= 0 ); + } + }; + }, + + "PSEUDO": function( pseudo, argument ) { + // pseudo-class names are case-insensitive + // http://www.w3.org/TR/selectors/#pseudo-classes + // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters + // Remember that setFilters inherits from pseudos + var args, + fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] || + Sizzle.error( "unsupported pseudo: " + pseudo ); + + // The user may use createPseudo to indicate that + // arguments are needed to create the filter function + // just as Sizzle does + if ( fn[ expando ] ) { + return fn( argument ); + } + + // But maintain support for old signatures + if ( fn.length > 1 ) { + args = [ pseudo, pseudo, "", argument ]; + return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ? + markFunction(function( seed, matches ) { + var idx, + matched = fn( seed, argument ), + i = matched.length; + while ( i-- ) { + idx = indexOf.call( seed, matched[i] ); + seed[ idx ] = !( matches[ idx ] = matched[i] ); + } + }) : + function( elem ) { + return fn( elem, 0, args ); + }; + } + + return fn; + } + }, + + pseudos: { + // Potentially complex pseudos + "not": markFunction(function( selector ) { + // Trim the selector passed to compile + // to avoid treating leading and trailing + // spaces as combinators + var input = [], + results = [], + matcher = compile( selector.replace( rtrim, "$1" ) ); + + return matcher[ expando ] ? + markFunction(function( seed, matches, context, xml ) { + var elem, + unmatched = matcher( seed, null, xml, [] ), + i = seed.length; + + // Match elements unmatched by `matcher` + while ( i-- ) { + if ( (elem = unmatched[i]) ) { + seed[i] = !(matches[i] = elem); + } + } + }) : + function( elem, context, xml ) { + input[0] = elem; + matcher( input, null, xml, results ); + return !results.pop(); + }; + }), + + "has": markFunction(function( selector ) { + return function( elem ) { + return Sizzle( selector, elem ).length > 0; + }; + }), + + "contains": markFunction(function( text ) { + return function( elem ) { + return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1; + }; + }), + + // "Whether an element is represented by a :lang() selector + // is based solely on the element's language value + // being equal to the identifier C, + // or beginning with the identifier C immediately followed by "-". + // The matching of C against the element's language value is performed case-insensitively. + // The identifier C does not have to be a valid language name." + // http://www.w3.org/TR/selectors/#lang-pseudo + "lang": markFunction( function( lang ) { + // lang value must be a valid identifider + if ( !ridentifier.test(lang || "") ) { + Sizzle.error( "unsupported lang: " + lang ); + } + lang = lang.replace( runescape, funescape ).toLowerCase(); + return function( elem ) { + var elemLang; + do { + if ( (elemLang = documentIsXML ? + elem.getAttribute("xml:lang") || elem.getAttribute("lang") : + elem.lang) ) { + + elemLang = elemLang.toLowerCase(); + return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0; + } + } while ( (elem = elem.parentNode) && elem.nodeType === 1 ); + return false; + }; + }), + + // Miscellaneous + "target": function( elem ) { + var hash = window.location && window.location.hash; + return hash && hash.slice( 1 ) === elem.id; + }, + + "root": function( elem ) { + return elem === docElem; + }, + + "focus": function( elem ) { + return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex); + }, + + // Boolean properties + "enabled": function( elem ) { + return elem.disabled === false; + }, + + "disabled": function( elem ) { + return elem.disabled === true; + }, + + "checked": function( elem ) { + // In CSS3, :checked should return both checked and selected elements + // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + var nodeName = elem.nodeName.toLowerCase(); + return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected); + }, + + "selected": function( elem ) { + // Accessing this property makes selected-by-default + // options in Safari work properly + if ( elem.parentNode ) { + elem.parentNode.selectedIndex; + } + + return elem.selected === true; + }, + + // Contents + "empty": function( elem ) { + // http://www.w3.org/TR/selectors/#empty-pseudo + // :empty is only affected by element nodes and content nodes(including text(3), cdata(4)), + // not comment, processing instructions, or others + // Thanks to Diego Perini for the nodeName shortcut + // Greater than "@" means alpha characters (specifically not starting with "#" or "?") + for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { + if ( elem.nodeName > "@" || elem.nodeType === 3 || elem.nodeType === 4 ) { + return false; + } + } + return true; + }, + + "parent": function( elem ) { + return !Expr.pseudos["empty"]( elem ); + }, + + // Element/input types + "header": function( elem ) { + return rheader.test( elem.nodeName ); + }, + + "input": function( elem ) { + return rinputs.test( elem.nodeName ); + }, + + "button": function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && elem.type === "button" || name === "button"; + }, + + "text": function( elem ) { + var attr; + // IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc) + // use getAttribute instead to test this case + return elem.nodeName.toLowerCase() === "input" && + elem.type === "text" && + ( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === elem.type ); + }, + + // Position-in-collection + "first": createPositionalPseudo(function() { + return [ 0 ]; + }), + + "last": createPositionalPseudo(function( matchIndexes, length ) { + return [ length - 1 ]; + }), + + "eq": createPositionalPseudo(function( matchIndexes, length, argument ) { + return [ argument < 0 ? argument + length : argument ]; + }), + + "even": createPositionalPseudo(function( matchIndexes, length ) { + var i = 0; + for ( ; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + }), + + "odd": createPositionalPseudo(function( matchIndexes, length ) { + var i = 1; + for ( ; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + }), + + "lt": createPositionalPseudo(function( matchIndexes, length, argument ) { + var i = argument < 0 ? argument + length : argument; + for ( ; --i >= 0; ) { + matchIndexes.push( i ); + } + return matchIndexes; + }), + + "gt": createPositionalPseudo(function( matchIndexes, length, argument ) { + var i = argument < 0 ? argument + length : argument; + for ( ; ++i < length; ) { + matchIndexes.push( i ); + } + return matchIndexes; + }) + } +}; + +// Add button/input type pseudos +for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) { + Expr.pseudos[ i ] = createInputPseudo( i ); +} +for ( i in { submit: true, reset: true } ) { + Expr.pseudos[ i ] = createButtonPseudo( i ); +} + +function tokenize( selector, parseOnly ) { + var matched, match, tokens, type, + soFar, groups, preFilters, + cached = tokenCache[ selector + " " ]; + + if ( cached ) { + return parseOnly ? 0 : cached.slice( 0 ); + } + + soFar = selector; + groups = []; + preFilters = Expr.preFilter; + + while ( soFar ) { + + // Comma and first run + if ( !matched || (match = rcomma.exec( soFar )) ) { + if ( match ) { + // Don't consume trailing commas as valid + soFar = soFar.slice( match[0].length ) || soFar; + } + groups.push( tokens = [] ); + } + + matched = false; + + // Combinators + if ( (match = rcombinators.exec( soFar )) ) { + matched = match.shift(); + tokens.push( { + value: matched, + // Cast descendant combinators to space + type: match[0].replace( rtrim, " " ) + } ); + soFar = soFar.slice( matched.length ); + } + + // Filters + for ( type in Expr.filter ) { + if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] || + (match = preFilters[ type ]( match ))) ) { + matched = match.shift(); + tokens.push( { + value: matched, + type: type, + matches: match + } ); + soFar = soFar.slice( matched.length ); + } + } + + if ( !matched ) { + break; + } + } + + // Return the length of the invalid excess + // if we're just parsing + // Otherwise, throw an error or return tokens + return parseOnly ? + soFar.length : + soFar ? + Sizzle.error( selector ) : + // Cache the tokens + tokenCache( selector, groups ).slice( 0 ); +} + +function toSelector( tokens ) { + var i = 0, + len = tokens.length, + selector = ""; + for ( ; i < len; i++ ) { + selector += tokens[i].value; + } + return selector; +} + +function addCombinator( matcher, combinator, base ) { + var dir = combinator.dir, + checkNonElements = base && dir === "parentNode", + doneName = done++; + + return combinator.first ? + // Check against closest ancestor/preceding element + function( elem, context, xml ) { + while ( (elem = elem[ dir ]) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + return matcher( elem, context, xml ); + } + } + } : + + // Check against all ancestor/preceding elements + function( elem, context, xml ) { + var data, cache, outerCache, + dirkey = dirruns + " " + doneName; + + // We can't set arbitrary data on XML nodes, so they don't benefit from dir caching + if ( xml ) { + while ( (elem = elem[ dir ]) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + if ( matcher( elem, context, xml ) ) { + return true; + } + } + } + } else { + while ( (elem = elem[ dir ]) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + outerCache = elem[ expando ] || (elem[ expando ] = {}); + if ( (cache = outerCache[ dir ]) && cache[0] === dirkey ) { + if ( (data = cache[1]) === true || data === cachedruns ) { + return data === true; + } + } else { + cache = outerCache[ dir ] = [ dirkey ]; + cache[1] = matcher( elem, context, xml ) || cachedruns; + if ( cache[1] === true ) { + return true; + } + } + } + } + } + }; +} + +function elementMatcher( matchers ) { + return matchers.length > 1 ? + function( elem, context, xml ) { + var i = matchers.length; + while ( i-- ) { + if ( !matchers[i]( elem, context, xml ) ) { + return false; + } + } + return true; + } : + matchers[0]; +} + +function condense( unmatched, map, filter, context, xml ) { + var elem, + newUnmatched = [], + i = 0, + len = unmatched.length, + mapped = map != null; + + for ( ; i < len; i++ ) { + if ( (elem = unmatched[i]) ) { + if ( !filter || filter( elem, context, xml ) ) { + newUnmatched.push( elem ); + if ( mapped ) { + map.push( i ); + } + } + } + } + + return newUnmatched; +} + +function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) { + if ( postFilter && !postFilter[ expando ] ) { + postFilter = setMatcher( postFilter ); + } + if ( postFinder && !postFinder[ expando ] ) { + postFinder = setMatcher( postFinder, postSelector ); + } + return markFunction(function( seed, results, context, xml ) { + var temp, i, elem, + preMap = [], + postMap = [], + preexisting = results.length, + + // Get initial elements from seed or context + elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ), + + // Prefilter to get matcher input, preserving a map for seed-results synchronization + matcherIn = preFilter && ( seed || !selector ) ? + condense( elems, preMap, preFilter, context, xml ) : + elems, + + matcherOut = matcher ? + // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results, + postFinder || ( seed ? preFilter : preexisting || postFilter ) ? + + // ...intermediate processing is necessary + [] : + + // ...otherwise use results directly + results : + matcherIn; + + // Find primary matches + if ( matcher ) { + matcher( matcherIn, matcherOut, context, xml ); + } + + // Apply postFilter + if ( postFilter ) { + temp = condense( matcherOut, postMap ); + postFilter( temp, [], context, xml ); + + // Un-match failing elements by moving them back to matcherIn + i = temp.length; + while ( i-- ) { + if ( (elem = temp[i]) ) { + matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem); + } + } + } + + if ( seed ) { + if ( postFinder || preFilter ) { + if ( postFinder ) { + // Get the final matcherOut by condensing this intermediate into postFinder contexts + temp = []; + i = matcherOut.length; + while ( i-- ) { + if ( (elem = matcherOut[i]) ) { + // Restore matcherIn since elem is not yet a final match + temp.push( (matcherIn[i] = elem) ); + } + } + postFinder( null, (matcherOut = []), temp, xml ); + } + + // Move matched elements from seed to results to keep them synchronized + i = matcherOut.length; + while ( i-- ) { + if ( (elem = matcherOut[i]) && + (temp = postFinder ? indexOf.call( seed, elem ) : preMap[i]) > -1 ) { + + seed[temp] = !(results[temp] = elem); + } + } + } + + // Add elements to results, through postFinder if defined + } else { + matcherOut = condense( + matcherOut === results ? + matcherOut.splice( preexisting, matcherOut.length ) : + matcherOut + ); + if ( postFinder ) { + postFinder( null, results, matcherOut, xml ); + } else { + push.apply( results, matcherOut ); + } + } + }); +} + +function matcherFromTokens( tokens ) { + var checkContext, matcher, j, + len = tokens.length, + leadingRelative = Expr.relative[ tokens[0].type ], + implicitRelative = leadingRelative || Expr.relative[" "], + i = leadingRelative ? 1 : 0, + + // The foundational matcher ensures that elements are reachable from top-level context(s) + matchContext = addCombinator( function( elem ) { + return elem === checkContext; + }, implicitRelative, true ), + matchAnyContext = addCombinator( function( elem ) { + return indexOf.call( checkContext, elem ) > -1; + }, implicitRelative, true ), + matchers = [ function( elem, context, xml ) { + return ( !leadingRelative && ( xml || context !== outermostContext ) ) || ( + (checkContext = context).nodeType ? + matchContext( elem, context, xml ) : + matchAnyContext( elem, context, xml ) ); + } ]; + + for ( ; i < len; i++ ) { + if ( (matcher = Expr.relative[ tokens[i].type ]) ) { + matchers = [ addCombinator(elementMatcher( matchers ), matcher) ]; + } else { + matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches ); + + // Return special upon seeing a positional matcher + if ( matcher[ expando ] ) { + // Find the next relative operator (if any) for proper handling + j = ++i; + for ( ; j < len; j++ ) { + if ( Expr.relative[ tokens[j].type ] ) { + break; + } + } + return setMatcher( + i > 1 && elementMatcher( matchers ), + i > 1 && toSelector( tokens.slice( 0, i - 1 ) ).replace( rtrim, "$1" ), + matcher, + i < j && matcherFromTokens( tokens.slice( i, j ) ), + j < len && matcherFromTokens( (tokens = tokens.slice( j )) ), + j < len && toSelector( tokens ) + ); + } + matchers.push( matcher ); + } + } + + return elementMatcher( matchers ); +} + +function matcherFromGroupMatchers( elementMatchers, setMatchers ) { + // A counter to specify which element is currently being matched + var matcherCachedRuns = 0, + bySet = setMatchers.length > 0, + byElement = elementMatchers.length > 0, + superMatcher = function( seed, context, xml, results, expandContext ) { + var elem, j, matcher, + setMatched = [], + matchedCount = 0, + i = "0", + unmatched = seed && [], + outermost = expandContext != null, + contextBackup = outermostContext, + // We must always have either seed elements or context + elems = seed || byElement && Expr.find["TAG"]( "*", expandContext && context.parentNode || context ), + // Use integer dirruns iff this is the outermost matcher + dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1); + + if ( outermost ) { + outermostContext = context !== document && context; + cachedruns = matcherCachedRuns; + } + + // Add elements passing elementMatchers directly to results + // Keep `i` a string if there are no elements so `matchedCount` will be "00" below + for ( ; (elem = elems[i]) != null; i++ ) { + if ( byElement && elem ) { + j = 0; + while ( (matcher = elementMatchers[j++]) ) { + if ( matcher( elem, context, xml ) ) { + results.push( elem ); + break; + } + } + if ( outermost ) { + dirruns = dirrunsUnique; + cachedruns = ++matcherCachedRuns; + } + } + + // Track unmatched elements for set filters + if ( bySet ) { + // They will have gone through all possible matchers + if ( (elem = !matcher && elem) ) { + matchedCount--; + } + + // Lengthen the array for every element, matched or not + if ( seed ) { + unmatched.push( elem ); + } + } + } + + // Apply set filters to unmatched elements + matchedCount += i; + if ( bySet && i !== matchedCount ) { + j = 0; + while ( (matcher = setMatchers[j++]) ) { + matcher( unmatched, setMatched, context, xml ); + } + + if ( seed ) { + // Reintegrate element matches to eliminate the need for sorting + if ( matchedCount > 0 ) { + while ( i-- ) { + if ( !(unmatched[i] || setMatched[i]) ) { + setMatched[i] = pop.call( results ); + } + } + } + + // Discard index placeholder values to get only actual matches + setMatched = condense( setMatched ); + } + + // Add matches to results + push.apply( results, setMatched ); + + // Seedless set matches succeeding multiple successful matchers stipulate sorting + if ( outermost && !seed && setMatched.length > 0 && + ( matchedCount + setMatchers.length ) > 1 ) { + + Sizzle.uniqueSort( results ); + } + } + + // Override manipulation of globals by nested matchers + if ( outermost ) { + dirruns = dirrunsUnique; + outermostContext = contextBackup; + } + + return unmatched; + }; + + return bySet ? + markFunction( superMatcher ) : + superMatcher; +} + +compile = Sizzle.compile = function( selector, group /* Internal Use Only */ ) { + var i, + setMatchers = [], + elementMatchers = [], + cached = compilerCache[ selector + " " ]; + + if ( !cached ) { + // Generate a function of recursive functions that can be used to check each element + if ( !group ) { + group = tokenize( selector ); + } + i = group.length; + while ( i-- ) { + cached = matcherFromTokens( group[i] ); + if ( cached[ expando ] ) { + setMatchers.push( cached ); + } else { + elementMatchers.push( cached ); + } + } + + // Cache the compiled function + cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) ); + } + return cached; +}; + +function multipleContexts( selector, contexts, results ) { + var i = 0, + len = contexts.length; + for ( ; i < len; i++ ) { + Sizzle( selector, contexts[i], results ); + } + return results; +} + +function select( selector, context, results, seed ) { + var i, tokens, token, type, find, + match = tokenize( selector ); + + if ( !seed ) { + // Try to minimize operations if there is only one group + if ( match.length === 1 ) { + + // Take a shortcut and set the context if the root selector is an ID + tokens = match[0] = match[0].slice( 0 ); + if ( tokens.length > 2 && (token = tokens[0]).type === "ID" && + context.nodeType === 9 && !documentIsXML && + Expr.relative[ tokens[1].type ] ) { + + context = Expr.find["ID"]( token.matches[0].replace( runescape, funescape ), context )[0]; + if ( !context ) { + return results; + } + + selector = selector.slice( tokens.shift().value.length ); + } + + // Fetch a seed set for right-to-left matching + i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length; + while ( i-- ) { + token = tokens[i]; + + // Abort if we hit a combinator + if ( Expr.relative[ (type = token.type) ] ) { + break; + } + if ( (find = Expr.find[ type ]) ) { + // Search, expanding context for leading sibling combinators + if ( (seed = find( + token.matches[0].replace( runescape, funescape ), + rsibling.test( tokens[0].type ) && context.parentNode || context + )) ) { + + // If seed is empty or no tokens remain, we can return early + tokens.splice( i, 1 ); + selector = seed.length && toSelector( tokens ); + if ( !selector ) { + push.apply( results, slice.call( seed, 0 ) ); + return results; + } + + break; + } + } + } + } + } + + // Compile and execute a filtering function + // Provide `match` to avoid retokenization if we modified the selector above + compile( selector, match )( + seed, + context, + documentIsXML, + results, + rsibling.test( selector ) + ); + return results; +} + +// Deprecated +Expr.pseudos["nth"] = Expr.pseudos["eq"]; + +// Easy API for creating new setFilters +function setFilters() {} +Expr.filters = setFilters.prototype = Expr.pseudos; +Expr.setFilters = new setFilters(); + +// Initialize with the default document +setDocument(); + +// Override sizzle attribute retrieval +Sizzle.attr = jQuery.attr; +jQuery.find = Sizzle; +jQuery.expr = Sizzle.selectors; +jQuery.expr[":"] = jQuery.expr.pseudos; +jQuery.unique = Sizzle.uniqueSort; +jQuery.text = Sizzle.getText; +jQuery.isXMLDoc = Sizzle.isXML; +jQuery.contains = Sizzle.contains; + + +})( window ); +var runtil = /Until$/, + rparentsprev = /^(?:parents|prev(?:Until|All))/, + isSimple = /^.[^:#\[\.,]*$/, + rneedsContext = jQuery.expr.match.needsContext, + // methods guaranteed to produce a unique set when starting from a unique set + guaranteedUnique = { + children: true, + contents: true, + next: true, + prev: true + }; + +jQuery.fn.extend({ + find: function( selector ) { + var i, ret, self, + len = this.length; + + if ( typeof selector !== "string" ) { + self = this; + return this.pushStack( jQuery( selector ).filter(function() { + for ( i = 0; i < len; i++ ) { + if ( jQuery.contains( self[ i ], this ) ) { + return true; + } + } + }) ); + } + + ret = []; + for ( i = 0; i < len; i++ ) { + jQuery.find( selector, this[ i ], ret ); + } + + // Needed because $( selector, context ) becomes $( context ).find( selector ) + ret = this.pushStack( len > 1 ? jQuery.unique( ret ) : ret ); + ret.selector = ( this.selector ? this.selector + " " : "" ) + selector; + return ret; + }, + + has: function( target ) { + var i, + targets = jQuery( target, this ), + len = targets.length; + + return this.filter(function() { + for ( i = 0; i < len; i++ ) { + if ( jQuery.contains( this, targets[i] ) ) { + return true; + } + } + }); + }, + + not: function( selector ) { + return this.pushStack( winnow(this, selector, false) ); + }, + + filter: function( selector ) { + return this.pushStack( winnow(this, selector, true) ); + }, + + is: function( selector ) { + return !!selector && ( + typeof selector === "string" ? + // If this is a positional/relative selector, check membership in the returned set + // so $("p:first").is("p:last") won't return true for a doc with two "p". + rneedsContext.test( selector ) ? + jQuery( selector, this.context ).index( this[0] ) >= 0 : + jQuery.filter( selector, this ).length > 0 : + this.filter( selector ).length > 0 ); + }, + + closest: function( selectors, context ) { + var cur, + i = 0, + l = this.length, + ret = [], + pos = rneedsContext.test( selectors ) || typeof selectors !== "string" ? + jQuery( selectors, context || this.context ) : + 0; + + for ( ; i < l; i++ ) { + cur = this[i]; + + while ( cur && cur.ownerDocument && cur !== context && cur.nodeType !== 11 ) { + if ( pos ? pos.index(cur) > -1 : jQuery.find.matchesSelector(cur, selectors) ) { + ret.push( cur ); + break; + } + cur = cur.parentNode; + } + } + + return this.pushStack( ret.length > 1 ? jQuery.unique( ret ) : ret ); + }, + + // Determine the position of an element within + // the matched set of elements + index: function( elem ) { + + // No argument, return index in parent + if ( !elem ) { + return ( this[0] && this[0].parentNode ) ? this.first().prevAll().length : -1; + } + + // index in selector + if ( typeof elem === "string" ) { + return jQuery.inArray( this[0], jQuery( elem ) ); + } + + // Locate the position of the desired element + return jQuery.inArray( + // If it receives a jQuery object, the first element is used + elem.jquery ? elem[0] : elem, this ); + }, + + add: function( selector, context ) { + var set = typeof selector === "string" ? + jQuery( selector, context ) : + jQuery.makeArray( selector && selector.nodeType ? [ selector ] : selector ), + all = jQuery.merge( this.get(), set ); + + return this.pushStack( jQuery.unique(all) ); + }, + + addBack: function( selector ) { + return this.add( selector == null ? + this.prevObject : this.prevObject.filter(selector) + ); + } +}); + +jQuery.fn.andSelf = jQuery.fn.addBack; + +function sibling( cur, dir ) { + do { + cur = cur[ dir ]; + } while ( cur && cur.nodeType !== 1 ); + + return cur; +} + +jQuery.each({ + parent: function( elem ) { + var parent = elem.parentNode; + return parent && parent.nodeType !== 11 ? parent : null; + }, + parents: function( elem ) { + return jQuery.dir( elem, "parentNode" ); + }, + parentsUntil: function( elem, i, until ) { + return jQuery.dir( elem, "parentNode", until ); + }, + next: function( elem ) { + return sibling( elem, "nextSibling" ); + }, + prev: function( elem ) { + return sibling( elem, "previousSibling" ); + }, + nextAll: function( elem ) { + return jQuery.dir( elem, "nextSibling" ); + }, + prevAll: function( elem ) { + return jQuery.dir( elem, "previousSibling" ); + }, + nextUntil: function( elem, i, until ) { + return jQuery.dir( elem, "nextSibling", until ); + }, + prevUntil: function( elem, i, until ) { + return jQuery.dir( elem, "previousSibling", until ); + }, + siblings: function( elem ) { + return jQuery.sibling( ( elem.parentNode || {} ).firstChild, elem ); + }, + children: function( elem ) { + return jQuery.sibling( elem.firstChild ); + }, + contents: function( elem ) { + return jQuery.nodeName( elem, "iframe" ) ? + elem.contentDocument || elem.contentWindow.document : + jQuery.merge( [], elem.childNodes ); + } +}, function( name, fn ) { + jQuery.fn[ name ] = function( until, selector ) { + var ret = jQuery.map( this, fn, until ); + + if ( !runtil.test( name ) ) { + selector = until; + } + + if ( selector && typeof selector === "string" ) { + ret = jQuery.filter( selector, ret ); + } + + ret = this.length > 1 && !guaranteedUnique[ name ] ? jQuery.unique( ret ) : ret; + + if ( this.length > 1 && rparentsprev.test( name ) ) { + ret = ret.reverse(); + } + + return this.pushStack( ret ); + }; +}); + +jQuery.extend({ + filter: function( expr, elems, not ) { + if ( not ) { + expr = ":not(" + expr + ")"; + } + + return elems.length === 1 ? + jQuery.find.matchesSelector(elems[0], expr) ? [ elems[0] ] : [] : + jQuery.find.matches(expr, elems); + }, + + dir: function( elem, dir, until ) { + var matched = [], + cur = elem[ dir ]; + + while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) { + if ( cur.nodeType === 1 ) { + matched.push( cur ); + } + cur = cur[dir]; + } + return matched; + }, + + sibling: function( n, elem ) { + var r = []; + + for ( ; n; n = n.nextSibling ) { + if ( n.nodeType === 1 && n !== elem ) { + r.push( n ); + } + } + + return r; + } +}); + +// Implement the identical functionality for filter and not +function winnow( elements, qualifier, keep ) { + + // Can't pass null or undefined to indexOf in Firefox 4 + // Set to 0 to skip string check + qualifier = qualifier || 0; + + if ( jQuery.isFunction( qualifier ) ) { + return jQuery.grep(elements, function( elem, i ) { + var retVal = !!qualifier.call( elem, i, elem ); + return retVal === keep; + }); + + } else if ( qualifier.nodeType ) { + return jQuery.grep(elements, function( elem ) { + return ( elem === qualifier ) === keep; + }); + + } else if ( typeof qualifier === "string" ) { + var filtered = jQuery.grep(elements, function( elem ) { + return elem.nodeType === 1; + }); + + if ( isSimple.test( qualifier ) ) { + return jQuery.filter(qualifier, filtered, !keep); + } else { + qualifier = jQuery.filter( qualifier, filtered ); + } + } + + return jQuery.grep(elements, function( elem ) { + return ( jQuery.inArray( elem, qualifier ) >= 0 ) === keep; + }); +} +function createSafeFragment( document ) { + var list = nodeNames.split( "|" ), + safeFrag = document.createDocumentFragment(); + + if ( safeFrag.createElement ) { + while ( list.length ) { + safeFrag.createElement( + list.pop() + ); + } + } + return safeFrag; +} + +var nodeNames = "abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|" + + "header|hgroup|mark|meter|nav|output|progress|section|summary|time|video", + rinlinejQuery = / jQuery\d+="(?:null|\d+)"/g, + rnoshimcache = new RegExp("<(?:" + nodeNames + ")[\\s/>]", "i"), + rleadingWhitespace = /^\s+/, + rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi, + rtagName = /<([\w:]+)/, + rtbody = /\s*$/g, + + // We have to close these tags to support XHTML (#13200) + wrapMap = { + option: [ 1, "" ], + legend: [ 1, "
", "
" ], + area: [ 1, "", "" ], + param: [ 1, "", "" ], + thead: [ 1, "", "
" ], + tr: [ 2, "", "
" ], + col: [ 2, "", "
" ], + td: [ 3, "", "
" ], + + // IE6-8 can't serialize link, script, style, or any html5 (NoScope) tags, + // unless wrapped in a div with non-breaking characters in front of it. + _default: jQuery.support.htmlSerialize ? [ 0, "", "" ] : [ 1, "X
", "
" ] + }, + safeFragment = createSafeFragment( document ), + fragmentDiv = safeFragment.appendChild( document.createElement("div") ); + +wrapMap.optgroup = wrapMap.option; +wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; +wrapMap.th = wrapMap.td; + +jQuery.fn.extend({ + text: function( value ) { + return jQuery.access( this, function( value ) { + return value === undefined ? + jQuery.text( this ) : + this.empty().append( ( this[0] && this[0].ownerDocument || document ).createTextNode( value ) ); + }, null, value, arguments.length ); + }, + + wrapAll: function( html ) { + if ( jQuery.isFunction( html ) ) { + return this.each(function(i) { + jQuery(this).wrapAll( html.call(this, i) ); + }); + } + + if ( this[0] ) { + // The elements to wrap the target around + var wrap = jQuery( html, this[0].ownerDocument ).eq(0).clone(true); + + if ( this[0].parentNode ) { + wrap.insertBefore( this[0] ); + } + + wrap.map(function() { + var elem = this; + + while ( elem.firstChild && elem.firstChild.nodeType === 1 ) { + elem = elem.firstChild; + } + + return elem; + }).append( this ); + } + + return this; + }, + + wrapInner: function( html ) { + if ( jQuery.isFunction( html ) ) { + return this.each(function(i) { + jQuery(this).wrapInner( html.call(this, i) ); + }); + } + + return this.each(function() { + var self = jQuery( this ), + contents = self.contents(); + + if ( contents.length ) { + contents.wrapAll( html ); + + } else { + self.append( html ); + } + }); + }, + + wrap: function( html ) { + var isFunction = jQuery.isFunction( html ); + + return this.each(function(i) { + jQuery( this ).wrapAll( isFunction ? html.call(this, i) : html ); + }); + }, + + unwrap: function() { + return this.parent().each(function() { + if ( !jQuery.nodeName( this, "body" ) ) { + jQuery( this ).replaceWith( this.childNodes ); + } + }).end(); + }, + + append: function() { + return this.domManip(arguments, true, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + this.appendChild( elem ); + } + }); + }, + + prepend: function() { + return this.domManip(arguments, true, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + this.insertBefore( elem, this.firstChild ); + } + }); + }, + + before: function() { + return this.domManip( arguments, false, function( elem ) { + if ( this.parentNode ) { + this.parentNode.insertBefore( elem, this ); + } + }); + }, + + after: function() { + return this.domManip( arguments, false, function( elem ) { + if ( this.parentNode ) { + this.parentNode.insertBefore( elem, this.nextSibling ); + } + }); + }, + + // keepData is for internal use only--do not document + remove: function( selector, keepData ) { + var elem, + i = 0; + + for ( ; (elem = this[i]) != null; i++ ) { + if ( !selector || jQuery.filter( selector, [ elem ] ).length > 0 ) { + if ( !keepData && elem.nodeType === 1 ) { + jQuery.cleanData( getAll( elem ) ); + } + + if ( elem.parentNode ) { + if ( keepData && jQuery.contains( elem.ownerDocument, elem ) ) { + setGlobalEval( getAll( elem, "script" ) ); + } + elem.parentNode.removeChild( elem ); + } + } + } + + return this; + }, + + empty: function() { + var elem, + i = 0; + + for ( ; (elem = this[i]) != null; i++ ) { + // Remove element nodes and prevent memory leaks + if ( elem.nodeType === 1 ) { + jQuery.cleanData( getAll( elem, false ) ); + } + + // Remove any remaining nodes + while ( elem.firstChild ) { + elem.removeChild( elem.firstChild ); + } + + // If this is a select, ensure that it displays empty (#12336) + // Support: IE<9 + if ( elem.options && jQuery.nodeName( elem, "select" ) ) { + elem.options.length = 0; + } + } + + return this; + }, + + clone: function( dataAndEvents, deepDataAndEvents ) { + dataAndEvents = dataAndEvents == null ? false : dataAndEvents; + deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents; + + return this.map( function () { + return jQuery.clone( this, dataAndEvents, deepDataAndEvents ); + }); + }, + + html: function( value ) { + return jQuery.access( this, function( value ) { + var elem = this[0] || {}, + i = 0, + l = this.length; + + if ( value === undefined ) { + return elem.nodeType === 1 ? + elem.innerHTML.replace( rinlinejQuery, "" ) : + undefined; + } + + // See if we can take a shortcut and just use innerHTML + if ( typeof value === "string" && !rnoInnerhtml.test( value ) && + ( jQuery.support.htmlSerialize || !rnoshimcache.test( value ) ) && + ( jQuery.support.leadingWhitespace || !rleadingWhitespace.test( value ) ) && + !wrapMap[ ( rtagName.exec( value ) || ["", ""] )[1].toLowerCase() ] ) { + + value = value.replace( rxhtmlTag, "<$1>" ); + + try { + for (; i < l; i++ ) { + // Remove element nodes and prevent memory leaks + elem = this[i] || {}; + if ( elem.nodeType === 1 ) { + jQuery.cleanData( getAll( elem, false ) ); + elem.innerHTML = value; + } + } + + elem = 0; + + // If using innerHTML throws an exception, use the fallback method + } catch(e) {} + } + + if ( elem ) { + this.empty().append( value ); + } + }, null, value, arguments.length ); + }, + + replaceWith: function( value ) { + var isFunc = jQuery.isFunction( value ); + + // Make sure that the elements are removed from the DOM before they are inserted + // this can help fix replacing a parent with child elements + if ( !isFunc && typeof value !== "string" ) { + value = jQuery( value ).not( this ).detach(); + } + + return this.domManip( [ value ], true, function( elem ) { + var next = this.nextSibling, + parent = this.parentNode; + + if ( parent ) { + jQuery( this ).remove(); + parent.insertBefore( elem, next ); + } + }); + }, + + detach: function( selector ) { + return this.remove( selector, true ); + }, + + domManip: function( args, table, callback ) { + + // Flatten any nested arrays + args = core_concat.apply( [], args ); + + var first, node, hasScripts, + scripts, doc, fragment, + i = 0, + l = this.length, + set = this, + iNoClone = l - 1, + value = args[0], + isFunction = jQuery.isFunction( value ); + + // We can't cloneNode fragments that contain checked, in WebKit + if ( isFunction || !( l <= 1 || typeof value !== "string" || jQuery.support.checkClone || !rchecked.test( value ) ) ) { + return this.each(function( index ) { + var self = set.eq( index ); + if ( isFunction ) { + args[0] = value.call( this, index, table ? self.html() : undefined ); + } + self.domManip( args, table, callback ); + }); + } + + if ( l ) { + fragment = jQuery.buildFragment( args, this[ 0 ].ownerDocument, false, this ); + first = fragment.firstChild; + + if ( fragment.childNodes.length === 1 ) { + fragment = first; + } + + if ( first ) { + table = table && jQuery.nodeName( first, "tr" ); + scripts = jQuery.map( getAll( fragment, "script" ), disableScript ); + hasScripts = scripts.length; + + // Use the original fragment for the last item instead of the first because it can end up + // being emptied incorrectly in certain situations (#8070). + for ( ; i < l; i++ ) { + node = fragment; + + if ( i !== iNoClone ) { + node = jQuery.clone( node, true, true ); + + // Keep references to cloned scripts for later restoration + if ( hasScripts ) { + jQuery.merge( scripts, getAll( node, "script" ) ); + } + } + + callback.call( + table && jQuery.nodeName( this[i], "table" ) ? + findOrAppend( this[i], "tbody" ) : + this[i], + node, + i + ); + } + + if ( hasScripts ) { + doc = scripts[ scripts.length - 1 ].ownerDocument; + + // Reenable scripts + jQuery.map( scripts, restoreScript ); + + // Evaluate executable scripts on first document insertion + for ( i = 0; i < hasScripts; i++ ) { + node = scripts[ i ]; + if ( rscriptType.test( node.type || "" ) && + !jQuery._data( node, "globalEval" ) && jQuery.contains( doc, node ) ) { + + if ( node.src ) { + // Hope ajax is available... + jQuery.ajax({ + url: node.src, + type: "GET", + dataType: "script", + async: false, + global: false, + "throws": true + }); + } else { + jQuery.globalEval( ( node.text || node.textContent || node.innerHTML || "" ).replace( rcleanScript, "" ) ); + } + } + } + } + + // Fix #11809: Avoid leaking memory + fragment = first = null; + } + } + + return this; + } +}); + +function findOrAppend( elem, tag ) { + return elem.getElementsByTagName( tag )[0] || elem.appendChild( elem.ownerDocument.createElement( tag ) ); +} + +// Replace/restore the type attribute of script elements for safe DOM manipulation +function disableScript( elem ) { + var attr = elem.getAttributeNode("type"); + elem.type = ( attr && attr.specified ) + "/" + elem.type; + return elem; +} +function restoreScript( elem ) { + var match = rscriptTypeMasked.exec( elem.type ); + if ( match ) { + elem.type = match[1]; + } else { + elem.removeAttribute("type"); + } + return elem; +} + +// Mark scripts as having already been evaluated +function setGlobalEval( elems, refElements ) { + var elem, + i = 0; + for ( ; (elem = elems[i]) != null; i++ ) { + jQuery._data( elem, "globalEval", !refElements || jQuery._data( refElements[i], "globalEval" ) ); + } +} + +function cloneCopyEvent( src, dest ) { + + if ( dest.nodeType !== 1 || !jQuery.hasData( src ) ) { + return; + } + + var type, i, l, + oldData = jQuery._data( src ), + curData = jQuery._data( dest, oldData ), + events = oldData.events; + + if ( events ) { + delete curData.handle; + curData.events = {}; + + for ( type in events ) { + for ( i = 0, l = events[ type ].length; i < l; i++ ) { + jQuery.event.add( dest, type, events[ type ][ i ] ); + } + } + } + + // make the cloned public data object a copy from the original + if ( curData.data ) { + curData.data = jQuery.extend( {}, curData.data ); + } +} + +function fixCloneNodeIssues( src, dest ) { + var nodeName, e, data; + + // We do not need to do anything for non-Elements + if ( dest.nodeType !== 1 ) { + return; + } + + nodeName = dest.nodeName.toLowerCase(); + + // IE6-8 copies events bound via attachEvent when using cloneNode. + if ( !jQuery.support.noCloneEvent && dest[ jQuery.expando ] ) { + data = jQuery._data( dest ); + + for ( e in data.events ) { + jQuery.removeEvent( dest, e, data.handle ); + } + + // Event data gets referenced instead of copied if the expando gets copied too + dest.removeAttribute( jQuery.expando ); + } + + // IE blanks contents when cloning scripts, and tries to evaluate newly-set text + if ( nodeName === "script" && dest.text !== src.text ) { + disableScript( dest ).text = src.text; + restoreScript( dest ); + + // IE6-10 improperly clones children of object elements using classid. + // IE10 throws NoModificationAllowedError if parent is null, #12132. + } else if ( nodeName === "object" ) { + if ( dest.parentNode ) { + dest.outerHTML = src.outerHTML; + } + + // This path appears unavoidable for IE9. When cloning an object + // element in IE9, the outerHTML strategy above is not sufficient. + // If the src has innerHTML and the destination does not, + // copy the src.innerHTML into the dest.innerHTML. #10324 + if ( jQuery.support.html5Clone && ( src.innerHTML && !jQuery.trim(dest.innerHTML) ) ) { + dest.innerHTML = src.innerHTML; + } + + } else if ( nodeName === "input" && manipulation_rcheckableType.test( src.type ) ) { + // IE6-8 fails to persist the checked state of a cloned checkbox + // or radio button. Worse, IE6-7 fail to give the cloned element + // a checked appearance if the defaultChecked value isn't also set + + dest.defaultChecked = dest.checked = src.checked; + + // IE6-7 get confused and end up setting the value of a cloned + // checkbox/radio button to an empty string instead of "on" + if ( dest.value !== src.value ) { + dest.value = src.value; + } + + // IE6-8 fails to return the selected option to the default selected + // state when cloning options + } else if ( nodeName === "option" ) { + dest.defaultSelected = dest.selected = src.defaultSelected; + + // IE6-8 fails to set the defaultValue to the correct value when + // cloning other types of input fields + } else if ( nodeName === "input" || nodeName === "textarea" ) { + dest.defaultValue = src.defaultValue; + } +} + +jQuery.each({ + appendTo: "append", + prependTo: "prepend", + insertBefore: "before", + insertAfter: "after", + replaceAll: "replaceWith" +}, function( name, original ) { + jQuery.fn[ name ] = function( selector ) { + var elems, + i = 0, + ret = [], + insert = jQuery( selector ), + last = insert.length - 1; + + for ( ; i <= last; i++ ) { + elems = i === last ? this : this.clone(true); + jQuery( insert[i] )[ original ]( elems ); + + // Modern browsers can apply jQuery collections as arrays, but oldIE needs a .get() + core_push.apply( ret, elems.get() ); + } + + return this.pushStack( ret ); + }; +}); + +function getAll( context, tag ) { + var elems, elem, + i = 0, + found = typeof context.getElementsByTagName !== core_strundefined ? context.getElementsByTagName( tag || "*" ) : + typeof context.querySelectorAll !== core_strundefined ? context.querySelectorAll( tag || "*" ) : + undefined; + + if ( !found ) { + for ( found = [], elems = context.childNodes || context; (elem = elems[i]) != null; i++ ) { + if ( !tag || jQuery.nodeName( elem, tag ) ) { + found.push( elem ); + } else { + jQuery.merge( found, getAll( elem, tag ) ); + } + } + } + + return tag === undefined || tag && jQuery.nodeName( context, tag ) ? + jQuery.merge( [ context ], found ) : + found; +} + +// Used in buildFragment, fixes the defaultChecked property +function fixDefaultChecked( elem ) { + if ( manipulation_rcheckableType.test( elem.type ) ) { + elem.defaultChecked = elem.checked; + } +} + +jQuery.extend({ + clone: function( elem, dataAndEvents, deepDataAndEvents ) { + var destElements, node, clone, i, srcElements, + inPage = jQuery.contains( elem.ownerDocument, elem ); + + if ( jQuery.support.html5Clone || jQuery.isXMLDoc(elem) || !rnoshimcache.test( "<" + elem.nodeName + ">" ) ) { + clone = elem.cloneNode( true ); + + // IE<=8 does not properly clone detached, unknown element nodes + } else { + fragmentDiv.innerHTML = elem.outerHTML; + fragmentDiv.removeChild( clone = fragmentDiv.firstChild ); + } + + if ( (!jQuery.support.noCloneEvent || !jQuery.support.noCloneChecked) && + (elem.nodeType === 1 || elem.nodeType === 11) && !jQuery.isXMLDoc(elem) ) { + + // We eschew Sizzle here for performance reasons: http://jsperf.com/getall-vs-sizzle/2 + destElements = getAll( clone ); + srcElements = getAll( elem ); + + // Fix all IE cloning issues + for ( i = 0; (node = srcElements[i]) != null; ++i ) { + // Ensure that the destination node is not null; Fixes #9587 + if ( destElements[i] ) { + fixCloneNodeIssues( node, destElements[i] ); + } + } + } + + // Copy the events from the original to the clone + if ( dataAndEvents ) { + if ( deepDataAndEvents ) { + srcElements = srcElements || getAll( elem ); + destElements = destElements || getAll( clone ); + + for ( i = 0; (node = srcElements[i]) != null; i++ ) { + cloneCopyEvent( node, destElements[i] ); + } + } else { + cloneCopyEvent( elem, clone ); + } + } + + // Preserve script evaluation history + destElements = getAll( clone, "script" ); + if ( destElements.length > 0 ) { + setGlobalEval( destElements, !inPage && getAll( elem, "script" ) ); + } + + destElements = srcElements = node = null; + + // Return the cloned set + return clone; + }, + + buildFragment: function( elems, context, scripts, selection ) { + var j, elem, contains, + tmp, tag, tbody, wrap, + l = elems.length, + + // Ensure a safe fragment + safe = createSafeFragment( context ), + + nodes = [], + i = 0; + + for ( ; i < l; i++ ) { + elem = elems[ i ]; + + if ( elem || elem === 0 ) { + + // Add nodes directly + if ( jQuery.type( elem ) === "object" ) { + jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem ); + + // Convert non-html into a text node + } else if ( !rhtml.test( elem ) ) { + nodes.push( context.createTextNode( elem ) ); + + // Convert html into DOM nodes + } else { + tmp = tmp || safe.appendChild( context.createElement("div") ); + + // Deserialize a standard representation + tag = ( rtagName.exec( elem ) || ["", ""] )[1].toLowerCase(); + wrap = wrapMap[ tag ] || wrapMap._default; + + tmp.innerHTML = wrap[1] + elem.replace( rxhtmlTag, "<$1>" ) + wrap[2]; + + // Descend through wrappers to the right content + j = wrap[0]; + while ( j-- ) { + tmp = tmp.lastChild; + } + + // Manually add leading whitespace removed by IE + if ( !jQuery.support.leadingWhitespace && rleadingWhitespace.test( elem ) ) { + nodes.push( context.createTextNode( rleadingWhitespace.exec( elem )[0] ) ); + } + + // Remove IE's autoinserted from table fragments + if ( !jQuery.support.tbody ) { + + // String was a , *may* have spurious + elem = tag === "table" && !rtbody.test( elem ) ? + tmp.firstChild : + + // String was a bare or + wrap[1] === "
" && !rtbody.test( elem ) ? + tmp : + 0; + + j = elem && elem.childNodes.length; + while ( j-- ) { + if ( jQuery.nodeName( (tbody = elem.childNodes[j]), "tbody" ) && !tbody.childNodes.length ) { + elem.removeChild( tbody ); + } + } + } + + jQuery.merge( nodes, tmp.childNodes ); + + // Fix #12392 for WebKit and IE > 9 + tmp.textContent = ""; + + // Fix #12392 for oldIE + while ( tmp.firstChild ) { + tmp.removeChild( tmp.firstChild ); + } + + // Remember the top-level container for proper cleanup + tmp = safe.lastChild; + } + } + } + + // Fix #11356: Clear elements from fragment + if ( tmp ) { + safe.removeChild( tmp ); + } + + // Reset defaultChecked for any radios and checkboxes + // about to be appended to the DOM in IE 6/7 (#8060) + if ( !jQuery.support.appendChecked ) { + jQuery.grep( getAll( nodes, "input" ), fixDefaultChecked ); + } + + i = 0; + while ( (elem = nodes[ i++ ]) ) { + + // #4087 - If origin and destination elements are the same, and this is + // that element, do not do anything + if ( selection && jQuery.inArray( elem, selection ) !== -1 ) { + continue; + } + + contains = jQuery.contains( elem.ownerDocument, elem ); + + // Append to fragment + tmp = getAll( safe.appendChild( elem ), "script" ); + + // Preserve script evaluation history + if ( contains ) { + setGlobalEval( tmp ); + } + + // Capture executables + if ( scripts ) { + j = 0; + while ( (elem = tmp[ j++ ]) ) { + if ( rscriptType.test( elem.type || "" ) ) { + scripts.push( elem ); + } + } + } + } + + tmp = null; + + return safe; + }, + + cleanData: function( elems, /* internal */ acceptData ) { + var elem, type, id, data, + i = 0, + internalKey = jQuery.expando, + cache = jQuery.cache, + deleteExpando = jQuery.support.deleteExpando, + special = jQuery.event.special; + + for ( ; (elem = elems[i]) != null; i++ ) { + + if ( acceptData || jQuery.acceptData( elem ) ) { + + id = elem[ internalKey ]; + data = id && cache[ id ]; + + if ( data ) { + if ( data.events ) { + for ( type in data.events ) { + if ( special[ type ] ) { + jQuery.event.remove( elem, type ); + + // This is a shortcut to avoid jQuery.event.remove's overhead + } else { + jQuery.removeEvent( elem, type, data.handle ); + } + } + } + + // Remove cache only if it was not already removed by jQuery.event.remove + if ( cache[ id ] ) { + + delete cache[ id ]; + + // IE does not allow us to delete expando properties from nodes, + // nor does it have a removeAttribute function on Document nodes; + // we must handle all of these cases + if ( deleteExpando ) { + delete elem[ internalKey ]; + + } else if ( typeof elem.removeAttribute !== core_strundefined ) { + elem.removeAttribute( internalKey ); + + } else { + elem[ internalKey ] = null; + } + + core_deletedIds.push( id ); + } + } + } + } + } +}); +var iframe, getStyles, curCSS, + ralpha = /alpha\([^)]*\)/i, + ropacity = /opacity\s*=\s*([^)]*)/, + rposition = /^(top|right|bottom|left)$/, + // swappable if display is none or starts with table except "table", "table-cell", or "table-caption" + // see here for display values: https://developer.mozilla.org/en-US/docs/CSS/display + rdisplayswap = /^(none|table(?!-c[ea]).+)/, + rmargin = /^margin/, + rnumsplit = new RegExp( "^(" + core_pnum + ")(.*)$", "i" ), + rnumnonpx = new RegExp( "^(" + core_pnum + ")(?!px)[a-z%]+$", "i" ), + rrelNum = new RegExp( "^([+-])=(" + core_pnum + ")", "i" ), + elemdisplay = { BODY: "block" }, + + cssShow = { position: "absolute", visibility: "hidden", display: "block" }, + cssNormalTransform = { + letterSpacing: 0, + fontWeight: 400 + }, + + cssExpand = [ "Top", "Right", "Bottom", "Left" ], + cssPrefixes = [ "Webkit", "O", "Moz", "ms" ]; + +// return a css property mapped to a potentially vendor prefixed property +function vendorPropName( style, name ) { + + // shortcut for names that are not vendor prefixed + if ( name in style ) { + return name; + } + + // check for vendor prefixed names + var capName = name.charAt(0).toUpperCase() + name.slice(1), + origName = name, + i = cssPrefixes.length; + + while ( i-- ) { + name = cssPrefixes[ i ] + capName; + if ( name in style ) { + return name; + } + } + + return origName; +} + +function isHidden( elem, el ) { + // isHidden might be called from jQuery#filter function; + // in that case, element will be second argument + elem = el || elem; + return jQuery.css( elem, "display" ) === "none" || !jQuery.contains( elem.ownerDocument, elem ); +} + +function showHide( elements, show ) { + var display, elem, hidden, + values = [], + index = 0, + length = elements.length; + + for ( ; index < length; index++ ) { + elem = elements[ index ]; + if ( !elem.style ) { + continue; + } + + values[ index ] = jQuery._data( elem, "olddisplay" ); + display = elem.style.display; + if ( show ) { + // Reset the inline display of this element to learn if it is + // being hidden by cascaded rules or not + if ( !values[ index ] && display === "none" ) { + elem.style.display = ""; + } + + // Set elements which have been overridden with display: none + // in a stylesheet to whatever the default browser style is + // for such an element + if ( elem.style.display === "" && isHidden( elem ) ) { + values[ index ] = jQuery._data( elem, "olddisplay", css_defaultDisplay(elem.nodeName) ); + } + } else { + + if ( !values[ index ] ) { + hidden = isHidden( elem ); + + if ( display && display !== "none" || !hidden ) { + jQuery._data( elem, "olddisplay", hidden ? display : jQuery.css( elem, "display" ) ); + } + } + } + } + + // Set the display of most of the elements in a second loop + // to avoid the constant reflow + for ( index = 0; index < length; index++ ) { + elem = elements[ index ]; + if ( !elem.style ) { + continue; + } + if ( !show || elem.style.display === "none" || elem.style.display === "" ) { + elem.style.display = show ? values[ index ] || "" : "none"; + } + } + + return elements; +} + +jQuery.fn.extend({ + css: function( name, value ) { + return jQuery.access( this, function( elem, name, value ) { + var len, styles, + map = {}, + i = 0; + + if ( jQuery.isArray( name ) ) { + styles = getStyles( elem ); + len = name.length; + + for ( ; i < len; i++ ) { + map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles ); + } + + return map; + } + + return value !== undefined ? + jQuery.style( elem, name, value ) : + jQuery.css( elem, name ); + }, name, value, arguments.length > 1 ); + }, + show: function() { + return showHide( this, true ); + }, + hide: function() { + return showHide( this ); + }, + toggle: function( state ) { + var bool = typeof state === "boolean"; + + return this.each(function() { + if ( bool ? state : isHidden( this ) ) { + jQuery( this ).show(); + } else { + jQuery( this ).hide(); + } + }); + } +}); + +jQuery.extend({ + // Add in style property hooks for overriding the default + // behavior of getting and setting a style property + cssHooks: { + opacity: { + get: function( elem, computed ) { + if ( computed ) { + // We should always get a number back from opacity + var ret = curCSS( elem, "opacity" ); + return ret === "" ? "1" : ret; + } + } + } + }, + + // Exclude the following css properties to add px + cssNumber: { + "columnCount": true, + "fillOpacity": true, + "fontWeight": true, + "lineHeight": true, + "opacity": true, + "orphans": true, + "widows": true, + "zIndex": true, + "zoom": true + }, + + // Add in properties whose names you wish to fix before + // setting or getting the value + cssProps: { + // normalize float css property + "float": jQuery.support.cssFloat ? "cssFloat" : "styleFloat" + }, + + // Get and set the style property on a DOM Node + style: function( elem, name, value, extra ) { + // Don't set styles on text and comment nodes + if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) { + return; + } + + // Make sure that we're working with the right name + var ret, type, hooks, + origName = jQuery.camelCase( name ), + style = elem.style; + + name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( style, origName ) ); + + // gets hook for the prefixed version + // followed by the unprefixed version + hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; + + // Check if we're setting a value + if ( value !== undefined ) { + type = typeof value; + + // convert relative number strings (+= or -=) to relative numbers. #7345 + if ( type === "string" && (ret = rrelNum.exec( value )) ) { + value = ( ret[1] + 1 ) * ret[2] + parseFloat( jQuery.css( elem, name ) ); + // Fixes bug #9237 + type = "number"; + } + + // Make sure that NaN and null values aren't set. See: #7116 + if ( value == null || type === "number" && isNaN( value ) ) { + return; + } + + // If a number was passed in, add 'px' to the (except for certain CSS properties) + if ( type === "number" && !jQuery.cssNumber[ origName ] ) { + value += "px"; + } + + // Fixes #8908, it can be done more correctly by specifing setters in cssHooks, + // but it would mean to define eight (for every problematic property) identical functions + if ( !jQuery.support.clearCloneStyle && value === "" && name.indexOf("background") === 0 ) { + style[ name ] = "inherit"; + } + + // If a hook was provided, use that value, otherwise just set the specified value + if ( !hooks || !("set" in hooks) || (value = hooks.set( elem, value, extra )) !== undefined ) { + + // Wrapped to prevent IE from throwing errors when 'invalid' values are provided + // Fixes bug #5509 + try { + style[ name ] = value; + } catch(e) {} + } + + } else { + // If a hook was provided get the non-computed value from there + if ( hooks && "get" in hooks && (ret = hooks.get( elem, false, extra )) !== undefined ) { + return ret; + } + + // Otherwise just get the value from the style object + return style[ name ]; + } + }, + + css: function( elem, name, extra, styles ) { + var num, val, hooks, + origName = jQuery.camelCase( name ); + + // Make sure that we're working with the right name + name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( elem.style, origName ) ); + + // gets hook for the prefixed version + // followed by the unprefixed version + hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; + + // If a hook was provided get the computed value from there + if ( hooks && "get" in hooks ) { + val = hooks.get( elem, true, extra ); + } + + // Otherwise, if a way to get the computed value exists, use that + if ( val === undefined ) { + val = curCSS( elem, name, styles ); + } + + //convert "normal" to computed value + if ( val === "normal" && name in cssNormalTransform ) { + val = cssNormalTransform[ name ]; + } + + // Return, converting to number if forced or a qualifier was provided and val looks numeric + if ( extra === "" || extra ) { + num = parseFloat( val ); + return extra === true || jQuery.isNumeric( num ) ? num || 0 : val; + } + return val; + }, + + // A method for quickly swapping in/out CSS properties to get correct calculations + swap: function( elem, options, callback, args ) { + var ret, name, + old = {}; + + // Remember the old values, and insert the new ones + for ( name in options ) { + old[ name ] = elem.style[ name ]; + elem.style[ name ] = options[ name ]; + } + + ret = callback.apply( elem, args || [] ); + + // Revert the old values + for ( name in options ) { + elem.style[ name ] = old[ name ]; + } + + return ret; + } +}); + +// NOTE: we've included the "window" in window.getComputedStyle +// because jsdom on node.js will break without it. +if ( window.getComputedStyle ) { + getStyles = function( elem ) { + return window.getComputedStyle( elem, null ); + }; + + curCSS = function( elem, name, _computed ) { + var width, minWidth, maxWidth, + computed = _computed || getStyles( elem ), + + // getPropertyValue is only needed for .css('filter') in IE9, see #12537 + ret = computed ? computed.getPropertyValue( name ) || computed[ name ] : undefined, + style = elem.style; + + if ( computed ) { + + if ( ret === "" && !jQuery.contains( elem.ownerDocument, elem ) ) { + ret = jQuery.style( elem, name ); + } + + // A tribute to the "awesome hack by Dean Edwards" + // Chrome < 17 and Safari 5.0 uses "computed value" instead of "used value" for margin-right + // Safari 5.1.7 (at least) returns percentage for a larger set of values, but width seems to be reliably pixels + // this is against the CSSOM draft spec: http://dev.w3.org/csswg/cssom/#resolved-values + if ( rnumnonpx.test( ret ) && rmargin.test( name ) ) { + + // Remember the original values + width = style.width; + minWidth = style.minWidth; + maxWidth = style.maxWidth; + + // Put in the new values to get a computed value out + style.minWidth = style.maxWidth = style.width = ret; + ret = computed.width; + + // Revert the changed values + style.width = width; + style.minWidth = minWidth; + style.maxWidth = maxWidth; + } + } + + return ret; + }; +} else if ( document.documentElement.currentStyle ) { + getStyles = function( elem ) { + return elem.currentStyle; + }; + + curCSS = function( elem, name, _computed ) { + var left, rs, rsLeft, + computed = _computed || getStyles( elem ), + ret = computed ? computed[ name ] : undefined, + style = elem.style; + + // Avoid setting ret to empty string here + // so we don't default to auto + if ( ret == null && style && style[ name ] ) { + ret = style[ name ]; + } + + // From the awesome hack by Dean Edwards + // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291 + + // If we're not dealing with a regular pixel number + // but a number that has a weird ending, we need to convert it to pixels + // but not position css attributes, as those are proportional to the parent element instead + // and we can't measure the parent instead because it might trigger a "stacking dolls" problem + if ( rnumnonpx.test( ret ) && !rposition.test( name ) ) { + + // Remember the original values + left = style.left; + rs = elem.runtimeStyle; + rsLeft = rs && rs.left; + + // Put in the new values to get a computed value out + if ( rsLeft ) { + rs.left = elem.currentStyle.left; + } + style.left = name === "fontSize" ? "1em" : ret; + ret = style.pixelLeft + "px"; + + // Revert the changed values + style.left = left; + if ( rsLeft ) { + rs.left = rsLeft; + } + } + + return ret === "" ? "auto" : ret; + }; +} + +function setPositiveNumber( elem, value, subtract ) { + var matches = rnumsplit.exec( value ); + return matches ? + // Guard against undefined "subtract", e.g., when used as in cssHooks + Math.max( 0, matches[ 1 ] - ( subtract || 0 ) ) + ( matches[ 2 ] || "px" ) : + value; +} + +function augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) { + var i = extra === ( isBorderBox ? "border" : "content" ) ? + // If we already have the right measurement, avoid augmentation + 4 : + // Otherwise initialize for horizontal or vertical properties + name === "width" ? 1 : 0, + + val = 0; + + for ( ; i < 4; i += 2 ) { + // both box models exclude margin, so add it if we want it + if ( extra === "margin" ) { + val += jQuery.css( elem, extra + cssExpand[ i ], true, styles ); + } + + if ( isBorderBox ) { + // border-box includes padding, so remove it if we want content + if ( extra === "content" ) { + val -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); + } + + // at this point, extra isn't border nor margin, so remove border + if ( extra !== "margin" ) { + val -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + } + } else { + // at this point, extra isn't content, so add padding + val += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); + + // at this point, extra isn't content nor padding, so add border + if ( extra !== "padding" ) { + val += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + } + } + } + + return val; +} + +function getWidthOrHeight( elem, name, extra ) { + + // Start with offset property, which is equivalent to the border-box value + var valueIsBorderBox = true, + val = name === "width" ? elem.offsetWidth : elem.offsetHeight, + styles = getStyles( elem ), + isBorderBox = jQuery.support.boxSizing && jQuery.css( elem, "boxSizing", false, styles ) === "border-box"; + + // some non-html elements return undefined for offsetWidth, so check for null/undefined + // svg - https://bugzilla.mozilla.org/show_bug.cgi?id=649285 + // MathML - https://bugzilla.mozilla.org/show_bug.cgi?id=491668 + if ( val <= 0 || val == null ) { + // Fall back to computed then uncomputed css if necessary + val = curCSS( elem, name, styles ); + if ( val < 0 || val == null ) { + val = elem.style[ name ]; + } + + // Computed unit is not pixels. Stop here and return. + if ( rnumnonpx.test(val) ) { + return val; + } + + // we need the check for style in case a browser which returns unreliable values + // for getComputedStyle silently falls back to the reliable elem.style + valueIsBorderBox = isBorderBox && ( jQuery.support.boxSizingReliable || val === elem.style[ name ] ); + + // Normalize "", auto, and prepare for extra + val = parseFloat( val ) || 0; + } + + // use the active box-sizing model to add/subtract irrelevant styles + return ( val + + augmentWidthOrHeight( + elem, + name, + extra || ( isBorderBox ? "border" : "content" ), + valueIsBorderBox, + styles + ) + ) + "px"; +} + +// Try to determine the default display value of an element +function css_defaultDisplay( nodeName ) { + var doc = document, + display = elemdisplay[ nodeName ]; + + if ( !display ) { + display = actualDisplay( nodeName, doc ); + + // If the simple way fails, read from inside an iframe + if ( display === "none" || !display ) { + // Use the already-created iframe if possible + iframe = ( iframe || + jQuery("