diff --git a/.github/workflows/appimage-build.yml b/.github/workflows/appimage-build.yml index a4d9b19a..86bfff30 100644 --- a/.github/workflows/appimage-build.yml +++ b/.github/workflows/appimage-build.yml @@ -45,6 +45,7 @@ jobs: rm -rf build meson setup build \ --prefix=/usr \ + -Dinstall-docs=true \ -Dtext-frontend=true \ -Dwith-perl=perl \ -Dwith-python=python3 \ diff --git a/.github/workflows/windows-build.yml b/.github/workflows/windows-build.yml index e1ad5afc..f72bd69b 100644 --- a/.github/workflows/windows-build.yml +++ b/.github/workflows/windows-build.yml @@ -40,7 +40,6 @@ jobs: python -m pip install --upgrade pip python -m pip install cffi python -m pip install zstandard - python -m pip install sphinx $ProgressPreference = 'SilentlyContinue' function Download-WithRetry { diff --git a/data/fonts/README.md b/data/fonts/README.md index 8cfed8ac..fb9acc8c 100644 --- a/data/fonts/README.md +++ b/data/fonts/README.md @@ -5,10 +5,14 @@ Unicode Emoji 17.0. It is vendored from Debian's `fonts-noto-color-emoji` 2.051 package, built from the corresponding Google Noto Emoji release. -Every GTK build installs this exact file: Windows (installer and portable -build files), AppImage, Flatpak and native Meson/RPM builds. It is loaded -into a private Pango/FreeType font map as `ZoiteChat Emoji`; an older system -Noto font cannot replace it. No font is installed globally on Windows. +By default, GTK builds install this exact file, including Windows +(installer and portable builds), AppImage, Flatpak, and native Meson/RPM. +Meson packagers can set `-Dinstall-emoji-font=false` to omit the bundled +font and its installed notices and use system emoji fonts instead. An +explicit `ZOITECHAT_EMOJI_FONT` path still enables the private font map +in such builds. With the bundled font, it is registered privately as +`ZoiteChat Emoji`; an older system Noto font cannot replace it. No font +is installed globally on Windows. Chat windows and the emoji picker share this map. Fontconfig still loads system fonts and configuration for ordinary text, and the configured text @@ -29,7 +33,9 @@ directory; Windows resolves it relative to the executable. AppImage sets ZOITECHAT_EMOJI_FONT="$PWD/data/fonts/NotoColorEmoji.ttf" build/src/fe-gtk/zoitechat ``` -A missing/unloadable file logs a warning and retains system-font fallback. +An unexpectedly missing or unloadable bundled font logs a warning and retains +system-font fallback. When installation is disabled deliberately, fallback is +quiet unless an explicit `ZOITECHAT_EMOJI_FONT` override is invalid. CI verifies the installed copy and tests catalog/font coverage; AppImage and Windows also run the interactive picker regression tests. Native themes, DPI and different Pango/Cairo versions can still affect pixel-level output. diff --git a/data/fonts/meson.build b/data/fonts/meson.build index eb3f545a..1d0e4f8d 100644 --- a/data/fonts/meson.build +++ b/data/fonts/meson.build @@ -1,13 +1,15 @@ emoji_font_dir = join_paths(get_option('datadir'), 'fonts', 'zoitechat') emoji_font_doc_dir = join_paths(get_option('datadir'), 'doc', 'zoitechat', 'fonts') -install_data( - 'NotoColorEmoji.ttf', - install_dir: emoji_font_dir, -) +if get_option('install-emoji-font') + install_data( + 'NotoColorEmoji.ttf', + install_dir: emoji_font_dir, + ) -install_data( - 'OFL.txt', - 'README.md', - install_dir: emoji_font_doc_dir, -) + install_data( + 'OFL.txt', + 'README.md', + install_dir: emoji_font_doc_dir, + ) +endif diff --git a/docs/README.md b/docs/README.md index dba73d56..3ae46b43 100644 --- a/docs/README.md +++ b/docs/README.md @@ -58,18 +58,23 @@ Build from the repository root: sphinx-build -b html docs docs/_build/html ``` -Use a clean output directory when switching themes, so stale Basicstrap -assets from an earlier build are not included in a package. +Use a clean output directory when switching themes so stale assets from +earlier builds are not included in a package. ## Debian packaging -The active theme does not use the bundled Basicstrap, Bootstrap, jQuery, -jQuery Cookie, Font Awesome, or icon fonts. Its font stack includes DejaVu -Sans and DejaVu Sans Mono; no font files are bundled by the theme. +The `zoitechat` theme uses Sphinx's built-in `basic` theme. It does not +bundle Bootstrap, jQuery, jQuery Cookie, Font Awesome, or icon fonts. +Its font stack includes DejaVu Sans and DejaVu Sans Mono; no font files +are bundled by the theme. -Packagers may exclude `docs/_theme/basicstrap/` from the source package. -The default theme continues to build without that directory. No pre-minified -third-party assets need to be added or rebuilt for this theme. +No pre-minified third-party theme assets need to be added or rebuilt. + +The Meson option `-Dinstall-docs` defaults to `false`, so platforms that +do not ship offline documentation do not need Sphinx just to build ZoiteChat. +Pass `-Dinstall-docs=true` when packaging local HTML documentation. Fedora +and AppImage enable it explicitly; the Debian documentation package can do +the same. Build with the distribution's `python3-sphinx`. After installing the HTML into the package staging directory, use `dh_sphinxdoc` (or `dh --with diff --git a/docs/_static/css/zoitechat-docs.css b/docs/_static/css/zoitechat-docs.css index a2ceb51c..2e665347 100644 --- a/docs/_static/css/zoitechat-docs.css +++ b/docs/_static/css/zoitechat-docs.css @@ -807,7 +807,7 @@ a.headerlink:focus-visible { :root { --page: var(--bg); --panel: var(--chrome); - --font: system-ui, -apple-system, "Segoe UI", sans-serif; + --font: system-ui, -apple-system, "Segoe UI", "DejaVu Sans", sans-serif; } .site-header { padding: 0; } .appearance select { min-height: 0; border-radius: 3px; } diff --git a/docs/_static/css/zoitechat-site.css b/docs/_static/css/zoitechat-site.css index 1b0951ca..ca3c3648 100644 --- a/docs/_static/css/zoitechat-site.css +++ b/docs/_static/css/zoitechat-site.css @@ -16,7 +16,7 @@ --success: #236741; --code: #f2f4f6; --shadow: none; - --mono: Consolas,"Liberation Mono",monospace; + --mono: Consolas,"DejaVu Sans Mono","Liberation Mono",monospace; } html[data-theme=dark] { @@ -45,7 +45,7 @@ body { margin: 0; background: var(--bg); color: var(--text); - font: 15px/1.6 system-ui,-apple-system,"Segoe UI",sans-serif; + font: 15px/1.6 system-ui,-apple-system,"Segoe UI","DejaVu Sans",sans-serif; } a { diff --git a/docs/_theme/basicstrap/layout.html b/docs/_theme/basicstrap/layout.html deleted file mode 100644 index 362ed4d1..00000000 --- a/docs/_theme/basicstrap/layout.html +++ /dev/null @@ -1,368 +0,0 @@ -{# - basicstrap/layout.html - ~~~~~~~~~~~~~~~~~~~~~~~~~ - - Master layout template for Sphinx themes. on Twitter Bootstrap - - :copyright: Copyright 2012 by tell-k. - :license: MIT Licence, see LICENSE for details. -#} -{%- block doctype -%} - -{%- endblock %} -{%- set reldelim1 = reldelim1 is not defined and ' »' or reldelim1 %} -{%- set reldelim2 = reldelim2 is not defined and ' |' or reldelim2 %} -{%- set render_sidebar = (not embedded) and (not theme_nosidebar|tobool) and -(sidebars != []) %} -{%- set url_root = pathto('', 1) %} -{# XXX necessary? #} -{%- if url_root == '#' %}{% set url_root = '' %}{% endif %} -{%- if not embedded and docstitle %} -{%- set titlesuffix = " — "|safe + docstitle|e %} -{%- else %} -{%- set titlesuffix = "" %} -{%- endif %} - -{%- if theme_bootstrap_version == "3" %} - {%- set bs_span_prefix = "col-md-" %} - {%- set class_device_xs= "xs" %} - {%- set class_device_sm= "sm" %} - {%- set class_device_md= "md" %} - {%- set class_row = "row" %} -{%- else %} - {%- set bs_span_prefix = "span" %} - {%- set class_device_xs= "phone" %} - {%- set class_device_sm= "tablet" %} - {%- set class_device_md= "desktop" %} - {%- if (not theme_row_fixed|tobool) %} - {%- set class_row = "row-fluid" %} - {%- else %} - {%- set class_row = "row" %} - {%- endif %} -{%- endif %} - -{%- macro relbar() %} -
-{%- endmacro %} - -{%- macro sidebar() %} -{%- if render_sidebar %} - -{%- endif %} -{%- endmacro %} - - -{% set script_files = (['_static/js/jquery.min.js'] if '_static/js/jquery.min.js' not in script_files else []) + script_files + ['_static/js/bootstrap' + theme_bootstrap_version + '.min.js'] %} -{%- macro script() %} -{%- if '_static/documentation_options.js' not in script_files %} - -{%- endif %} -{%- for scriptfile in script_files %} - {%- if scriptfile is string -%} - - {%- else -%} - {{ js_tag(scriptfile) }} - {%- endif -%} -{%- endfor %} -{%- if theme_theme_preview|tobool %} - -{%- endif %} - - -{%- endmacro %} - -{%- macro css() %} -{%- if (theme_googlewebfont|tobool) %} - -{%- endif %} - - - -{%- if (theme_inner_theme|tobool) %} - - -{%- else %} - - -{%- endif %} - -{%- if theme_bootstrap_version == "3" and theme_noflatdesign|tobool %} - -{%- endif %} - - -{% if (theme_nav_fixed_top|tobool) %} - -{% endif %} - -{%- if (not theme_noresponsive|tobool) and theme_bootstrap_version == "2" %} - -{%- endif %} - -{%- if theme_noresponsive|tobool and theme_bootstrap_version == "3" %} - -{%- endif %} - -{# Keep project CSS last so Bootstrap/basicstrap cannot re-float or resize the docs columns. #} -{%- for cssfile in css_files %} - {%- if cssfile is string -%} - - {%- else -%} - {{ css_tag(cssfile) }} - {%- endif -%} -{%- endfor %} - -{%- endmacro %} - - - - - {{ metatags }} - {%- block htmltitle %} -- {% trans %}Please activate JavaScript to enable the search - functionality.{% endtrans %} -
-- {% trans %}From here you can search these documents. Enter your search - words into the box below and click "search". Note that the search - function will automatically search for all of the words. Pages - containing fewer words won't appear in the result list.{% endtrans %} -
- - -{{ _('Your search did not match any results.') }}
- {% endif %} - {% endif %} -- {{ _('Enter search terms or a module, class or function name.') }} -
-- From here you can search these documents. Enter your search - words into the box below and click "search". -
- -{%- if search_performed %} -Your search did not match any results.
- {%- endif %} -{%- endif %} -").html($(this).html());
- });
- }});
-
- /*
- * Scroll the window to avoid the topnav bar
- * https://github.com/twitter/bootstrap/issues/1768
- */
- if ($(".navbar.navbar-fixed-top").length > 0) {
- // var navHeight = $(".navbar").height(),
- var navHeight = 40,
- shiftWindow = function() { scrollBy(0, -navHeight - 10); };
- if (location.hash) {
- setTimeout(shiftWindow, 1);
- }
- window.addEventListener("hashchange", shiftWindow);
- }
-
- {%- if theme_theme_preview|tobool %}
-
- var makeHtmlOptions = function(){
- var header_inverse = ($.cookie('header_inverse') == 'inverse') ? "True" : "False";
- var relbar_inverse = ($.cookie('relbar_inverse') == 'inverse') ? "True" : "False";
- var inner_theme = ($.cookie('inner_theme') != '') ? "True" : "False";
-
- var options_text = "html_theme_options = {\n";
- options_text += " 'header_inverse': " + header_inverse + ",\n";
- options_text += " 'relbar_inverse': " + relbar_inverse + ",\n";
- options_text += " 'inner_theme': " + inner_theme + ",\n";
- if(inner_theme == "True") {
- options_text += " 'inner_theme_name': '" + $.cookie('inner_theme') + "',\n";
- }
- options_text += "}";
- $("#quick-preview-theme-options div.highlight pre").html(options_text);
- }
-
- /*
- * for QuickPreviewModal
- */
- if($.cookie('inner_theme')) {
- var bootstrap_version = $("#bootstrap-version").html();
- $("#current-theme").attr({href: "_static/css/bootstrap" + bootstrap_version + "/" +$.cookie('inner_theme') + ".css"})
- $("#current-adjust-theme").attr({href: "_static/css/adjust_theme/" + $.cookie('inner_theme') + ".css"})
- $('#select-theme').val($.cookie('inner_theme'));
- }
- if($.cookie('header_inverse')) {
- $("#navbar-top").removeClass("navbar-default");
- $("#navbar-top").removeClass("navbar-inverse");
- $("#navbar-top").addClass("navbar-" + $.cookie('header_inverse'));
- if ($.cookie('header_inverse') == 'inverse') {
- $('#select-header-inverse').attr('checked', true);
- }
- }
- if($.cookie('relbar_inverse')) {
- $("#navbar-related").removeClass("navbar-default");
- $("#navbar-related").removeClass("navbar-inverse");
- $("#navbar-related").addClass("navbar-" + $.cookie('relbar_inverse'));
- if ($.cookie('relbar_inverse') == 'inverse') {
- $('#select-relbar-inverse').attr('checked', true);
- }
- }
- if($.cookie('inner_theme') || $.cookie('header_inverse') || $.cookie('relbar_inverse')) {
- makeHtmlOptions();
- }
-
- $("#select-theme").change(function(e){
- e.preventDefault();
- var bootstrap_version = $("#bootstrap-version").html();
- var theme;
- $("#select-theme option:selected").each(function () {
- theme = $(this).val();
- });
- if (theme == '') {
- $("#current-theme").attr({href: "_static/css/bootstrap" + bootstrap_version + "/bootstrap.min.css"})
- $("#current-adjust-theme").attr({href: ""})
- $.cookie('inner_theme', theme, {expires: 1, path: '/'});
- makeHtmlOptions();
- return
- }
- $("#current-theme").attr({href: "_static/css/bootstrap" + bootstrap_version + "/" + theme + ".css"})
- $("#current-adjust-theme").attr({href: "_static/css/adjust_theme/" + theme + ".css"})
- $.cookie('inner_theme', theme, {expires: 1, path: '/'});
- makeHtmlOptions();
- });
- $("#select-header-inverse").change(function(e){
- var inverse = $('#select-header-inverse').prop("checked");
- var inverse_type = (inverse) ? 'inverse' : 'default';
-
- $("#navbar-top").removeClass("navbar-default");
- $("#navbar-top").removeClass("navbar-inverse");
- $("#navbar-top").addClass("navbar-" + inverse_type);
- $.cookie('header_inverse', inverse_type, {expires: 1, path: '/'});
- makeHtmlOptions();
- });
- $("#select-relbar-inverse").change(function(e){
- var inverse = $('#select-relbar-inverse').prop("checked");
- var inverse_type = (inverse) ? 'inverse' : 'default';
-
- $("#navbar-related").removeClass("navbar-default");
- $("#navbar-related").removeClass("navbar-inverse");
- $("#navbar-related").addClass("navbar-" + inverse_type);
- $.cookie('relbar_inverse', inverse_type, {expires: 1, path: '/'});
- makeHtmlOptions();
- });
- {%- endif %}
-
-});
diff --git a/docs/_theme/basicstrap/static/js/bootstrap2.min.js b/docs/_theme/basicstrap/static/js/bootstrap2.min.js
deleted file mode 100644
index f9cbdae7..00000000
--- a/docs/_theme/basicstrap/static/js/bootstrap2.min.js
+++ /dev/null
@@ -1,6 +0,0 @@
-/*!
-* Bootstrap.js by @fat & @mdo
-* Copyright 2012 Twitter, Inc.
-* http://www.apache.org/licenses/LICENSE-2.0.txt
-*/
-!function(e){"use strict";e(function(){e.support.transition=function(){var e=function(){var e=document.createElement("bootstrap"),t={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"},n;for(n in t)if(e.style[n]!==undefined)return t[n]}();return e&&{end:e}}()})}(window.jQuery),!function(e){"use strict";var t='[data-dismiss="alert"]',n=function(n){e(n).on("click",t,this.close)};n.prototype.close=function(t){function s(){i.trigger("closed").remove()}var n=e(this),r=n.attr("data-target"),i;r||(r=n.attr("href"),r=r&&r.replace(/.*(?=#[^\s]*$)/,"")),i=e(r),t&&t.preventDefault(),i.length||(i=n.hasClass("alert")?n:n.parent()),i.trigger(t=e.Event("close"));if(t.isDefaultPrevented())return;i.removeClass("in"),e.support.transition&&i.hasClass("fade")?i.on(e.support.transition.end,s):s()};var r=e.fn.alert;e.fn.alert=function(t){return this.each(function(){var r=e(this),i=r.data("alert");i||r.data("alert",i=new n(this)),typeof t=="string"&&i[t].call(r)})},e.fn.alert.Constructor=n,e.fn.alert.noConflict=function(){return e.fn.alert=r,this},e(document).on("click.alert.data-api",t,n.prototype.close)}(window.jQuery),!function(e){"use strict";var t=function(t,n){this.$element=e(t),this.options=e.extend({},e.fn.button.defaults,n)};t.prototype.setState=function(e){var t="disabled",n=this.$element,r=n.data(),i=n.is("input")?"val":"html";e+="Text",r.resetText||n.data("resetText",n[i]()),n[i](r[e]||this.options[e]),setTimeout(function(){e=="loadingText"?n.addClass(t).attr(t,t):n.removeClass(t).removeAttr(t)},0)},t.prototype.toggle=function(){var e=this.$element.closest('[data-toggle="buttons-radio"]');e&&e.find(".active").removeClass("active"),this.$element.toggleClass("active")};var n=e.fn.button;e.fn.button=function(n){return this.each(function(){var r=e(this),i=r.data("button"),s=typeof n=="object"&&n;i||r.data("button",i=new t(this,s)),n=="toggle"?i.toggle():n&&i.setState(n)})},e.fn.button.defaults={loadingText:"loading..."},e.fn.button.Constructor=t,e.fn.button.noConflict=function(){return e.fn.button=n,this},e(document).on("click.button.data-api","[data-toggle^=button]",function(t){var n=e(t.target);n.hasClass("btn")||(n=n.closest(".btn")),n.button("toggle")})}(window.jQuery),!function(e){"use strict";var t=function(t,n){this.$element=e(t),this.$indicators=this.$element.find(".carousel-indicators"),this.options=n,this.options.pause=="hover"&&this.$element.on("mouseenter",e.proxy(this.pause,this)).on("mouseleave",e.proxy(this.cycle,this))};t.prototype={cycle:function(t){return t||(this.paused=!1),this.interval&&clearInterval(this.interval),this.options.interval&&!this.paused&&(this.interval=setInterval(e.proxy(this.next,this),this.options.interval)),this},getActiveIndex:function(){return this.$active=this.$element.find(".item.active"),this.$items=this.$active.parent().children(),this.$items.index(this.$active)},to:function(t){var n=this.getActiveIndex(),r=this;if(t>this.$items.length-1||t<0)return;return this.sliding?this.$element.one("slid",function(){r.to(t)}):n==t?this.pause().cycle():this.slide(t>n?"next":"prev",e(this.$items[t]))},pause:function(t){return t||(this.paused=!0),this.$element.find(".next, .prev").length&&e.support.transition.end&&(this.$element.trigger(e.support.transition.end),this.cycle(!0)),clearInterval(this.interval),this.interval=null,this},next:function(){if(this.sliding)return;return this.slide("next")},prev:function(){if(this.sliding)return;return this.slide("prev")},slide:function(t,n){var r=this.$element.find(".item.active"),i=n||r[t](),s=this.interval,o=t=="next"?"left":"right",u=t=="next"?"first":"last",a=this,f;this.sliding=!0,s&&this.pause(),i=i.length?i:this.$element.find(".item")[u](),f=e.Event("slide",{relatedTarget:i[0],direction:o});if(i.hasClass("active"))return;this.$indicators.length&&(this.$indicators.find(".active").removeClass("active"),this.$element.one("slid",function(){var t=e(a.$indicators.children()[a.getActiveIndex()]);t&&t.addClass("active")}));if(e.support.transition&&this.$element.hasClass("slide")){this.$element.trigger(f);if(f.isDefaultPrevented())return;i.addClass(t),i[0].offsetWidth,r.addClass(o),i.addClass(o),this.$element.one(e.support.transition.end,function(){i.removeClass([t,o].join(" ")).addClass("active"),r.removeClass(["active",o].join(" ")),a.sliding=!1,setTimeout(function(){a.$element.trigger("slid")},0)})}else{this.$element.trigger(f);if(f.isDefaultPrevented())return;r.removeClass("active"),i.addClass("active"),this.sliding=!1,this.$element.trigger("slid")}return s&&this.cycle(),this}};var n=e.fn.carousel;e.fn.carousel=function(n){return this.each(function(){var r=e(this),i=r.data("carousel"),s=e.extend({},e.fn.carousel.defaults,typeof n=="object"&&n),o=typeof n=="string"?n:s.slide;i||r.data("carousel",i=new t(this,s)),typeof n=="number"?i.to(n):o?i[o]():s.interval&&i.pause().cycle()})},e.fn.carousel.defaults={interval:5e3,pause:"hover"},e.fn.carousel.Constructor=t,e.fn.carousel.noConflict=function(){return e.fn.carousel=n,this},e(document).on("click.carousel.data-api","[data-slide], [data-slide-to]",function(t){var n=e(this),r,i=e(n.attr("data-target")||(r=n.attr("href"))&&r.replace(/.*(?=#[^\s]+$)/,"")),s=e.extend({},i.data(),n.data()),o;i.carousel(s),(o=n.attr("data-slide-to"))&&i.data("carousel").pause().to(o).cycle(),t.preventDefault()})}(window.jQuery),!function(e){"use strict";var t=function(t,n){this.$element=e(t),this.options=e.extend({},e.fn.collapse.defaults,n),this.options.parent&&(this.$parent=e(this.options.parent)),this.options.toggle&&this.toggle()};t.prototype={constructor:t,dimension:function(){var e=this.$element.hasClass("width");return e?"width":"height"},show:function(){var t,n,r,i;if(this.transitioning||this.$element.hasClass("in"))return;t=this.dimension(),n=e.camelCase(["scroll",t].join("-")),r=this.$parent&&this.$parent.find("> .accordion-group > .in");if(r&&r.length){i=r.data("collapse");if(i&&i.transitioning)return;r.collapse("hide"),i||r.data("collapse",null)}this.$element[t](0),this.transition("addClass",e.Event("show"),"shown"),e.support.transition&&this.$element[t](this.$element[0][n])},hide:function(){var t;if(this.transitioning||!this.$element.hasClass("in"))return;t=this.dimension(),this.reset(this.$element[t]()),this.transition("removeClass",e.Event("hide"),"hidden"),this.$element[t](0)},reset:function(e){var t=this.dimension();return this.$element.removeClass("collapse")[t](e||"auto")[0].offsetWidth,this.$element[e!==null?"addClass":"removeClass"]("collapse"),this},transition:function(t,n,r){var i=this,s=function(){n.type=="show"&&i.reset(),i.transitioning=0,i.$element.trigger(r)};this.$element.trigger(n);if(n.isDefaultPrevented())return;this.transitioning=1,this.$element[t]("in"),e.support.transition&&this.$element.hasClass("collapse")?this.$element.one(e.support.transition.end,s):s()},toggle:function(){this[this.$element.hasClass("in")?"hide":"show"]()}};var n=e.fn.collapse;e.fn.collapse=function(n){return this.each(function(){var r=e(this),i=r.data("collapse"),s=e.extend({},e.fn.collapse.defaults,r.data(),typeof n=="object"&&n);i||r.data("collapse",i=new t(this,s)),typeof n=="string"&&i[n]()})},e.fn.collapse.defaults={toggle:!0},e.fn.collapse.Constructor=t,e.fn.collapse.noConflict=function(){return e.fn.collapse=n,this},e(document).on("click.collapse.data-api","[data-toggle=collapse]",function(t){var n=e(this),r,i=n.attr("data-target")||t.preventDefault()||(r=n.attr("href"))&&r.replace(/.*(?=#[^\s]+$)/,""),s=e(i).data("collapse")?"toggle":n.data();n[e(i).hasClass("in")?"addClass":"removeClass"]("collapsed"),e(i).collapse(s)})}(window.jQuery),!function(e){"use strict";function r(){e(".dropdown-backdrop").remove(),e(t).each(function(){i(e(this)).removeClass("open")})}function i(t){var n=t.attr("data-target"),r;n||(n=t.attr("href"),n=n&&/#/.test(n)&&n.replace(/.*(?=#[^\s]*$)/,"")),r=n&&e(n);if(!r||!r.length)r=t.parent();return r}var t="[data-toggle=dropdown]",n=function(t){var n=e(t).on("click.dropdown.data-api",this.toggle);e("html").on("click.dropdown.data-api",function(){n.parent().removeClass("open")})};n.prototype={constructor:n,toggle:function(t){var n=e(this),s,o;if(n.is(".disabled, :disabled"))return;return s=i(n),o=s.hasClass("open"),r(),o||("ontouchstart"in document.documentElement&&e('').insertBefore(e(this)).on("click",r),s.toggleClass("open")),n.focus(),!1},keydown:function(n){var r,s,o,u,a,f;if(!/(38|40|27)/.test(n.keyCode))return;r=e(this),n.preventDefault(),n.stopPropagation();if(r.is(".disabled, :disabled"))return;u=i(r),a=u.hasClass("open");if(!a||a&&n.keyCode==27)return n.which==27&&u.find(t).focus(),r.click();s=e("[role=menu] li:not(.divider):visible a",u);if(!s.length)return;f=s.index(s.filter(":focus")),n.keyCode==38&&f>0&&f--,n.keyCode==40&&f| t |