From fd0a0e63d78138b485c2440781f6c210dd3df8a2 Mon Sep 17 00:00:00 2001 From: "Danilo M." Date: Fri, 11 Sep 2026 18:51:17 +0200 Subject: feat(palette): generate the Kvantum theme so Qt apps follow the scheme Qt and GTK were the one part of the desktop the palette never reached: Kvantum was pinned to a hand-installed catppuccin-macchiato-lavender directory, so pcmanfm-qt and every other Qt app stayed Macchiato no matter which scheme was selected. A Kvantum theme is a .kvconfig of colours and a .svg of widget artwork with colours baked into the paths, which looked like it needed redrawing. It did not: the SVG carries only 27 distinct colours, 12 of them palette colours and the rest neutral greys that are shading, not theme colour. Both files are now templates with the 12 as placeholders, derived from the theme this desktop was already running. Installs to ~/.config/Kvantum/udt/ under one fixed name for every scheme, so a switch needs no change to kvantum.kvconfig and leaves no stale theme behind. Adds accent_dim and accent_bright roles for Kvantum's hover and pressed states. Verified: no placeholders survive generation, the SVG still parses as XML, and pcmanfm-qt picks up the new colours on restart. Qt reads a theme at startup only, so running apps need restarting; AGENTS.md says so. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_015gbjA2bmswN8jyPDKzrvqe --- .gitignore | 2 + AGENTS.md | 16 +- bin/udt-palette | 24 + install.sh | 9 + palette/roles-dracula.conf | 4 + palette/roles-frappe.conf | 4 + palette/roles-macchiato.conf | 4 + palette/roles-material-darker.conf | 4 + palette/roles-material-ocean.conf | 4 + palette/roles-material-palenight.conf | 4 + palette/roles-mocha.conf | 4 + palette/roles-nord.conf | 4 + palette/roles-tokyo-night.conf | 4 + templates/kvantum/theme.kvconfig.in | 476 ++++++++ templates/kvantum/theme.svg.in | 1959 +++++++++++++++++++++++++++++++++ 15 files changed, 2520 insertions(+), 2 deletions(-) create mode 100644 templates/kvantum/theme.kvconfig.in create mode 100644 templates/kvantum/theme.svg.in diff --git a/.gitignore b/.gitignore index e7bab11..6a1e992 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,5 @@ __pycache__/ /templates/waybar/theme.css /templates/terminal/kitty-theme.conf /bin/udt_colors.py +/templates/kvantum/theme.kvconfig +/templates/kvantum/theme.svg diff --git a/AGENTS.md b/AGENTS.md index b022a38..412fe41 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -39,8 +39,20 @@ Generated files are gitignored, because tracking them would turn every scheme switch into a diff. Editing one is pointless: the next install overwrites it. The generated set is `rofi/udt/palette.rasi`, `templates/dunstrc`, `templates/conky.conf`, `templates/waybar/theme.css`, -`templates/terminal/kitty-theme.conf`, `templates/homepage/custom.css` and -`bin/udt_colors.py`. +`templates/terminal/kitty-theme.conf`, `templates/homepage/custom.css`, +`templates/kvantum/theme.{kvconfig,svg}` and `bin/udt_colors.py`. + +Qt and GTK apps reach the palette through Kvantum. Its theme is a `.kvconfig` +of colours plus a `.svg` of widget artwork with the colours baked into the +paths, so both are templates: the twelve palette colours are placeholders and +the fifteen neutral greys are left alone, because those are shading rather than +theme colour. It installs to `~/.config/Kvantum/udt/` under one fixed name for +every scheme, so switching needs no change to `kvantum.kvconfig` and leaves no +stale theme behind. Derived from `catppuccin-macchiato-lavender`, which this +desktop was already running by hand. + +**Qt apps only read a theme at startup**, so a running one keeps the old +colours until restarted. `install.sh` cannot signal them and does not try. The homepage stylesheet is the one output that leaves this machine. `install.sh` scp's it to `homepage:hp-stage/`, with a five second timeout and a diff --git a/bin/udt-palette b/bin/udt-palette index 18dc0b1..edde7f3 100755 --- a/bin/udt-palette +++ b/bin/udt-palette @@ -223,6 +223,28 @@ def gen_kitty(res, scheme, palette): return "\n".join(lines) + "\n" +KVANTUM_ROLES = ["bg", "bg_alt", "surface", "surface_alt", "surface_high", + "fg", "fg_dim", "fg_faint", "mid_high", "accent", + "accent_dim", "accent_bright", "highlight", "critical"] + + +def gen_kvantum(res, scheme, palette, template): + """Kvantum: substitute the palette into the widget theme. + + A Kvantum theme is a .kvconfig of colours and a .svg of widget artwork with + colours baked into the paths. Only the palette colours are placeholders; + the neutral greys in the SVG are shading and shadow, not theme colour, so + they are left exactly as upstream drew them. + + Derived from the catppuccin-macchiato-lavender theme, which is what this + desktop was already running by hand. + """ + out = template + for role in KVANTUM_ROLES: + out = out.replace(f"@{role.upper()}@", hex6(res[role])) + return out + + def gen_homepage(res, scheme, palette): """gethomepage: a custom.css overriding its ten-step colour ramp. @@ -414,6 +436,8 @@ TARGETS = [ ("templates/conky.conf", gen_conky, "templates/conky.conf.in"), ("bin/udt_colors.py", gen_accent_py, None), ("templates/homepage/custom.css", gen_homepage, None), + ("templates/kvantum/theme.kvconfig", gen_kvantum, "templates/kvantum/theme.kvconfig.in"), + ("templates/kvantum/theme.svg", gen_kvantum, "templates/kvantum/theme.svg.in"), ] diff --git a/install.sh b/install.sh index 6bc0341..e7e2177 100755 --- a/install.sh +++ b/install.sh @@ -61,6 +61,15 @@ fi install -Dm644 "$repo/templates/terminal/kitty-theme.conf" \ "$HOME/.config/kitty/current-theme.conf" +# Kvantum wants a directory per theme, named after itself, and qt5ct/qt6ct +# reach Qt apps through it. The theme is installed under one fixed name rather +# than one per scheme: Kvantum caches by name, so reusing it means a switch +# needs no change to kvantum.kvconfig and no second theme left behind. +kv="$HOME/.config/Kvantum/udt" +install -Dm644 "$repo/templates/kvantum/theme.kvconfig" "$kv/udt.kvconfig" +install -Dm644 "$repo/templates/kvantum/theme.svg" "$kv/udt.svg" +printf '[General]\ntheme=udt\n' > "$HOME/.config/Kvantum/kvantum.kvconfig" + # Stage the homepage stylesheet on the dashboard host. Staged, not installed: # /opt/homepage/config is root-owned and this script does not hold root there. # Never fatal, and never slow: a laptop away from that network must still be diff --git a/palette/roles-dracula.conf b/palette/roles-dracula.conf index ea3d71f..8c54813 100644 --- a/palette/roles-dracula.conf +++ b/palette/roles-dracula.conf @@ -103,6 +103,10 @@ scrollbar_track = current_line bell_border = yellow tab_bar_bg = surface_low +# Kvantum hover and pressed states, a shade either side of the accent. +accent_dim = purple*92 +accent_bright = purple*110 + [accents] # Dracula ships six accents. snap = pink purple red orange yellow green cyan diff --git a/palette/roles-frappe.conf b/palette/roles-frappe.conf index 4ae5ea4..bfe5ac2 100644 --- a/palette/roles-frappe.conf +++ b/palette/roles-frappe.conf @@ -115,6 +115,10 @@ scrollbar_track = surface1 bell_border = yellow tab_bar_bg = crust +# Kvantum hover and pressed states, a shade either side of the accent. +accent_dim = lavender*92 +accent_bright = lavender*105 + [accents] # The hues udt-accent snaps a wallpaper to. Near-neutral tints (rosewater, # flamingo) and near-duplicate hues (maroon, sapphire) are left out so the diff --git a/palette/roles-macchiato.conf b/palette/roles-macchiato.conf index f5d12ea..a7c11d7 100644 --- a/palette/roles-macchiato.conf +++ b/palette/roles-macchiato.conf @@ -115,6 +115,10 @@ scrollbar_track = surface1 bell_border = yellow tab_bar_bg = crust +# Kvantum hover and pressed states, a shade either side of the accent. +accent_dim = lavender*92 +accent_bright = lavender*105 + [accents] # The hues udt-accent snaps a wallpaper to. Near-neutral tints (rosewater, # flamingo) and near-duplicate hues (maroon, sapphire) are left out so the diff --git a/palette/roles-material-darker.conf b/palette/roles-material-darker.conf index 0db4a58..152e179 100644 --- a/palette/roles-material-darker.conf +++ b/palette/roles-material-darker.conf @@ -103,6 +103,10 @@ scrollbar_track = surface bell_border = yellow tab_bar_bg = deep +# Kvantum hover and pressed states, a shade either side of the accent. +accent_dim = cyan*92 +accent_bright = cyan*110 + [accents] # Material ships one accent per hue, seven usable. snap = purple violet blue cyan green yellow orange red diff --git a/palette/roles-material-ocean.conf b/palette/roles-material-ocean.conf index 6291123..8a657a9 100644 --- a/palette/roles-material-ocean.conf +++ b/palette/roles-material-ocean.conf @@ -103,6 +103,10 @@ scrollbar_track = surface bell_border = yellow tab_bar_bg = deep +# Kvantum hover and pressed states, a shade either side of the accent. +accent_dim = cyan*92 +accent_bright = cyan*110 + [accents] # Material ships one accent per hue, seven usable. snap = purple violet blue cyan green yellow orange red diff --git a/palette/roles-material-palenight.conf b/palette/roles-material-palenight.conf index e09d54b..3e6a985 100644 --- a/palette/roles-material-palenight.conf +++ b/palette/roles-material-palenight.conf @@ -103,6 +103,10 @@ scrollbar_track = surface bell_border = yellow tab_bar_bg = deep +# Kvantum hover and pressed states, a shade either side of the accent. +accent_dim = cyan*92 +accent_bright = cyan*110 + [accents] # Material ships one accent per hue, seven usable. snap = purple violet blue cyan green yellow orange red diff --git a/palette/roles-mocha.conf b/palette/roles-mocha.conf index 8d5c509..318edce 100644 --- a/palette/roles-mocha.conf +++ b/palette/roles-mocha.conf @@ -115,6 +115,10 @@ scrollbar_track = surface1 bell_border = yellow tab_bar_bg = crust +# Kvantum hover and pressed states, a shade either side of the accent. +accent_dim = lavender*92 +accent_bright = lavender*105 + [accents] # The hues udt-accent snaps a wallpaper to. Near-neutral tints (rosewater, # flamingo) and near-duplicate hues (maroon, sapphire) are left out so the diff --git a/palette/roles-nord.conf b/palette/roles-nord.conf index b79e6f4..29b2854 100644 --- a/palette/roles-nord.conf +++ b/palette/roles-nord.conf @@ -103,6 +103,10 @@ scrollbar_track = nord2 bell_border = aurora_yellow tab_bar_bg = nord0 +# Kvantum hover and pressed states, a shade either side of the accent. +accent_dim = frost_cyan*92 +accent_bright = frost_cyan*110 + [accents] # Nord has nine usable hues, one fewer than Catppuccin. snap = aurora_purple frost_blue aurora_red aurora_orange aurora_yellow aurora_green frost_teal frost_cyan frost_deep diff --git a/palette/roles-tokyo-night.conf b/palette/roles-tokyo-night.conf index d56659c..984876b 100644 --- a/palette/roles-tokyo-night.conf +++ b/palette/roles-tokyo-night.conf @@ -102,5 +102,9 @@ scrollbar_track = fg_gutter bell_border = yellow tab_bar_bg = bg_dark +# Kvantum hover and pressed states, a shade either side of the accent. +accent_dim = blue*92 +accent_bright = blue*110 + [accents] snap = magenta purple blue red orange yellow green teal cyan blue1 diff --git a/templates/kvantum/theme.kvconfig.in b/templates/kvantum/theme.kvconfig.in new file mode 100644 index 0000000..7b687f9 --- /dev/null +++ b/templates/kvantum/theme.kvconfig.in @@ -0,0 +1,476 @@ +[%General] +author=elkrien based on Arc Dark style +comment=Catppuccin-Macchiato-Lavender +combo_focus_rect=true +spread_menuitems=true +left_tabs=true +mirror_doc_tabs=true +scroll_width=8 +attach_active_tab=true +composite=true +menu_shadow_depth=7 +tooltip_shadow_depth=0 +splitter_width=7 +check_size=16 +slider_width=4 +slider_handle_width=18 +slider_handle_length=18 +textless_progressbar=false +menubar_mouse_tracking=true +slim_toolbars=false +toolbutton_style=1 +x11drag=menubar_and_primary_toolbar +double_click=false +translucent_windows=false +blurring=false +popup_blurring=true +opaque=kaffeine,kmplayer,subtitlecomposer,kdenlive,vlc,smplayer,smplayer2,avidemux,avidemux2_qt4,avidemux3_qt4,avidemux3_qt5,kamoso,QtCreator,VirtualBox,trojita,dragon,digikam,qmplay2 +group_toolbar_buttons=false +vertical_spin_indicators=false +fill_rubberband=false +spread_progressbar=true +merge_menubar_with_toolbar=true +small_icon_size=16 +large_icon_size=32 +button_icon_size=16 +scroll_arrows=false +iconless_pushbutton=true +toolbar_icon_size=16 +combo_as_lineedit=true +button_contents_shift=false +groupbox_top_label=true +inline_spin_indicators=true +joined_inactive_tabs=false +layout_spacing=2 +submenu_overlap=0 +tooltip_delay=-1 +animate_states=false +transient_scrollbar=true +alt_mnemonic=true +combo_menu=true +layout_margin=4 +no_window_pattern=false +respect_DE=true +scroll_min_extent=36 +scrollable_menu=false +scrollbar_in_view=false +spin_button_width=16 +submenu_delay=250 +tree_branch_line=true +progressbar_thickness=8 +click_behavior=0 +contrast=1.00 +dialog_button_layout=0 +drag_from_buttons=false +hide_combo_checkboxes=false +intensity=1.00 +no_inactiveness=false +reduce_menu_opacity=0 +reduce_window_opacity=10 +saturation=1.00 +shadowless_popup=false +transient_groove=false + +[GeneralColors] +window.color=@BG@ +base.color=@BG_ALT@ +alt.base.color=@BG_ALT@ +button.color=@SURFACE@ +light.color=@SURFACE_ALT@ +mid.light.color=@SURFACE_ALT@ +dark.color=@BG_ALT@ +mid.color=@BG_ALT@ +highlight.color=@ACCENT@4D +inactive.highlight.color=@SURFACE_ALT@ +tooltip.base.color=@BG_ALT@ +text.color=@FG@ +window.text.color=@FG@ +button.text.color=@FG@ +disabled.text.color=@SURFACE_HIGH@ +tooltip.text.color=@FG@ +highlight.text.color=@FG@ +link.color=@ACCENT@ +link.visited.color=@ACCENT_BRIGHT@ + +[ItemView] +inherits=PanelButtonCommand +frame.element=itemview +interior.element=itemview +frame=true +interior=true +text.iconspacing=3 +text.press.color=@FG@ +text.toggle.color=@FG@ + +[RadioButton] +inherits=PanelButtonCommand +frame=false +interior.element=radio + +[CheckBox] +inherits=PanelButtonCommand +frame=false +interior.element=checkbox + +[TreeExpander] +indicator.element=tree +indicator.size=8 + +[ToolTip] +frame.top=4 +frame.right=4 +frame.bottom=4 +frame.left=4 +frame=true + +[PanelButtonCommand] +inherits=PanelButtonCommand +interior.element=button +frame.element=button +text.normal.color=@FG@ +text.focus.color=@FG@ +text.press.color=@FG@ +text.toggle.color=@FG@ + +[PanelButtonTool] +inherits=PanelButtonCommand + +[DockTitle] +inherits=PanelButtonCommand +interior=false +frame=false +text.margin.top=5 +text.margin.bottom=5 +text.margin.left=5 +text.margin.right=5 +indicator.size=0 + +[Dock] +interior.element=toolbar +frame.element=toolbar +frame=true +interior=true + +[GroupBox] +inherits=PanelButtonCommand +interior.element=tabframe +interior=true +frame=false + +[Focus] +inherits=PanelButtonCommand +frame=true +frame.element=focus +frame.top=1 +frame.bottom=1 +frame.left=1 +frame.right=1 +frame.patternsize=20 + +[GenericFrame] +inherits=PanelButtonCommand +frame.element=common +frame.top=1 +frame.bottom=1 +frame.left=1 +frame.right=1 + +[Slider] +inherits=PanelButtonCommand +interior=true +frame.element=slider +interior.element=slider +frame.top=3 +frame.bottom=3 +frame.left=3 +frame.right=3 +focusFrame=true + +[SliderCursor] +inherits=PanelButtonCommand +interior=true +interior.element=slidercursor +frame=false + +[LineEdit] +inherits=PanelButtonCommand +frame.element=lineedit +interior.element=lineedit + +[IndicatorSpinBox] +inherits=LineEdit +frame.element=lineedit +interior.element=lineedit +frame.top=0 +frame.bottom=2 +frame.left=2 +frame.right=2 +indicator.size=8 + +[DropDownButton] +inherits=PanelButtonCommand +frame.top=2 +frame.bottom=2 +frame.left=0 +frame.right=1 +indicator.size=8 + +[ToolboxTab] +inherits=PanelButtonCommand +frame.element=tabframe +frame.top=1 +frame.bottom=1 +frame.left=1 +frame.right=1 + +[Tab] +inherits=PanelButtonCommand +interior.element=tab +frame.element=tab +frame.top=2 +frame.bottom=3 +frame.left=3 +frame.right=3 +indicator.size=10 +text.normal.color=@MID_HIGH@ +text.focus.color=@FG@ +text.press.color=@FG@ +text.toggle.color=@FG@ +focusFrame=true + +[TabBarFrame] +inherits=GenericFrame +frame=true +frame.element=tabBarFrame +interior=false +frame.top=4 +frame.bottom=4 +frame.left=4 +frame.right=4 + +[TabFrame] +inherits=PanelButtonCommand +frame.element=tabframe +interior.element=tabframe + +[Dialog] +inherits=TabBarFrame +frame.element=tabframe +interior=false +frame=false +frame.top=1 +frame.bottom=1 +frame.left=1 +frame.right=1 + +[HeaderSection] +inherits=PanelButtonCommand +interior.element=header +frame.element=header +frame.top=0 +frame.bottom=1 +frame.left=1 +frame.right=1 +frame.expansion=0 +text.normal.color=@FG@ +text.focus.color=@ACCENT@ +text.press.color=@FG@ +text.toggle.color=@FG@ +indicator.element=harrow + +[SizeGrip] +inherits=PanelButtonCommand +frame=false +interior=false +indicator.element=resize-grip +indicator.size=0 + +[Toolbar] +inherits=PanelButtonCommand +interior.element=menubar +frame.element=menubar +frame=true +frame.bottom=4 +frame.left=4 +frame.right=4 +text.normal.color=@FG@ +text.focus.color=@FG@ +text.press.color=@ACCENT@ +text.toggle.color=@ACCENT@ +text.bold=false + +[MenuBar] +inherits=PanelButtonCommand +frame.element=menubar +interior.element=menubar +frame.bottom=0 +text.normal.color=@FG@ +frame.expansion=0 +text.bold=false + +[ToolbarButton] +frame.element=tbutton +interior.element=tbutton +indicator.element=arrow +text.normal.color=@FG@ +text.focus.color=@FG@ +text.press.color=@FG@ +text.toggle.color=@FG@ +text.bold=false + +[ToolbarLineEdit] +frame.element=lineedit +interior.element=lineedit + +[Scrollbar] +inherits=PanelButtonCommand +indicator.size=0 +interior=false +frame=false + +[ScrollbarGroove] +inherits=PanelButtonCommand +interior=false +frame=false + +[ScrollbarSlider] +inherits=PanelButtonCommand +interior=false +frame.element=scrollbarslider +frame.top=4 +frame.bottom=4 +frame.left=4 +frame.right=4 + +[ProgressbarContents] +inherits=PanelButtonCommand +frame=true +frame.element=progress-pattern +interior.element=progress-pattern +frame.top=2 +frame.bottom=2 +frame.left=2 +frame.right=2 + +[Progressbar] +inherits=PanelButtonCommand +frame.element=progress +interior.element=progress +frame.top=2 +frame.bottom=2 +frame.left=2 +frame.right=2 +text.margin=0 +text.normal.color=@FG@ +text.focus.color=@FG@ +text.press.color=@BG_ALT@ +text.toggle.color=@BG_ALT@ +text.bold=false +frame.expansion=18 + +[RadioButton] +inherits=PanelButtonCommand + +[Menu] +frame.element=menu +interior.element=menu +inherits=PanelButtonCommand +text.press.color=@BG_ALT@ +text.toggle.color=@BG_ALT@ +text.bold=false +frame.top=3 +frame.bottom=3 +frame.left=3 +frame.right=3 + +[MenuItem] +inherits=PanelButtonCommand +interior.element=menuitem +indicator.size=8 +frame=true +frame.element=menuitem +frame.right=10 +frame.left=10 +text.focus.color=@FG@ +text.press.color=@FG@ + +[MenuBarItem] +inherits=PanelButtonCommand +interior.element=menubaritem +frame=false +text.margin.top=3 +text.margin.bottom=3 +text.margin.left=5 +text.margin.right=5 + +[StatusBar] +inherits=Toolbar +frame.element=toolbar +font.bold=true +text.normal.color=@FG@ +frame=true +frame.top=0 +frame.bottom=0 + +[TitleBar] +inherits=PanelButtonCommand +frame=false +interior=false +text.margin.top=2 +text.margin.bottom=2 +text.margin.left=3 +text.margin.right=3 + +[ComboBox] +inherits=PanelButtonCommand +indicator.size=8 +frame.top=3 +frame.bottom=3 +frame.left=3 +frame.right=3 +text.margin.top=1 +text.margin.bottom=1 +text.margin.left=3 +text.margin.right=3 +text.press.color=@FG@ +text.toggle.color=@FG@ + +[ToolboxTab] +inherits=PanelButtonCommand +text.normal.color=@FG@ +text.press.color=@FG@ +text.focus.color=@FG@ + +[Hacks] +transparent_dolphin_view=false +blur_konsole=true +transparent_ktitle_label=true +transparent_menutitle=true +respect_darkness=true +kcapacitybar_as_progressbar=true +force_size_grip=false +iconless_pushbutton=true +iconless_menu=false +disabled_icon_opacity=100 +lxqtmainmenu_iconsize=0 +normal_default_pushbutton=true +single_top_toolbar=false +tint_on_mouseover=0 +transparent_pcmanfm_sidepane=true +transparent_pcmanfm_view=false +blur_translucent=true +centered_forms=false +kinetic_scrolling=false +middle_click_scroll=false +no_selection_tint=true +noninteger_translucency=false +style_vertical_toolbars=false +blur_only_active_window=false + +[Window] +interior=true +interior.element=window +frame.top=0 +frame.bottom=0 +frame.left=0 +frame.right=0 diff --git a/templates/kvantum/theme.svg.in b/templates/kvantum/theme.svg.in new file mode 100644 index 0000000..a2ff659 --- /dev/null +++ b/templates/kvantum/theme.svg.in @@ -0,0 +1,1959 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -- cgit v1.2.3