diff options
94 files changed, 13704 insertions, 0 deletions
diff --git a/.cache/wal/chromium/Cached Theme.pak b/.cache/wal/chromium/Cached Theme.pak Binary files differnew file mode 100644 index 0000000..f075cfe --- /dev/null +++ b/.cache/wal/chromium/Cached Theme.pak diff --git a/.cache/wal/chromium/bg.png b/.cache/wal/chromium/bg.png Binary files differnew file mode 100644 index 0000000..a3058f4 --- /dev/null +++ b/.cache/wal/chromium/bg.png diff --git a/.cache/wal/chromium/manifest.json b/.cache/wal/chromium/manifest.json new file mode 100644 index 0000000..6ae3e9a --- /dev/null +++ b/.cache/wal/chromium/manifest.json @@ -0,0 +1,90 @@ +{ + "description": "Colorscheme generated by jswal", + "manifest_version": 2, + "name": "pywal", + "theme": { + "images": { + "theme_frame": "bg.png" + }, + "colors": { + "bookmark_text": [ + 196, + 196, + 196 + ], + "frame": [ + 255, + 255, + 255 + ], + "ntp_background": [ + 19, + 19, + 21 + ], + "ntp_text": [ + 19, + 19, + 21 + ], + "tab_background_text": [ + 137, + 137, + 137 + ], + "tab_background_text_inactive": [ + 137, + 137, + 137 + ], + "tab_background_text_incognito": [ + 137, + 137, + 137 + ], + "tab_background_text_incognito_inactive": [ + 137, + 137, + 137 + ], + "tab_text": [ + 196, + 196, + 196 + ], + "toolbar": [ + 26, + 26, + 27 + ], + "button_background": [ + 255, + 255, + 255 + ] + }, + "tints": { + "buttons": [ + 0.0972222222222219, + 11.76470588235294, + 40 + ], + "frame_inactive": [ + -1, + -1, + -1 + ], + "frame_incognito": [ + -1, + -1, + -1 + ], + "frame_incognito_inactive": [ + -1, + -1, + -1 + ] + } + }, + "version": "2" +}
\ No newline at end of file diff --git a/.cache/wal/colors b/.cache/wal/colors new file mode 100644 index 0000000..e28d163 --- /dev/null +++ b/.cache/wal/colors @@ -0,0 +1,16 @@ +#141415 +#292b37 +#3c2a27 +#3b3033 +#3f3330 +#4b4240 +#66615a +#c4c4c4 +#4e4e4f +#292b37 +#3c2a27 +#3b3033 +#3f3330 +#4b4240 +#66615a +#c4c4c4 diff --git a/.cache/wal/colors-kitty.conf b/.cache/wal/colors-kitty.conf new file mode 100644 index 0000000..a56601f --- /dev/null +++ b/.cache/wal/colors-kitty.conf @@ -0,0 +1,20 @@ +foreground #c4c4c4 +background #141415 +cursor #c4c4c4 + +color0 #141415 +color8 #4e4e4f +color1 #292b37 +color9 #292b37 +color2 #3c2a27 +color10 #3c2a27 +color3 #3b3033 +color11 #3b3033 +color4 #3f3330 +color12 #3f3330 +color5 #4b4240 +color13 #4b4240 +color6 #66615a +color14 #66615a +color7 #c4c4c4 +color15 #c4c4c4 diff --git a/.cache/wal/colors-konsole.colorscheme b/.cache/wal/colors-konsole.colorscheme new file mode 100644 index 0000000..c09a9de --- /dev/null +++ b/.cache/wal/colors-konsole.colorscheme @@ -0,0 +1,63 @@ +[Background] +Color=20,20,21 + +[BackgroundIntense] +Color=20,20,21 + +[Color0] +Color=20,20,21 + +[Color0Intense] +Color=78,78,79 + +[Color1] +Color=88,91,113 + +[Color1Intense] +Color=88,91,113 + +[Color2] +Color=116,85,80 + +[Color2Intense] +Color=116,85,80 + +[Color3] +Color=103,86,90 + +[Color3Intense] +Color=103,86,90 + +[Color4] +Color=102,84,80 + +[Color4Intense] +Color=102,84,80 + +[Color5] +Color=75,66,64 + +[Color5Intense] +Color=75,66,64 + +[Color6] +Color=102,97,90 + +[Color6Intense] +Color=102,97,90 + +[Color7] +Color=196,196,196 + +[Color7Intense] +Color=196,196,196 + +[Foreground] +Color=196,196,196 + +[ForegroundIntense] +Color=196,196,196 + +[General] +Description=Colorscheme generated by wal +Opacity=0.92
\ No newline at end of file diff --git a/.cache/wal/colors-oomox b/.cache/wal/colors-oomox new file mode 100644 index 0000000..806f6b6 --- /dev/null +++ b/.cache/wal/colors-oomox @@ -0,0 +1,17 @@ +NAME=wal +BG=141415 +FG=c4c4c4 +MENU_BG=141415 +MENU_FG=c4c4c4 +SEL_BG=292b37 +SEL_FG=141415 +TXT_BG=141415 +TXT_FG=c4c4c4 +BTN_BG=3c2a27 +BTN_FG=c4c4c4 +HDR_BTN_BG=3b3033 +HDR_BTN_FG=c4c4c4 +GTK3_GENERATE_DARK=True +ROUNDNESS=0 +SPACING=3 +GRADIENT=0.0 diff --git a/.cache/wal/colors-putty.reg b/.cache/wal/colors-putty.reg new file mode 100644 index 0000000..2708554 --- /dev/null +++ b/.cache/wal/colors-putty.reg @@ -0,0 +1,26 @@ +Windows Registry Editor Version 5.00 + +[HKEY_CURRENT_USER\Software\SimonTatham\PuTTY\Sessions\wal] +"Colour0"="196,196,196" ; Default Foreground +"Colour1"="196,196,196" ; Default Bold Foreground +"Colour2"="20,20,21" ; Default Background +"Colour3"="20,20,21" ; Default Bold Background +"Colour4"="20,20,21" ; Cursor Text +"Colour5"="196,196,196" ; Cursor Color +"Colour6"="20,20,21" ; ANSI Black +"Colour7"="78,78,79" ; ANSI Black Bold +"Colour8"="41,43,55" ; ANSI Red +"Colour9"="41,43,55" ; ANSI Red Bold +"Colour10"="60,42,39" ; ANSI Green +"Colour11"="60,42,39" ; ANSI Green Bold +"Colour12"="59,48,51" ; ANSI Yellow +"Colour13"="59,48,51" ; ANSI Yellow Bold +"Colour14"="63,51,48" ; ANSI Blue +"Colour15"="63,51,48" ; ANSI Blue Bold +"Colour16"="75,66,64" ; ANSI Magenta +"Colour17"="75,66,64" ; ANSI Magenta Bold +"Colour18"="102,97,90" ; ANSI Cyan +"Colour19"="102,97,90" ; ANSI Cyan Bold +"Colour20"="196,196,196" ; ANSI White +"Colour21"="196,196,196" ; ANSI White Bold + diff --git a/.cache/wal/colors-rofi-dark.rasi b/.cache/wal/colors-rofi-dark.rasi new file mode 100644 index 0000000..77b916d --- /dev/null +++ b/.cache/wal/colors-rofi-dark.rasi @@ -0,0 +1,161 @@ +* { + active-background: #3c2a27; + active-foreground: @foreground; + normal-background: @background; + normal-foreground: @foreground; + urgent-background: #292b37; + urgent-foreground: @foreground; + + alternate-active-background: @background; + alternate-active-foreground: @foreground; + alternate-normal-background: @background; + alternate-normal-foreground: @foreground; + alternate-urgent-background: @background; + alternate-urgent-foreground: @foreground; + + selected-active-background: #292b37; + selected-active-foreground: @foreground; + selected-normal-background: #3c2a27; + selected-normal-foreground: @foreground; + selected-urgent-background: #3b3033; + selected-urgent-foreground: @foreground; + + background-color: @background; + background: #141415; + foreground: #c4c4c4; + border-color: @background; + spacing: 2; +} + +#window { + background-color: @background; + border: 0; + padding: 2.5ch; +} + +#mainbox { + border: 0; + padding: 0; +} + +#message { + border: 2px 0px 0px; + border-color: @border-color; + padding: 1px; +} + +#textbox { + text-color: @foreground; +} + +#inputbar { + children: [ prompt,textbox-prompt-colon,entry,case-indicator ]; +} + +#textbox-prompt-colon { + expand: false; + str: ":"; + margin: 0px 0.3em 0em 0em; + text-color: @normal-foreground; +} + +#listview { + fixed-height: 0; + border: 2px 0px 0px; + border-color: @border-color; + spacing: 2px; + scrollbar: true; + padding: 2px 0px 0px; +} + +#element { + border: 0; + padding: 1px; +} + +#element.normal.normal { + background-color: @normal-background; + text-color: @normal-foreground; +} + +#element.normal.urgent { + background-color: @urgent-background; + text-color: @urgent-foreground; +} + +#element.normal.active { + background-color: @active-background; + text-color: @active-foreground; +} + +#element.selected.normal { + background-color: @selected-normal-background; + text-color: @selected-normal-foreground; +} + +#element.selected.urgent { + background-color: @selected-urgent-background; + text-color: @selected-urgent-foreground; +} + +#element.selected.active { + background-color: @selected-active-background; + text-color: @selected-active-foreground; +} + +#element.alternate.normal { + background-color: @alternate-normal-background; + text-color: @alternate-normal-foreground; +} + +#element.alternate.urgent { + background-color: @alternate-urgent-background; + text-color: @alternate-urgent-foreground; +} + +#element.alternate.active { + background-color: @alternate-active-background; + text-color: @alternate-active-foreground; +} + +#scrollbar { + width: 4px; + border: 0; + handle-width: 8px; + padding: 0; +} + +#sidebar { + border: 2px 0px 0px; + border-color: @border-color; +} + +#button { + text-color: @normal-foreground; +} + +#button.selected { + background-color: @selected-normal-background; + text-color: @selected-normal-foreground; +} + +#inputbar { + spacing: 0; + text-color: @normal-foreground; + padding: 1px; +} + +#case-indicator { + spacing: 0; + text-color: @normal-foreground; +} + +#entry { + spacing: 0; + text-color: @normal-foreground; +} + +#prompt { + spacing: 0; + text-color: @normal-foreground; +} diff --git a/.cache/wal/colors-rofi-light.rasi b/.cache/wal/colors-rofi-light.rasi new file mode 100644 index 0000000..8e67236 --- /dev/null +++ b/.cache/wal/colors-rofi-light.rasi @@ -0,0 +1,161 @@ +* { + active-background: #3c2a27; + active-foreground: @foreground; + normal-background: @background; + normal-foreground: @foreground; + urgent-background: #292b37; + urgent-foreground: @foreground; + + alternate-active-background: @background; + alternate-active-foreground: @foreground; + alternate-normal-background: @background; + alternate-normal-foreground: @foreground; + alternate-urgent-background: @background; + alternate-urgent-foreground: @foreground; + + selected-active-background: #292b37; + selected-active-foreground: @foreground; + selected-normal-background: #3c2a27; + selected-normal-foreground: @foreground; + selected-urgent-background: #3b3033; + selected-urgent-foreground: @foreground; + + background-color: @background; + background: #c4c4c4; + foreground: #141415; + border-color: @background; + spacing: 2; +} + +#window { + background-color: @background; + border: 0; + padding: 2.5ch; +} + +#mainbox { + border: 0; + padding: 0; +} + +#message { + border: 2px 0px 0px; + border-color: @border-color; + padding: 1px; +} + +#textbox { + text-color: @foreground; +} + +#inputbar { + children: [ prompt,textbox-prompt-colon,entry,case-indicator ]; +} + +#textbox-prompt-colon { + expand: false; + str: ":"; + margin: 0px 0.3em 0em 0em; + text-color: @normal-foreground; +} + +#listview { + fixed-height: 0; + border: 2px 0px 0px; + border-color: @border-color; + spacing: 2px; + scrollbar: true; + padding: 2px 0px 0px; +} + +#element { + border: 0; + padding: 1px; +} + +#element.normal.normal { + background-color: @normal-background; + text-color: @normal-foreground; +} + +#element.normal.urgent { + background-color: @urgent-background; + text-color: @urgent-foreground; +} + +#element.normal.active { + background-color: @active-background; + text-color: @active-foreground; +} + +#element.selected.normal { + background-color: @selected-normal-background; + text-color: @selected-normal-foreground; +} + +#element.selected.urgent { + background-color: @selected-urgent-background; + text-color: @selected-urgent-foreground; +} + +#element.selected.active { + background-color: @selected-active-background; + text-color: @selected-active-foreground; +} + +#element.alternate.normal { + background-color: @alternate-normal-background; + text-color: @alternate-normal-foreground; +} + +#element.alternate.urgent { + background-color: @alternate-urgent-background; + text-color: @alternate-urgent-foreground; +} + +#element.alternate.active { + background-color: @alternate-active-background; + text-color: @alternate-active-foreground; +} + +#scrollbar { + width: 4px; + border: 0; + handle-width: 8px; + padding: 0; +} + +#sidebar { + border: 2px 0px 0px; + border-color: @border-color; +} + +#button { + text-color: @normal-foreground; +} + +#button.selected { + background-color: @selected-normal-background; + text-color: @selected-normal-foreground; +} + +#inputbar { + spacing: 0; + text-color: @normal-foreground; + padding: 1px; +} + +#case-indicator { + spacing: 0; + text-color: @normal-foreground; +} + +#entry { + spacing: 0; + text-color: @normal-foreground; +} + +#prompt { + spacing: 0; + text-color: @normal-foreground; +} diff --git a/.cache/wal/colors-speedcrunch.json b/.cache/wal/colors-speedcrunch.json new file mode 100644 index 0000000..ead54c0 --- /dev/null +++ b/.cache/wal/colors-speedcrunch.json @@ -0,0 +1,15 @@ +{ + "cursor": "#c4c4c4", + "number": "#c4c4c4", + "parens": "#4b4240", + "result": "#3f3330", + "comment": "#4e4e4f", + "matched": "#3f3330", + "function": "#292b37", + "operator": "#3b3033", + "variable": "#3c2a27", + "scrollbar": "#3b3033", + "separator": "#3b3033", + "background": "#141415", + "editorbackground": "#141415" +} diff --git a/.cache/wal/colors-sway b/.cache/wal/colors-sway new file mode 100644 index 0000000..09f95c7 --- /dev/null +++ b/.cache/wal/colors-sway @@ -0,0 +1,21 @@ +set $wallpaper /home/loek/.config/wpg/wallpapers/pywal.png + +set $background #141415 +set $foreground #c4c4c4 + +set $color0 #141415 +set $color1 #292b37 +set $color2 #3c2a27 +set $color3 #3b3033 +set $color4 #3f3330 +set $color5 #4b4240 +set $color6 #66615a +set $color7 #c4c4c4 +set $color8 #4e4e4f +set $color9 #292b37 +set $color10 #3c2a27 +set $color11 #3b3033 +set $color12 #3f3330 +set $color13 #4b4240 +set $color14 #66615a +set $color15 #c4c4c4 diff --git a/.cache/wal/colors-tty.sh b/.cache/wal/colors-tty.sh new file mode 100644 index 0000000..3e7acdb --- /dev/null +++ b/.cache/wal/colors-tty.sh @@ -0,0 +1,19 @@ +#!/bin/sh +[ "${TERM:-none}" = "linux" ] && \ + printf '%b' '\e]P0141415 + \e]P1292b37 + \e]P23c2a27 + \e]P33b3033 + \e]P43f3330 + \e]P54b4240 + \e]P666615a + \e]P7c4c4c4 + \e]P84e4e4f + \e]P9292b37 + \e]PA3c2a27 + \e]PB3b3033 + \e]PC3f3330 + \e]PD4b4240 + \e]PE66615a + \e]PFc4c4c4 + \ec' diff --git a/.cache/wal/colors-wal-dmenu.h b/.cache/wal/colors-wal-dmenu.h new file mode 100644 index 0000000..43ddfac --- /dev/null +++ b/.cache/wal/colors-wal-dmenu.h @@ -0,0 +1,6 @@ +static const char *colors[SchemeLast][2] = { + /* fg bg */ + [SchemeNorm] = { "#c4c4c4", "#141415" }, + [SchemeSel] = { "#c4c4c4", "#292b37" }, + [SchemeOut] = { "#c4c4c4", "#66615a" }, +}; diff --git a/.cache/wal/colors-wal-dwm.h b/.cache/wal/colors-wal-dwm.h new file mode 100644 index 0000000..2380319 --- /dev/null +++ b/.cache/wal/colors-wal-dwm.h @@ -0,0 +1,18 @@ +static const char norm_fg[] = "#c4c4c4"; +static const char norm_bg[] = "#141415"; +static const char norm_border[] = "#4e4e4f"; + +static const char sel_fg[] = "#c4c4c4"; +static const char sel_bg[] = "#3c2a27"; +static const char sel_border[] = "#c4c4c4"; + +static const char urg_fg[] = "#c4c4c4"; +static const char urg_bg[] = "#292b37"; +static const char urg_border[] = "#292b37"; + +static const char *colors[][3] = { + /* fg bg border */ + [SchemeNorm] = { norm_fg, norm_bg, norm_border }, // unfocused wins + [SchemeSel] = { sel_fg, sel_bg, sel_border }, // the focused win + [SchemeUrg] = { urg_fg, urg_bg, urg_border }, +}; diff --git a/.cache/wal/colors-wal-st.h b/.cache/wal/colors-wal-st.h new file mode 100644 index 0000000..55463ed --- /dev/null +++ b/.cache/wal/colors-wal-st.h @@ -0,0 +1,34 @@ +const char *colorname[] = { + + /* 8 normal colors */ + [0] = "#141415", /* black */ + [1] = "#292b37", /* red */ + [2] = "#3c2a27", /* green */ + [3] = "#3b3033", /* yellow */ + [4] = "#3f3330", /* blue */ + [5] = "#4b4240", /* magenta */ + [6] = "#66615a", /* cyan */ + [7] = "#c4c4c4", /* white */ + + /* 8 bright colors */ + [8] = "#4e4e4f", /* black */ + [9] = "#292b37", /* red */ + [10] = "#3c2a27", /* green */ + [11] = "#3b3033", /* yellow */ + [12] = "#3f3330", /* blue */ + [13] = "#4b4240", /* magenta */ + [14] = "#66615a", /* cyan */ + [15] = "#c4c4c4", /* white */ + + /* special colors */ + [256] = "#141415", /* background */ + [257] = "#c4c4c4", /* foreground */ + [258] = "#c4c4c4", /* cursor */ +}; + +/* Default colors (colorname index) + * foreground, background, cursor */ + unsigned int defaultbg = 0; + unsigned int defaultfg = 257; + unsigned int defaultcs = 258; + unsigned int defaultrcs= 258; diff --git a/.cache/wal/colors-wal-tabbed.h b/.cache/wal/colors-wal-tabbed.h new file mode 100644 index 0000000..01d5d13 --- /dev/null +++ b/.cache/wal/colors-wal-tabbed.h @@ -0,0 +1,6 @@ +static const char* selbgcolor = "#141415"; +static const char* selfgcolor = "#c4c4c4"; +static const char* normbgcolor = "#3c2a27"; +static const char* normfgcolor = "#c4c4c4"; +static const char* urgbgcolor = "#292b37"; +static const char* urgfgcolor = "#c4c4c4"; diff --git a/.cache/wal/colors-wal.vim b/.cache/wal/colors-wal.vim new file mode 100644 index 0000000..a23e0f7 --- /dev/null +++ b/.cache/wal/colors-wal.vim @@ -0,0 +1,23 @@ +" Special +let wallpaper = "/home/loek/.config/wpg/wallpapers/pywal.png" +let background = "#141415" +let foreground = "#c4c4c4" +let cursor = "#c4c4c4" + +" Colors +let color0 = "#141415" +let color1 = "#292b37" +let color2 = "#3c2a27" +let color3 = "#3b3033" +let color4 = "#3f3330" +let color5 = "#4b4240" +let color6 = "#66615a" +let color7 = "#c4c4c4" +let color8 = "#4e4e4f" +let color9 = "#292b37" +let color10 = "#3c2a27" +let color11 = "#3b3033" +let color12 = "#3f3330" +let color13 = "#4b4240" +let color14 = "#66615a" +let color15 = "#c4c4c4" diff --git a/.cache/wal/colors-waybar.css b/.cache/wal/colors-waybar.css new file mode 100644 index 0000000..ede28aa --- /dev/null +++ b/.cache/wal/colors-waybar.css @@ -0,0 +1,20 @@ +@define-color foreground #c4c4c4; +@define-color background #141415; +@define-color cursor #c4c4c4; + +@define-color color0 #141415; +@define-color color1 #292b37; +@define-color color2 #3c2a27; +@define-color color3 #3b3033; +@define-color color4 #3f3330; +@define-color color5 #4b4240; +@define-color color6 #66615a; +@define-color color7 #c4c4c4; +@define-color color8 #4e4e4f; +@define-color color9 #292b37; +@define-color color10 #3c2a27; +@define-color color11 #3b3033; +@define-color color12 #3f3330; +@define-color color13 #4b4240; +@define-color color14 #66615a; +@define-color color15 #c4c4c4; diff --git a/.cache/wal/colors.Xresources b/.cache/wal/colors.Xresources new file mode 100644 index 0000000..cebd8a2 --- /dev/null +++ b/.cache/wal/colors.Xresources @@ -0,0 +1,68 @@ +! X colors. +! Generated by 'wal' +*foreground: #c4c4c4 +*background: #141415 +*.foreground: #c4c4c4 +*.background: #141415 +emacs*foreground: #c4c4c4 +emacs*background: #141415 +URxvt*foreground: #c4c4c4 +XTerm*foreground: #c4c4c4 +UXTerm*foreground: #c4c4c4 +URxvt*background: [100]#141415 +XTerm*background: #141415 +UXTerm*background: #141415 +URxvt*cursorColor: #c4c4c4 +XTerm*cursorColor: #c4c4c4 +UXTerm*cursorColor: #c4c4c4 +URxvt*borderColor: [100]#141415 + +! Colors 0-15. +*.color0: #141415 +*color0: #141415 +*.color1: #292b37 +*color1: #292b37 +*.color2: #3c2a27 +*color2: #3c2a27 +*.color3: #3b3033 +*color3: #3b3033 +*.color4: #3f3330 +*color4: #3f3330 +*.color5: #4b4240 +*color5: #4b4240 +*.color6: #66615a +*color6: #66615a +*.color7: #c4c4c4 +*color7: #c4c4c4 +*.color8: #4e4e4f +*color8: #4e4e4f +*.color9: #292b37 +*color9: #292b37 +*.color10: #3c2a27 +*color10: #3c2a27 +*.color11: #3b3033 +*color11: #3b3033 +*.color12: #3f3330 +*color12: #3f3330 +*.color13: #4b4240 +*color13: #4b4240 +*.color14: #66615a +*color14: #66615a +*.color15: #c4c4c4 +*color15: #c4c4c4 + +! Black color that will not be affected by bold highlighting. +*.color66: #141415 +*color66: #141415 + +! Xclock colors. +XClock*foreground: #c4c4c4 +XClock*background: #141415 +XClock*majorColor: rgba:c4/c4/c4/ff +XClock*minorColor: rgba:c4/c4/c4/ff +XClock*hourColor: rgba:c4/c4/c4/ff +XClock*minuteColor: rgba:c4/c4/c4/ff +XClock*secondColor: rgba:c4/c4/c4/ff + +! Set depth to make transparency work. +URxvt*depth: 32 diff --git a/.cache/wal/colors.css b/.cache/wal/colors.css new file mode 100644 index 0000000..f4d80a0 --- /dev/null +++ b/.cache/wal/colors.css @@ -0,0 +1,28 @@ +/* CSS variables + Generated by 'wal' */ +:root { + --wallpaper: url("/home/loek/.config/wpg/wallpapers/pywal.png"); + + /* Special */ + --background: #141415; + --foreground: #c4c4c4; + --cursor: #c4c4c4; + + /* Colors */ + --color0: #141415; + --color1: #292b37; + --color2: #3c2a27; + --color3: #3b3033; + --color4: #3f3330; + --color5: #4b4240; + --color6: #66615a; + --color7: #c4c4c4; + --color8: #4e4e4f; + --color9: #292b37; + --color10: #3c2a27; + --color11: #3b3033; + --color12: #3f3330; + --color13: #4b4240; + --color14: #66615a; + --color15: #c4c4c4; +} diff --git a/.cache/wal/colors.hs b/.cache/wal/colors.hs new file mode 100644 index 0000000..3265973 --- /dev/null +++ b/.cache/wal/colors.hs @@ -0,0 +1,37 @@ +--Place this file in your .xmonad/lib directory and import module Colors into .xmonad/xmonad.hs config +--The easy way is to create a soft link from this file to the file in .xmonad/lib using ln -s +--Then recompile and restart xmonad. + +module Colors + ( wallpaper + , background, foreground, cursor + , color0, color1, color2, color3, color4, color5, color6, color7 + , color8, color9, color10, color11, color12, color13, color14, color15 + ) where + +-- Shell variables +-- Generated by 'wal' +wallpaper="/home/loek/.config/wpg/wallpapers/pywal.png" + +-- Special +background="#141415" +foreground="#c4c4c4" +cursor="#c4c4c4" + +-- Colors +color0="#141415" +color1="#292b37" +color2="#3c2a27" +color3="#3b3033" +color4="#3f3330" +color5="#4b4240" +color6="#66615a" +color7="#c4c4c4" +color8="#4e4e4f" +color9="#292b37" +color10="#3c2a27" +color11="#3b3033" +color12="#3f3330" +color13="#4b4240" +color14="#66615a" +color15="#c4c4c4" diff --git a/.cache/wal/colors.json b/.cache/wal/colors.json new file mode 100644 index 0000000..9148f6c --- /dev/null +++ b/.cache/wal/colors.json @@ -0,0 +1,28 @@ +{ + "wallpaper": "/home/loek/.config/wpg/wallpapers/pywal.png", + "alpha": "100", + + "special": { + "background": "#141415", + "foreground": "#c4c4c4", + "cursor": "#c4c4c4" + }, + "colors": { + "color0": "#141415", + "color1": "#292b37", + "color2": "#3c2a27", + "color3": "#3b3033", + "color4": "#3f3330", + "color5": "#4b4240", + "color6": "#66615a", + "color7": "#c4c4c4", + "color8": "#4e4e4f", + "color9": "#292b37", + "color10": "#3c2a27", + "color11": "#3b3033", + "color12": "#3f3330", + "color13": "#4b4240", + "color14": "#66615a", + "color15": "#c4c4c4" + } +} diff --git a/.cache/wal/colors.scss b/.cache/wal/colors.scss new file mode 100644 index 0000000..04d3d4d --- /dev/null +++ b/.cache/wal/colors.scss @@ -0,0 +1,26 @@ +// SCSS Variables +// Generated by 'wal' +$wallpaper: "/home/loek/.config/wpg/wallpapers/pywal.png"; + +// Special +$background: #141415; +$foreground: #c4c4c4; +$cursor: #c4c4c4; + +// Colors +$color0: #141415; +$color1: #292b37; +$color2: #3c2a27; +$color3: #3b3033; +$color4: #3f3330; +$color5: #4b4240; +$color6: #66615a; +$color7: #c4c4c4; +$color8: #4e4e4f; +$color9: #292b37; +$color10: #3c2a27; +$color11: #3b3033; +$color12: #3f3330; +$color13: #4b4240; +$color14: #66615a; +$color15: #c4c4c4; diff --git a/.cache/wal/colors.sh b/.cache/wal/colors.sh new file mode 100644 index 0000000..30ebe31 --- /dev/null +++ b/.cache/wal/colors.sh @@ -0,0 +1,36 @@ +# Shell variables +# Generated by 'wal' +wallpaper='/home/loek/.config/wpg/wallpapers/pywal.png' + +# Special +background='#141415' +foreground='#c4c4c4' +cursor='#c4c4c4' + +# Colors +color0='#141415' +color1='#292b37' +color2='#3c2a27' +color3='#3b3033' +color4='#3f3330' +color5='#4b4240' +color6='#66615a' +color7='#c4c4c4' +color8='#4e4e4f' +color9='#292b37' +color10='#3c2a27' +color11='#3b3033' +color12='#3f3330' +color13='#4b4240' +color14='#66615a' +color15='#c4c4c4' + +# FZF colors +export FZF_DEFAULT_OPTS=" + $FZF_DEFAULT_OPTS + --color fg:7,bg:0,hl:1,fg+:232,bg+:1,hl+:255 + --color info:7,prompt:2,spinner:1,pointer:232,marker:1 +" + +# Fix LS_COLORS being unreadable. +export LS_COLORS="${LS_COLORS}:su=30;41:ow=30;42:st=30;44:" diff --git a/.cache/wal/colors.yml b/.cache/wal/colors.yml new file mode 100644 index 0000000..4552903 --- /dev/null +++ b/.cache/wal/colors.yml @@ -0,0 +1,24 @@ +wallpaper: "/home/loek/.config/wpg/wallpapers/pywal.png" + +special: + background: "#141415" + foreground: "#c4c4c4" + cursor: "#c4c4c4" + +colors: + color0: "#141415" + color1: "#292b37" + color2: "#3c2a27" + color3: "#3b3033" + color4: "#3f3330" + color5: "#4b4240" + color6: "#66615a" + color7: "#c4c4c4" + color8: "#4e4e4f" + color9: "#292b37" + color10: "#3c2a27" + color11: "#3b3033" + color12: "#3f3330" + color13: "#4b4240" + color14: "#66615a" + color15: "#c4c4c4" diff --git a/.cache/wal/sequences b/.cache/wal/sequences new file mode 100644 index 0000000..5094427 --- /dev/null +++ b/.cache/wal/sequences @@ -0,0 +1 @@ +]4;0;#141415\]4;1;#292b37\]4;2;#3c2a27\]4;3;#3b3033\]4;4;#3f3330\]4;5;#4b4240\]4;6;#66615a\]4;7;#c4c4c4\]4;8;#4e4e4f\]4;9;#292b37\]4;10;#3c2a27\]4;11;#3b3033\]4;12;#3f3330\]4;13;#4b4240\]4;14;#66615a\]4;15;#c4c4c4\]10;#c4c4c4\]11;#141415\]12;#c4c4c4\]13;#c4c4c4\]17;#c4c4c4\]19;#141415\]4;232;#141415\]4;256;#c4c4c4\]708;#141415\
\ No newline at end of file diff --git a/.cache/wal/wal b/.cache/wal/wal new file mode 100644 index 0000000..30e642d --- /dev/null +++ b/.cache/wal/wal @@ -0,0 +1 @@ +/home/loek/.config/wpg/wallpapers/pywal.png
\ No newline at end of file diff --git a/.config/BetterDiscord/plugins/BDFDB.config.json b/.config/BetterDiscord/plugins/BDFDB.config.json new file mode 100644 index 0000000..7b5a5ac --- /dev/null +++ b/.config/BetterDiscord/plugins/BDFDB.config.json @@ -0,0 +1,5 @@ +{ + "welcomeScreen": { + "seen": false + } +}
\ No newline at end of file diff --git a/.config/BetterDiscord/plugins/BadgesEverywhere.config.json b/.config/BetterDiscord/plugins/BadgesEverywhere.config.json new file mode 100644 index 0000000..404c91c --- /dev/null +++ b/.config/BetterDiscord/plugins/BadgesEverywhere.config.json @@ -0,0 +1,29 @@ +{ + "badges": { + "1": true, + "2": true, + "4": true, + "8": true, + "64": true, + "128": true, + "256": true, + "512": true, + "16384": true, + "131072": true, + "262144": true, + "524288": true + }, + "changelog": { + "currentversion": "1.5.5" + }, + "indicators": { + "CURRENT_GUILD_BOOST": true + }, + "settings": { + "showInChat": true, + "showInMemberList": true, + "showInPopout": true, + "showNitroDate": true, + "useColoredVersion": true + } +}
\ No newline at end of file diff --git a/.config/BetterDiscord/plugins/BetterSearchPage.config.json b/.config/BetterDiscord/plugins/BetterSearchPage.config.json new file mode 100644 index 0000000..856dabf --- /dev/null +++ b/.config/BetterDiscord/plugins/BetterSearchPage.config.json @@ -0,0 +1,7 @@ +{ + "settings": { + "addFirstLast": true, + "addJumpTo": true, + "cloneToTheTop": true + } +}
\ No newline at end of file diff --git a/.config/BetterDiscord/plugins/BetterSearchPage.plugin.js b/.config/BetterDiscord/plugins/BetterSearchPage.plugin.js new file mode 100644 index 0000000..64b71e4 --- /dev/null +++ b/.config/BetterDiscord/plugins/BetterSearchPage.plugin.js @@ -0,0 +1,194 @@ +//META{"name":"BetterSearchPage","authorId":"278543574059057154","invite":"Jx3TjNS","donate":"https://www.paypal.me/MircoWittrien","patreon":"https://www.patreon.com/MircoWittrien","website":"https://github.com/mwittrien/BetterDiscordAddons/tree/master/Plugins/BetterSearchPage","source":"https://raw.githubusercontent.com/mwittrien/BetterDiscordAddons/master/Plugins/BetterSearchPage/BetterSearchPage.plugin.js"}*// + +var BetterSearchPage = (_ => { + return class BetterSearchPage { + getName () {return "BetterSearchPage";} + + getVersion () {return "1.1.5";} + + getAuthor () {return "DevilBro";} + + getDescription () {return "Adds some extra controls to the search results page.";} + + constructor () { + this.patchedModules = { + after: { + SearchResultsInner: "default" + } + }; + } + + initConstructor () { + this.defaults = { + settings: { + addFirstLast: {value:true, description:"Adds a first and last page button."}, + addJumpTo: {value:true, description:"Adds a jump to input field (press enter to jump)."}, + cloneToTheTop: {value:true, description:"Clones the controls to the top of the results page."} + } + }; + } + + getSettingsPanel () { + if (!window.BDFDB || typeof BDFDB != "object" || !BDFDB.loaded || !this.started) return; + let settings = BDFDB.DataUtils.get(this, "settings"); + let settingsPanel, settingsItems = []; + + for (let key in settings) settingsItems.push(BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SettingsSaveItem, { + className: BDFDB.disCN.marginbottom8, + type: "Switch", + plugin: this, + keys: ["settings", key], + label: this.defaults.settings[key].description, + value: settings[key] + })); + + return settingsPanel = BDFDB.PluginUtils.createSettingsPanel(this, settingsItems); + } + + // Legacy + load () {} + + start () { + if (!window.BDFDB) window.BDFDB = {myPlugins:{}}; + if (window.BDFDB && window.BDFDB.myPlugins && typeof window.BDFDB.myPlugins == "object") window.BDFDB.myPlugins[this.getName()] = this; + let libraryScript = document.querySelector("head script#BDFDBLibraryScript"); + if (!libraryScript || (performance.now() - libraryScript.getAttribute("date")) > 600000) { + if (libraryScript) libraryScript.remove(); + libraryScript = document.createElement("script"); + libraryScript.setAttribute("id", "BDFDBLibraryScript"); + libraryScript.setAttribute("type", "text/javascript"); + libraryScript.setAttribute("src", "https://mwittrien.github.io/BetterDiscordAddons/Plugins/BDFDB.min.js"); + libraryScript.setAttribute("date", performance.now()); + libraryScript.addEventListener("load", _ => {this.initialize();}); + document.head.appendChild(libraryScript); + } + else if (window.BDFDB && typeof BDFDB === "object" && BDFDB.loaded) this.initialize(); + this.startTimeout = setTimeout(_ => { + try {return this.initialize();} + catch (err) {console.error(`%c[${this.getName()}]%c`, "color: #3a71c1; font-weight: 700;", "", "Fatal Error: Could not initiate plugin! " + err);} + }, 30000); + } + + initialize () { + if (window.BDFDB && typeof BDFDB === "object" && BDFDB.loaded) { + if (this.started) return; + BDFDB.PluginUtils.init(this); + + BDFDB.ModuleUtils.forceAllUpdates(this); + } + else console.error(`%c[${this.getName()}]%c`, "color: #3a71c1; font-weight: 700;", "", "Fatal Error: Could not load BD functions!"); + } + + stop () { + if (window.BDFDB && typeof BDFDB === "object" && BDFDB.loaded) { + this.stopping = true; + + BDFDB.ModuleUtils.forceAllUpdates(this); + + BDFDB.PluginUtils.clear(this); + } + } + + + // Begin of own functions + + onSettingsClosed (e) { + if (this.SettingsUpdated) { + delete this.SettingsUpdated; + BDFDB.ModuleUtils.forceAllUpdates(this); + } + } + + processSearchResultsInner (e) { + if (e.instance.props.search) { + let [children, index] = BDFDB.ReactUtils.findChildren(e.returnvalue, {name:"SearchPagination"}); + if (index > -1) { + let settings = BDFDB.DataUtils.get(this, "settings"); + let currentpage = parseInt(Math.floor(e.instance.props.search.offset / BDFDB.DiscordConstants.SEARCH_PAGE_SIZE)) + 1; + let maxpage = e.instance.props.search.totalResults > 5000 ? parseInt(Math.ceil(5000 / BDFDB.DiscordConstants.SEARCH_PAGE_SIZE)) : parseInt(Math.ceil(e.instance.props.search.totalResults / BDFDB.DiscordConstants.SEARCH_PAGE_SIZE)); + let doJump = page => { + page = page < 1 ? 1 : (page > maxpage ? maxpage : page); + if (page < currentpage) BDFDB.LibraryModules.SearchPageUtils.searchPreviousPage(e.instance.props.searchId, (currentpage - page) * BDFDB.DiscordConstants.SEARCH_PAGE_SIZE); + else if (page > currentpage) BDFDB.LibraryModules.SearchPageUtils.searchNextPage(e.instance.props.searchId, (page - currentpage) * BDFDB.DiscordConstants.SEARCH_PAGE_SIZE); + }; + let pagination = children[index].type(children[index].props); + if (!pagination) return; + + if (currentpage >= maxpage) { + pagination.props.children[2].props.className = BDFDB.DOMUtils.formatClassName(pagination.props.children[2].props.className, BDFDB.disCN.searchresultspaginationdisabled); + pagination.props.children[2].props.onClick = _ => {}; + } + pagination.props.children[0] = BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.TooltipContainer, { + text: "Previous", + children: pagination.props.children[0] + }); + pagination.props.children[2] = BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.TooltipContainer, { + text: currentpage >= maxpage ? "Max Page is 200" : "Next", + tooltipConfig: {color: currentpage >= maxpage && BDFDB.LibraryComponents.TooltipContainer.Colors.RED}, + children: pagination.props.children[2] + }); + if (settings.addFirstLast) { + pagination.props.children.unshift(BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.TooltipContainer, { + text: "First", + "aria-label": "First", + onClick: _ => {if (currentpage != 1) doJump(1);}, + children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Clickable, { + className: BDFDB.DOMUtils.formatClassName(BDFDB.disCN.searchresultspaginationbutton, currentpage == 1 && BDFDB.disCN.searchresultspaginationdisabled), + children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SvgIcon, { + className: BDFDB.disCN.searchresultspaginationicon, + nativeClass: true, + iconSVG: `<svg width="24" height="24" viewBox="0 0 24 24"><g fill="none" fill-rule="evenodd"><polygon fill="currentColor" fill-rule="nonzero" points="12.35 4.35 10 2 0 12 10 22 12.35 19.65 4.717 12"></polygon><polygon fill="currentColor" fill-rule="nonzero" points="24.35 4.35 22 2 12 12 22 22 24.35 19.65 16.717 12"></polygon><polygon points="0 0 24 0 24 24 0 24"></polygon></g></svg>` + }) + }) + })); + pagination.props.children.push(BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.TooltipContainer, { + text: currentpage >= maxpage ? "Max Page is 200" : "Last", + tooltipConfig: {color: currentpage >= maxpage && BDFDB.LibraryComponents.TooltipContainer.Colors.RED}, + "aria-label": "Last", + onClick: _ => {if (currentpage != maxpage) doJump(maxpage);}, + children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Clickable, { + className: BDFDB.DOMUtils.formatClassName(BDFDB.disCN.searchresultspaginationbutton, currentpage >= maxpage && BDFDB.disCN.searchresultspaginationdisabled), + children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SvgIcon, { + className: BDFDB.disCN.searchresultspaginationicon, + nativeClass: true, + iconSVG: `<svg width="24" height="24" viewBox="0 0 24 24"><g fill="none" fill-rule="evenodd"><polygon fill="currentColor" fill-rule="nonzero" points="2.47 2 0.12 4.35 7.753 12 0.12 19.65 2.47 22 12.47 12"></polygon><polygon fill="currentColor" fill-rule="nonzero" points="14.47 2 12.12 4.35 19.753 12 12.12 19.65 14.47 22 24.47 12"></polygon><polygon points="0 0 24 0 24 24 0 24"></polygon></g></svg>` + }) + }) + })); + } + if (settings.addJumpTo) { + pagination.props.children.push(BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.TextInput, { + key: "BSP-pagination-jumpinput", + type: "number", + size: BDFDB.LibraryComponents.TextInput.Sizes.MINI, + suppress: true, + value: currentpage, + min: 1, + max: maxpage, + onKeyDown: (e, inputinstance) => {if (e.which == 13) doJump(inputinstance.props.value);} + })); + pagination.props.children.push(BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.TooltipContainer, { + text: BDFDB.LanguageUtils.LanguageStrings.JUMP, + "aria-label": BDFDB.LanguageUtils.LanguageStrings.JUMP, + onClick: (e, buttoninstance) => { + let jumpinput = BDFDB.ReactUtils.findOwner(buttoninstance._reactInternalFiber.return, {key:"BSP-pagination-jumpinput"}); + if (jumpinput) doJump(jumpinput.props.value); + }, + children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Clickable, { + className: BDFDB.disCN.searchresultspaginationbutton, + children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SvgIcon, { + className: BDFDB.disCN.searchresultspaginationicon, + nativeClass: true, + style: {transform: "rotate(90deg"}, + name: BDFDB.LibraryComponents.SvgIcon.Names.RIGHT_CARET + }) + }) + })); + } + children[index] = pagination; + if (settings.cloneToTheTop) children.unshift(pagination); + } + } + } + } +})();
\ No newline at end of file diff --git a/.config/BetterDiscord/plugins/EditChannels.config.json b/.config/BetterDiscord/plugins/EditChannels.config.json new file mode 100644 index 0000000..ac031cf --- /dev/null +++ b/.config/BetterDiscord/plugins/EditChannels.config.json @@ -0,0 +1,17 @@ +{ + "changelog": { + "currentversion": "4.1.3" + }, + "settings": { + "changeChannelIcon": true, + "changeInAuditLog": true, + "changeInAutoComplete": true, + "changeInChannelHeader": true, + "changeInChannelList": true, + "changeInChatTextarea": true, + "changeInInviteLog": true, + "changeInMentions": true, + "changeInQuickSwitcher": true, + "changeInRecentMentions": true + } +}
\ No newline at end of file diff --git a/.config/BetterDiscord/plugins/EditChannels.plugin.js b/.config/BetterDiscord/plugins/EditChannels.plugin.js new file mode 100644 index 0000000..955776e --- /dev/null +++ b/.config/BetterDiscord/plugins/EditChannels.plugin.js @@ -0,0 +1,773 @@ +//META{"name":"EditChannels","authorId":"278543574059057154","invite":"Jx3TjNS","donate":"https://www.paypal.me/MircoWittrien","patreon":"https://www.patreon.com/MircoWittrien","website":"https://github.com/mwittrien/BetterDiscordAddons/tree/master/Plugins/EditChannels","source":"https://raw.githubusercontent.com/mwittrien/BetterDiscordAddons/master/Plugins/EditChannels/EditChannels.plugin.js"}*// + +var EditChannels = (_ => { + return class EditChannels { + getName () {return "EditChannels";} + + getVersion () {return "4.1.3";} + + getAuthor () {return "DevilBro";} + + getDescription () {return "Allows you to rename and recolor channelnames.";} + + constructor () { + this.changelog = { + "fixed":[["Context Menu Update","Fixes for the context menu update, yaaaaaay"]] + }; + + this.patchedModules = { + before: { + ChannelEditorContainer: "render", + ChannelAutoComplete: "render", + AutocompleteChannelResult: "render", + AuditLog: "render", + SettingsInvites: "render", + HeaderBarContainer: "render", + ChannelCategoryItem: "render", + ChannelItem: "render", + QuickSwitchChannelResult: "render", + MessageContent: "type" + }, + after: { + AutocompleteChannelResult: "render", + AuditLog: "render", + HeaderBarContainer: "render", + ChannelCategoryItem: "render", + ChannelItem: "render", + QuickSwitchChannelResult: "render", + MessagesPopout: "render" + } + }; + } + + initConstructor () { + this.css = ` + ${BDFDB.dotCN.messagespopoutchannelname}:hover > span[style*="color"] { + text-decoration: underline; + } + ${BDFDB.dotCN.categorywrapper}:hover ${BDFDB.dotCN.categoryname} span[style*="color"], + ${BDFDB.dotCN.categorywrapper}:hover ${BDFDB.dotCN.categoryicon}.EC-changed, + ${BDFDB.dotCN.channelwrapper + BDFDB.notCN.channelmodeselected + BDFDB.notCN.channelmodeconnected}:hover ${BDFDB.dotCN.channelname} span[style*="color"], + ${BDFDB.dotCN.channelwrapper + BDFDB.notCN.channelmodeselected + BDFDB.notCN.channelmodeconnected}:hover ${BDFDB.dotCN.channelicon}.EC-changed { + filter: brightness(150%); + } + `; + + this.defaults = { + settings: { + changeChannelIcon: {value:true, inner:false, description:"Change color of Channel Icon"}, + changeInChatTextarea: {value:true, inner:true, description:"Chat Textarea"}, + changeInMentions: {value:true, inner:true, description:"Mentions"}, + changeInChannelList: {value:true, inner:true, description:"Channel List"}, + changeInChannelHeader: {value:true, inner:true, description:"Channel Header"}, + changeInRecentMentions: {value:true, inner:true, description:"Recent Mentions Popout"}, + changeInAutoComplete: {value:true, inner:true, description:"Autocomplete Menu"}, + changeInAuditLog: {value:true, inner:true, description:"Audit Log"}, + changeInInviteLog: {value:true, inner:true, description:"Invite Log"}, + changeInQuickSwitcher: {value:true, inner:true, description:"Quick Switcher"} + } + }; + } + + getSettingsPanel () { + if (!window.BDFDB || typeof BDFDB != "object" || !BDFDB.loaded || !this.started) return; + let settings = BDFDB.DataUtils.get(this, "settings"); + let settingsPanel, settingsItems = [], innerItems = []; + + for (let key in settings) (!this.defaults.settings[key].inner ? settingsItems : innerItems).push(BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SettingsSaveItem, { + className: BDFDB.disCN.marginbottom8, + type: "Switch", + plugin: this, + keys: ["settings", key], + label: this.defaults.settings[key].description, + value: settings[key] + })); + settingsItems.push(BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SettingsPanelInner, { + title: "Change Channels in:", + first: settingsItems.length == 0, + children: innerItems + })); + settingsItems.push(BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SettingsItem, { + type: "Button", + className: BDFDB.disCN.marginbottom8, + color: BDFDB.LibraryComponents.Button.Colors.RED, + label: "Reset all Channels", + onClick: _ => { + BDFDB.ModalUtils.confirm(this, "Are you sure you want to reset all channels?", _ => { + BDFDB.DataUtils.remove(this, "channels"); + this.forceUpdateAll(); + }); + }, + children: BDFDB.LanguageUtils.LanguageStrings.RESET + })); + + return settingsPanel = BDFDB.PluginUtils.createSettingsPanel(this, settingsItems); + } + + // Legacy + load () {} + + start () { + if (!window.BDFDB) window.BDFDB = {myPlugins:{}}; + if (window.BDFDB && window.BDFDB.myPlugins && typeof window.BDFDB.myPlugins == "object") window.BDFDB.myPlugins[this.getName()] = this; + let libraryScript = document.querySelector("head script#BDFDBLibraryScript"); + if (!libraryScript || (performance.now() - libraryScript.getAttribute("date")) > 600000) { + if (libraryScript) libraryScript.remove(); + libraryScript = document.createElement("script"); + libraryScript.setAttribute("id", "BDFDBLibraryScript"); + libraryScript.setAttribute("type", "text/javascript"); + libraryScript.setAttribute("src", "https://mwittrien.github.io/BetterDiscordAddons/Plugins/BDFDB.min.js"); + libraryScript.setAttribute("date", performance.now()); + libraryScript.addEventListener("load", _ => {this.initialize();}); + document.head.appendChild(libraryScript); + } + else if (window.BDFDB && typeof BDFDB === "object" && BDFDB.loaded) this.initialize(); + this.startTimeout = setTimeout(_ => { + try {return this.initialize();} + catch (err) {console.error(`%c[${this.getName()}]%c`, "color: #3a71c1; font-weight: 700;", "", "Fatal Error: Could not initiate plugin! " + err);} + }, 30000); + } + + initialize () { + if (window.BDFDB && typeof BDFDB === "object" && BDFDB.loaded) { + if (this.started) return; + BDFDB.PluginUtils.init(this); + + let observer = new MutationObserver(_ => {this.changeAppTitle();}); + BDFDB.ObserverUtils.connect(this, document.head.querySelector("title"), {name:"appTitleObserver",instance:observer}, {childList:true}); + + this.forceUpdateAll(); + } + else console.error(`%c[${this.getName()}]%c`, "color: #3a71c1; font-weight: 700;", "", "Fatal Error: Could not load BD functions!"); + } + + stop () { + if (window.BDFDB && typeof BDFDB === "object" && BDFDB.loaded) { + this.stopping = true; + + let data = BDFDB.DataUtils.load(this, "channels"); + BDFDB.DataUtils.remove(this, "channels"); + try {this.forceUpdateAll();} catch (err) {} + BDFDB.DataUtils.save(data, this, "channels"); + + BDFDB.PluginUtils.clear(this); + } + } + + + // Begin of own functions + + onChannelContextMenu (e) { + if (e.instance.props.channel) { + let [children, index] = BDFDB.ContextMenuUtils.findItem(e.returnvalue, {id: "devmode-copy-id", group: true}); + children.splice(index > -1 ? index : children.length, 0, BDFDB.ContextMenuUtils.createItem(BDFDB.LibraryComponents.MenuItems.MenuGroup, { + children: BDFDB.ContextMenuUtils.createItem(BDFDB.LibraryComponents.MenuItems.MenuItem, { + label: this.labels.context_localchannelsettings_text, + id: BDFDB.ContextMenuUtils.createItemId(this.name, "settings-submenu"), + children: BDFDB.ContextMenuUtils.createItem(BDFDB.LibraryComponents.MenuItems.MenuGroup, { + children: [ + BDFDB.ContextMenuUtils.createItem(BDFDB.LibraryComponents.MenuItems.MenuItem, { + label: this.labels.submenu_channelsettings_text, + id: BDFDB.ContextMenuUtils.createItemId(this.name, "settings-change"), + action: _ => { + BDFDB.ContextMenuUtils.close(e.instance); + this.openChannelSettingsModal(e.instance.props.channel); + } + }), + BDFDB.ContextMenuUtils.createItem(BDFDB.LibraryComponents.MenuItems.MenuItem, { + label: this.labels.submenu_resetsettings_text, + id: BDFDB.ContextMenuUtils.createItemId(this.name, "settings-reset"), + disabled: !BDFDB.DataUtils.load(this, "channels", e.instance.props.channel.id), + action: _ => { + BDFDB.ContextMenuUtils.close(e.instance); + BDFDB.DataUtils.remove(this, "channels", e.instance.props.channel.id); + this.forceUpdateAll(); + } + }) + ] + }) + }) + })); + } + } + + onSettingsClosed () { + if (this.SettingsUpdated) { + delete this.SettingsUpdated; + this.forceUpdateAll(); + } + } + + processChannelEditorContainer (e) { + if (!e.instance.props.disabled && e.instance.props.channel && BDFDB.ChannelUtils.isTextChannel(e.instance.props.channel) && e.instance.props.type == BDFDB.DiscordConstants.TextareaTypes.NORMAL && BDFDB.DataUtils.get(this, "settings", "changeInChatTextarea")) { + let data = BDFDB.DataUtils.load(this, "channels", e.instance.props.channel.id); + e.instance.props.placeholder = BDFDB.LanguageUtils.LanguageStringsFormat("TEXTAREA_PLACEHOLDER", `#${data && data.name || e.instance.props.channel.name}`); + } + } + + processChannelAutoComplete (e) { + if (e.instance.state.autocompleteType == "CHANNELS" && BDFDB.ArrayUtils.is(e.instance.state.autocompletes.channels) && e.instance.props.channel && e.instance.props.channel.guild_id) { + let lastword = (e.instance.props.textValue || "").slice(1).toLowerCase(); + let channels = BDFDB.DataUtils.load(this, "channels"); + if (!channels || !lastword) return; + let channelarray = []; + for (let id in channels) if (channels[id] && channels[id].name) { + let channel = BDFDB.LibraryModules.ChannelStore.getChannel(id); + let category = channel && channel.parent_id && BDFDB.LibraryModules.ChannelStore.getChannel(channel.parent_id); + let catdata = category && channels[category.id] || {}; + if (BDFDB.ChannelUtils.isTextChannel(channel) && channel.guild_id == e.instance.props.channel.guild_id) channelarray.push(Object.assign({ + lowercasename: channels[id].name.toLowerCase(), + lowercasecatname: catdata && catdata.name && catdata.name.toLowerCase(), + channel, + category, + catdata + }, channels[id])); + } + channelarray = BDFDB.ArrayUtils.keySort(channelarray.filter(n => e.instance.state.autocompletes.channels.every(channel => channel.id != n.channel.id) && (n.lowercasename.indexOf(lastword) != -1 || (n.lowercasecatname && n.lowercasecatname.indexOf(lastword) != -1))), "lowercasename"); + e.instance.state.autocompletes.channels = [].concat(e.instance.state.autocompletes.channels, channelarray.map(n => n.channel)).slice(0, BDFDB.DiscordConstants.MAX_AUTOCOMPLETE_RESULTS); + } + } + + processAutocompleteChannelResult (e) { + if (e.instance.props.channel && BDFDB.DataUtils.get(this, "settings", "changeInAutoComplete")) { + if (!e.returnvalue) { + e.instance.props.channel = this.getChannelData(e.instance.props.channel.id); + if (e.instance.props.category) e.instance.props.category = this.getChannelData(e.instance.props.category.id); + } + else { + let [children, index] = BDFDB.ReactUtils.findChildren(e.returnvalue, {props:[["className", BDFDB.disCN.marginleft4]]}); + if (index > -1) this.changeChannelColor(children[index], e.instance.props.channel.id); + [children, index] = BDFDB.ReactUtils.findChildren(e.returnvalue, {props:[["className", BDFDB.disCN.autocompleteicon]]}); + if (index > -1) this.changeChannelIconColor(children[index], e.instance.props.channel.id, {alpha: 0.6}); + if (e.instance.props.category) { + [children, index] = BDFDB.ReactUtils.findChildren(e.returnvalue, {props:[["className", BDFDB.disCN.autocompletedescription]]}); + if (index > -1) this.changeChannelColor(children[index], e.instance.props.category.id); + } + } + } + } + + processAuditLog (e) { + let channel = BDFDB.ReactUtils.getValue(e.instance, "props.log.options.channel"); + if (channel && BDFDB.DataUtils.get(this, "settings", "changeInAuditLog")) { + if (!e.returnvalue) e.instance.props.log.options.channel = this.getChannelData(channel.id); + else { + let [children, index] = BDFDB.ReactUtils.findChildren(e.returnvalue, {props:[["children", [["#" + channel.name]]]]}); + if (index > -1) this.changeChannelColor(children[index], channel.id); + } + } + } + + processSettingsInvites (e) { + if (BDFDB.ObjectUtils.is(e.instance.props.invites) && BDFDB.DataUtils.get(this, "settings", "changeInInviteLog")) { + e.instance.props.invites = Object.assign({}, e.instance.props.invites); + for (let id in e.instance.props.invites) e.instance.props.invites[id] = new BDFDB.DiscordObjects.Invite(Object.assign({}, e.instance.props.invites[id], {channel: this.getChannelData(e.instance.props.invites[id].channel.id)})); + } + } + + processHeaderBarContainer (e) { + let channel = BDFDB.LibraryModules.ChannelStore.getChannel(e.instance.props.channelId); + if (channel && BDFDB.ChannelUtils.isTextChannel(channel) && BDFDB.DataUtils.get(this, "settings", "changeInChannelHeader")) { + if (!e.returnvalue) { + let [children, index] = BDFDB.ReactUtils.findChildren(e.instance, {name: "Title"}); + if (index > -1) { + children[index].props.children = this.getChannelData(channel.id).name; + this.changeChannelColor(children[index], channel.id); + } + } + else { + let [children, index] = BDFDB.ReactUtils.findChildren(e.instance, {name: "Icon"}); + if (index > -1) { + let icon = BDFDB.ReactUtils.createElement(children[index].props.icon, { + className: BDFDB.disCN.channelheadericon + }); + this.changeChannelIconColor(icon, channel.id, {alpha: 0.6}); + children[index] = BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCN.channelheadericonwrapper, + children: icon + }) + } + } + } + } + + processChannelCategoryItem (e) { + if (e.instance.props.channel && BDFDB.DataUtils.get(this, "settings", "changeInChannelList")) { + if (!e.returnvalue) e.instance.props.channel = this.getChannelData(e.instance.props.channel.id); + else { + let modify = BDFDB.ObjectUtils.extract(e.instance.props, "muted", "locked", "selected", "unread", "connected"); + let [children, index] = BDFDB.ReactUtils.findChildren(e.returnvalue, {props:[["className", BDFDB.disCN.categoryname]]}); + if (index > -1) this.changeChannelColor(children[index], e.instance.props.channel.id, modify); + [children, index] = BDFDB.ReactUtils.findChildren(e.returnvalue, {props:[["className", BDFDB.disCN.categoryicon]]}); + if (index > -1) this.changeChannelIconColor(children[index], e.instance.props.channel.id, Object.assign({alpha: 0.6}, modify)); + } + } + } + + processChannelItem (e) { + if (e.instance.props.channel && BDFDB.DataUtils.get(this, "settings", "changeInChannelList")) { + if (!e.returnvalue) e.instance.props.channel = this.getChannelData(e.instance.props.channel.id); + else { + let modify = BDFDB.ObjectUtils.extract(e.instance.props, "muted", "locked", "selected", "unread", "connected"); + let [children, index] = BDFDB.ReactUtils.findChildren(e.returnvalue, {props:[["className", BDFDB.disCN.channelname]]}); + if (index > -1) this.changeChannelColor(children[index], e.instance.props.channel.id, modify); + [children, index] = BDFDB.ReactUtils.findChildren(e.returnvalue, {props:[["className", BDFDB.disCN.channelicon]]}); + if (index > -1) this.changeChannelIconColor(children[index], e.instance.props.channel.id, Object.assign({alpha: 0.6}, modify)); + } + } + } + + processQuickSwitchChannelResult (e) { + if (e.instance.props.channel && BDFDB.DataUtils.get(this, "settings", "changeInQuickSwitcher")) { + if (!e.returnvalue) { + e.instance.props.channel = this.getChannelData(e.instance.props.channel.id); + if (e.instance.props.category) e.instance.props.category = this.getChannelData(e.instance.props.category.id); + } + else { + let modify = BDFDB.ObjectUtils.extract(e.instance.props, "focused", "unread", "mentions"); + let [children, index] = BDFDB.ReactUtils.findChildren(e.returnvalue, {props:[["className", BDFDB.disCN.quickswitchresultmatch]]}); + if (index > -1) this.changeChannelColor(children[index], e.instance.props.channel.id, modify); + [children, index] = BDFDB.ReactUtils.findChildren(e.returnvalue, {props:[["className", BDFDB.disCN.quickswitchresulticon]]}); + if (index > -1) this.changeChannelIconColor(children[index], e.instance.props.channel.id, Object.assign({alpha: 0.6}, modify)); + if (e.instance.props.category) { + [children, index] = BDFDB.ReactUtils.findChildren(e.returnvalue, {props:[["className", BDFDB.disCN.quickswitchresultnote]]}); + if (index > -1) this.changeChannelColor(children[index], e.instance.props.category.id); + } + } + } + } + + processMessagesPopout (e) { + if (BDFDB.DataUtils.get(this, "settings", "changeInRecentMentions")) { + let [children, index] = BDFDB.ReactUtils.findChildren(e.returnvalue, {name: "VerticalScroller"}); + if (index > -1 && children[index].props.children && BDFDB.ArrayUtils.is(children[index].props.children[0])) for (let i in children[index].props.children[0]) { + let divider = children[index].props.children[0][i]; + if (divider && divider.props && divider.props.className == BDFDB.disCN.messagespopoutchannelseparator) { + let channel = BDFDB.ReactUtils.findValue(children[index].props.children[0][parseInt(i)+1], "channel"); + if (BDFDB.ChannelUtils.isTextChannel(channel)) { + let [children2, index2] = BDFDB.ReactUtils.findChildren(divider, {props:[["className", BDFDB.disCN.messagespopoutchannelname]]}); + if (index2 > -1) { + children2[index2].props.children = "#" + this.getChannelData(channel.id).name; + this.changeChannelColor(children2[index2], channel.id); + } + } + } + } + } + } + + processMessageContent (e) { + if (BDFDB.ArrayUtils.is(e.instance.props.content) && BDFDB.DataUtils.get(this, "settings", "changeInMentions")) for (let ele of e.instance.props.content) { + if (BDFDB.ReactUtils.isValidElement(ele) && ele.type && ele.type.displayName == "Tooltip" && typeof ele.props.children == "function") { + let children = ele.props.children({}); + if (children && children.type.displayName == "Mention" && children.props.children && typeof children.props.children[0] == "string" && children.props.children[0][0] == "#") { + let channelName = children.props.children[0].slice(1); + let guildId = BDFDB.LibraryModules.LastGuildStore.getGuildId(); + let channels = guildId && (BDFDB.LibraryModules.GuildChannelStore.getChannels(guildId)[0] || BDFDB.LibraryModules.GuildChannelStore.getChannels(guildId).SELECTABLE); + if (Array.isArray(channels)) for (let channelObj of channels) { + if (channelName == channelObj.channel.name) { + let category = BDFDB.LibraryModules.ChannelStore.getChannel(channelObj.channel.parent_id); + if (!category || category && ele.props.text == category.name) { + if (category) { + let categoryData = BDFDB.DataUtils.load(this, "channels", category.id); + if (categoryData && categoryData.name) ele.props.text = categoryData.name; + } + let name = (BDFDB.DataUtils.load(this, "channels", channelObj.channel.id) || {}).name; + let color = this.getChannelDataColor(channelObj.channel.id); + if (name || color) { + let renderChildren = ele.props.children; + ele.props.children = (...args) => { + let renderedChildren = renderChildren(...args); + if (name) renderedChildren.props.children[0] = "#" + name; + if (color) { + let color1_0 = BDFDB.ColorUtils.convert(BDFDB.ObjectUtils.is(color) ? color[0] : color, "RGBA"); + let color0_1 = BDFDB.ColorUtils.setAlpha(color1_0, 0.1, "RGBA"); + let color0_7 = BDFDB.ColorUtils.setAlpha(color1_0, 0.7, "RGBA"); + renderedChildren.props.style = Object.assign({}, renderedChildren.props.style, { + background: color0_1, + color: color1_0 + }); + let onMouseEnter = renderedChildren.props.onMouseEnter || ( _ => {}); + renderedChildren.props.onMouseEnter = event => { + onMouseEnter(event); + event.target.style.setProperty("background", color0_7, "important"); + event.target.style.setProperty("color", "#FFFFFF", "important"); + }; + let onMouseLeave = renderedChildren.props.onMouseLeave || ( _ => {}); + renderedChildren.props.onMouseLeave = event => { + onMouseLeave(event); + event.target.style.setProperty("background", color0_1, "important"); + event.target.style.setProperty("color", color1_0, "important"); + }; + } + return renderedChildren; + } + } + break; + } + } + } + } + } + } + } + + changeAppTitle () { + let channel = BDFDB.LibraryModules.ChannelStore.getChannel(BDFDB.LibraryModules.LastChannelStore.getChannelId()); + let title = document.head.querySelector("title"); + if (title && BDFDB.ChannelUtils.isTextChannel(channel)) BDFDB.DOMUtils.setText(title, "@" + this.getChannelData(channel.id, BDFDB.DataUtils.get(this, "settings", "changeAppTitle")).name); + } + + changeChannelColor (child, channelId, modify) { + let color = this.getChannelDataColor(channelId); + if (color) { + color = modify ? this.chooseColor(color, modify) : BDFDB.ColorUtils.convert(color, "RGBA"); + let fontGradient = BDFDB.ObjectUtils.is(color); + if (fontGradient) child.props.children = BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.TextGradientElement, { + gradient: BDFDB.ColorUtils.createGradient(color), + children: child.props.children + }); + else child.props.children = BDFDB.ReactUtils.createElement("span", { + style: {color: color}, + children: child.props.children + }); + } + } + + changeChannelIconColor (child, channelId, modify) { + let color = this.getChannelDataColor(channelId); + if (color && BDFDB.DataUtils.get(this, "settings", "changeChannelIcon")) { + color = modify ? this.chooseColor(BDFDB.ObjectUtils.is(color) ? color[0] : color, modify) : BDFDB.ColorUtils.convert(BDFDB.ObjectUtils.is(color) ? color[0] : color, "RGBA"); + child.props.color = color || "currentColor"; + if (color) { + child.props.foreground = null; + child.props.className = BDFDB.DOMUtils.formatClassName(child.props.className, "EC-changed"); + } + } + } + + chooseColor (color, config) { + if (color) { + if (BDFDB.ObjectUtils.is(config)) { + if (config.mentions || config.focused || config.hovered || config.selected || config.unread || config.connected) color = BDFDB.ColorUtils.change(color, 0.5); + else if (config.muted || config.locked) color = BDFDB.ColorUtils.change(color, -0.5); + } + return BDFDB.ColorUtils.convert(color, "RGBA"); + } + return null; + } + + getChannelDataColor (channelId) { + let channel = BDFDB.LibraryModules.ChannelStore.getChannel(channelId); + if (!channel) return null; + let channelData = BDFDB.DataUtils.load(this, "channels", channel.id); + if (channelData && channelData.color) return channelData.color; + let category = channel.parent_id && BDFDB.LibraryModules.ChannelStore.getChannel(channel.parent_id); + if (category) { + let categoryData = BDFDB.DataUtils.load(this, "channels", category.id); + if (categoryData && categoryData.inheritColor && categoryData.color) return categoryData.color; + } + return null; + } + + getChannelData (channelId, change = true) { + let channel = BDFDB.LibraryModules.ChannelStore.getChannel(channelId); + if (!channel) return new BDFDB.DiscordObjects.Channel({}); + let data = change && BDFDB.DataUtils.load(this, "channels", channel.id); + if (data) { + let nativeObject = new BDFDB.DiscordObjects.Channel(channel); + nativeObject.name = data.name || nativeObject.name; + return nativeObject; + } + return new BDFDB.DiscordObjects.Channel(channel); + } + + forceUpdateAll () { + this.changeAppTitle(); + BDFDB.ModuleUtils.forceAllUpdates(this); + BDFDB.ReactUtils.forceUpdate(BDFDB.ReactUtils.findOwner(document.querySelector(BDFDB.dotCN.app), {name:"Channel", unlimited:true})); + } + + openChannelSettingsModal (channel) { + let data = BDFDB.DataUtils.load(this, "channels", channel.id) || {}; + + BDFDB.ModalUtils.open(this, { + size: "MEDIUM", + header: this.labels.modal_header_text, + subheader: channel.name, + children: [ + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.FormComponents.FormItem, { + title: this.labels.modal_channelname_text, + className: BDFDB.disCN.marginbottom20 + " input-channelname", + children: [ + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.TextInput, { + value: data.name, + placeholder: channel.name, + autoFocus: true + }), + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.FormComponents.FormDivider, { + className: BDFDB.disCN.dividerdefault + }) + ] + }), + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.FormComponents.FormItem, { + title: this.labels.modal_colorpicker1_text, + className: BDFDB.disCN.marginbottom20, + children: [ + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.ColorSwatches, { + color: data.color, + number: 1 + }) + ] + }), + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SettingsItem, { + type: "Switch", + className: BDFDB.disCN.marginbottom20 + " input-inheritcolor", + label: this.labels.modal_inheritcolor_text, + tag: BDFDB.LibraryComponents.FormComponents.FormTitle.Tags.H5, + value: channel.type == 4 && data.inheritColor, + disabled: channel.type != 4 + }) + ], + buttons: [{ + contents: BDFDB.LanguageUtils.LanguageStrings.SAVE, + color: "BRAND", + close: true, + click: modal => { + let olddata = Object.assign({}, data); + + data.name = modal.querySelector(".input-channelname " + BDFDB.dotCN.input).value.trim() || null; + + data.color = BDFDB.ColorUtils.getSwatchColor(modal, 1); + if (data.color != null && !BDFDB.ObjectUtils.is(data.color)) { + if (data.color[0] < 30 && data.color[1] < 30 && data.color[2] < 30) data.color = BDFDB.ColorUtils.change(data.color, 30); + else if (data.color[0] > 225 && data.color[1] > 225 && data.color[2] > 225) data.color = BDFDB.ColorUtils.change(data.color, -30); + } + + data.inheritColor = modal.querySelector(".input-inheritcolor " + BDFDB.dotCN.switchinner).checked; + + let changed = false; + if (Object.keys(data).every(key => data[key] == null || data[key] == false) && (changed = true)) BDFDB.DataUtils.remove(this, "channels", channel.id); + else if (!BDFDB.equals(olddata, data) && (changed = true)) BDFDB.DataUtils.save(data, this, "channels", channel.id); + if (changed) this.forceUpdateAll(); + } + }] + }); + } + + setLabelsByLanguage () { + switch (BDFDB.LanguageUtils.getLanguage().id) { + case "hr": //croatian + return { + context_localchannelsettings_text: "Postavke lokalnih kanala", + submenu_channelsettings_text: "Promijeni postavke", + submenu_resetsettings_text: "Vraćanje kanala", + modal_header_text: "Postavke lokalnih kanala", + modal_channelname_text: "Naziv lokalnog kanala", + modal_colorpicker1_text: "Boja lokalnog kanala", + modal_inheritcolor_text: "Naslijedi boju u potkanale" + }; + case "da": //danish + return { + context_localchannelsettings_text: "Lokal kanalindstillinger", + submenu_channelsettings_text: "Skift indstillinger", + submenu_resetsettings_text: "Nulstil kanal", + modal_header_text: "Lokal kanalindstillinger", + modal_channelname_text: "Lokalt kanalnavn", + modal_colorpicker1_text: "Lokal kanalfarve", + modal_inheritcolor_text: "Arve farve til subkanaler" + }; + case "de": //german + return { + context_localchannelsettings_text: "Lokale Kanaleinstellungen", + submenu_channelsettings_text: "Einstellungen ändern", + submenu_resetsettings_text: "Kanal zurücksetzen", + modal_header_text: "Lokale Kanaleinstellungen", + modal_channelname_text: "Lokaler Kanalname", + modal_colorpicker1_text: "Lokale Kanalfarbe", + modal_inheritcolor_text: "Farbe an Unterkanäle vererben" + }; + case "es": //spanish + return { + context_localchannelsettings_text: "Ajustes local de canal", + submenu_channelsettings_text: "Cambiar ajustes", + submenu_resetsettings_text: "Restablecer canal", + modal_header_text: "Ajustes local de canal", + modal_channelname_text: "Nombre local del canal", + modal_colorpicker1_text: "Color local del canal", + modal_inheritcolor_text: "Heredar color a sub-canales" + }; + case "fr": //french + return { + context_localchannelsettings_text: "Paramètres locale du salon", + submenu_channelsettings_text: "Modifier les paramètres", + submenu_resetsettings_text: "Réinitialiser le salon", + modal_header_text: "Paramètres locale du salon", + modal_channelname_text: "Nom local du salon", + modal_colorpicker1_text: "Couleur locale du salon", + modal_inheritcolor_text: "Hériter de la couleur sur les sous-salons" + }; + case "it": //italian + return { + context_localchannelsettings_text: "Impostazioni locale canale", + submenu_channelsettings_text: "Cambia impostazioni", + submenu_resetsettings_text: "Ripristina canale", + modal_header_text: "Impostazioni locale canale", + modal_channelname_text: "Nome locale canale", + modal_colorpicker1_text: "Colore locale canale", + modal_inheritcolor_text: "Eredita colore per sub-canali" + }; + case "nl": //dutch + return { + context_localchannelsettings_text: "Lokale kanaalinstellingen", + submenu_channelsettings_text: "Verandere instellingen", + submenu_resetsettings_text: "Reset kanaal", + modal_header_text: "Lokale kanaalinstellingen", + modal_channelname_text: "Lokale kanaalnaam", + modal_colorpicker1_text: "Lokale kanaalkleur", + modal_inheritcolor_text: "Overerving van kleuren naar subkanalen" + }; + case "no": //norwegian + return { + context_localchannelsettings_text: "Lokal kanalinnstillinger", + submenu_channelsettings_text: "Endre innstillinger", + submenu_resetsettings_text: "Tilbakestill kanal", + modal_header_text: "Lokal kanalinnstillinger", + modal_channelname_text: "Lokalt kanalnavn", + modal_colorpicker1_text: "Lokal kanalfarge", + modal_inheritcolor_text: "Arve farge til underkanaler" + }; + case "pl": //polish + return { + context_localchannelsettings_text: "Lokalne ustawienia kanału", + submenu_channelsettings_text: "Zmień ustawienia", + submenu_resetsettings_text: "Resetuj ustawienia", + modal_header_text: "Lokalne ustawienia kanału", + modal_channelname_text: "Lokalna nazwa kanału", + modal_colorpicker1_text: "Lokalny kolor kanału", + modal_inheritcolor_text: "Dziedzicz kolor do podkanałów" + }; + case "pt-BR": //portuguese (brazil) + return { + context_localchannelsettings_text: "Configurações local do canal", + submenu_channelsettings_text: "Mudar configurações", + submenu_resetsettings_text: "Redefinir canal", + modal_header_text: "Configurações local do canal", + modal_channelname_text: "Nome local do canal", + modal_colorpicker1_text: "Cor local do canal", + modal_inheritcolor_text: "Herdar cor aos sub-canais" + }; + case "fi": //finnish + return { + context_localchannelsettings_text: "Paikallinen kanavan asetukset", + submenu_channelsettings_text: "Vaihda asetuksia", + submenu_resetsettings_text: "Nollaa kanava", + modal_header_text: "Paikallinen kanavan asetukset", + modal_channelname_text: "Paikallinen kanavanimi", + modal_colorpicker1_text: "Paikallinen kanavanväri", + modal_inheritcolor_text: "Hävitä väri alikanaville" + }; + case "sv": //swedish + return { + context_localchannelsettings_text: "Lokal kanalinställningar", + submenu_channelsettings_text: "Ändra inställningar", + submenu_resetsettings_text: "Återställ kanal", + modal_header_text: "Lokal kanalinställningar", + modal_channelname_text: "Lokalt kanalnamn", + modal_colorpicker1_text: "Lokal kanalfärg", + modal_inheritcolor_text: "Inherit färg till subkanaler" + }; + case "tr": //turkish + return { + context_localchannelsettings_text: "Yerel Kanal Ayarları", + submenu_channelsettings_text: "Ayarları Değiştir", + submenu_resetsettings_text: "Kanal Sıfırla", + modal_header_text: "Yerel Kanal Ayarları", + modal_channelname_text: "Yerel Kanal Adı", + modal_colorpicker1_text: "Yerel Kanal Rengi", + modal_inheritcolor_text: "Renkleri alt kanallara miras alma" + }; + case "cs": //czech + return { + context_localchannelsettings_text: "Místní nastavení kanálu", + submenu_channelsettings_text: "Změnit nastavení", + submenu_resetsettings_text: "Obnovit kanál", + modal_header_text: "Místní nastavení kanálu", + modal_channelname_text: "Místní název kanálu", + modal_colorpicker1_text: "Místní barvy kanálu", + modal_inheritcolor_text: "Zdědit barvu na subkanály" + }; + case "bg": //bulgarian + return { + context_localchannelsettings_text: "Настройки за локални канали", + submenu_channelsettings_text: "Промяна на настройките", + submenu_resetsettings_text: "Възстановяване на канал", + modal_header_text: "Настройки за локални канали", + modal_channelname_text: "Локално име на канал", + modal_colorpicker1_text: "Локален цветен канал", + modal_inheritcolor_text: "Наследи цвета до подканали" + }; + case "ru": //russian + return { + context_localchannelsettings_text: "Настройки локального канала", + submenu_channelsettings_text: "Изменить настройки", + submenu_resetsettings_text: "Сбросить канал", + modal_header_text: "Настройки локального канала", + modal_channelname_text: "Имя локального канала", + modal_colorpicker1_text: "Цвет локального канала", + modal_inheritcolor_text: "Наследовать цвет на подканалы" + }; + case "uk": //ukrainian + return { + context_localchannelsettings_text: "Налаштування локального каналу", + submenu_channelsettings_text: "Змінити налаштування", + submenu_resetsettings_text: "Скидання каналу", + modal_header_text: "Налаштування локального каналу", + modal_channelname_text: "Локальне ім'я каналу", + modal_colorpicker1_text: "Колір місцевого каналу", + modal_inheritcolor_text: "Успадковують колір до підканалів" + }; + case "ja": //japanese + return { + context_localchannelsettings_text: "ローカルチャネル設定", + submenu_channelsettings_text: "設定を変更する", + submenu_resetsettings_text: "チャネルをリセットする", + modal_header_text: "ローカルチャネル設定", + modal_channelname_text: "ローカルチャネル名", + modal_colorpicker1_text: "ローカルチャネルの色", + modal_inheritcolor_text: "サブチャンネルに色を継承" + }; + case "zh-TW": //chinese (traditional) + return { + context_localchannelsettings_text: "本地頻道設置", + submenu_channelsettings_text: "更改設置", + submenu_resetsettings_text: "重置通道", + modal_header_text: "本地頻道設置", + modal_channelname_text: "本地頻道名稱", + modal_colorpicker1_text: "本地頻道顏色", + modal_inheritcolor_text: "繼承子通道的顏色" + }; + case "ko": //korean + return { + context_localchannelsettings_text: "로컬 채널 설정", + submenu_channelsettings_text: "설정 변경", + submenu_resetsettings_text: "채널 재설정", + modal_header_text: "로컬 채널 설정", + modal_channelname_text: "로컬 채널 이름", + modal_colorpicker1_text: "지역 채널 색깔", + modal_inheritcolor_text: "하위 채널에 색상 상속" + }; + default: //default: english + return { + context_localchannelsettings_text: "Local Channelsettings", + submenu_channelsettings_text: "Change Settings", + submenu_resetsettings_text: "Reset Channel", + modal_header_text: "Local Channelsettings", + modal_channelname_text: "Local Channelname", + modal_colorpicker1_text: "Local Channelcolor", + modal_inheritcolor_text: "Inherit color to Sub-Channels" + }; + } + } + } +})();
\ No newline at end of file diff --git a/.config/BetterDiscord/plugins/EditServers.config.json b/.config/BetterDiscord/plugins/EditServers.config.json new file mode 100644 index 0000000..8544d34 --- /dev/null +++ b/.config/BetterDiscord/plugins/EditServers.config.json @@ -0,0 +1,28 @@ +{ + "changelog": { + "currentversion": "2.2.1" + }, + "servers": { + "624859996949315584": { + "banner": "https://media.discordapp.net/attachments/624865812888420352/715196061400039474/8PiLwbX.png", + "color1": null, + "color2": null, + "color3": null, + "color4": null, + "ignoreCustomName": false, + "name": "Gerrit", + "removeBanner": false, + "removeIcon": false, + "shortName": null, + "url": null + } + }, + "settings": { + "addOriginalTooltip": true, + "changeInGuildHeader": true, + "changeInGuildList": true, + "changeInMutualGuilds": true, + "changeInQuickSwitcher": true, + "changeInRecentMentions": true + } +}
\ No newline at end of file diff --git a/.config/BetterDiscord/plugins/EditServers.plugin.js b/.config/BetterDiscord/plugins/EditServers.plugin.js new file mode 100644 index 0000000..3291113 --- /dev/null +++ b/.config/BetterDiscord/plugins/EditServers.plugin.js @@ -0,0 +1,1079 @@ +//META{"name":"EditServers","authorId":"278543574059057154","invite":"Jx3TjNS","donate":"https://www.paypal.me/MircoWittrien","patreon":"https://www.patreon.com/MircoWittrien","website":"https://github.com/mwittrien/BetterDiscordAddons/tree/master/Plugins/EditServers","source":"https://raw.githubusercontent.com/mwittrien/BetterDiscordAddons/master/Plugins/EditServers/EditServers.plugin.js"}*// + +var EditServers = (_ => { + return class EditServers { + getName () {return "EditServers";} + + getVersion () {return "2.2.1";} + + getAuthor () {return "DevilBro";} + + getDescription () {return "Allows you to change the icon, name and color of servers.";} + + constructor () { + this.changelog = { + "fixed":[["Context Menu Update","Fixes for the context menu update, yaaaaaay"]] + }; + + this.patchedModules = { + before: { + Guild: "render", + GuildIconWrapper: "render", + MutualGuilds: "render", + FriendRow: "render", + QuickSwitcher: "render", + QuickSwitchChannelResult: "render", + GuildSidebar: "render", + GuildHeader: "render" + }, + after: { + MessagesPopout: "render", + Guild: "render", + BlobMask: "render", + GuildIconWrapper: "render", + GuildIcon: "render", + GuildHeader: "render" + } + }; + + this.patchPriority = 7; + } + + initConstructor () { + this.defaults = { + settings: { + addOriginalTooltip: {value:true, inner:false, description:"Hovering over a changed Server Header shows the original Name as Tooltip"}, + changeInGuildList: {value:true, inner:true, description:"Server List"}, + changeInGuildHeader: {value:true, inner:true, description:"Server Header"}, + changeInMutualGuilds: {value:true, inner:true, description:"Mutual Servers"}, + changeInRecentMentions: {value:true, inner:true, description:"Recent Mentions Popout"}, + changeInQuickSwitcher: {value:true, inner:true, description:"Quick Switcher"} + } + }; + } + + getSettingsPanel () { + if (!window.BDFDB || typeof BDFDB != "object" || !BDFDB.loaded || !this.started) return; + let settings = BDFDB.DataUtils.get(this, "settings"); + let settingsPanel, settingsItems = [], innerItems = []; + + for (let key in settings) (!this.defaults.settings[key].inner ? settingsItems : innerItems).push(BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SettingsSaveItem, { + className: BDFDB.disCN.marginbottom8, + type: "Switch", + plugin: this, + keys: ["settings", key], + label: this.defaults.settings[key].description, + value: settings[key] + })); + settingsItems.push(BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SettingsPanelInner, { + title: "Change Servers in:", + first: settingsItems.length == 0, + children: innerItems + })); + settingsItems.push(BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SettingsItem, { + type: "Button", + className: BDFDB.disCN.marginbottom8, + color: BDFDB.LibraryComponents.Button.Colors.RED, + label: "Reset all Servers", + onClick: _ => { + BDFDB.ModalUtils.confirm(this, "Are you sure you want to reset all Servers?", _ => { + BDFDB.DataUtils.remove(this, "servers"); + BDFDB.ModuleUtils.forceAllUpdates(this);; + }); + }, + children: BDFDB.LanguageUtils.LanguageStrings.RESET + })); + + return settingsPanel = BDFDB.PluginUtils.createSettingsPanel(this, settingsItems); + } + + // Legacy + load () {} + + start () { + if (!window.BDFDB) window.BDFDB = {myPlugins:{}}; + if (window.BDFDB && window.BDFDB.myPlugins && typeof window.BDFDB.myPlugins == "object") window.BDFDB.myPlugins[this.getName()] = this; + let libraryScript = document.querySelector("head script#BDFDBLibraryScript"); + if (!libraryScript || (performance.now() - libraryScript.getAttribute("date")) > 600000) { + if (libraryScript) libraryScript.remove(); + libraryScript = document.createElement("script"); + libraryScript.setAttribute("id", "BDFDBLibraryScript"); + libraryScript.setAttribute("type", "text/javascript"); + libraryScript.setAttribute("src", "https://mwittrien.github.io/BetterDiscordAddons/Plugins/BDFDB.min.js"); + libraryScript.setAttribute("date", performance.now()); + libraryScript.addEventListener("load", _ => {this.initialize();}); + document.head.appendChild(libraryScript); + } + else if (window.BDFDB && typeof BDFDB === "object" && BDFDB.loaded) this.initialize(); + this.startTimeout = setTimeout(_ => { + try {return this.initialize();} + catch (err) {console.error(`%c[${this.getName()}]%c`, "color: #3a71c1; font-weight: 700;", "", "Fatal Error: Could not initiate plugin! " + err);} + }, 30000); + } + + initialize () { + if (window.BDFDB && typeof BDFDB === "object" && BDFDB.loaded) { + if (this.started) return; + BDFDB.PluginUtils.init(this); + + BDFDB.ModuleUtils.patch(this, BDFDB.LibraryModules.IconUtils, "getGuildBannerURL", {instead:e => { + let guild = BDFDB.LibraryModules.GuildStore.getGuild(e.methodArguments[0].id); + if (guild) { + if (e.methodArguments[0].id == "410787888507256842") return guild.banner; + let data = BDFDB.DataUtils.load(this, "servers", guild.id); + if (data && data.banner && !data.removeBanner) return data.banner; + } + return e.callOriginalMethod(); + }}); + + BDFDB.ModuleUtils.patch(this, BDFDB.LibraryComponents.GuildComponents.Guild.prototype, "render", { + before: e => {this.processGuild({instance:e.thisObject, returnvalue:e.returnValue, methodname:"render"});}, + after: e => {this.processGuild({instance:e.thisObject, returnvalue:e.returnValue, methodname:"render"});} + }); + + BDFDB.ModuleUtils.patch(this, BDFDB.LibraryComponents.Connectors.Link.prototype, "render", { + after: e => { + if (e.thisObject.props.className && e.thisObject.props.className.indexOf(BDFDB.disCN.guildiconwrapper) > -1) this.processGuildAcronym({instance:e.thisObject, returnvalue:e.returnValue, methodname:"render"}); + } + }); + + BDFDB.ModuleUtils.forceAllUpdates(this); + } + else console.error(`%c[${this.getName()}]%c`, "color: #3a71c1; font-weight: 700;", "", "Fatal Error: Could not load BD functions!"); + } + + stop () { + if (window.BDFDB && typeof BDFDB === "object" && BDFDB.loaded) { + this.stopping = true; + + BDFDB.ModuleUtils.forceAllUpdates(this); + + for (let guildobj of BDFDB.GuildUtils.getAll()) if (guildobj.instance) delete guildobj.instance.props.guild.EditServersCachedBanner; + + BDFDB.PluginUtils.clear(this); + } + } + + // Begin of own functions + + onGuildContextMenu (e) { + if (e.instance.props.guild) { + let [children, index] = BDFDB.ContextMenuUtils.findItem(e.returnvalue, {id: "devmode-copy-id", group: true}); + children.splice(index > -1 ? index : children.length, 0, BDFDB.ContextMenuUtils.createItem(BDFDB.LibraryComponents.MenuItems.MenuGroup, { + children: BDFDB.ContextMenuUtils.createItem(BDFDB.LibraryComponents.MenuItems.MenuItem, { + label: this.labels.context_localserversettings_text, + id: BDFDB.ContextMenuUtils.createItemId(this.name, "settings-submenu"), + children: BDFDB.ContextMenuUtils.createItem(BDFDB.LibraryComponents.MenuItems.MenuGroup, { + children: [ + BDFDB.ContextMenuUtils.createItem(BDFDB.LibraryComponents.MenuItems.MenuItem, { + label: this.labels.submenu_serversettings_text, + id: BDFDB.ContextMenuUtils.createItemId(this.name, "settings-change"), + action: _ => { + BDFDB.ContextMenuUtils.close(e.instance); + this.openGuildSettingsModal(e.instance.props.guild.id); + } + }), + BDFDB.ContextMenuUtils.createItem(BDFDB.LibraryComponents.MenuItems.MenuItem, { + label: this.labels.submenu_resetsettings_text, + id: BDFDB.ContextMenuUtils.createItemId(this.name, "settings-reset"), + disabled: !BDFDB.DataUtils.load(this, "servers", e.instance.props.guild.id), + action: _ => { + BDFDB.ContextMenuUtils.close(e.instance); + BDFDB.DataUtils.remove(this, "servers", e.instance.props.guild.id); + BDFDB.ModuleUtils.forceAllUpdates(this); + } + }) + ] + }) + }) + })); + } + } + + processGuild (e) { + if (BDFDB.GuildUtils.is(e.instance.props.guild) && BDFDB.DataUtils.get(this, "settings", "changeInGuildList")) { + e.instance.props.guild = this.getGuildData(e.instance.props.guild.id); + if (e.returnvalue) { + let data = BDFDB.DataUtils.load(this, "servers", e.instance.props.guild.id); + if (data && (data.color3 || data.color4)) { + let [children, index] = BDFDB.ReactUtils.findChildren(e.returnvalue, {name: ["GuildTooltip", "BDFDB_TooltipContainer"]}); + if (index > -1) children[index] = BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.TooltipContainer, { + tooltipConfig: { + type: "right", + guild: e.instance.props.guild, + list: true, + offset: 12, + backgroundColor: data.color3, + fontColor: data.color4 + }, + children: children[index].props.children + }); + } + } + } + } + + processBlobMask (e) { + if (BDFDB.DataUtils.get(this, "settings", "changeInGuildList")) { + let [children, index] = BDFDB.ReactUtils.findChildren(e.returnvalue, {name: "NavItem"}); + if (index > -1 && children[index].props.to && children[index].props.to.pathname) { + let guild = BDFDB.LibraryModules.GuildStore.getGuild((children[index].props.to.pathname.split("/channels/")[1] || "").split("/")[0]); + if (guild) { + let data = BDFDB.DataUtils.load(this, "servers", guild.id); + if (data) { + if (data.shortName) children[index].props.name = data.shortName.split("").join(" "); + else if (data.name && data.ignoreCustomName) children[index].props.name = guild.name; + } + } + } + } + } + + processGuildAcronym (e) { + if (typeof e.returnvalue.props.children == "function" && BDFDB.DataUtils.get(this, "settings", "changeInGuildList")) { + let pathname = BDFDB.ReactUtils.getValue(e.instance, "props.to.pathname"); + let data = pathname && BDFDB.DataUtils.load(this, "servers", (pathname.split("/channels/")[1] || "").split("/")[0]); + if (data) { + let renderChildren = e.returnvalue.props.children; + e.returnvalue.props.children = (...args) => { + let renderedChildren = renderChildren(...args); + let [children, index] = BDFDB.ReactUtils.findChildren(renderedChildren, {props:[["className", BDFDB.disCN.guildiconacronym]]}); + if (index > -1) { + let fontGradient = BDFDB.ObjectUtils.is(data.color2); + children[index].props.style = Object.assign({}, children[index].props.style, { + background: BDFDB.ObjectUtils.is(data.color1) ? BDFDB.ColorUtils.createGradient(data.color1) : BDFDB.ColorUtils.convert(data.color1, "RGBA"), + color: !fontGradient && BDFDB.ColorUtils.convert(data.color2, "RGBA") + }); + if (fontGradient) children[index].props.children = BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.TextGradientElement, { + gradient: BDFDB.ColorUtils.createGradient(data.color2), + children: children[index].props.children + }); + } + return renderedChildren; + }; + } + } + } + + processGuildIconWrapper (e) { + if (BDFDB.GuildUtils.is(e.instance.props.guild)) { + let settings = BDFDB.DataUtils.get(this, "settings"); + if (e.instance.props.className && e.instance.props.className.indexOf(BDFDB.disCN.guildfolderguildicon) > -1) e.instance.props.guild = this.getGuildData(e.instance.props.guild.id, settings.changeInGuildList); + else if (e.instance.props.className && e.instance.props.className.indexOf(BDFDB.disCN.listavatar) > -1) e.instance.props.guild = this.getGuildData(e.instance.props.guild.id, settings.changeInMutualGuilds); + else e.instance.props.guild = this.getGuildData(e.instance.props.guild.id); + } + } + + processGuildIcon (e) { + if (BDFDB.GuildUtils.is(e.instance.props.guild) && e.instance.props.style && (!e.instance.props.style.backgroundImage || e.instance.props.style.backgroundImage == "none")) { + let data = BDFDB.DataUtils.load(this, "servers", e.instance.props.guild.id); + if (data) { + let settings = BDFDB.DataUtils.get(this, "settings"); + if (e.instance.props.className && e.instance.props.className.indexOf(BDFDB.disCN.guildfolderguildicon) > -1) this.changeGuildIcon(e, data, settings.changeInGuildList); + else if (e.instance.props.className && e.instance.props.className.indexOf(BDFDB.disCN.listavatar) > -1 || BDFDB.ReactUtils.findConstructor(e.instance, "MutualGuild", {up: true})) this.changeGuildIcon(e, data, settings.changeInMutualGuilds); + else this.changeGuildIcon(e, data); + } + } + } + + processMutualGuilds (e) { + if (BDFDB.DataUtils.get(this, "settings", "changeInMutualGuilds")) for (let i in e.instance.props.mutualGuilds) e.instance.props.mutualGuilds[i].guild = this.getGuildData(e.instance.props.mutualGuilds[i].guild.id); + } + + processFriendRow (e) { + if (BDFDB.DataUtils.get(this, "settings", "changeInMutualGuilds")) for (let i in e.instance.props.mutualGuilds) e.instance.props.mutualGuilds[i] = this.getGuildData(e.instance.props.mutualGuilds[i].id); + } + + processQuickSwitcher (e) { + if (BDFDB.DataUtils.get(this, "settings", "changeInQuickSwitcher")) for (let i in e.instance.props.results) if (e.instance.props.results[i].type == "GUILD") e.instance.props.results[i].record = this.getGuildData(e.instance.props.results[i].record.id); + } + + processQuickSwitchChannelResult (e) { + if (e.instance.props.channel && e.instance.props.channel.guild_id && BDFDB.DataUtils.get(this, "settings", "changeInQuickSwitcher")) { + e.instance.props.children.props.children = this.getGuildData(e.instance.props.channel.guild_id).name; + } + } + + processMessagesPopout (e) { + if (BDFDB.DataUtils.get(this, "settings", "changeInRecentMentions")) { + let [children, index] = BDFDB.ReactUtils.findChildren(e.returnvalue, {name: "VerticalScroller"}); + if (index > -1 && children[index].props.children && BDFDB.ArrayUtils.is(children[index].props.children[0])) for (let i in children[index].props.children[0]) { + let divider = children[index].props.children[0][i]; + if (divider && divider.props && divider.props.className == BDFDB.disCN.messagespopoutchannelseparator) { + let channel = BDFDB.ReactUtils.findValue(children[index].props.children[0][parseInt(i)+1], "channel"); + if (BDFDB.ChannelUtils.isTextChannel(channel)) { + let [children2, index2] = BDFDB.ReactUtils.findChildren(divider, {props:[["className", BDFDB.disCN.messagespopoutguildname]]}); + if (index2 > -1) children2[index2].props.children = this.getGuildData(channel.guild_id).name; + } + } + } + } + } + + processGuildSidebar (e) { + if (e.instance.props.guild) { + let data = BDFDB.DataUtils.load(this, "servers", e.instance.props.guild.id); + if (data) { + if (data.removeBanner) e.instance.props.guild = new BDFDB.DiscordObjects.Guild(Object.assign({}, e.instance.props.guild, {banner: null})); + else if (data.banner) e.instance.props.guild = new BDFDB.DiscordObjects.Guild(Object.assign({}, e.instance.props.guild, {banner: data.banner})); + } + } + } + + processGuildHeader (e) { + if (e.instance.props.guild) { + let settings = BDFDB.DataUtils.get(this, "settings"); + if (settings.changeInGuildHeader) { + e.instance.props.guild = this.getGuildData(e.instance.props.guild.id); + let oldName = (BDFDB.LibraryModules.GuildStore.getGuild(e.instance.props.guild.id) || {}).name; + if (e.returnvalue && settings.addOriginalTooltip && oldName != e.instance.props.guild.name) { + e.returnvalue.props.children[0] = BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.TooltipContainer, { + text: oldName, + children: e.returnvalue.props.children[0], + tooltipConfig: {type: "right"} + }); + } + } + } + } + + getGuildData (guildId, change = true) { + let guild = BDFDB.LibraryModules.GuildStore.getGuild(guildId); + if (!guild) return new BDFDB.DiscordObjects.Guild({}); + let data = change && BDFDB.DataUtils.load(this, "servers", guild.id); + if (data) { + let newGuildObject = {}, nativeObject = new BDFDB.DiscordObjects.Guild(guild); + for (let key in nativeObject) newGuildObject[key] = nativeObject[key]; + newGuildObject.name = data.name || nativeObject.name; + newGuildObject.acronym = data.shortName && data.shortName.replace(/\s/g, "") || BDFDB.LibraryModules.StringUtils.getAcronym(!data.ignoreCustomName && data.name || nativeObject.name); + if (data.removeIcon) { + newGuildObject.icon = null; + newGuildObject.getIconURL = _ => {return null;}; + } + else if (data.url) { + newGuildObject.icon = data.url; + newGuildObject.getIconURL = _ => {return data.url;}; + } + if (data.removeBanner) newGuildObject.banner = null; + else if (data.banner) newGuildObject.banner = data.banner; + return newGuildObject; + } + return new BDFDB.DiscordObjects.Guild(guild); + } + + changeGuildIcon (e, data, change = true) { + if (change) { + let fontGradient = BDFDB.ObjectUtils.is(data.color2); + e.returnvalue.props.style = Object.assign({}, e.returnvalue.props.style, { + background: BDFDB.ObjectUtils.is(data.color1) ? BDFDB.ColorUtils.createGradient(data.color1) : BDFDB.ColorUtils.convert(data.color1, "RGBA"), + color: !fontGradient && BDFDB.ColorUtils.convert(data.color2, "RGBA") + }); + if (fontGradient) e.returnvalue.props.children[0] = BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.TextGradientElement, { + gradient: BDFDB.ColorUtils.createGradient(data.color2), + children: e.returnvalue.props.children[0] + }); + } + } + + openGuildSettingsModal (guildId) { + let guild = BDFDB.LibraryModules.GuildStore.getGuild(guildId); + if (!guild) return; + let data = BDFDB.DataUtils.load(this, "servers", guild.id) || {}; + + let currentIgnoreCustomNameState = data.ignoreCustomName; + + BDFDB.ModalUtils.open(this, { + size: "MEDIUM", + header: this.labels.modal_header_text, + subheader: guild.name, + children: [ + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.ModalComponents.ModalTabContent, { + tab: this.labels.modal_tabheader1_text, + children: [ + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.FormComponents.FormItem, { + title: this.labels.modal_guildname_text, + className: BDFDB.disCN.marginbottom20, + children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.TextInput, { + className: "input-guildname", + key: "GUILDNAME", + value: data.name, + placeholder: guild.name, + autoFocus: true, + onChange: (value, instance) => { + if (!currentIgnoreCustomNameState) { + let acronymInputIns = BDFDB.ReactUtils.findOwner(instance._reactInternalFiber.return.return.return, {key: "GUILDACRONYM"}); + if (acronymInputIns) { + acronymInputIns.props.placeholder = value && BDFDB.LibraryModules.StringUtils.getAcronym(value) || guild.acronym; + BDFDB.ReactUtils.forceUpdate(acronymInputIns); + } + } + } + }) + }), + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.FormComponents.FormItem, { + title: this.labels.modal_guildacronym_text, + className: BDFDB.disCN.marginbottom8, + children: + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.TextInput, { + className: "input-guildacronym", + key: "GUILDACRONYM", + value: data.shortName, + placeholder: !data.ignoreCustomName && data.name && BDFDB.LibraryModules.StringUtils.getAcronym(data.name) || guild.acronym + }) + }), + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SettingsItem, { + type: "Switch", + className: BDFDB.disCN.marginbottom20 + " input-ignorecustomname", + label: this.labels.modal_ignorecustomname_text, + tag: BDFDB.LibraryComponents.FormComponents.FormTitle.Tags.H5, + value: data.ignoreCustomName, + onChange: (value, instance) => { + currentIgnoreCustomNameState = value; + let nameInputIns = BDFDB.ReactUtils.findOwner(instance._reactInternalFiber.return, {key: "GUILDNAME"}); + let acronymInputIns = BDFDB.ReactUtils.findOwner(instance._reactInternalFiber.return, {key: "GUILDACRONYM"}); + if (nameInputIns && acronymInputIns) { + acronymInputIns.props.placeholder = !value && nameInputIns.props.value && BDFDB.LibraryModules.StringUtils.getAcronym(nameInputIns.props.value) || guild.acronym; + BDFDB.ReactUtils.forceUpdate(acronymInputIns); + } + } + }), + BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCN.marginbottom20, + children: [ + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Flex, { + className: BDFDB.disCN.marginbottom8, + align: BDFDB.LibraryComponents.Flex.Align.CENTER, + direction: BDFDB.LibraryComponents.Flex.Direction.HORIZONTAL, + children: [ + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.FormComponents.FormTitle, { + className: BDFDB.disCN.marginreset, + tag: BDFDB.LibraryComponents.FormComponents.FormTitle.Tags.H5, + children: this.labels.modal_guildicon_text + }), + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SettingsItem, { + className: "input-removeicon", + type: "Switch", + grow: 0, + label: BDFDB.LanguageUtils.LanguageStrings.REMOVE, + tag: BDFDB.LibraryComponents.FormComponents.FormTitle.Tags.H5, + value: data.removeIcon, + onChange: (value, instance) => { + let iconInputIins = BDFDB.ReactUtils.findOwner(instance._reactInternalFiber.return.return, {key: "GUILDICON"}); + if (iconInputIins) { + delete iconInputIins.props.success; + delete iconInputIins.props.errorMessage; + iconInputIins.props.disabled = value; + BDFDB.ReactUtils.forceUpdate(iconInputIins); + } + } + }) + ] + }), + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.TextInput, { + className: "input-guildicon", + key: "GUILDICON", + success: !data.removeIcon && data.url, + maxLength: 100000000000000000000, + value: data.url, + placeholder: BDFDB.GuildUtils.getIcon(guild.id), + disabled: data.removeIcon, + onChange: (value, instance) => { + this.checkUrl(value, instance); + } + }) + ] + }), + BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCN.marginbottom20, + children: [ + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Flex, { + className: BDFDB.disCN.marginbottom8, + align: BDFDB.LibraryComponents.Flex.Align.CENTER, + direction: BDFDB.LibraryComponents.Flex.Direction.HORIZONTAL, + children: [ + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.FormComponents.FormTitle, { + className: BDFDB.disCN.marginreset, + tag: BDFDB.LibraryComponents.FormComponents.FormTitle.Tags.H5, + children: this.labels.modal_guildbanner_text + }), + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SettingsItem, { + className: "input-removebanner", + type: "Switch", + grow: 0, + label: BDFDB.LanguageUtils.LanguageStrings.REMOVE, + tag: BDFDB.LibraryComponents.FormComponents.FormTitle.Tags.H5, + value: data.removeBanner && guild.id != "410787888507256842", + disabled: guild.id == "410787888507256842", + onChange: (value, instance) => { + let bannerInputIns = BDFDB.ReactUtils.findOwner(instance._reactInternalFiber.return.return, {key: "GUILDBANNER"}); + if (bannerInputIns) { + delete bannerInputIns.props.success; + delete bannerInputIns.props.errorMessage; + bannerInputIns.props.disabled = value; + BDFDB.ReactUtils.forceUpdate(bannerInputIns); + } + } + }) + ] + }), + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.TextInput, { + className: "input-guildbanner", + key: "GUILDBANNER", + success: !data.removeBanner && data.banner, + maxLength: 100000000000000000000, + value: data.banner, + placeholder: BDFDB.GuildUtils.getBanner(guild.id), + disabled: data.removeBanner || guild.id == "410787888507256842", + onChange: (value, instance) => { + this.checkUrl(value, instance); + } + }) + ] + }) + ] + }), + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.ModalComponents.ModalTabContent, { + tab: this.labels.modal_tabheader2_text, + children: [ + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.FormComponents.FormItem, { + title: this.labels.modal_colorpicker1_text, + className: BDFDB.disCN.marginbottom20, + children: [ + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.ColorSwatches, { + color: data.color1, + number: 1 + }) + ] + }), + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.FormComponents.FormItem, { + title: this.labels.modal_colorpicker2_text, + className: BDFDB.disCN.marginbottom20, + children: [ + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.ColorSwatches, { + color: data.color2, + number: 2 + }) + ] + }) + ] + }), + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.ModalComponents.ModalTabContent, { + tab: this.labels.modal_tabheader3_text, + children: [ + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.FormComponents.FormItem, { + title: this.labels.modal_colorpicker3_text, + className: BDFDB.disCN.marginbottom20, + children: [ + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.ColorSwatches, { + color: data.color3, + number: 3 + }) + ] + }), + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.FormComponents.FormItem, { + title: this.labels.modal_colorpicker4_text, + className: BDFDB.disCN.marginbottom20, + children: [ + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.ColorSwatches, { + color: data.color4, + number: 4 + }) + ] + }) + ] + }) + ], + buttons: [{ + contents: BDFDB.LanguageUtils.LanguageStrings.SAVE, + color: "BRAND", + close: true, + click: modal => { + let olddata = Object.assign({}, data); + + let guildnameinput = modal.querySelector(".input-guildname " + BDFDB.dotCN.input); + let guildacronyminput = modal.querySelector(".input-guildacronym " + BDFDB.dotCN.input); + let ignorecustomnameinput = modal.querySelector(".input-ignorecustomname " + BDFDB.dotCN.switchinner); + let guildiconinput = modal.querySelector(".input-guildicon " + BDFDB.dotCN.input); + let removeiconinput = modal.querySelector(".input-removeicon " + BDFDB.dotCN.switchinner); + let guildbannerinput = modal.querySelector(".input-guildbanner " + BDFDB.dotCN.input); + let removebannerinput = modal.querySelector(".input-removebanner " + BDFDB.dotCN.switchinner); + + data.name = guildnameinput.value.trim() || null; + data.shortName = guildacronyminput.value.trim() || null; + data.ignoreCustomName = ignorecustomnameinput.checked; + data.url = (!data.removeIcon && BDFDB.DOMUtils.containsClass(guildiconinput, BDFDB.disCN.inputsuccess) ? guildiconinput.value.trim() : null) || null; + data.removeIcon = removeiconinput.checked; + data.banner = (!data.removeBanner && BDFDB.DOMUtils.containsClass(guildbannerinput, BDFDB.disCN.inputsuccess) ? guildbannerinput.value.trim() : null) || null; + data.removeBanner = removebannerinput.checked && guild.id != "410787888507256842"; + + data.color1 = BDFDB.ColorUtils.getSwatchColor(modal, 1); + data.color2 = BDFDB.ColorUtils.getSwatchColor(modal, 2); + data.color3 = BDFDB.ColorUtils.getSwatchColor(modal, 3); + data.color4 = BDFDB.ColorUtils.getSwatchColor(modal, 4); + + let changed = false; + if (Object.keys(data).every(key => !data[key]) && (changed = true)) BDFDB.DataUtils.remove(this, "servers", guild.id); + else if (!BDFDB.equals(olddata, data) && (changed = true)) BDFDB.DataUtils.save(data, this, "servers", guild.id); + if (changed) BDFDB.ModuleUtils.forceAllUpdates(this);; + } + }] + }); + } + + checkUrl (url, instance) { + BDFDB.TimeUtils.clear(instance.checkTimeout); + if (url == null || !url.trim()) { + delete instance.props.success; + delete instance.props.errorMessage; + instance.forceUpdate(); + } + else instance.checkTimeout = BDFDB.TimeUtils.timeout(_ => { + BDFDB.LibraryRequires.request(url.trim(), (error, response, result) => { + if (response && response.headers["content-type"] && response.headers["content-type"].indexOf("image") != -1) { + instance.props.success = true; + delete instance.props.errorMessage; + } + else { + delete instance.props.success; + instance.props.errorMessage = this.labels.modal_invalidurl_text; + } + delete instance.checkTimeout; + instance.forceUpdate(); + }); + }, 1000); + } + + setBanner (id, data) { + data = data || {}; + let guild = BDFDB.LibraryModules.GuildStore.getGuild(id); + if (!guild) return; + if (guild.EditServersCachedBanner === undefined) guild.EditServersCachedBanner = guild.banner; + guild.banner = data.removeBanner ? null : (data.banner || guild.EditServersCachedBanner); + } + + setLabelsByLanguage () { + switch (BDFDB.LanguageUtils.getLanguage().id) { + case "hr": //croatian + return { + context_localserversettings_text: "Lokalne postavke poslužitelja", + submenu_serversettings_text: "Promijeni postavke", + submenu_resetsettings_text: "Ponovno postavite poslužitelj", + modal_header_text: "Lokalne postavke poslužitelja", + modal_guildname_text: "Naziv lokalnog poslužitelja", + modal_guildacronym_text: "Akronim lokalnog poslužitelja", + modal_ignorecustomname_text: "Koristite izvorno ime poslužitelja za akronim poslužitelja", + modal_guildicon_text: "Ikona", + modal_guildbanner_text: "Baner", + modal_tabheader1_text: "Poslužitelja", + modal_tabheader2_text: "Boja ikona", + modal_tabheader3_text: "Boja tooltip", + modal_colorpicker1_text: "Boja ikona", + modal_colorpicker2_text: "Boja fonta", + modal_colorpicker3_text: "Boja tooltip", + modal_colorpicker4_text: "Boja fonta", + modal_invalidurl_text: "Nevažeći URL" + }; + case "da": //danish + return { + context_localserversettings_text: "Lokal serverindstillinger", + submenu_serversettings_text: "Skift indstillinger", + submenu_resetsettings_text: "Nulstil server", + modal_header_text: "Lokal serverindstillinger", + modal_guildname_text: "Lokalt servernavn", + modal_guildacronym_text: "Lokalt serverakronym", + modal_ignorecustomname_text: "Brug det originale servernavn til serverens akronym", + modal_guildicon_text: "Ikon", + modal_guildbanner_text: "Banner", + modal_tabheader1_text: "Server", + modal_tabheader2_text: "Ikonfarve", + modal_tabheader3_text: "Tooltipfarve", + modal_colorpicker1_text: "Ikonfarve", + modal_colorpicker2_text: "Skriftfarve", + modal_colorpicker3_text: "Tooltipfarve", + modal_colorpicker4_text: "Skriftfarve", + modal_invalidurl_text: "Ugyldig URL" + }; + case "de": //german + return { + context_localserversettings_text: "Lokale Servereinstellungen", + submenu_serversettings_text: "Einstellungen ändern", + submenu_resetsettings_text: "Server zurücksetzen", + modal_header_text: "Lokale Servereinstellungen", + modal_guildname_text: "Lokaler Servername", + modal_guildacronym_text: "Lokales Serverkürzel", + modal_ignorecustomname_text: "Benutze den ursprünglichen Servernamen für das Serverkürzel", + modal_guildicon_text: "Icon", + modal_guildbanner_text: "Banner", + modal_tabheader1_text: "Server", + modal_tabheader2_text: "Iconfarbe", + modal_tabheader3_text: "Tooltipfarbe", + modal_colorpicker1_text: "Iconfarbe", + modal_colorpicker2_text: "Schriftfarbe", + modal_colorpicker3_text: "Tooltipfarbe", + modal_colorpicker4_text: "Schriftfarbe", + modal_invalidurl_text: "Ungültige URL" + }; + case "es": //spanish + return { + context_localserversettings_text: "Ajustes local de servidor", + submenu_serversettings_text: "Cambiar ajustes", + submenu_resetsettings_text: "Restablecer servidor", + modal_header_text: "Ajustes local de servidor", + modal_guildname_text: "Nombre local del servidor", + modal_guildacronym_text: "Acrónimo local del servidor", + modal_ignorecustomname_text: "Use el nombre del servidor original para el acrónimo del servidor", + modal_guildicon_text: "Icono", + modal_guildbanner_text: "Bandera", + modal_tabheader1_text: "Servidor", + modal_tabheader2_text: "Color del icono", + modal_tabheader3_text: "Color de tooltip", + modal_colorpicker1_text: "Color del icono", + modal_colorpicker2_text: "Color de fuente", + modal_colorpicker3_text: "Color de tooltip", + modal_colorpicker4_text: "Color de fuente", + modal_invalidurl_text: "URL inválida" + }; + case "fr": //french + return { + context_localserversettings_text: "Paramètres locale du serveur", + submenu_serversettings_text: "Modifier les paramètres", + submenu_resetsettings_text: "Réinitialiser le serveur", + modal_header_text: "Paramètres locale du serveur", + modal_guildname_text: "Nom local du serveur", + modal_guildacronym_text: "Acronyme local de serveur", + modal_ignorecustomname_text: "Utilisez le nom de serveur d'origine pour l'acronyme de serveur", + modal_guildicon_text: "Icône", + modal_guildbanner_text: "Bannière", + modal_tabheader1_text: "Serveur", + modal_tabheader2_text: "Couleur de l'icône", + modal_tabheader3_text: "Couleur de tooltip", + modal_colorpicker1_text: "Couleur de l'icône", + modal_colorpicker2_text: "Couleur de la police", + modal_colorpicker3_text: "Couleur de tooltip", + modal_colorpicker4_text: "Couleur de la police", + modal_invalidurl_text: "URL invalide" + }; + case "it": //italian + return { + context_localserversettings_text: "Impostazioni locale server", + submenu_serversettings_text: "Cambia impostazioni", + submenu_resetsettings_text: "Ripristina server", + modal_header_text: "Impostazioni locale server", + modal_guildname_text: "Nome locale server", + modal_guildacronym_text: "Acronimo locale server", + modal_ignorecustomname_text: "Utilizzare il nome del server originale per l'acronimo del server", + modal_guildicon_text: "Icona", + modal_guildbanner_text: "Bandiera", + modal_tabheader1_text: "Server", + modal_tabheader2_text: "Colore dell'icona", + modal_tabheader3_text: "Colore della tooltip", + modal_colorpicker1_text: "Colore dell'icona", + modal_colorpicker2_text: "Colore del carattere", + modal_colorpicker3_text: "Colore della tooltip", + modal_colorpicker4_text: "Colore del carattere", + modal_invalidurl_text: "URL non valido" + }; + case "nl": //dutch + return { + context_localserversettings_text: "Lokale serverinstellingen", + submenu_serversettings_text: "Verandere instellingen", + submenu_resetsettings_text: "Reset server", + modal_header_text: "Lokale serverinstellingen", + modal_guildname_text: "Lokale servernaam", + modal_guildacronym_text: "Lokale server acroniem", + modal_ignorecustomname_text: "Gebruik de oorspronkelijke servernaam voor het serveracrononiem", + modal_guildicon_text: "Icoon", + modal_guildbanner_text: "Banier", + modal_tabheader1_text: "Server", + modal_tabheader2_text: "Icoonkleur", + modal_tabheader3_text: "Tooltipkleur", + modal_colorpicker1_text: "Icoonkleur", + modal_colorpicker2_text: "Doopvontkleur", + modal_colorpicker3_text: "Tooltipkleur", + modal_colorpicker4_text: "Doopvontkleur", + modal_invalidurl_text: "Ongeldige URL" + }; + case "no": //norwegian + return { + context_localserversettings_text: "Lokal serverinnstillinger", + submenu_serversettings_text: "Endre innstillinger", + submenu_resetsettings_text: "Tilbakestill server", + modal_header_text: "Lokal serverinnstillinger", + modal_guildname_text: "Lokalt servernavn", + modal_guildacronym_text: "Lokalt serverforkortelse", + modal_ignorecustomname_text: "Bruk det originale servernavnet til serverforkortelsen", + modal_guildicon_text: "Ikon", + modal_guildbanner_text: "Banner", + modal_tabheader1_text: "Server", + modal_tabheader2_text: "Ikonfarge", + modal_tabheader3_text: "Tooltipfarge", + modal_colorpicker1_text: "Ikonfarge", + modal_colorpicker2_text: "Skriftfarge", + modal_colorpicker3_text: "Tooltipfarge", + modal_colorpicker4_text: "Skriftfarge", + modal_invalidurl_text: "Ugyldig URL" + }; + case "pl": //polish + return { + context_localserversettings_text: "Lokalne ustawienia serwera", + submenu_serversettings_text: "Zmień ustawienia", + submenu_resetsettings_text: "Resetuj ustawienia", + modal_header_text: "Lokalne ustawienia serwera", + modal_guildname_text: "Lokalna nazwa serwera", + modal_guildacronym_text: "Akronim lokalnego serwera", + modal_ignorecustomname_text: "Użyj oryginalnej nazwy serwera dla akronimu serwera", + modal_guildicon_text: "Ikona", + modal_guildbanner_text: "Baner", + modal_tabheader1_text: "Serwer", + modal_tabheader2_text: "Kolor ikony", + modal_tabheader3_text: "Kolor podpowiedzi", + modal_colorpicker1_text: "Kolor ikony", + modal_colorpicker2_text: "Kolor czcionki", + modal_colorpicker3_text: "Kolor podpowiedzi", + modal_colorpicker4_text: "Kolor czcionki", + modal_invalidurl_text: "Nieprawidłowe URL" + }; + case "pt-BR": //portuguese (brazil) + return { + context_localserversettings_text: "Configurações local do servidor", + submenu_serversettings_text: "Mudar configurações", + submenu_resetsettings_text: "Redefinir servidor", + modal_header_text: "Configurações local do servidor", + modal_guildname_text: "Nome local do servidor", + modal_guildacronym_text: "Acrônimo local de servidor", + modal_ignorecustomname_text: "Use o nome do servidor original para a sigla do servidor", + modal_guildicon_text: "Icone", + modal_guildbanner_text: "Bandeira", + modal_tabheader1_text: "Servidor", + modal_tabheader2_text: "Cor do ícone", + modal_tabheader3_text: "Cor da tooltip", + modal_colorpicker1_text: "Cor do ícone", + modal_colorpicker2_text: "Cor da fonte", + modal_colorpicker3_text: "Cor da tooltip", + modal_colorpicker4_text: "Cor da fonte", + modal_invalidurl_text: "URL inválida" + }; + case "fi": //finnish + return { + context_localserversettings_text: "Paikallinen palvelimen asetukset", + submenu_serversettings_text: "Vaihda asetuksia", + submenu_resetsettings_text: "Nollaa palvelimen", + modal_header_text: "Paikallinen palvelimen asetukset", + modal_guildname_text: "Paikallinen palvelimenimi", + modal_guildacronym_text: "Paikallisen palvelimen lyhenne", + modal_ignorecustomname_text: "Käytä alkuperäistä palvelimen nimeä palvelimen lyhenteessä", + modal_guildicon_text: "Ikonin", + modal_guildbanner_text: "Banneri", + modal_tabheader1_text: "Palvelimen", + modal_tabheader2_text: "Ikoninväri", + modal_tabheader3_text: "Tooltipväri", + modal_colorpicker1_text: "Ikoninväri", + modal_colorpicker2_text: "Fontinväri", + modal_colorpicker3_text: "Tooltipväri", + modal_colorpicker4_text: "Fontinväri", + modal_invalidurl_text: "Virheellinen URL" + }; + case "sv": //swedish + return { + context_localserversettings_text: "Lokal serverinställningar", + submenu_serversettings_text: "Ändra inställningar", + submenu_resetsettings_text: "Återställ server", + modal_header_text: "Lokal serverinställningar", + modal_guildname_text: "Lokalt servernamn", + modal_guildacronym_text: "Lokal server förkortning", + modal_ignorecustomname_text: "Använd det ursprungliga servernamnet för serverförkortningen", + modal_guildicon_text: "Ikon", + modal_guildbanner_text: "Banderoll", + modal_tabheader1_text: "Server", + modal_tabheader2_text: "Ikonfärg", + modal_tabheader3_text: "Tooltipfärg", + modal_colorpicker1_text: "Ikonfärg", + modal_colorpicker2_text: "Fontfärg", + modal_colorpicker3_text: "Tooltipfärg", + modal_colorpicker4_text: "Fontfärg", + modal_invalidurl_text: "Ogiltig URL" + }; + case "tr": //turkish + return { + context_localserversettings_text: "Yerel Sunucu Ayarları", + submenu_serversettings_text: "Ayarları Değiştir", + submenu_resetsettings_text: "Sunucu Sıfırla", + modal_header_text: "Yerel sunucu ayarları", + modal_guildname_text: "Yerel sunucu adı", + modal_guildacronym_text: "Yerel sunucu kısaltması", + modal_ignorecustomname_text: "Sunucu kısaltması için orijinal sunucu adını kullanın", + modal_guildicon_text: "Simge", + modal_guildbanner_text: "Afişi", + modal_tabheader1_text: "Sunucu", + modal_tabheader2_text: "Simge rengi", + modal_tabheader3_text: "Tooltip rengi", + modal_colorpicker1_text: "Simge rengi", + modal_colorpicker2_text: "Yazı rengi", + modal_colorpicker3_text: "Tooltip rengi", + modal_colorpicker4_text: "Yazı rengi", + modal_invalidurl_text: "Geçersiz URL" + }; + case "cs": //czech + return { + context_localserversettings_text: "Místní nastavení serveru", + submenu_serversettings_text: "Změnit nastavení", + submenu_resetsettings_text: "Obnovit server", + modal_header_text: "Místní nastavení serveru", + modal_guildname_text: "Místní název serveru", + modal_guildacronym_text: "Zkratka místního serveru", + modal_ignorecustomname_text: "Pro zkratku serveru použijte původní název serveru", + modal_guildicon_text: "Ikony", + modal_guildbanner_text: "Prapor", + modal_tabheader1_text: "Server", + modal_tabheader2_text: "Barva ikony", + modal_tabheader3_text: "Barva tooltip", + modal_colorpicker1_text: "Barva ikony", + modal_colorpicker2_text: "Barva fontu", + modal_colorpicker3_text: "Barva tooltip", + modal_colorpicker4_text: "Barva fontu", + modal_invalidurl_text: "Neplatná URL" + }; + case "bg": //bulgarian + return { + context_localserversettings_text: "Настройки за локални cървър", + submenu_serversettings_text: "Промяна на настройките", + submenu_resetsettings_text: "Възстановяване на cървър", + modal_header_text: "Настройки за локални cървър", + modal_guildname_text: "Локално име на cървър", + modal_guildacronym_text: "Акроним на локалния сървър", + modal_ignorecustomname_text: "Използвайте оригиналното име на сървъра за съкращението на сървъра", + modal_guildicon_text: "Икона", + modal_guildbanner_text: "Знаме", + modal_tabheader1_text: "Cървър", + modal_tabheader2_text: "Цвят на иконата", + modal_tabheader3_text: "Цвят на подсказка", + modal_colorpicker1_text: "Цвят на иконата", + modal_colorpicker2_text: "Цвят на шрифта", + modal_colorpicker3_text: "Цвят на подсказка", + modal_colorpicker4_text: "Цвят на шрифта", + modal_invalidurl_text: "Невалиден URL" + }; + case "ru": //russian + return { + context_localserversettings_text: "Настройки локального cервер", + submenu_serversettings_text: "Изменить настройки", + submenu_resetsettings_text: "Сбросить cервер", + modal_header_text: "Настройки локального cервер", + modal_guildname_text: "Имя локального cервер", + modal_guildacronym_text: "Акроним локального сервера", + modal_ignorecustomname_text: "Используйте оригинальное имя сервера для сокращения сервера", + modal_guildicon_text: "Значок", + modal_guildbanner_text: "Баннер", + modal_tabheader1_text: "Cервер", + modal_tabheader2_text: "Цвет значков", + modal_tabheader3_text: "Цвет подсказка", + modal_colorpicker1_text: "Цвет значков", + modal_colorpicker2_text: "Цвет шрифта", + modal_colorpicker3_text: "Цвет подсказка", + modal_colorpicker4_text: "Цвет шрифта", + modal_invalidurl_text: "Неверная URL" + }; + case "uk": //ukrainian + return { + context_localserversettings_text: "Налаштування локального cервер", + submenu_serversettings_text: "Змінити налаштування", + submenu_resetsettings_text: "Скидання cервер", + modal_header_text: "Налаштування локального cервер", + modal_guildname_text: "Локальне ім'я cервер", + modal_guildacronym_text: "Акронім локального сервера", + modal_ignorecustomname_text: "Використовуйте оригінальне ім'я сервера для абревіатури сервера", + modal_guildicon_text: "Іконка", + modal_guildbanner_text: "Банер", + modal_tabheader1_text: "Cервер", + modal_tabheader2_text: "Колір ікони", + modal_tabheader3_text: "Колір підказка", + modal_colorpicker1_text: "Колір ікони", + modal_colorpicker2_text: "Колір шрифту", + modal_colorpicker3_text: "Колір підказка", + modal_colorpicker4_text: "Колір шрифту", + modal_invalidurl_text: "Недійсна URL" + }; + case "ja": //japanese + return { + context_localserversettings_text: "ローカルサーバー設定", + submenu_serversettings_text: "設定を変更する", + submenu_resetsettings_text: "サーバーをリセットする", + modal_header_text: "ローカルサーバー設定", + modal_guildname_text: "ローカルサーバー名", + modal_guildacronym_text: "ローカルサーバーの頭字語", + modal_ignorecustomname_text: "サーバーの頭字語に元のサーバー名を使用する", + modal_guildicon_text: "アイコン", + modal_guildbanner_text: "バナー", + modal_tabheader1_text: "サーバー", + modal_tabheader2_text: "アイコンの色", + modal_tabheader3_text: "ツールチップの色", + modal_colorpicker1_text: "アイコンの色", + modal_colorpicker2_text: "フォントの色", + modal_colorpicker3_text: "ツールチップの色", + modal_colorpicker4_text: "フォントの色", + modal_invalidurl_text: "無効な URL" + }; + case "zh-TW": //chinese (traditional) + return { + context_localserversettings_text: "本地服務器設置", + submenu_serversettings_text: "更改設置", + submenu_resetsettings_text: "重置服務器", + modal_header_text: "本地服務器設置", + modal_guildname_text: "服務器名稱", + modal_guildacronym_text: "本地服務器縮寫", + modal_ignorecustomname_text: "使用原始服務器名稱作為服務器首字母縮寫", + modal_guildicon_text: "圖標", + modal_guildbanner_text: "旗幟", + modal_tabheader1_text: "服務器", + modal_tabheader2_text: "圖標顏色", + modal_tabheader3_text: "工具提示顏色", + modal_colorpicker1_text: "圖標顏色", + modal_colorpicker2_text: "字體顏色", + modal_colorpicker3_text: "工具提示顏色", + modal_colorpicker4_text: "字體顏色", + modal_invalidurl_text: "無效的 URL" + }; + case "ko": //korean + return { + context_localserversettings_text: "로컬 서버 설정", + submenu_serversettings_text: "설정 변경", + submenu_resetsettings_text: "서버 재설정", + modal_header_text: "로컬 서버 설정", + modal_guildname_text: "로컬 서버 이름", + modal_guildacronym_text: "로컬 서버 약어", + modal_ignorecustomname_text: "서버 약어에 원래 서버 이름을 사용하십시오", + modal_guildicon_text: "상", + modal_guildbanner_text: "기치", + modal_tabheader1_text: "서버", + modal_tabheader2_text: "상 색깔", + modal_tabheader3_text: "툴팁 색깔", + modal_colorpicker1_text: "상 색깔", + modal_colorpicker2_text: "글꼴 색깔", + modal_colorpicker3_text: "툴팁 색깔", + modal_colorpicker4_text: "글꼴 색깔", + modal_invalidurl_text: "잘못된 URL" + }; + default: //default: english + return { + context_localserversettings_text: "Local Serversettings", + submenu_serversettings_text: "Change Settings", + submenu_resetsettings_text: "Reset Server", + modal_header_text: "Local Serversettings", + modal_guildname_text: "Local Servername", + modal_guildacronym_text: "Local Serveracronym", + modal_ignorecustomname_text: "Use the original Servername for the Serveracronym", + modal_guildicon_text: "Icon", + modal_guildbanner_text: "Banner", + modal_tabheader1_text: "Server", + modal_tabheader2_text: "Iconcolor", + modal_tabheader3_text: "Tooltipcolor", + modal_colorpicker1_text: "Iconcolor", + modal_colorpicker2_text: "Fontcolor", + modal_colorpicker3_text: "Tooltipcolor", + modal_colorpicker4_text: "Fontcolor", + modal_invalidurl_text: "Invalid URL" + }; + } + } + } +})();
\ No newline at end of file diff --git a/.config/BetterDiscord/plugins/NotificationSounds.config.json b/.config/BetterDiscord/plugins/NotificationSounds.config.json new file mode 100644 index 0000000..5101ee4 --- /dev/null +++ b/.config/BetterDiscord/plugins/NotificationSounds.config.json @@ -0,0 +1,356 @@ +{ + "audios": { + "---": { + "---": null + }, + "Default": { + "Communication Channel": "https://notificationsounds.com/soundfiles/63538fe6ef330c13a05a3ed7e599d5f7/file-sounds-917-communication-channel.wav", + "Isn't it": "https://notificationsounds.com/soundfiles/ba2fd310dcaa8781a9a652a31baf3c68/file-sounds-969-isnt-it.wav", + "Job Done": "https://notificationsounds.com/soundfiles/5b69b9cb83065d403869739ae7f0995e/file-sounds-937-job-done.wav", + "Served": "https://notificationsounds.com/soundfiles/b337e84de8752b27eda3a12363109e80/file-sounds-913-served.wav", + "Solemn": "https://notificationsounds.com/soundfiles/53fde96fcc4b4ce72d7739202324cd49/file-sounds-882-solemn.wav", + "System Fault": "https://notificationsounds.com/soundfiles/ebd9629fc3ae5e9f6611e2ee05a31cef/file-sounds-990-system-fault.wav", + "You wouldn't believe": "https://notificationsounds.com/soundfiles/087408522c31eeb1f982bc0eaf81d35f/file-sounds-949-you-wouldnt-believe.wav" + }, + "Discord": { + "HotKeys Window Down": "/assets/71f048f8aa7d4b24bf4268a87cbbb192.mp3", + "HotKeys Window Left": "/assets/1de04408e62b5d52ae3ebbb91e9e1978.mp3", + "HotKeys Window Right": "/assets/2c0433f93db8449e4a82b76dc520cb29.mp3", + "HotKeys Window Up": "/assets/68472713f7a62c7c37e0a6a5d5a1faeb.mp3", + "Human Man Voice": "/assets/a37dcd6272ae41cf49295d58c9806fe3.mp3", + "Incoming Call": "/assets/84a1b4e11d634dbfa1e5dd97a96de3ad.mp3", + "Incoming Call Beat": "/assets/b9411af07f154a6fef543e7e442e4da9.mp3", + "Mention Ping": "/assets/fa4d62c3cbc80733bf1f01b9c6f181de.mp3", + "Mention Ping 2": "/assets/a5f42064e8120e381528b14fd3188b72.mp3", + "Mention Ping 3": "/assets/84c9fa3d07da865278bd77c97d952db4.mp3", + "New Chatmessage": "/assets/dd920c06a01e5bb8b09678581e29d56f.mp3", + "New Chatmessage 2": "/assets/15fe810f6cfab609c7fcda61652b9b34.mp3", + "New Chatmessage 3": "/assets/53ce6a92d3c233e8b4ac529d34d374e4.mp3", + "Outgoing Call": "/assets/c6e92752668dde4eee5923d70441579f.mp3", + "Overlay Unlocked": "/assets/ad322ffe0a88436296158a80d5d11baa.mp3", + "Push2Talk Start": "/assets/8b63833c8d252fedba6b9c4f2517c705.mp3", + "Push2Talk Stop": "/assets/74ab980d6890a0fa6aa0336182f9f620.mp3", + "Robot Man Voice": "/assets/66598bea6e59eb8acdf32cf2d9d75ba9.mp3", + "Stream Ended": "/assets/4e30f98aa537854f79f49a76af822bbc.mp3", + "Stream Started": "/assets/9ca817f41727edc1b2f1bc4f1911107c.mp3", + "Stream User Joined": "/assets/5827bbf9a67c61cbb0e02ffbf434b654.mp3", + "Stream User Left": "/assets/7cdcdcbc426cc43583365a671c24b740.mp3", + "Unknown": "/assets/ae7d16bb2eea76b9b9977db0fad66658.mp3", + "Voicechat Deafen": "/assets/e4d539271704b87764dc465b1a061abd.mp3", + "Voicechat Disconnect": "/assets/7e125dc075ec6e5ae796e4c3ab83abb3.mp3", + "Voicechat Mute": "/assets/429d09ee3b86e81a75b5e06d3fb482be.mp3", + "Voicechat Reconnect": "/assets/471cfd0005b112ff857705e894bf41a6.mp3", + "Voicechat Undeafen": "/assets/5a000a0d4dff083d12a1d4fc2c7cbf66.mp3", + "Voicechat Unmute": "/assets/43805b9dd757ac4f6b9b58c1a8ee5f0d.mp3", + "Voicechat User Joined": "/assets/5dd43c946894005258d85770f0d10cff.mp3", + "Voicechat User Left": "/assets/4fcfeb2cba26459c4750e60f626cebdc.mp3", + "Voicechat User Moved": "/assets/e81d11590762728c1b811eadfa5be766.mp3" + }, + "Google": { + "Cyclist": "data:audio/mpeg;base64,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", + "Crosswalk": "data:audio/mpeg;base64,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", + "Bubble": "data:audio/mpeg;base64,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" + } + }, + "changelog": { + "currentversion": "3.4.5" + }, + "choices": { + "message1": { + "category": "Google", + "focus": null, + "mute": true, + "song": "Cyclist", + "src": "data:audio/mpeg;base64,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", + "volume": 100 + }, + "dm": { + "category": "Discord", + "focus": true, + "mute": true, + "song": "New Chatmessage 3", + "src": "/assets/53ce6a92d3c233e8b4ac529d34d374e4.mp3", + "volume": 100 + }, + "mentioned": { + "category": "Google", + "focus": true, + "mute": true, + "song": "Crosswalk", + "src": "data:audio/mpeg;base64,T2dnUwACAAAAAAAAAACKvWM5AAAAAPdrL7YBHgF2b3JiaXMAAAAAAYC7AAAAAAAAgDgBAAAAAAC4AU9nZ1MAAAAAAAAAAAAAir1jOQEAAAA6LNkzDqf///////////////+BA3ZvcmJpczUAAABYaXBoLk9yZyBsaWJWb3JiaXMgSSAyMDE4MDMxNiAoTm93IDEwMCUgZmV3ZXIgc2hlbGxzKQIAAAASAAAAQU5EUk9JRF9MT09QPWZhbHNlSAAAAFRJVExFPWFuZHJvaWQucmVzb3VyY2U6Ly9jb20uZ29vZ2xlLmFuZHJvaWQuc291bmRwaWNrZXIvc3RyaW5nL2Nyb3Nzd2FsawEFdm9yYmlzIkJDVgEAQAAAJHMYKkalcxaEEBpCUBnjHELOa+wZQkwRghwyTFvLJXOQIaSgQohbKIHQkFUAAEAAAIdBeBSEikEIIYQlPViSgyc9CCGEiDl4FIRpQQghhBBCCCGEEEIIIYRFOWiSgydBCB2E4zA4DIPlOPgchEU5WBCDJ0HoIIQPQriag6w5CCGEJDVIUIMGOegchMIsKIqCxDC4FoQENSiMguQwyNSDC0KImoNJNfgahGdBeBaEaUEIIYQkQUiQgwZByBiERkFYkoMGObgUhMtBqBqEKjkIH4QgNGQVAJAAAKCiKIqiKAoQGrIKAMgAABBAURTHcRzJkRzJsRwLCA1ZBQAAAQAIAACgSIqkSI7kSJIkWZIlWZIlWZLmiaosy7Isy7IsyzIQGrIKAEgAAFBRDEVxFAcIDVkFAGQAAAigOIqlWIqlaIrniI4IhIasAgCAAAAEAAAQNENTPEeURM9UVde2bdu2bdu2bdu2bdu2bVuWZRkIDVkFAEAAABDSaWapBogwAxkGQkNWAQAIAACAEYowxIDQkFUAAEAAAIAYSg6iCa0535zjoFkOmkqxOR2cSLV5kpuKuTnnnHPOyeacMc4555yinFkMmgmtOeecxKBZCpoJrTnnnCexedCaKq0555xxzulgnBHGOeecJq15kJqNtTnnnAWtaY6aS7E555xIuXlSm0u1Oeecc84555xzzjnnnOrF6RycE84555yovbmWm9DFOeecT8bp3pwQzjnnnHPOOeecc84555wgNGQVAAAEAEAQho1h3CkI0udoIEYRYhoy6UH36DAJGoOcQurR6GiklDoIJZVxUkonCA1ZBQAAAgBACCGFFFJIIYUUUkghhRRiiCGGGHLKKaeggkoqqaiijDLLLLPMMssss8w67KyzDjsMMcQQQyutxFJTbTXWWGvuOeeag7RWWmuttVJKKaWUUgpCQ1YBACAAAARCBhlkkFFIIYUUYogpp5xyCiqogNCQVQAAIACAAAAAAE/yHNERHdERHdERHdERHdHxHM8RJVESJVESLdMyNdNTRVV1ZdeWdVm3fVvYhV33fd33fd34dWFYlmVZlmVZlmVZlmVZlmVZliA0ZBUAAAIAACCEEEJIIYUUUkgpxhhzzDnoJJQQCA1ZBQAAAgAIAAAAcBRHcRzJkRxJsiRL0iTN0ixP8zRPEz1RFEXTNFXRFV1RN21RNmXTNV1TNl1VVm1Xlm1btnXbl2Xb933f933f933f933f931dB0JDVgEAEgAAOpIjKZIiKZLjOI4kSUBoyCoAQAYAQAAAiuIojuM4kiRJkiVpkmd5lqiZmumZniqqQGjIKgAAEABAAAAAAAAAiqZ4iql4iqh4juiIkmiZlqipmivKpuy6ruu6ruu6ruu6ruu6ruu6ruu6ruu6ruu6ruu6ruu6ruu6rguEhqwCACQAAHQkR3IkR1IkRVIkR3KA0JBVAIAMAIAAABzDMSRFcizL0jRP8zRPEz3REz3TU0VXdIHQkFUAACAAgAAAAAAAAAzJsBTL0RxNEiXVUi1VUy3VUkXVU1VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVU3TNE0TCA1ZCQAAAQDQWnPMrZeOQeisl8gopKDXTjnmpNfMKIKc5xAxY5jHUjFDDMaWQYSUBUJDVgQAUQAAgDHIMcQccs5J6iRFzjkqHaXGOUepo9RRSrGmWjtKpbZUa+Oco9RRyiilWkurHaVUa6qxAACAAAcAgAALodCQFQFAFAAAgQxSCimFlGLOKeeQUso55hxiijmnnGPOOSidlMo5J52TEimlnGPOKeeclM5J5pyT0kkoAAAgwAEAIMBCKDRkRQAQJwDgcBxNkzRNFCVNE0VPFF3XE0XVlTTNNDVRVFVNFE3VVFVZFk1VliVNM01NFFVTE0VVFVVTlk1VtWXPNG3ZVFXdFlXVtmVb9n1XlnXdM03ZFlXVtk1VtXVXlnVdtm3dlzTNNDVRVFVNFFXXVFXbNlXVtjVRdF1RVWVZVFVZdl1Z11VX1n1NFFXVU03ZFVVVllXZ1WVVlnVfdFXdVl3Z11VZ1n3b1oVf1n3CqKq6bsqurquyrPuyLvu67euUSdNMUxNFVdVEUVVNV7VtU3VtWxNF1xVV1ZZFU3VlVZZ9X3Vl2ddE0XVFVZVlUVVlWZVlXXdlV7dFVdVtVXZ933RdXZd1XVhmW/eF03V1XZVl31dlWfdlXcfWdd/3TNO2TdfVddNVdd/WdeWZbdv4RVXVdVWWhV+VZd/XheF5bt0XnlFVdd2UXV9XZVkXbl832r5uPK9tY9s+sq8jDEe+sCxd2za6vk2Ydd3oG0PhN4Y007Rt01V13XRdX5d13WjrulBUVV1XZdn3VVf2fVv3heH2fd8YVdf3VVkWhtWWnWH3faXuC5VVtoXf1nXnmG1dWH7j6Py+MnR1W2jrurHMvq48u3F0hj4CAAAGHAAAAkwoA4WGrAgA4gQAGIScQ0xBiBSDEEJIKYSQUsQYhMw5KRlzUkIpqYVSUosYg5A5JiVzTkoooaVQSkuhhNZCKbGFUlpsrdWaWos1hNJaKKW1UEqLqaUaW2s1RoxByJyTkjknpZTSWiiltcw5Kp2DlDoIKaWUWiwpxVg5JyWDjkoHIaWSSkwlpRhDKrGVlGIsKcXYWmy5xZhzKKXFkkpsJaVYW0w5thhzjhiDkDknJXNOSiiltVJSa5VzUjoIKWUOSiopxVhKSjFzTkoHIaUOQkolpRhTSrGFUmIrKdVYSmqxxZhzSzHWUFKLJaUYS0oxthhzbrHl1kFoLaQSYyglxhZjrq21GkMpsZWUYiwp1RZjrb3FmHMoJcaSSo0lpVhbjbnGGHNOseWaWqy5xdhrbbn1mnPQqbVaU0y5thhzjrkFWXPuvYPQWiilxVBKjK21WluMOYdSYisp1VhKirXFmHNrsfZQSowlpVhLSjW2GGuONfaaWqu1xZhrarHmmnPvMebYU2s1txhrTrHlWnPuvebWYwEAAAMOAAABJpSBQkNWAgBRAAAEIUoxBqFBiDHnpDQIMeaclIox5yCkUjHmHIRSMucglJJS5hyEUlIKpaSSUmuhlFJSaq0AAIACBwCAABs0JRYHKDRkJQCQCgBgcBzL8jxRNFXZdizJ80TRNFXVth3L8jxRNE1VtW3L80TRNFXVdXXd8jxRNFVVdV1d90RRNVXVdWVZ9z1RNFVVdV1Z9n3TVFXVdWVZtoVfNFVXdV1ZlmXfWF3VdWVZtnVbGFbVdV1Zlm1bN4Zb13Xd94VhOTq3buu67/vC8TvHAADwBAcAoAIbVkc4KRoLLDRkJQCQAQBAGIOQQUghgxBSSCGlEFJKCQAAGHAAAAgwoQwUGrISAIgCAAAIkVJKKY2UUkoppZFSSimllBJCCCGEEEIIIYQQQgghhBBCCCGEEEIIIYQQQgghhBBCCAUA+E84APg/2KApsThAoSErAYBwAADAGKWYcgw6CSk1jDkGoZSUUmqtYYwxCKWk1FpLlXMQSkmptdhirJyDUFJKrcUaYwchpdZarLHWmjsIKaUWa6w52BxKaS3GWHPOvfeQUmsx1lpz772X1mKsNefcgxDCtBRjrrn24HvvKbZaa809+CCEULHVWnPwQQghhIsx99yD8D0IIVyMOecehPDBB2EAAHeDAwBEgo0zrCSdFY4GFxqyEgAICQAgEGKKMeecgxBCCJFSjDnnHIQQQiglUoox55yDDkIIJWSMOecchBBCKKWUjDHnnIMQQgmllJI55xyEEEIopZRSMueggxBCCaWUUkrnHIQQQgillFJK6aCDEEIJpZRSSikhhBBCCaWUUkopJYQQQgmllFJKKaWEEEoopZRSSimllBBCKaWUUkoppZQSQiillFJKKaWUkkIppZRSSimllFJSKKWUUkoppZRSSgmllFJKKaWUlFJJBQAAHDgAAAQYQScZVRZhowkXHoBCQ1YCAEAAABTEVlOJnUHMMWepIQgxqKlCSimGMUPKIKYpUwohhSFziiECocVWS8UAAAAQBAAICAkAMEBQMAMADA4QPgdBJ0BwtAEACEJkhkg0LASHB5UAETEVACQmKOQCQIXFRdrFBXQZ4IIu7joQQhCCEMTiAApIwMEJNzzxhifc4ASdolIHAQAAAABgAAAPAADHBRAR0RxGhsYGR4fHB0hIAAAAAAC4AMAHAMAhAkRENIeRobHB0eHxARISAAAAAAAAAAAABAQEAAAAAAACAAAABARPZ2dTAABAaQAAAAAAAIq9YzkCAAAA7Mjily8oKZWZqqazGx4hICUnKZKQp6urHB4iHyYoKZeZqKenHR8gHicpKoVNVlpxgVZWVtzQT6lK3aY6hCTxrHzcbybLBae+H/7gvJlaHnnA98/6j1Sv9n+OfwEU7bNXZ8BVfy6ac/Y+A5h8v31eg9VEbTIrauvfV89Dc8XTdy48ZZzsADpX3YyPzaRvfYqQXhc5t1nf7iBujNuTY9zcntyZTRecoJOd59kMkMIqCAQDwMO31ug7xu12iZE0ab6U7O8YtLduHN5squlD43r7dO8dherqF1XVV79dXdUZCRV75CL0ZadLmkDM/lj99myzAACAswAAQK21Hn7/h29xNxgAwLx83r19+u581ztg6N05JCiATHQkFpAmPrY8b/0HENCgNjyAiNzU6JjADERbckaCCAYo5cxc5gj+ZM7Xz7bsg+Cj65+6/mHb6lpc9osD9+FmYDDoIzeBo3rXUD1P87JlgSitkjivR+7E9EltTxlZXbI/903RLpJuaZFsNUwMZFVL431VVKC0yww+xIulXzPHIllGY7nFEst/vdlc7ZBv4eVfEZLaqivtxvRqvXNsmWACHrbkLq9v+snukudH0ibZVytuHM0gtusjM8PGRSiKYKm39SX2i1S0V5JTnh88Rn7kArcaH8cd2iTcGs75b3Rb6Yc2KWByklvLfnFOh650fSBLH3hmrLx4asqRLHjfLSqiAORW39tb2UAeoeseaPV8Hl25DwZ9XyYccnWDsK1kbOg+Q5jFYT3l/kor1Dbi3FrtCgUBdZEWtuWopjlLWG+6yMmd2bueTZ8PeAD+tbT3t94Qo7kfxfbVihuxfYjhCK0xVh1KEoNlx86+tneP+VU/1Wrs30/R90WrHtrBHKA7rZ7cXnmp+7zlaHw5nu3CNzATo6pX3Wm/0+rfmkzytlQviVfo5Io/f4hw8ODka2US4vaeWznYxBpJvh+zEy15KmnSdyqjO+9beAn1j/Q3E8QxylcqbIKnu8Jn9IudyNCOJqhp042QpRVV1tltx9I7YwFoFrbkbq+v+chcgp+PYJt7NePZo7e8Mo6e2KxXTQCQGWvPY0EES8Myk9zGaoJN07VN+zdt7wRODWVfvmfWNzGa+edsjmiT8pMKiB3K2/v+XogryJp1OJKwYwQG5Ix3t7XaD81ut2vIALCN337IMggBUeFo+88YxizPsVXLOqnJHPbX3nfCm66YfuaAZop3ll1YvUPrcdWTyCU5N7Wu7wgj4nIriqer1L9uhArfCnfpDv4aBQCE0JhefPA9mQ0gYO/pQiZ0YlPym/Wr9F2vuwJ80K5/ZfrhNOPgQMNolnDXKNps+hiHBARh+xlhlQaEzpWFUrBYV3sONoUHANCY1ZtpjKeACjeKHlZsIaZUnAGE0FZ/J1w49RhI4ZwA/MKXoxpfrCo4i+b8fCM3pZ4SFoTQU6tK/77J0HXqTECSY1DtkYpSwY1+xSb1+txwDbF1EeoJ4gE87VNPD2betGWtawrafs8bhg1WTg3aP279KCfHWqmvBzk5fK6ONw/87lPlM+d/d3OPaqcAuGKAZEsAAF/e7DVREBrV/7sEYyDx2FjvQRfATxpH3Yzbj379MzvkdH9J/QSu+bRHHjeMMYzbn5pMY6SCpAApBhHBAFoLJt6cLJ8vx/j87f/eWtKQr08aWF1dXV39p/90Ffqq5ptVFJaWTfZHS2bZbCZLy9XVL6UaAABwVisvb6mvm+au1XsHAMhKPbx+szE97ggAf0cHL1lVtR2AhXOoAhOIMwqISUzT10zF9sICPracH9PPHmTgNS27pjhgt2C0JSEArMTef9m4bnQFf8BVH27MasqhFp0MhC9AcDre7viCTMj9ZackGTiBgJqIs3R+bMdagTYa0w1a5Hk6f3PXm5Gp9nE3Cg4isJtvFUIfGuwYEFewVr65jVN8v/oIdsDFRGrMdYjNoVvHYYuviGK3N8J82fsC7LfeTBWTytRNHrbkj6e+lsiWvH9r2nT214obWnZb9WbHDBsjlCCQhvZ/lawttbok52g92OqHn8GYbaudWsp6tJYF0KiHkf7PSL/8TiT+1Ch+TQTIbDfgujX3ne4yrpWF2KY1UDhGSwCALPNDPZIByGzLiQaYZkHcX3j9zAYhwrFjgsqjkKFeD3sNhilpVt48+VmtB5ZUQqj1ut/VN4/eN8PfNUMaRLkuRRmhuNUtswEetlTOp94GMornozg82asVj9hOcxuzYEPPADSurkZbksCyk85bcp7Eo/djT+160CLW3GC9Q2VEWq1T1StS+tqrxZdTH3z7vPNaRj9d4oClUT7FIO3Z7mSizaQbEBkGim6QoCSX9mXzvBlifk87tsqLCNJSyc17bV3E7nyDVcbmGrVa4q6S2HxlQwOv3efFNWhbZ6/bdgftqYm29oY/7CrZ/te/CCBKdfBkKAAWtuSez5/9mCv6vpIl+2tKzmZ9ZD32ON/TerOWEoDMWEtQgoAu86bJYr+xSrL4ev/W5rWTKpfucpPOT5mCoFGdR7L8ciQLkk7KBxzZNLgEp+E1o1WWMsJr/ySTSoUgXhRqDwAo/YfNI7mQovGfXnPZZas7+pVmk3SC9qdsLFQMPgnbV0z3u1upkBaybTvUjL5NpVCZOHHJCqjY6qNGIBlR7clxGzEnyK1BFBmE0BRdmF6XGQAcbg99Z3cj9POSY+MmtaYrY7oEjM4uf6mkhndus0nDMXotc4ju6+0fBwyZCBxbDTklhNCzjM5oDyA8AMASsC/gJU1eSQ3OvSTJmSluh/Pep5DuDITQFn/h9sKzImj6AUCT9tFkx9UioCjHe0lAjBKEGhOM0FOMSl7XN+x7YQnQLXfxM3N1vRGaLvO7B8eHyYk+e9vZ2w7sozTvs5WeGN8P3aztsKcEoPZkzt/t/MTLVeRe++Hzs13m2YyVdphmaAD87rPiY4X44xgA0DEAugAAIPEZgAj6fQ0mw382Q0eSGUcTX0+Pz1WAH/o23cyvX/r1f+5I6fNKTkPNbHcUz0aPvH8V1+3BGANgBqngBD30GACQchARDKCt6SlGwvvrjFu49n2vCe8YHmOMkbPllJfxCLGahEVTecnq6urqJzAsqwlLy1o+HzwfGXj/WF39J1tkAQBwesIDAJD1+M2TPt85Hw4A4Owc/p9stLrKQqW6eqsBQB/Kfg1Z7TUIP4/IRQE+tjwe/UsgKCbUjCPMGIOUJQQDnOvTPs77Ts9/wsh9u13vSj60SuR877FLzPpM1Ufa2NeEX/XdGi4hr4JrLyGdQJWLTMohssDKq65r3rG7nlnFo6wsJCB/u0kNruBNkR6chni8nNpWWYwq7tDNuUHmNks3VKxeQi7NLm0qosbEfOQn/8d/Kb6y6I5QhlT/2dRV5pzFRRazAWgetiSPx0/+BJ6fzTrr14yHoDnE0XF0HB0JIEtsFJ1FGUjDtfnUkdhlSpJ0r5icNVwoDaXBMU02jpHJu1vLct1iWQ7FXU7ieQVK2MRMZpyrxq4wTQ6UPs/cmsrd2/g7mT20GgRZbg+2scsAuMi5t/PV6+ezedzbFblZQ+xKDnW0BYY1i1zfHO6IztCA9SiMqXQds4Lu0TA+PiWF5soGilgJXDVX0rgHnQcetrSOt76SBMP9KPb/GpMjVtrQaUEkAD1jHUoSgkXnnwHv+S54suiuSlW1VbCxCwdqR5XpPD9KdzpcSPfqa+qAtS/urLXt3SKyvg/05APmOuZO4NQ49s4mnWxqfXvdojthhECj7Z97/8R5pk3R3PI3ZSN22CuzGO79pplWqmzVAeK6qp7kkMzrV7gf/pysIvPXy90JjbRUbAcrqSuxB0dvJbX0TPQFABa25O+vr/jZWPl5BdusrSnZbMbRkat4GXFkjI0oSgjYZY4JLv8S49r1590Pj5+fb7ScZVzGv9DjemxDf+CtZU85T6WAkOJQPsD1L1QmcfIzavzPX59P2jLn6G8/OSrb19DKBQDl+lGNnSow5FYcyng5D6T9DEmR9yaHT20Bg9Gql9wSLxPfsd/rgws4clJJkOLq3ojp170CUGEQ/1AP/kfxdxtY1KEDfNDcU3R6kUoLOOC+rbaG91asiQx0E2UpP/Cg9wCE0LMKNZgvvPMIajQ480Zsibb4jx8PCeDYP/5HyoMMhM6zVZV5ogAasAToJHW3oUCJK9PEZouAnr71vtlkLAWE0Ba/u/DNiw7hA4DL+cd4OmJEHQD3vdmu5lYcYgHs2mtkNqOncXRQM7b05n/+q3Yy215YT/4dL3wAAfw/bpPst3pikgA07YuW2O/vYtAZEcRNRQIbBxx5nCYNB/HaJFlLCMNz4+w0caYCIcdbCfTu36C/5+6rIZ0XQOkDRDAgfxXMcl4DMFuG6wFARVBlZH79rQQgeEbBCLqJZu/lcwQj6Z7//WP1SxzqgnAUUAbeAQDAFBgjGWOMBIJ0BwAAEgEgBfKOMcYIAADAXLJpU6DWfLYmAECMMUagn+9O37399sazMTq8fvOkrz+eDvLQOK618u0W23zNVldVawXy8KPee++9fyRQAgAAf1peNgEAnMF6dfXbVQT9RAUAAAB+WT5v6beuQQS/tf/+68tbT4rgAYBJAEDyBQAAAIB0BwAAAgApAACcQwFgbQAAAKBNAAAAAIOpZhSN43x+iKuk8ywECqqAhQliCgAAAP4oXm8rT7/2IvgIP/6zb5rsUUa/ACC/AwAAUAKkOwAAEABIgRsBAAAgFgAAAADbzi/huklNK/jLOfYTVhp+DUSfR2GVBQA+pwAAgFzeYxSMg+YMAAAAfvid7gdPv/rAr/T1r8MeYfQrANMBAMkXAAAAA0hfAQAgAFJAAUBWAwC7AQAAwJkCAAAAbOJ7moph4KPrPrivG+29HU313NLMp7juFsCinAyDDnBO8CYAAAAA3rftt4XdXn7gM/35j26yRxlaFg2gAugXAEByAQCAKgjSDQAgIBFwa4y0qw21eXpwFYC9AgBrBAAAgNkAAAAADNBsbh8jn8/96f2I2ZimSDMGPJDw8qBfPWYHijM6gEVjIktxsac7vJjogAbwRwAAAACel42PK7fdfJiW+faf6MgeZWzH3BsDElQAJgEAyN8AAFwFMbkAABRBCvzp2zouFdaS5hYA0N8CgDcAAAC4CgAAAExpah1fOgfHhOvfHxfVrI9rWyIGpCwXLO9lh6DXkXutr8O7rAYwG6Bfli0AL4F0uuFZDmQZ+kgPCh3gVwAAAAC+h02PF++zeXCs4e1/PzU8e3dC8ApADQBAPgcAAAiC9AUAAAEGUgAAuAAARAAAALgpAAAAQB8aByDrt2c3U18Wkj6RDBwWV+44SwKwrziz0IC/AAAAAL53Tc8n37N9cCzh7X99m+0djCYAMAMAkhcAAAgEQfpKAAAEghQAANwBgNwAAADgFgAAAAC06V9FFLB9vgxNz6/7WRkPYIFCo3Q6ALAND8AGgF8AAAAAfmdNjyf3s33wtKS3/6HN9i4CcNAAJQAguQUAAIEA6U4AAMFACgAA8VQASCMAAADMrgAAAIDUYzCA6Q+d7h1flBELAG44AY0+aQCgMbvTJIDlOwAAAABPZ2dTAABA9QAAAAAAAIq9YzkDAAAAvce3bCNcWVxgZGJlaWx1bnB1d3t8fHZ/dn+Bf4J/f4GHhIyGj4WRkV5Xjc8H9z28eFvL2/9dTc7eRQgOGrADAIB8CgAAYQGkOwEARJACAACrAsAnAAAAgFUAAACgn5xVgYn3no46gXq1W0QHgIUwwvZ4zGIGoLm3XQelN809gBMAAAAAPldNjwf3vn3xtoav/3569i5C8ABAAQBIJgAAIMDASHcJABAQpAAA0FwAYEYAAAAoowAAAICYAvFKY04Fario/UYJALjhWfy3KBwB0AAqN4aIRcECzQsAAABeR43PF9+zefDVp7f/S3v27gTgAUDPAIDkFAAAAsFIKwEAiCAFAIA7BQB6AwAAgCkKAAAAyAUAM01Y3B8aTOlz9gA4gwqdu7ZSmCSmBzwA10rJYsNOmAAxDAAAAD43Lc8H3zu+mNb29r++NZm9i5AYAPQBAEgmAAAgyQBpJQCACFIAADi3AkApAAAAIAAAAADULaOyAeBuJp4L57q4UgCgA0DYvVxJ7ZS9McQimbNAMzRqcy09gEo4CQAAAB4nLc873zM+uK3l6/9/a3L2LgIDGmAAAJISAACCwUgrAQCIIAUAgPNXALgCAAAAVwAAAACgk/Niybqn8W6Km1l9Yq4GAEzkpU62mAoUzj5BB52U2oomd1Ij63rdHpEAbxsAAAAeJy3PB9+zfXEs5el//bX2LkIvAFADAJIKAAAIBiO9CQBABCkAANwLABwKAAAAnhUAAAAAsnsJGY/69ym/83S/w6sDAOjsDCPbBDnJWkyaniYAA4DI4En1uOGTQJj8CgAAAP4mTc8n7715cSzp6X+lrb2DETwAMAMAkkoAAAiBkd4EAJCJAAAwCwAwAgAAAEQAAABgpRx5UHF2RpKPdVZs9LZhAcAEF/NFy5os7VeYl/fQKMCkFDD/7txuCL9RFp5Ex98BAAAA/hYtzzvfs3lxLO3tf3MNZ+8gQgQNUAkASAoAAAgLbLIJAEAmAgBAFAWApgAAAFABAAAAWPpg9zhXsuqjw/AqzI8QSxkAdDhQrm3HWaYGTtQjQAHoQNc7zPWaapXs04gHdAoAwS8AAAAAvgb1zwfPPbyYlvb0j8Vl8fYOJuAkgL0AAEkJAABJRtKbAABkIgAA8AEAUwAAAOAmCgAAAEwHZYa8KT7fi9hwO05eADA9PfukfWS9VgMze6H3HWkoeHig0WmMkHf1JmBCjND9/jUPCnwHAAAAvvbUrzffk714yvfbf12OZ+8AQgwAFACA5AQAQBBOHgAAZCIAAIQuAOAKAAAAMwIAAAD8SYzQkTXzMLfJCi9SBwBA91o4WJOnkPiUWi7bbv4WI0Nn2wxrHAomYNLolvkb5xnqYs/C791JDssfktBpy4kKAAAAvvbUrzffm1585fvtP06Os3cQkgOAXgBAMgkAgA4E6QUAQCYCAIB3AAABAACA6wAAAABgy/eluiDez1pBpM0ezuMpAAAmdLhbXomJlh5OpTXBkhumoR4RCV6fii7WOKTMkJmbDw2KGQIEbAoAAAB+5pSvN8+bXnzlc/uPlmPtUUJyAKAEACQnAAACg5FeAAABiQAAEFUBQBUAAABuAgAAAABbi4/Oztzi6+gxiIes6+lOCgCgM/FPkWC2UF+yYyWvORhFgatxyXaM8H2mmjppciWBZlRDL0Xg0YkYAEAAXtaU7xfPbX9M+dz+uznNHgX0A4AdAADkAQAwDklvAACQiQAAgAAAWQAAAPAbAQAAALCxeBWTaphnZrgOX7t99s9EAUAtdXtqCWZvcHy5OtGe10BOevtqK7bS/TCQQGp8b3e5NkqxO+c6eooDaRyAThMAgAAAXsbUrxfvnX7c6tn+05Nl7VEggwQgAADJKwCAIhjpDQAAIgEAAFoiAJA7AAAAlAsAAAAASGbOE9sIkuxl3Tavxn2kncuHPKcJgA7tE8eVuhmzUTLDMCl+A4qTt9S+YuZ2MImO30VgigX1UmDe/IlCN00Fv/9VLAA+xmSvN89jf9zic/tv5Wh7BMggAfQ9AAD5BgBABUZ6AwCATAQAgDoAgO4AAACUJwIAAAAg0mhRyp+eg4g8Y2gK5XxdvTHWcwLICLklaSS1++fpgyeK2n8SUa2Jip02C24HWEzm+CH4+hypmBI5qjSXA8fQG5qOFwCAAQAexmTPN89nP9ziPf0H5aj2KGMJAFQCAJDvAQDgwskGAAAhEQAA1BUAQgEAACjTCAAAABCi+Fr6My8OGofytniybSU1yH/e0gag0aY2yjThXGXhOv0SGUlxqGALqZ8VZx3LA/hOJ17H6Xu1r21f3PfkkgqewBDgEx8AAAAAPrbUrxffbX885Xv6TzQntUeADB8A+QYAYAQ2UQAAkImAOAAAAlBWAAAAAEDyeW4ldt+miRyfD6U+2N5cW1WOIwAAANfvAAC7n6ZUjOLOD4w9YJMQO0YtuuA7K/5b67nOiQBa16hcR0W24Zvq17NTckGqaag92MkjAABgAN61lM/HfWYQt3wP/+lrDmQPgQwiAPI9AAAKJwoAADIB6AUAAACoAAAAAIDwrP3BFN441LTjDzJDt/ds6ne50gAAyIcAAC3CmqvbkL6/pDWYp7da+92Zw06mVx9IAMidjDYqqdyGW94yXjZEX7/C1mEf828BAAD+tTTPB/dJP5r83P77yZHsIeAgATgAAMkFAJDDiQAAxAgAAHMqAGQHAABQphEAAACA6VBy8txaT5fDdctp+pyc1IQ04soIAL5VIbwRykbCu2dUFUyqnvzO3Wnu+oSdRqRuZ4EHTKYUS8Xv+hDgl4SfpsUec9uc0UbXM/7gJGEC/rXUz8d7WYgj38N/Opd2IfFJABIAgPwAAMQ86QAAIBMAAOAeCgBfAQCAA1cEAAAAsCHyDVXG3CbKk61D6VEFEzgtQEUSfvcmElwGZ02MPWPDftoexZBF+mPDkPHAZKDM+d+JvPmc5M41DyJqCTFizQITvAAAAB62jM8b78l+bPU9/IcnB7IHhMMHQL4AAEY86QAAIBPApgMAAA4FAAAAAAx0nkElyjnmYYXt9/jt66q0U8GPaMYEAAB8XgEAI9lKdYfBJHtv2ySsoXl32nL8uzfOxN2Nba1Z8cCEBetbJEkWYbAzTTRB5NKhxYAej5XMmg0ACAD+tfTPG/dKP7b8nP7TebQLcAQACgBA8gAATMQqZAQDAKQEAHoBAIiDA5Ci66BIrgfN8946fzzPZ3tbK7Qm2827AwBYovqxnwuPI0D6ZGZIuG19u88nsHpE9PkgQgf9I3hUtvAzAgAAAKCgFM9YFJFnGfFaljZQkrSBuAEd/QzQMQEetnSvJ++xH7Z4mv8G9kBxkAD6AQAkPwMAqHjSAACGCAYAeAYA/ggA4AWAARwAAAAGcH64NQ3rTNB+e1bTnd5bDlacig6A+PPbY8USLhbiXpzWHtY1v3LfmkbchV7xVo4VfEnCmqzv1gOR1ewobIUlDTOQAAyD7FwV1+StAWACHrZMz8tnGURQn9v/PB7rkUgJACQAIHkBABjKkwYAQDEAAGhWADAFAEDhDg0HAFAAAAYz/ftfLGhvalzdvMS2g9ZuxPJ0FAA77gPL8C9FYjLJs+rkPUmLuh9ry2xGlYPH2KVmBE0XJOxkhW7ftmBosQh8GdB5IHcmQi8rnKx1OFNgAf61NM/7+0iILd/bfxrVSEYAoAYAJB8AABKcNADAIIIBALcAAImA4gAUggIAgAIAZC2J+nGW73P8FQbR7we2E78Z0soAAHg3V1qvb1ZOFVBOBlFCaBC2typrGeMvMyvSZDe1raChR9E5GUfaZkBGr3cmlj+F9/Q9gsZfdU9BARbetTSPO3uXP251T/9p1BPj8AGSbwAAOZw0AEBi4GiAOyAIrlgHAABQAFCx1qwgiK0tbbj5CVZtP/feZ6FW1gAAAPv/AQATsLeQo4ciWu5SdtBfOi/3LBvR431XhzjZIQtIPBOj0OeTGfuJ/TlqsiqVK7RaLktQ4nzpT9uZpRcA/rU0zyf3ej40D8V/nxWuemQsJAAJAEFSAwAi5SpkBAMAvBQAogIA0ABAcnzLs0L8lK27T42Tc/9+25h6zcs7AGj6vEgJRcBlLhYwi5BXVjckU5UGVvikpXgg1sza0Hqtlee18jNqAIABALohz00flzfNAAVeG3dXHPAdN989BKAB3rU0jwf3ej9ML8N/2RJXPRMWHwTJAQBIcVVMAAoAABzxBpC0PMALD6+dbioZxtwbQd/Su+3QOQYAAPj8HgBAdAPbTZiiTnZwNzuRdJCL7UZvc8aJDSu8jQrij5rc624QofBHLDSHqAEGAABwUOFmB+oQiZjO7+1pfJdaLpw2DfefGlPyzgIA/rWMjxv3eX4Mn6b/FEsc9cQ4AgABAEFSAwBM5CpkBACAmwgACACAgAAAIMrMYZO6NyKm7zTN9nRrrnYNZm/EA+Bp6jwQ7qhg82HVRk+z4iPyvL2yj+OHkqoTAtfskzTLDUMjjLPHTAAAAwDl3M38/vuxmtK3yYkcI91jGq42C6B8mh4CHrZMzxvv/XxoPuLwn2pM69G4AWgYAYAAgCA5AABGTAooBANAANpkhwQAmBcAyAIAqgCi31v5m97DQ6jeb3s/L9fCBIDcLDu0Jwnro7EdO5Xa0IYwqYq8sSvm7HNxelaQ+xLm98jcQ9aI3mVMEAAJwKbiJEqTOZUvnY0z15ZFsh+KWeDn2pmmRkcDIAH+tYyPO/faP2wPw78V1cKknhSLD5IkNQDAjrAKhcCDAgAAHADEYeIeM3posxTdRVtR311AtuEELAAA+wMAAOgcBrXE7QiMG1ilfF+JnpIaLqIdtRZlh3xAPGKT7UFMFZMevN3/kFEAAIChuKXVOPLjeie/cxMi3zQiJVZn0xKSfY72jpgLEv61jM87d90vjkeY/isWJvVYHAGABIAEkgQAhBGrUAwGANRWAPgBABShcGCQgHp+sL/oJTwf3pyz/rmfJYV2fC84BYC9mLMPKq79CCygCLYeqgQXPdYtzTuQTWrBYbt9O3oEZjeL1mc6Ee4JRI0FCQCI1yBOS2+kbFskSQ6f1T9yoXmESWT40octQy5NxAMCHrYsz/Mzb4jp0Yb/roVIreiTQZIkAACGsSrIQKIAEB0XXGGdJ7dv6gxyenPzfrj6NQHUN6qFBQAA5hQAAOCa4N9ZOaXuVr0ujP5IefwaJxApIZKbFzd5hygG9BgnQWlqXFwxB3ACAKzKLsapnB+MDL9sLL99L5VDslSCSoaG1b4tz1zwAP61TI8rd39/DK/Y/FtpWYLWjIMEYAaAJEkCAFKulhAMAJgWAEgFKAAoHABmaPW988+rq3xmN5/nZq70on3f60pBzx5q231pRcGr+EoTqkSgBiHDbZSprIoaka6WvfDjdrbi5bHv4AssupkdcsUkSQAAsGoz+gi21HsSJX4dWZebOlJW1Ehgd2HbVHKj7jXMBTwetkzPO895XzRXbr7+tzCpFX3QACUAJJAEAEBSVYwAAKBWAcCAUwAAcwK0e1rL1Q73A7r0S/B+H7Sn5+IzkoEMGv3HsmzzGiVmu5K0ONmWhZPVp3c/auT2bsXVvWX0fyeyrb6fYvN6RBaJpRTn1ewaAXiWTRZ3OUADd1u7fouUuNZsqq8gWsjrI65Ec2C7C7IAT2dnUwAAQGUBAAAAAACKvWM5BAAAAE+pIT4ci5aPj5COj5SPkJSWk5aXj5iVlJecmJ2cmZuanh62rM8L77p/BA/N/4WFsFYsZJAEnQCAaKuGyEAEwIESUQAAh/OmT5stzOSqh/zbkDhf8RncsQALAMDnFwCADePhqf5r8xcrM28Vq0n85H23Ny22r3/t2rz1WneDc8sd0H8ff1Uo5oDF2XyFJJVJilI4EA/s7Bn50oS+sqYNCulFeSKc0/XOFhilpy3+tez3g2c+P5JXHf7HFia14ggAFACQADoAAGS5WoxgAIB0AYCnOACARBwSyA7i1xWt8Sv64EZQ3tf98Yy3H88KLisgtNIm23Pfb+DFBhJyxLNzweDoOAXjrdOR0n7xCbIDjFvkOSIVciBr6konlB9DB2eCp46ULTsjirrlLH/puZOtCW//zB7oj0zp8i4dWnIwZiQPpQDetaz3Lft6fnAZvv1r4atmHAFALwAkiUmNJUYwAMABAIBknL1T8cst2+c6zWV/zNa4vQdXkTTsOg8AGZoBMnvPspwqAADoS0MTfXgbiPdO7Dw+rlV8tWwWb9fTbeVg6fHvPJRDiGOhlzHvs3g2YLTsYofcizxyoxFxBGyVqSBGqNk7kX/oWn0/CMyeO4EGDx62nB4Hb+0/klds/rcsoDVjCQCUAJBAjE61GMEAgDgUAABDJuLXokbfH+ha5cvvVx5fZJpywFAbgBXIXx/Ox7dK8BAAGKBkDSm2qMiNeNctxucg0rMJbeI5L0q+t2VWnsiINb6shIt2v/vah+6VDCM0iD3zGQDZ4Qi11rVhA7+yBt9m5/3DcMZsJ57WYQF0HracHjtPv3+wav53jY+acfjg5BhlSQwGAEAZr0OeIti+kCek9waVPbs6foUOAMD1JgAAKKAeGpH3gkfWZ8eqV07FAICHbv/VPpKZTbTs/9GS3FYzrwmLns1WyUe+WxxmLDuZhwm7A9jNR+VZpvERqxIpRc/Cj09CEjObEs0nTdj5pFGVhWV7K4gEngbfTNAAHrac7zvvvH8Erzj8t4xJzVgCAAUAJCKmYxZEAABohwAADIEH5sr/Y+R1+OvcYrbLXj3BIv+CNyULQxsDe+GDQIyDxmzeNgAphiHMY1fZYiA5Vo73otfEwjImIldmS3Xb0uf2U3Ziwop5tySU448PqjqPncXIDmHxAn8tlALSiN2lZ9Z5eVBi62VOSpt4Ev617PeDuz0/oiUP3/83JrXiCAB6ASARWQwdi8EAgDsAAAAoaw1stspr3+IZ1Ffv4YeAmatwJW3XIwAAWVVgy+mP+zQ3BK8ZGCCHSbgFYU57eE0qB5EOrcX4ZX73qZTW3Cjd9m9i8Pj8n591VsCtvOYHu8l1wB9xggxKV6FFaNt29eRG9rio57XlZ8MyUdABHrYcHyfvPD+CPjRf/bQAa8YRACgB0DeRLYnBAADNCgBAYit9H8RyjoQlZ+9vxxt5mzoTNnJ5HMwALA9ZnH2My3KwgT8aADRQTVzpptfPzmdz1LxbOYjGXHLGTAvRW+/9M81RSlXD96e2zVN2PuuMV0dNuhEtimmQQVDf3O6CzaW0ABdrtLYu9yy+vg9gMlnb9j0ABf61XG4Ld18fgiUM/1VjqA2LD8lpc1WQwQBg8I29PLb8vu+x63HLOu6zqtYvx4+W9wAAXL8DAIABsnuPv8bbl8x/FgC/kTmQs0jSjhjIspptr7E4a4cbSYbAbu7ZyQIvE+IoieUErFsGqTiaUCyAYXINw+NehmaUdWkjwwhso9+ycUEiDl60cUsbXLthKYAA3rVcrjP7nD+qJU3/OwG5VswAQADA/ejYkhAAAMITAAAIbYfNxgv46y/Ubj8d86djsSO4djbRCZjP1IR2VNyw0ZqMOQXvgxIyZaGVKM8xFS+z3Tp/rofDbI7QQfvRoKzUrGYrJBuf6ugr5gDn8cSCuFygX50LqYsZXqTfrmi+bFW1pre9zxVLPYKknZPnBIIH/rVcbwt3az+C3vCfSKgZi08I3AAAqHNVCYEvaLVAcFQlBgeImUc3eq13mVd5ezwfs6lL9aiP77TRbRQAYH8YAACHbQjo2s9pZlytGHf96mrOt940WaXi7a00G3+qt9ry9sLZill4ikZ0NmPcuxceIjBjQ0p0YteItTgM4eF1qO0mHf83RXYi562iHgGc8yxfNMIHDR62PG4L74wfVW/4b0trxhEASAAB9AIAFDqxGAwAqKwAMIACkQpeQgcAZ07Xr73dm/jhvL8fvxaSKo1yWu/yFkviLhBLqyjP/m2qrFWyJhVL+fbV/WuoM1tZeT/ejlCge287Md2VmL4M9aEaEg8MAe31ybfoXlq7dCe2DXkxIvvT9lH0JlMlwS6CtktYgQi9gwW38R4CAB623N4m3tIPq0Xzv1quHRafALoBAEaKEgM4OBoBgAKwF/spsf30Yw+3+99on767rAUEHTa5SrZHAODzCACgGS71tvu62Uzfsd2bkP3vStbPruxACWaJF49nYfhRbsLaJd7r71YrlxhV2HvbCMb2MALdOWaYwqiSdH53dYEKT0juw3KnF5wRZIzPyC4wtlq+ETovAd61PC4Te8QPOs2Xv9SK5ApAAYCVBQBQ6ixLDAYAiBEAQHu5RATkAkBgRzvMoqOv3IeNhqs8N1eCIx7aAUrMOzH09+ajZBjZHgLEbyqd2m4Pue5yBcyzaCu3vWbKwN17i9i5BWyNG+jF7XLGm/3eiKzsQzMjBrDlbE5KbrYYS9jXh5/1bDvqK5BhYuo3TXMhN7cUVyQPAN61PC4je9SHIBv+A6gNSwXQCwAnR3A5ZgYDAKoDAABivDTvccHuDrkyer3ruopNw6AT3fEsoJnNaWBW9V0F9qXr5y9ckZ/KRTIsxCLzTUSqirgr5UauBIHNkfZdi7mpd2IS9PuJaR+m+PsE/Yz+c30+au7ZCfucHW/LZ5HTX6m52FcTovRA7SHTeGyyZx8lW98IhaDRAQ8etrzcJt7yD51O89+Qa8MSACgBKl7IDCECAEBfFAAAUPD0yX4Vbcw5NZHHqJK1tviJzxV1ZQL2Nkak82/lNy1CvSe2Smq5bL4GJxlqmTU4YcD69olHYo17g8wkMQeySvfJqFTkEDOBwifrprHyOm3PPhWtWVe/wjxPCa5orh+BDph7OZk54RvBb/pwEP8wWR62vF4nHvcPUVX8J1Er+kWVBgCkxIIMZjRgUcW9cFci7cr1t7PuiJx1cvbweD7S5CdVGYoASwBgTgkAsDPVIRrY0sU7a1HqKbJX3O8Znfxn8a2sUyy72m45QWdaA/+2Xa/ynY7uioEFZPVaxDMqcBxRQ8Zp/eXcyBYlmaZOxGKdwSVm3fvA1Zpj2iDDfhKltKIdUVgB6IACHra8XjtP+IeoGv4jUStuACyrqMgTQ4cAgBtiUTaccxyep4zxKk9JXav2jE/TeqT8MhbEAMD+NgCgiMDanNp7kX/05q1qd9riybz+vymAlcrJxZ6ldYLmX52jf9e+0bkf2DAq7rva2MnYK3pEsrBDOWXPu4axgd5ZCnwYvnAxldlkbaU3K6DUFACR8xMGFf2e93JxDwDetbxcOnuIH1HUPP/KNeOoAJQAY0cqoRgAAOJQAACABHzUdFf7/8q09XA/Hx8OPgell4o6mamsooXKparZ0yXF3SYCoBjDWBuTG8Vm0NETtFU9RrFBlGSoK9PYTCj6i0g4TqGmb77fbgXD77GoUXxm9iU8xSMX4xEyFdnVNyhlmm3smhRKEemE0NL/4NmyLmRuHv8JHrZ8XDuvyw+9qPngz9SMo9BMOSqIYAAoZ7Z8a99zic+Jpm14PNu112EJKRYqM5OELABwvQkALFherfB63vID811ejhVMZFeRjEfgil7ju926pkEW57A0UX6w93ZQ2cnJx/3lgWEwhNfdI2/7NhU0J8iyJbcQz6Qai+S4bScZJ8tdmrtp3pqLoQ0i3N4U318/2bsiKIIJAN61vF46O/ojiYYP/lIzjgpAAFyJHpXEAArAdQEAgEQ7axzftOur8C9TGvtBlzJwEupWj+FzNL4DbnWP2c0V5tLkEE5eSFsqT9iUsLI8xVlVbRnccm5Log+ccJjD0+l3KC94F3H5mrMgdWlIpPcOwuPge4Ien0oiobASZg3XR5U/6WG4EbF5V8JDm/SiJdMc8poKkf+wDsLVEO2MBB62fF4qj9Afnah5/qVWLAGAAGSaKAkiAAD4FQAAqR4Lu9/fnSNfd/e5f76bIfvkJyq1+r1j6sp16Hq46IeDAW+6Vd/QRhsyNVh0tTGnsJ9UDIUlc+V6zjIRNny5ANfrRRNvO1xV7uPSxsF8VP+bAusjss220O9T1/a/h0xTfy2FeBDSV/PwUBIIM7enylQTIdClsySKGZ0F/rV8bgu364deNn34T9SKGwDIKGFJJzFkAHCvopzPi7y+8Ch/da4tLc+O2bwdCk14FgD2BwCI7r0tJhzGqrxkzqGJdsxaepV+O9F/Mnb2dajKmYsQ5ALNOh3IE2XovoAuQB+ZKH3ifNimCGbbzZC7VULbDiGHLke1EqTB/yjvnpzzKWr9C3pZV6qq0TZX28l7w18pvG+ChTyyeAAiAP61fFwKd4gPK6ZP/9SKowKQgJ4uhJIQTACgJgAIAEBJgnqYGCVyaL3etgfP46EFhFAiC+HL6twwZlgwzwH3cNIQXHdsxAf5+3puxEcTJu7FIkDJvrfzk54vbeSlvklRJIZcMYswd8M6RXEEjDiMCoy4PQv0UZHCylFOkC22e3+xbT8+NsW0TxNfcmjsXr7gdplAHHNij7jsTWvgAR62fF0qj8sfq2j4+pOasVQAApBeOsNiBgCAmgAAQLhla0bIDHG+Dk53rz/pc3w4ajPIixt6VsMdt+PosB7n+lBV3ooZOSo0BgorHpo4KysaXkkXIzgliveyc2xcbO/jPfFYh2smSmVoYXebszDXUDm2lBboEzzhcYpJBTRb75zF/pYejNFN+qE+BaY8ve4hx32J2n0e7hUICR62vN86L/qDZHh+TK04SpZoJCGCAaQSSedn/fq7pf/dw2g97M4rDFDZdcsx6w2SBGD/F2CYFOkOoA+1ePK4o0h/Y5wF1sZ3gWpPjMoU7dkY0DX6cSgOQuKmODY65+fPZm1vkO2oRnFFmq8MnjOiTjtnMc98/dtNJtQcdgQvqvnM+4FIlIwIpU1Xz9SY5cXcxOzv0pa0XEWCaHgAHrb83EZetx962fChL7ViqQCUAC+jcZaEQAGAJgqgEaBHRwSmOeUXRLkx2njVX7XVFegleukVDES/wBR3O9tYm+m2rTYegvLhXjBR6kjIhlsDSJWIJRMYMlWpFYGMrswJvq2x1/EwBbRK5iG77VsLnnOOek2RzRpcsVkpSurz/Wfr7EWpF6/VvTnDuKP2MJB4bJNCrDRuHO70kB62fF8qr8oXHaaPPlArlpIZGjkxgwHQ2DDlQdn4diqZ11FMzvtlJgMzXHTFtJUEgM8jAMldbuvXIy8HVcSxZbcQtr8JI3AMUj+hWmc/IOUENrjIaS7VX+CQ8kYzhmG5wo8zy6q4e10IuvQx9b64Ez3nQKa2qjuemMwldUBklkLNueZC3S/Nal3ahCft1GxOvZU+h+y1xontdyMmT5kAT2dnUwAEAHcBAAAAAACKvWM5BQAAAIzU2MIFqJuamVX+tXxtK7ebD71o+PA+NeOoAAQgvVR0EoN1CkCaAAgAjKf38nSNf4u3ag/+XpFtEq+zjyPPsXu95V9cnFU4vyRGvULIZtAGxTu7yORUhDRxQTxlWh6olMzB41ATLTnSIa0CqEMWv8nu3s/XgwnvyD6iqRUsAz55czD9d/r6pdnqfi0D02+LESrCpcvRlQnhZd3m/sVEdhvJWAnzJ2b9a2800lpFMjsWgAcetvy4FF61Lwia56U2HE1GQy05IRgAUIoKrhN1dtPIZ/JY2kFuhzJe3+u2sdgTd+Q1IFSGn7MWwem43ZaT5sZ2xIgr8SIH4ld0VWuFUbivk60RqbK8CjYutHhQDuyhWPl15GZXAifUfWBrHec0bFE6zfCPi+fTE9dYg648GjvMqfPGwPA7Kh81ViKXyJadJMVIfmntWjCbYXwAJh62fF8qr5oPWdY8l6hmLCXDUA46RjAAm7kaHwMP07gOXzlXpNBUqlxvcl7LuQuUE4kA9qgxwGm4Btpgd4c0BUqqN3rLhLi4Fh2iHJo0R9dbrpvN5vTqrHgesjvVJNBSG9TsqYlazlTVi8hUhzH2mON53LWD+koH815UYhq2idnRioq5p2jTyIvIDXbs56Pn1Yk2tVpTtGOeAAD+tXxuR27BByhQK470Mso4MQMAGEDRVH4pyLLa2oardDJo/m/O76V8dmdDqkje1KIzMptBvZVpW14S5nnioc2YetqFDsrKeRmMw9pPsz+LMk9xTEgmqWm6mEbccg4Wl3Bra+mtqGmD5rhii5av6sqrckDVZD7LbPNwVDy3pGdt1WnYg+vJ3III5C2FmgLcA2YwFnL26zA+OwAetvzvKLz4DnhDTRGEXBSCAEMwALDpQ5V3mE8BS8svH/DxwWFSgNlawtKa8+7MLtOQqyi40uCB+fxwlhW2YIl415T49BvgzgBDgEcVJndabjX4wSYA", + "volume": 100 + }, + "role": { + "category": "Default", + "focus": true, + "mute": true, + "song": "You wouldn't believe", + "src": "https://notificationsounds.com/soundfiles/087408522c31eeb1f982bc0eaf81d35f/file-sounds-949-you-wouldnt-believe.wav", + "volume": 100 + }, + "everyone": { + "category": "Google", + "focus": true, + "mute": true, + "song": "Crosswalk", + "src": "data:audio/mpeg;base64,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", + "volume": 100 + }, + "here": { + "category": "Google", + "focus": true, + "mute": true, + "song": "Crosswalk", + "src": "data:audio/mpeg;base64,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", + "volume": 100 + }, + "deafen": { + "category": "---", + "focus": null, + "mute": false, + "song": "---", + "src": "/assets/e4d539271704b87764dc465b1a061abd.mp3", + "volume": 100 + }, + "mute": { + "category": "---", + "focus": null, + "mute": false, + "song": "---", + "src": "/assets/429d09ee3b86e81a75b5e06d3fb482be.mp3", + "volume": 100 + }, + "disconnect": { + "category": "Discord", + "focus": null, + "mute": false, + "song": "Push2Talk Stop", + "src": "/assets/74ab980d6890a0fa6aa0336182f9f620.mp3", + "volume": 100 + }, + "undeafen": { + "category": "---", + "focus": null, + "mute": false, + "song": "---", + "src": "/assets/5a000a0d4dff083d12a1d4fc2c7cbf66.mp3", + "volume": 100 + }, + "unmute": { + "category": "---", + "focus": null, + "mute": false, + "song": "---", + "src": "/assets/43805b9dd757ac4f6b9b58c1a8ee5f0d.mp3", + "volume": 100 + }, + "user_join": { + "category": "Discord", + "focus": null, + "mute": false, + "song": "Push2Talk Start", + "src": "/assets/8b63833c8d252fedba6b9c4f2517c705.mp3", + "volume": 100 + }, + "user_leave": { + "category": "---", + "focus": null, + "mute": false, + "song": "---", + "src": "/assets/4fcfeb2cba26459c4750e60f626cebdc.mp3", + "volume": 100 + }, + "user_moved": { + "category": "---", + "focus": null, + "mute": false, + "song": "---", + "src": "/assets/e81d11590762728c1b811eadfa5be766.mp3", + "volume": 100 + }, + "reconnect": { + "category": "---", + "focus": null, + "mute": true, + "song": "---", + "src": "/assets/471cfd0005b112ff857705e894bf41a6.mp3", + "volume": 100 + }, + "ptt_start": { + "category": "---", + "focus": null, + "mute": false, + "song": "---", + "src": "/assets/8b63833c8d252fedba6b9c4f2517c705.mp3", + "volume": 100 + }, + "ptt_stop": { + "category": "---", + "focus": null, + "mute": false, + "song": "---", + "src": "/assets/74ab980d6890a0fa6aa0336182f9f620.mp3", + "volume": 100 + }, + "call_calling": { + "category": "---", + "focus": null, + "mute": false, + "song": "---", + "src": "/assets/c6e92752668dde4eee5923d70441579f.mp3", + "volume": 100 + }, + "call_ringing": { + "category": "Discord", + "focus": null, + "mute": true, + "song": "Incoming Call Beat", + "src": "/assets/b9411af07f154a6fef543e7e442e4da9.mp3", + "volume": 54.5 + }, + "call_ringing_beat": { + "category": "---", + "focus": null, + "mute": true, + "song": "---", + "src": "/assets/b9411af07f154a6fef543e7e442e4da9.mp3", + "volume": 100 + }, + "stream_started": { + "category": "Discord", + "focus": null, + "mute": false, + "song": "Unknown", + "src": "/assets/ae7d16bb2eea76b9b9977db0fad66658.mp3", + "volume": 100 + }, + "stream_ended": { + "category": "---", + "focus": null, + "mute": false, + "song": "---", + "src": "/assets/4e30f98aa537854f79f49a76af822bbc.mp3", + "volume": 100 + }, + "stream_user_joined": { + "category": "---", + "focus": null, + "mute": false, + "song": "---", + "src": "/assets/5827bbf9a67c61cbb0e02ffbf434b654.mp3", + "volume": 100 + }, + "stream_user_left": { + "category": "---", + "focus": null, + "mute": false, + "song": "---", + "src": "/assets/7cdcdcbc426cc43583365a671c24b740.mp3", + "volume": 100 + }, + "ddr-down": { + "category": "---", + "focus": null, + "mute": false, + "song": "---", + "src": "/assets/71f048f8aa7d4b24bf4268a87cbbb192.mp3", + "volume": 100 + }, + "ddr-left": { + "category": "---", + "focus": null, + "mute": false, + "song": "---", + "src": "/assets/1de04408e62b5d52ae3ebbb91e9e1978.mp3", + "volume": 100 + }, + "ddr-right": { + "category": "---", + "focus": null, + "mute": false, + "song": "---", + "src": "/assets/2c0433f93db8449e4a82b76dc520cb29.mp3", + "volume": 100 + }, + "ddr-up": { + "category": "---", + "focus": null, + "mute": false, + "song": "---", + "src": "/assets/68472713f7a62c7c37e0a6a5d5a1faeb.mp3", + "volume": 100 + }, + "mention1": { + "category": "---", + "focus": null, + "mute": true, + "song": "---", + "src": "/assets/fa4d62c3cbc80733bf1f01b9c6f181de.mp3", + "volume": 100 + }, + "mention2": { + "category": "---", + "focus": null, + "mute": true, + "song": "---", + "src": "/assets/a5f42064e8120e381528b14fd3188b72.mp3", + "volume": 100 + }, + "mention3": { + "category": "---", + "focus": null, + "mute": true, + "song": "---", + "src": "/assets/84c9fa3d07da865278bd77c97d952db4.mp3", + "volume": 100 + }, + "message2": { + "category": "---", + "focus": null, + "mute": true, + "song": "---", + "src": "/assets/15fe810f6cfab609c7fcda61652b9b34.mp3", + "volume": 100 + }, + "message3": { + "category": "---", + "focus": null, + "mute": true, + "song": "---", + "src": "/assets/53ce6a92d3c233e8b4ac529d34d374e4.mp3", + "volume": 100 + }, + "human_man": { + "category": "---", + "focus": null, + "mute": true, + "song": "---", + "src": "/assets/a37dcd6272ae41cf49295d58c9806fe3.mp3", + "volume": 100 + }, + "robot_man": { + "category": "---", + "focus": null, + "mute": true, + "song": "---", + "src": "/assets/66598bea6e59eb8acdf32cf2d9d75ba9.mp3", + "volume": 100 + }, + "discodo": { + "category": "---", + "focus": null, + "mute": true, + "song": "---", + "src": "/assets/ae7d16bb2eea76b9b9977db0fad66658.mp3", + "volume": 100 + }, + "overlayunlock": { + "category": "---", + "focus": null, + "mute": true, + "song": "---", + "src": "/assets/ad322ffe0a88436296158a80d5d11baa.mp3", + "volume": 100 + } + } +}
\ No newline at end of file diff --git a/.config/BetterDiscord/plugins/NotificationSounds.plugin.js b/.config/BetterDiscord/plugins/NotificationSounds.plugin.js new file mode 100644 index 0000000..8e48187 --- /dev/null +++ b/.config/BetterDiscord/plugins/NotificationSounds.plugin.js @@ -0,0 +1,546 @@ +//META{"name":"NotificationSounds","authorId":"278543574059057154","invite":"Jx3TjNS","donate":"https://www.paypal.me/MircoWittrien","patreon":"https://www.patreon.com/MircoWittrien","website":"https://github.com/mwittrien/BetterDiscordAddons/tree/master/Plugins/NotificationSounds","source":"https://raw.githubusercontent.com/mwittrien/BetterDiscordAddons/master/Plugins/NotificationSounds/NotificationSounds.plugin.js"}*// + +var NotificationSounds = (_ => { + var audios, choices, firedEvents, repatchIncoming, callAudio; + + const settingsAudio = new Audio(); + + /* NEVER CHANGE THE SRC LINKS IN THE PLUGIN FILE, TO ADD NEW SONGS ADD THEM IN THE SETTINGS GUI IN THE PLUGINS PAGE */ + const types = { + "message1": {implemented:true, name:"New Chatmessage", src:"/assets/dd920c06a01e5bb8b09678581e29d56f.mp3", mute:true, focus:null, include:true}, + "dm": {implemented:true, name:"Direct Message", src:"/assets/84c9fa3d07da865278bd77c97d952db4.mp3", mute:true, focus:true, include:false}, + "mentioned": {implemented:true, name:"Mentioned", src:"/assets/a5f42064e8120e381528b14fd3188b72.mp3", mute:true, focus:true, include:false}, + "role": {implemented:true, name:"Mentioned (role)", src:"/assets/a5f42064e8120e381528b14fd3188b72.mp3", mute:true, focus:true, include:false}, + "everyone": {implemented:true, name:"Mentioned (@everyone)", src:"/assets/a5f42064e8120e381528b14fd3188b72.mp3", mute:true, focus:true, include:false}, + "here": {implemented:true, name:"Mentioned (@here)", src:"/assets/a5f42064e8120e381528b14fd3188b72.mp3", mute:true, focus:true, include:false}, + "deafen": {implemented:true, name:"Voicechat Deafen", src:"/assets/e4d539271704b87764dc465b1a061abd.mp3", mute:false, focus:null, include:true}, + "mute": {implemented:true, name:"Voicechat Mute", src:"/assets/429d09ee3b86e81a75b5e06d3fb482be.mp3", mute:false, focus:null, include:true}, + "disconnect": {implemented:true, name:"Voicechat Disconnect", src:"/assets/7e125dc075ec6e5ae796e4c3ab83abb3.mp3", mute:false, focus:null, include:true}, + "undeafen": {implemented:true, name:"Voicechat Undeafen", src:"/assets/5a000a0d4dff083d12a1d4fc2c7cbf66.mp3", mute:false, focus:null, include:true}, + "unmute": {implemented:true, name:"Voicechat Unmute", src:"/assets/43805b9dd757ac4f6b9b58c1a8ee5f0d.mp3", mute:false, focus:null, include:true}, + "user_join": {implemented:true, name:"Voicechat User Joined", src:"/assets/5dd43c946894005258d85770f0d10cff.mp3", mute:false, focus:null, include:true}, + "user_leave": {implemented:true, name:"Voicechat User Left", src:"/assets/4fcfeb2cba26459c4750e60f626cebdc.mp3", mute:false, focus:null, include:true}, + "user_moved": {implemented:true, name:"Voicechat User Moved", src:"/assets/e81d11590762728c1b811eadfa5be766.mp3", mute:false, focus:null, include:true}, + "reconnect": {implemented:false, name:"Voicechat Reconnect", src:"/assets/471cfd0005b112ff857705e894bf41a6.mp3", mute:true, focus:null, include:true}, + "ptt_start": {implemented:true, name:"Push2Talk Start", src:"/assets/8b63833c8d252fedba6b9c4f2517c705.mp3", mute:false, focus:null, include:true}, + "ptt_stop": {implemented:true, name:"Push2Talk Stop", src:"/assets/74ab980d6890a0fa6aa0336182f9f620.mp3", mute:false, focus:null, include:true}, + "call_calling": {implemented:true, name:"Outgoing Call", src:"/assets/c6e92752668dde4eee5923d70441579f.mp3", mute:false, focus:null, include:true}, + "call_ringing": {implemented:true, name:"Incoming Call", src:"/assets/84a1b4e11d634dbfa1e5dd97a96de3ad.mp3", mute:true, focus:null, include:true}, + "call_ringing_beat": {implemented:false, name:"Incoming Call Beat", src:"/assets/b9411af07f154a6fef543e7e442e4da9.mp3", mute:true, focus:null, include:true}, + "stream_started": {implemented:true, name:"Stream Started", src:"/assets/9ca817f41727edc1b2f1bc4f1911107c.mp3", mute:false, focus:null, include:true}, + "stream_ended": {implemented:true, name:"Stream Ended", src:"/assets/4e30f98aa537854f79f49a76af822bbc.mp3", mute:false, focus:null, include:true}, + "stream_user_joined": {implemented:true, name:"Stream User Joined", src:"/assets/5827bbf9a67c61cbb0e02ffbf434b654.mp3", mute:false, focus:null, include:true}, + "stream_user_left": {implemented:true, name:"Stream User Left", src:"/assets/7cdcdcbc426cc43583365a671c24b740.mp3", mute:false, focus:null, include:true}, + "ddr-down": {implemented:true, name:"HotKeys Window Down", src:"/assets/71f048f8aa7d4b24bf4268a87cbbb192.mp3", mute:false, focus:null, include:true}, + "ddr-left": {implemented:true, name:"HotKeys Window Left", src:"/assets/1de04408e62b5d52ae3ebbb91e9e1978.mp3", mute:false, focus:null, include:true}, + "ddr-right": {implemented:true, name:"HotKeys Window Right", src:"/assets/2c0433f93db8449e4a82b76dc520cb29.mp3", mute:false, focus:null, include:true}, + "ddr-up": {implemented:true, name:"HotKeys Window Up", src:"/assets/68472713f7a62c7c37e0a6a5d5a1faeb.mp3", mute:false, focus:null, include:true}, + "mention1": {implemented:false, name:"Mention Ping", src:"/assets/fa4d62c3cbc80733bf1f01b9c6f181de.mp3", mute:true, focus:null, include:true}, + "mention2": {implemented:false, name:"Mention Ping 2", src:"/assets/a5f42064e8120e381528b14fd3188b72.mp3", mute:true, focus:null, include:true}, + "mention3": {implemented:false, name:"Mention Ping 3", src:"/assets/84c9fa3d07da865278bd77c97d952db4.mp3", mute:true, focus:null, include:true}, + "message2": {implemented:false, name:"New Chatmessage 2", src:"/assets/15fe810f6cfab609c7fcda61652b9b34.mp3", mute:true, focus:null, include:true}, + "message3": {implemented:false, name:"New Chatmessage 3", src:"/assets/53ce6a92d3c233e8b4ac529d34d374e4.mp3", mute:true, focus:null, include:true}, + "human_man": {implemented:false, name:"Human Man Voice", src:"/assets/a37dcd6272ae41cf49295d58c9806fe3.mp3", mute:true, focus:null, include:true}, + "robot_man": {implemented:false, name:"Robot Man Voice", src:"/assets/66598bea6e59eb8acdf32cf2d9d75ba9.mp3", mute:true, focus:null, include:true}, + "discodo": {implemented:false, name:"Unknown", src:"/assets/ae7d16bb2eea76b9b9977db0fad66658.mp3", mute:true, focus:null, include:true}, + "overlayunlock": {implemented:false, name:"Overlay Unlocked", src:"/assets/ad322ffe0a88436296158a80d5d11baa.mp3", mute:true, focus:null, include:true} + }; + + /* NEVER CHANGE THE SRC LINKS IN THE PLUGIN FILE, TO ADD NEW SONGS ADD THEM IN THE SETTINGS GUI IN THE PLUGINS PAGE */ + const defaultAudios = { + "---": { + "---": null + }, + "Default": { + "Communication Channel": "https://notificationsounds.com/soundfiles/63538fe6ef330c13a05a3ed7e599d5f7/file-sounds-917-communication-channel.wav", + "Isn't it": "https://notificationsounds.com/soundfiles/ba2fd310dcaa8781a9a652a31baf3c68/file-sounds-969-isnt-it.wav", + "Job Done": "https://notificationsounds.com/soundfiles/5b69b9cb83065d403869739ae7f0995e/file-sounds-937-job-done.wav", + "Served": "https://notificationsounds.com/soundfiles/b337e84de8752b27eda3a12363109e80/file-sounds-913-served.wav", + "Solemn": "https://notificationsounds.com/soundfiles/53fde96fcc4b4ce72d7739202324cd49/file-sounds-882-solemn.wav", + "System Fault": "https://notificationsounds.com/soundfiles/ebd9629fc3ae5e9f6611e2ee05a31cef/file-sounds-990-system-fault.wav", + "You wouldn't believe": "https://notificationsounds.com/soundfiles/087408522c31eeb1f982bc0eaf81d35f/file-sounds-949-you-wouldnt-believe.wav" + }, + "Discord": {} + }; + + for (let id in types) if (types[id].include) defaultAudios.Discord[types[id].name] = types[id].src; + + return class NotificationSounds { + getName () {return "NotificationSounds";} + + getVersion () {return "3.4.5";} + + getAuthor () {return "DevilBro";} + + getDescription () {return "Allows you to replace the native sounds of Discord with your own";} + + constructor () { + this.changelog = { + "fixed":[["Mention Sound","No longer plays when the server/channel has message notifications completely disabled"]] + }; + + this.patchedModules = { + after: { + Shakeable: "render" + } + }; + } + + initConstructor () { + audios = {}; + choices = {}; + firedEvents = {}; + } + + getSettingsPanel (collapseStates = {}) { + if (!window.BDFDB || typeof BDFDB != "object" || !BDFDB.loaded || !this.started) return; + let settingsPanel = {node: null}, settingsItems = []; + + settingsItems.push(BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.CollapseContainer, { + title: "Add new Song", + collapseStates: collapseStates, + children: [ + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Flex, { + className: BDFDB.disCN.margintop4, + children: [ + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Flex.Child, { + children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.FormComponents.FormItem, { + title: "Categoryname", + children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.TextInput, { + className: "input-newsong input-category", + value: "", + placeholder: "Categoryname" + }) + }) + }), + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Flex.Child, { + children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.FormComponents.FormItem, { + title: "Songname", + children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.TextInput, { + className: "input-newsong input-song", + value: "", + placeholder: "Songname" + }) + }) + }) + ] + }), + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Flex, { + className: BDFDB.disCN.margintop4, + align: BDFDB.LibraryComponents.Flex.Align.END, + children: [ + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Flex.Child, { + children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.FormComponents.FormItem, { + title: "Source", + children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.TextInput, { + className: "input-newsong input-source", + type: "file", + filter: ["audio", "video"], + useFilePath: true, + value: "", + placeholder: "Source" + }) + }) + }), + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Button, { + style: {marginBottom: 1}, + onClick: _ => { + for (let input of settingsPanel.node.querySelectorAll(".input-newsong " + BDFDB.dotCN.input)) if (!input.value || input.value.length == 0 || input.value.trim().length == 0) return BDFDB.NotificationUtils.toast("Fill out all fields to add a new song.", {type:"danger"}); + let category = settingsPanel.node.querySelector(".input-category " + BDFDB.dotCN.input).value.trim(); + let song = settingsPanel.node.querySelector(".input-song " + BDFDB.dotCN.input).value.trim(); + let source = settingsPanel.node.querySelector(".input-source " + BDFDB.dotCN.input).value.trim(); + if (source.indexOf("http") == 0) BDFDB.LibraryRequires.request(source, (error, response, result) => { + if (response) { + let type = response.headers["content-type"]; + if (type && (type.indexOf("octet-stream") > -1 || type.indexOf("audio") > -1 || type.indexOf("video") > -1)) return this.successSavedAudio(settingsPanel.node, collapseStates, {category, song, source}); + } + BDFDB.NotificationUtils.toast("Use a valid direct link to a video or audio source. They usually end on something like .mp3, .mp4 or .wav.", {type:"danger"}); + }); + else BDFDB.LibraryRequires.fs.readFile(source, (error, response) => { + if (error) BDFDB.NotificationUtils.toast("Could not fetch file. Please make sure the file exists.", {type:"danger"}); + else return this.successSavedAudio(settingsPanel.node, collapseStates, {category, song, source:`data:audio/mpeg;base64,${response.toString("base64")}`}); + }); + }, + children: BDFDB.LanguageUtils.LanguageStrings.SAVE + }) + ] + }) + ] + })); + settingsItems.push(BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.CollapseContainer, { + title: "Implemented Sounds", + collapseStates: collapseStates, + dividertop: true, + children: Object.keys(BDFDB.ObjectUtils.filter(types, typedata => typedata.implemented)).map(type => this.createSoundCard(type, settingsPanel, collapseStates)).flat(10).filter(n => n) + })); + settingsItems.push(BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.CollapseContainer, { + title: "Unimplemented Sounds", + collapseStates: collapseStates, + dividertop: true, + children: Object.keys(BDFDB.ObjectUtils.filter(types, typedata => !typedata.implemented)).map(type => this.createSoundCard(type, settingsPanel, collapseStates)).flat(10).filter(n => n) + })); + settingsItems.push(BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.CollapseContainer, { + title: "Remove Songs", + collapseStates: collapseStates, + dividertop: true, + children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SettingsItem, { + type: "Button", + className: BDFDB.disCN.marginbottom8, + color: BDFDB.LibraryComponents.Button.Colors.RED, + label: "Delete all added songs", + onClick: _ => { + BDFDB.ModalUtils.confirm(this, "Are you sure you want to delete all added songs?", _ => { + BDFDB.DataUtils.remove(this, "choices"); + BDFDB.DataUtils.remove(this, "audios"); + this.loadAudios(); + this.loadChoices(); + BDFDB.PluginUtils.refreshSettingsPanel(this, settingsPanel.node, collapseStates); + }); + }, + children: BDFDB.LanguageUtils.LanguageStrings.DELETE + }) + })); + + return settingsPanel.node = BDFDB.PluginUtils.createSettingsPanel(this, settingsItems); + } + + createSoundCard (type, settingsPanel, collapseStates) { + return [ + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Flex, { + className: BDFDB.disCN.marginbottom8, + align: BDFDB.LibraryComponents.Flex.Align.CENTER, + direction: BDFDB.LibraryComponents.Flex.Direction.HORIZONTAL, + children: [ + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SettingsLabel, { + label: types[type].name + }), + types[type].focus != null ? BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SettingsItem, { + type: "Switch", + mini: true, + grow: 0, + label: "Mute when Channel focused:", + value: choices[type].focus, + onChange: value => { + choices[type].focus = value; + this.saveChoice(type, false); + } + }) : null, + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SettingsItem, { + type: "Switch", + mini: true, + grow: 0, + label: "Mute in DnD:", + value: choices[type].mute, + onChange: value => { + choices[type].mute = value; + this.saveChoice(type, false); + } + }) + ].filter(n => n) + }), + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Flex, { + className: BDFDB.disCN.marginbottom8, + children: [ + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Flex.Child, { + grow: 0, + shrink: 0, + basis: "31%", + children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.FormComponents.FormItem, { + title: "Category", + children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Select, { + value: choices[type].category, + options: Object.keys(audios).map(name => {return {value:name, label:name}}), + searchable: true, + onChange: category => { + choices[type].category = category.value; + choices[type].song = Object.keys(audios[category.value] || {})[0]; + choices[type].src = audios[choices[type].category][choices[type].song] || types[type].src; + this.saveChoice(type, true); + BDFDB.PluginUtils.refreshSettingsPanel(this, settingsPanel.node, collapseStates); + } + }) + }) + }), + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Flex.Child, { + grow: 0, + shrink: 0, + basis: "31%", + children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.FormComponents.FormItem, { + title: "Song", + children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Select, { + value: choices[type].song, + options: Object.keys(audios[choices[type].category] || {}).map(name => {return {value:name, label:name}}), + searchable: true, + onChange: song => { + choices[type].song = song.value; + choices[type].src = audios[choices[type].category][choices[type].song] || types[type].src; + this.saveChoice(type, true); + BDFDB.PluginUtils.refreshSettingsPanel(this, settingsPanel.node, collapseStates); + } + }) + }) + }), + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Flex.Child, { + grow: 0, + shrink: 0, + basis: "31%", + children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.FormComponents.FormItem, { + title: "Volume", + children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Slider, { + defaultValue: choices[type].volume, + digits: 1, + onValueRender: value => { + return value + "%"; + }, + onValueChange: value => { + choices[type].volume = value; + this.saveChoice(type, true); + } + }) + }) + }) + ] + }), + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.FormComponents.FormDivider, { + className: BDFDB.disCN.marginbottom8 + }) + ]; + } + + // Legacy + load () {} + + start () { + if (!window.BDFDB) window.BDFDB = {myPlugins:{}}; + if (window.BDFDB && window.BDFDB.myPlugins && typeof window.BDFDB.myPlugins == "object") window.BDFDB.myPlugins[this.getName()] = this; + let libraryScript = document.querySelector("head script#BDFDBLibraryScript"); + if (!libraryScript || (performance.now() - libraryScript.getAttribute("date")) > 600000) { + if (libraryScript) libraryScript.remove(); + libraryScript = document.createElement("script"); + libraryScript.setAttribute("id", "BDFDBLibraryScript"); + libraryScript.setAttribute("type", "text/javascript"); + libraryScript.setAttribute("src", "https://mwittrien.github.io/BetterDiscordAddons/Plugins/BDFDB.min.js"); + libraryScript.setAttribute("date", performance.now()); + libraryScript.addEventListener("load", _ => {this.initialize();}); + document.head.appendChild(libraryScript); + } + else if (window.BDFDB && typeof BDFDB === "object" && BDFDB.loaded) this.initialize(); + this.startTimeout = setTimeout(_ => { + try {return this.initialize();} + catch (err) {console.error(`%c[${this.getName()}]%c`, "color: #3a71c1; font-weight: 700;", "", "Fatal Error: Could not initiate plugin! " + err);} + }, 30000); + } + + initialize () { + if (window.BDFDB && typeof BDFDB === "object" && BDFDB.loaded) { + if (this.started) return; + BDFDB.PluginUtils.init(this); + + BDFDB.ModuleUtils.patch(this, BDFDB.LibraryModules.DispatchApiUtils, "dirtyDispatch", {before: e => { + if (BDFDB.ObjectUtils.is(e.methodArguments[0]) && e.methodArguments[0].type == BDFDB.DiscordConstants.ActionTypes.MESSAGE_CREATE && e.methodArguments[0].message) { + let message = e.methodArguments[0].message; + let guildId = message.guild_id || null; + if (!BDFDB.LibraryModules.MutedUtils.isGuildOrCategoryOrChannelMuted(guildId, message.channel_id) && message.author.id != BDFDB.UserUtils.me.id && !BDFDB.LibraryModules.FriendUtils.isBlocked(message.author.id)) { + if (!guildId && !(choices.dm.focus && document.hasFocus() && BDFDB.LibraryModules.LastChannelStore.getChannelId() == message.channel_id)) { + this.fireEvent("dm"); + this.playAudio("dm"); + return; + } + else if (BDFDB.LibraryModules.MentionUtils.isRawMessageMentioned(message, BDFDB.UserUtils.me.id)) { + if (message.mentions.length && !this.isSuppressMentionEnabled(guildId, message.channel_id) && !(choices.mentioned.focus && document.hasFocus() && BDFDB.LibraryModules.LastChannelStore.getChannelId() == message.channel_id)) for (let mention of message.mentions) if (mention.id == BDFDB.UserUtils.me.id) { + this.fireEvent("mentioned"); + this.playAudio("mentioned"); + return; + } + if (guildId && message.mention_roles.length && !BDFDB.LibraryModules.MutedUtils.isSuppressRolesEnabled(guildId, message.channel_id) && !(choices.role.focus && document.hasFocus() && BDFDB.LibraryModules.LastChannelStore.getChannelId() == message.channel_id)) { + let member = BDFDB.LibraryModules.MemberStore.getMember(guildId, BDFDB.UserUtils.me.id); + if (member && member.roles.length) for (let roleId of message.mention_roles) if (member.roles.includes(roleId)) { + this.fireEvent("role"); + this.playAudio("role"); + return; + } + } + if (message.mention_everyone && !BDFDB.LibraryModules.MutedUtils.isSuppressEveryoneEnabled(guildId, message.channel_id)) { + if (message.content.indexOf("@everyone") > -1 && !(choices.everyone.focus && document.hasFocus() && BDFDB.LibraryModules.LastChannelStore.getChannelId() == message.channel_id)) { + this.fireEvent("everyone"); + this.playAudio("everyone"); + return; + } + if (message.content.indexOf("@here") > -1 && !(choices.here.focus && document.hasFocus() && BDFDB.LibraryModules.LastChannelStore.getChannelId() == message.channel_id)) { + this.fireEvent("here"); + this.playAudio("here"); + return; + } + } + } + } + } + }}); + + BDFDB.ModuleUtils.patch(this, BDFDB.LibraryModules.SoundUtils, "playSound", {instead: e => { + let type = e.methodArguments[0]; + if (choices[type]) BDFDB.TimeUtils.timeout(_ => { + if (type == "message1") { + if (firedEvents["dm"]) firedEvents["dm"] = false; + else if (firedEvents["mentioned"]) firedEvents["mentioned"] = false; + else if (firedEvents["role"]) firedEvents["role"] = false; + else if (firedEvents["everyone"]) firedEvents["everyone"] = false; + else if (firedEvents["here"]) firedEvents["here"] = false; + else this.playAudio(type); + } + else this.playAudio(type); + }); + else e.callOriginalMethod(); + }}); + BDFDB.ModuleUtils.patch(this, BDFDB.LibraryModules.SoundUtils, "createSound", {after: e => { + let type = e.methodArguments[0]; + let audio = new Audio(); + audio.src = choices[type].src; + audio.volume = choices[type].volume/100; + e.returnValue.play = _ => { + if (!audio.paused || this.dontPlayAudio(type)) return; + audio.loop = false; + audio.play(); + }; + e.returnValue.loop = _ => { + if (!audio.paused || this.dontPlayAudio(type)) return; + audio.loop = true; + audio.play(); + }; + e.returnValue.stop = _ => {audio.pause();} + }}); + + + for (let key in defaultAudios) defaultAudios[key] = BDFDB.ObjectUtils.sort(defaultAudios[key]); + + this.loadAudios(); + this.loadChoices(); + + let callListenerModule = BDFDB.ModuleUtils.findByProperties("handleRingUpdate"); + if (callListenerModule) { + callListenerModule.terminate(); + BDFDB.ModuleUtils.patch(this, callListenerModule, "handleRingUpdate", {instead: e => { + BDFDB.LibraryModules.CallUtils.getCalls().filter(call => call.ringing.length > 0 && BDFDB.LibraryModules.VoiceUtils.getCurrentClientVoiceChannelId() === call.channelId).length > 0 && !BDFDB.LibraryModules.SoundStateUtils.isSoundDisabled("call_calling") && !BDFDB.LibraryModules.StreamerModeStore.disableSounds ? callAudio.loop() : callAudio.stop(); + }}); + callListenerModule.initialize(); + } + + this.forceUpdateAll(); + } + else console.error(`%c[${this.getName()}]%c`, "color: #3a71c1; font-weight: 700;", "", "Fatal Error: Could not load BD functions!"); + } + + + stop () { + if (window.BDFDB && typeof BDFDB === "object" && BDFDB.loaded) { + this.stopping = true; + + BDFDB.PluginUtils.clear(this); + settingsAudio.pause(); + } + } + + + // Begin of own functions + + onSettingsClosed () { + if (this.SettingsUpdated) { + delete this.SettingsUpdated; + settingsAudio.pause(); + + this.forceUpdateAll(); + } + } + + processShakeable (e) { + let [children, index] = BDFDB.ReactUtils.findChildren(e.returnvalue, {name: "IncomingCalls"}); + if (index > -1) { + if (repatchIncoming) { + children[index] = null; + BDFDB.TimeUtils.timeout(_ => { + repatchIncoming = false; + BDFDB.ReactUtils.forceUpdate(BDFDB.ReactUtils.findOwner(document.querySelector(BDFDB.dotCN.app), {name:"App", up:true})) + }); + } + else children[index] = BDFDB.ReactUtils.createElement(children[index].type, {}); + } + } + + successSavedAudio (settingsPanel, collapseStates, data) { + BDFDB.NotificationUtils.toast(`Song ${data.song} was added to category ${data.category}.`, {type:"success"}); + if (!audios[data.category]) audios[data.category] = {}; + audios[data.category][data.song] = data.source; + BDFDB.DataUtils.save(audios, this, "audios"); + BDFDB.PluginUtils.refreshSettingsPanel(this, settingsPanel, collapseStates); + + } + + forceUpdateAll () { + repatchIncoming = true; + callAudio = BDFDB.LibraryModules.SoundUtils.createSound("call_calling"); + + BDFDB.ModuleUtils.forceAllUpdates(this); + } + + loadAudios () { + audios = Object.assign({}, defaultAudios, BDFDB.DataUtils.load(this, "audios")); + BDFDB.DataUtils.save(audios, this, "audios"); + } + + loadChoices () { + let loadedChoices = BDFDB.DataUtils.load(this, "choices"); + for (let type in types) { + let choice = loadedChoices[type] || {}, songFound = false; + for (let category in audios) if (choice.category == category) for (let song in audios[category]) if (choice.song == song) { + songFound = true; + break; + } + if (!songFound) choice = { + category: "---", + song: "---", + volume: 100, + src: types[type].src, + mute: types[type].mute, + focus: types[type].focus + }; + choices[type] = choice; + this.saveChoice(type, false); + } + } + + saveChoice (type, play) { + if (!choices[type]) return; + BDFDB.DataUtils.save(choices[type], this, "choices", type); + if (play) { + this.SettingsUpdated = true; + this.playAudio(type, settingsAudio); + } + } + + playAudio (type, audio) { + if (!audio) { + if (this.dontPlayAudio(type)) return; + audio = new Audio(); + } + else audio.pause(); + audio.src = choices[type].src; + audio.volume = choices[type].volume/100; + audio.play(); + } + + isSuppressMentionEnabled (guildId, channelId) { + let channelSettings = BDFDB.LibraryModules.MutedUtils.getChannelMessageNotifications(guildId, channelId); + return channelSettings && (channelSettings == BDFDB.DiscordConstants.UserNotificationSettings.NO_MESSAGES || channelSettings == BDFDB.DiscordConstants.UserNotificationSettings.NULL && BDFDB.LibraryModules.MutedUtils.getMessageNotifications(guildId) == BDFDB.DiscordConstants.UserNotificationSettings.NO_MESSAGES); + } + + dontPlayAudio (type) { + let status = BDFDB.UserUtils.getStatus(); + return choices[type].mute && (status == "dnd" || status == "streaming"); + } + + fireEvent (type) { + firedEvents[type] = true; + BDFDB.TimeUtils.timeout(_ => {firedEvents[type] = false;},3000); + } + } +})();
\ No newline at end of file diff --git a/.config/BetterDiscord/plugins/PinDMs.config.json b/.config/BetterDiscord/plugins/PinDMs.config.json new file mode 100644 index 0000000..63542a6 --- /dev/null +++ b/.config/BetterDiscord/plugins/PinDMs.config.json @@ -0,0 +1,40 @@ +{ + "changelog": { + "currentversion": "1.7.2" + }, + "dmCategories": { + "3516090637537661": { + "collapsed": false, + "color": null, + "dms": [ + "456428001463369729", + "390601823523962892", + "450987439041806346", + "390786176652673034" + ], + "id": "3516090637537661", + "name": "Gouden mannen", + "pos": 1 + }, + "3586821958853646": { + "collapsed": false, + "color": null, + "dms": [ + "606832163404644352", + "590888637877452840", + "458302680998215690", + "514803935761006592" + ], + "id": "3586821958853646", + "name": "Jongens", + "pos": 0 + } + }, + "settings": { + "showCategoryAmount": false, + "showCategoryUnread": true, + "showPinIcon": true, + "sortInRecentOrder": false, + "sortInRecentOrderGuild": false + } +}
\ No newline at end of file diff --git a/.config/BetterDiscord/plugins/PinDMs.plugin.js b/.config/BetterDiscord/plugins/PinDMs.plugin.js new file mode 100644 index 0000000..4c5b002 --- /dev/null +++ b/.config/BetterDiscord/plugins/PinDMs.plugin.js @@ -0,0 +1,1149 @@ +//META{"name":"PinDMs","authorId":"278543574059057154","invite":"Jx3TjNS","donate":"https://www.paypal.me/MircoWittrien","patreon":"https://www.patreon.com/MircoWittrien","website":"https://github.com/mwittrien/BetterDiscordAddons/tree/master/Plugins/PinDMs","source":"https://raw.githubusercontent.com/mwittrien/BetterDiscordAddons/master/Plugins/PinDMs/PinDMs.plugin.js"}*// + +var PinDMs = (_ => { + let hoveredCategory, draggedCategory, releasedCategory; + let hoveredChannel, draggedChannel, releasedChannel; + + return class PinDMs { + getName () {return "PinDMs";} + + getVersion () {return "1.7.2";} + + getAuthor () {return "DevilBro";} + + getDescription () {return "Allows you to pin DMs, making them appear at the top of your DMs/Guild-list.";} + + constructor () { + this.changelog = { + "fixed":[["Context Menu Update","Fixes for the context menu update, yaaaaaay"]] + }; + + this.patchedModules = { + before: { + PrivateChannelsList: "render", + UnreadDMs: "render" + }, + after: { + PrivateChannelsList: "render", + UnreadDMs: "render", + PrivateChannel: ["render", "componentDidMount"], + DirectMessage: ["render", "componentDidMount", "componentWillUnmount"] + } + }; + } + + initConstructor () { + this.css = ` + ${BDFDB.dotCNS.dmchannel + BDFDB.dotCN.namecontainerchildren} { + display: flex; + } + ${BDFDB.dotCN.dmchannel}:hover ${BDFDB.dotCN._pindmsunpinbutton} { + display: block; + } + ${BDFDB.dotCN._pindmspinnedchannelsheadercontainer} { + display: flex; + cursor: pointer; + } + ${BDFDB.dotCNS._pindmspinnedchannelsheadercontainer + BDFDB.dotCN.dmchannelheadertext} { + margin-right: 6px; + } + ${BDFDB.dotCN._pindmspinnedchannelsheadercontainer + BDFDB.dotCN._pindmspinnedchannelsheadercolored}:hover ${BDFDB.dotCN.dmchannelheadertext} { + filter: brightness(150%); + } + ${BDFDB.dotCNS._pindmspinnedchannelsheadercontainer + BDFDB.dotCN._pindmspinnedchannelsheaderamount} { + position: relative; + top: -1px; + margin-right: 6px; + } + ${BDFDB.dotCN._pindmspinnedchannelsheaderarrow} { + flex: 0; + width: 16px; + height: 16px; + margin-left: 0; + margin-right: 2px; + } + ${BDFDB.dotCNS._pindmspinnedchannelsheadercollapsed + BDFDB.dotCN._pindmspinnedchannelsheaderarrow + BDFDB.dotCN.channelheadericonwrapper} { + transform: rotate(-90deg); + } + ${BDFDB.dotCN._pindmsunpinbutton} { + display: none; + width: 16px; + height: 16px; + opacity: .7; + margin: 2px; + } + ${BDFDB.dotCN._pindmsunpinbutton}:hover { + opacity: 1; + } + ${BDFDB.dotCN._pindmsunpinicon} { + display: block; + width: 16px; + height: 16px; + } + ${BDFDB.dotCNS._pindmsdmchannelplaceholder + BDFDB.dotCN.namecontainerlayout} { + box-sizing: border-box; + border: 1px dashed currentColor; + } + ${BDFDB.dotCN._pindmspinnedchannelsheadercontainer + BDFDB.dotCN._pindmsdmchannelplaceholder} { + margin-left: 8px; + height: 12px; + box-sizing: border-box; + border: 1px dashed currentColor; + } + ${BDFDB.dotCN._pindmsdragpreview} { + pointer-events: none !important; + position: absolute !important; + opacity: 0.5 !important; + z-index: 10000 !important; + }`; + + this.defaults = { + settings: { + sortInRecentOrder: {value:false, inner:true, description:"Channel List"}, + sortInRecentOrderGuild: {value:false, inner:true, description:"Guild List"}, + showPinIcon: {value:true, inner:false, description:"Shows a little 'Pin' icon for pinned DMs in the server list:"}, + showCategoryUnread: {value:true, inner:false, description:"Shows the amount of unread Messages in a category in the channel list:"}, + showCategoryAmount: {value:true, inner:false, description:"Shows the amount of pinned DMs in a category in the channel list:"} + } + }; + } + + getSettingsPanel () { + if (!window.BDFDB || typeof BDFDB != "object" || !BDFDB.loaded || !this.started) return; + let settings = BDFDB.DataUtils.get(this, "settings"); + let settingsPanel, settingsItems = [], innerItems = []; + + for (let key in settings) (!this.defaults.settings[key].inner ? settingsItems : innerItems).push(BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SettingsSaveItem, { + className: BDFDB.disCN.marginbottom8, + type: "Switch", + plugin: this, + keys: ["settings", key], + label: this.defaults.settings[key].description, + value: settings[key] + })); + settingsItems.push(BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SettingsPanelInner, { + title: "Sort pinned DMs in the recent message order instead of the pinned at order in:", + first: settingsItems.length == 0, + children: innerItems + })); + settingsItems.push(BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SettingsItem, { + type: "Button", + className: BDFDB.disCN.marginbottom8, + color: BDFDB.LibraryComponents.Button.Colors.RED, + label: "Unpin all pinned DMs", + onClick: _ => { + BDFDB.ModalUtils.confirm(this, "Are you sure you want to unpin all pinned DMs?", _ => { + BDFDB.DataUtils.remove(this, "dmCategories"); + BDFDB.DataUtils.remove(this, "pinnedRecents"); + }); + }, + children: BDFDB.LanguageUtils.LanguageStrings.UNPIN + })); + + return settingsPanel = BDFDB.PluginUtils.createSettingsPanel(this, settingsItems); + } + + // Legacy + load () {} + + start () { + if (!window.BDFDB) window.BDFDB = {myPlugins:{}}; + if (window.BDFDB && window.BDFDB.myPlugins && typeof window.BDFDB.myPlugins == "object") window.BDFDB.myPlugins[this.getName()] = this; + let libraryScript = document.querySelector("head script#BDFDBLibraryScript"); + if (!libraryScript || (performance.now() - libraryScript.getAttribute("date")) > 600000) { + if (libraryScript) libraryScript.remove(); + libraryScript = document.createElement("script"); + libraryScript.setAttribute("id", "BDFDBLibraryScript"); + libraryScript.setAttribute("type", "text/javascript"); + libraryScript.setAttribute("src", "https://mwittrien.github.io/BetterDiscordAddons/Plugins/BDFDB.min.js"); + libraryScript.setAttribute("date", performance.now()); + libraryScript.addEventListener("load", _ => {this.initialize();}); + document.head.appendChild(libraryScript); + } + else if (window.BDFDB && typeof BDFDB === "object" && BDFDB.loaded) this.initialize(); + this.startTimeout = setTimeout(_ => { + try {return this.initialize();} + catch (err) {console.error(`%c[${this.getName()}]%c`, "color: #3a71c1; font-weight: 700;", "", "Fatal Error: Could not initiate plugin! " + err);} + }, 30000); + } + + initialize () { + if (window.BDFDB && typeof BDFDB === "object" && BDFDB.loaded) { + if (this.started) return; + BDFDB.PluginUtils.init(this); + + this.forceUpdateAll(); + } + else console.error(`%c[${this.getName()}]%c`, "color: #3a71c1; font-weight: 700;", "", "Fatal Error: Could not load BD functions!"); + } + + stop () { + if (window.BDFDB && typeof BDFDB === "object" && BDFDB.loaded) { + this.stopping = true; + + this.forceUpdateAll(true); + + let unreadDMsInstance = BDFDB.ReactUtils.findOwner(document.querySelector(BDFDB.dotCN.app), {name:"UnreadDMs", unlimited:true}); + if (unreadDMsInstance) { + delete unreadDMsInstance.props.pinnedPrivateChannelIds; + unreadDMsInstance.props.unreadPrivateChannelIds = BDFDB.LibraryModules.DirectMessageUnreadStore.getUnreadPrivateChannelIds(); + BDFDB.ReactUtils.forceUpdate(unreadDMsInstance); + } + + BDFDB.PluginUtils.clear(this); + } + } + + + // Begin of own functions + + onSettingsClosed (instance, wrapper, returnvalue) { + if (this.SettingsUpdated) { + delete this.SettingsUpdated; + this.forceUpdateAll(); + } + } + + onUserContextMenu (e) { + if (e.instance.props.user) { + let [children, index] = BDFDB.ContextMenuUtils.findItem(e.returnvalue, {id: "close-dm"}); + if (index > -1) { + let id = BDFDB.LibraryModules.ChannelStore.getDMFromUserId(e.instance.props.user.id); + if (id) this.injectItem(e.instance, id, children, index); + } + } + } + + onGroupDMContextMenu (e) { + if (e.instance.props.channel) { + let [children, index] = BDFDB.ContextMenuUtils.findItem(e.returnvalue, {id: "change-icon"}); + if (index > -1) this.injectItem(e.instance, e.instance.props.channel.id, children, index + 1); + } + } + + injectItem (instance, id, children, index) { + let pinnedInGuild = this.isPinned(id, "pinnedRecents"); + + let categories = this.sortAndUpdateCategories("dmCategories", true); + let currentCategory = this.getCategory(id, "dmCategories"); + + children.splice(index, 0, BDFDB.ContextMenuUtils.createItem(BDFDB.LibraryComponents.MenuItems.MenuItem, { + label: this.labels.context_pindm_text, + id: BDFDB.ContextMenuUtils.createItemId(this.name, "submenu-pin"), + children: [ + BDFDB.ContextMenuUtils.createItem(BDFDB.LibraryComponents.MenuItems.MenuItem, { + label: this.labels.context_pinchannel_text, + id: BDFDB.ContextMenuUtils.createItemId(this.name, "submenu-channelist"), + children: [ + BDFDB.ContextMenuUtils.createItem(BDFDB.LibraryComponents.MenuItems.MenuGroup, { + children: currentCategory ? BDFDB.ContextMenuUtils.createItem(BDFDB.LibraryComponents.MenuItems.MenuItem, { + label: this.labels.context_unpinchannel_text, + id: BDFDB.ContextMenuUtils.createItemId(this.name, "unpin-channellist"), + color: BDFDB.LibraryComponents.MenuItems.Colors.DANGER, + action: _ => { + BDFDB.ContextMenuUtils.close(instance); + this.removeFromCategory(id, currentCategory, "dmCategories"); + } + }) : BDFDB.ContextMenuUtils.createItem(BDFDB.LibraryComponents.MenuItems.MenuItem, { + label: this.labels.context_addtonewcategory_text, + id: BDFDB.ContextMenuUtils.createItemId(this.name, "new-channellist"), + color: BDFDB.LibraryComponents.MenuItems.Colors.BRAND, + action: _ => { + BDFDB.ContextMenuUtils.close(instance); + this.openCategorySettingsModal({ + id: this.generateID("dmCategories").toString(), + name: `${this.labels.header_pinneddms_text} #${categories.length + 1}`, + dms: [id], + pos: categories.length, + collapsed: false, + color: null + }, "dmCategories", true); + } + }) + }), + categories.length ? BDFDB.ContextMenuUtils.createItem(BDFDB.LibraryComponents.MenuItems.MenuGroup, { + children: categories.map(category => currentCategory && currentCategory.id == category.id ? null : BDFDB.ContextMenuUtils.createItem(BDFDB.LibraryComponents.MenuItems.MenuItem, { + label: category.name || this.labels.header_pinneddms_text, + id: BDFDB.ContextMenuUtils.createItemId(this.name, "pin-channellist", category.id), + action: _ => { + BDFDB.ContextMenuUtils.close(instance); + if (currentCategory) this.removeFromCategory(id, currentCategory, "dmCategories"); + this.addToCategory(id, category, "dmCategories"); + } + })).filter(n => n) + }) : null + ].filter(n => n) + }), + BDFDB.ContextMenuUtils.createItem(BDFDB.LibraryComponents.MenuItems.MenuItem, { + label: this.labels[pinnedInGuild ? "context_unpinguild_text" : "context_pinguild_text"], + id: BDFDB.ContextMenuUtils.createItemId(this.name, pinnedInGuild ? "unpin-serverlist" : "pin-serverlist"), + danger: pinnedInGuild, + action: _ => { + BDFDB.ContextMenuUtils.close(instance); + if (!pinnedInGuild) this.addPin(id, "pinnedRecents"); + else this.removePin(id, "pinnedRecents"); + } + }) + ] + })); + } + + processPrivateChannelsList (e) { + let categories = this.sortAndUpdateCategories("dmCategories", true); + if (categories.length) { + e.instance.props.channels = Object.assign({}, e.instance.props.channels); + e.instance.props.privateChannelIds = [].concat(e.instance.props.privateChannelIds || []); + e.instance.props.pinnedChannelIds = Object.assign({}, e.instance.props.pinnedChannelIds); + if (!e.returnvalue) { + if (draggedChannel && releasedChannel) { + let categoryId = releasedChannel.split("header_")[1]; + let category = categories.find(n => categoryId != undefined ? n.id == categoryId : n.dms.includes(releasedChannel)); + if (category) { + BDFDB.ArrayUtils.remove(category.dms, draggedChannel, true); + category.dms.splice(categoryId != undefined ? 0 : category.dms.indexOf(releasedChannel) + 1, 0, draggedChannel); + BDFDB.DataUtils.save(category, this, "dmCategories", category.id); + } + draggedChannel = null; + releasedChannel = null; + } + if (draggedCategory && releasedCategory) { + let maybedDraggedCategory = categories.find(n => n.id == draggedCategory); + let maybedReleasedCategory = categories.find(n => n.id == releasedCategory); + if (maybedDraggedCategory && maybedReleasedCategory) { + BDFDB.ArrayUtils.remove(categories, maybedDraggedCategory, true); + categories.splice(categories.indexOf(maybedReleasedCategory) + 1, 0, maybedDraggedCategory); + let newCategories = {}, newPos = 0; + for (let category of [].concat(categories).reverse()) newCategories[category.id] = Object.assign(category, {pos:newPos++}); + BDFDB.DataUtils.save(newCategories, this, "dmCategories"); + } + draggedCategory = null; + releasedCategory = null; + } + e.instance.props.pinnedChannelIds = {}; + for (let category of [].concat(categories).reverse()) { + e.instance.props.pinnedChannelIds[category.id] = []; + for (let id of this.sortDMsByTime(this.filterDMs(category.dms), "dmCategories").reverse()) { + BDFDB.ArrayUtils.remove(e.instance.props.privateChannelIds, id, true); + if (!category.collapsed || e.instance.props.selectedChannelId == id) { + e.instance.props.privateChannelIds.unshift(id); + e.instance.props.pinnedChannelIds[category.id].push(id); + } + } + } + } + else { + e.returnvalue.props.sections = []; + e.returnvalue.props.sections.push(e.instance.state.preRenderedChildren); + let shownPinnedIds = BDFDB.ObjectUtils.toArray(e.instance.props.pinnedChannelIds).reverse(); + for (let ids of shownPinnedIds) e.returnvalue.props.sections.push(ids.length || 1); + e.returnvalue.props.sections.push(e.instance.props.privateChannelIds.length - shownPinnedIds.flat().length); + + let sectionHeight = e.returnvalue.props.sectionHeight; + let sectionHeightFunc = typeof sectionHeight != "function" ? _ => sectionHeight : sectionHeight; + e.returnvalue.props.sectionHeight = (...args) => { + if (args[0] != 0 && args[0] != e.returnvalue.props.sections.length - 1) { + let category = categories[args[0] - 1]; + if (category) return 40; + } + return sectionHeightFunc(...args); + }; + + let rowHeight = e.returnvalue.props.rowHeight; + let rowHeightFunc = typeof rowHeight != "function" ? _ => rowHeight : rowHeight; + e.returnvalue.props.rowHeight = (...args) => { + if (args[0] != 0 && args[0] != e.returnvalue.props.sections.length - 1) { + let category = categories[args[0] - 1]; + if (category && (category.collapsed || category.id == draggedCategory)) return 0; + } + return rowHeightFunc(...args); + }; + } + + let settings = BDFDB.DataUtils.get(this, "settings"); + BDFDB.ModuleUtils.unpatch(this, e.instance, "renderSection"); + BDFDB.ModuleUtils.patch(this, e.instance, "renderSection", {after: e2 => { + if (e2.methodArguments[0].section != 0 && e2.methodArguments[0].section != e.instance.props.listRef.current.props.sections.length - 1) { + let category = categories[e2.methodArguments[0].section - 1]; + if (category && draggedCategory != category.id) { + let color = BDFDB.ColorUtils.convert(category.color, "RGBA"); + let foundDMs = this.filterDMs(category.dms); + let unreadAmount = settings.showCategoryUnread && BDFDB.ArrayUtils.sum(foundDMs.map(id => BDFDB.LibraryModules.UnreadChannelUtils.getMentionCount(id))); + e2.returnValue = [ + BDFDB.ReactUtils.createElement("h2", { + className: BDFDB.DOMUtils.formatClassName(BDFDB.disCN.dmchannelheadercontainer, BDFDB.disCN._pindmspinnedchannelsheadercontainer, category.collapsed && BDFDB.disCN._pindmspinnedchannelsheadercollapsed, color && BDFDB.disCN._pindmspinnedchannelsheadercolored, BDFDB.disCN.namecontainernamecontainer), + categoryId: category.id, + onMouseDown: event => { + event = event.nativeEvent || event; + let node = BDFDB.DOMUtils.getParent(BDFDB.dotCN._pindmspinnedchannelsheadercontainer, event.target).cloneNode(true); + let mousemove = event2 => { + if (Math.sqrt((event.pageX - event2.pageX)**2) > 20 || Math.sqrt((event.pageY - event2.pageY)**2) > 20) { + BDFDB.ListenerUtils.stopEvent(event); + draggedCategory = category.id; + this.updateContainer("dmCategories"); + let dragPreview = this.createDragPreview(node, event2); + document.removeEventListener("mousemove", mousemove); + document.removeEventListener("mouseup", mouseup); + let dragging = event3 => { + this.updateDragPreview(dragPreview, event3); + let placeholder = BDFDB.DOMUtils.getParent(BDFDB.dotCN._pindmsdmchannelplaceholder, event3.target); + let categoryNode = BDFDB.DOMUtils.getParent(BDFDB.dotCN._pindmspinnedchannelsheadercontainer, placeholder ? placeholder.previousSibling : event3.target); + let maybeHoveredCategory = categoryNode && categoryNode.getAttribute("categoryId"); + let update = maybeHoveredCategory != hoveredCategory; + if (maybeHoveredCategory) hoveredCategory = maybeHoveredCategory; + else hoveredCategory = null; + if (update) this.updateContainer("dmCategories"); + }; + let releasing = event3 => { + BDFDB.DOMUtils.remove(dragPreview); + if (hoveredCategory) releasedCategory = hoveredCategory; + else draggedCategory = null; + hoveredCategory = null; + this.updateContainer("dmCategories"); + document.removeEventListener("mousemove", dragging); + document.removeEventListener("mouseup", releasing); + }; + document.addEventListener("mousemove", dragging); + document.addEventListener("mouseup", releasing); + } + }; + let mouseup = _ => { + document.removeEventListener("mousemove", mousemove); + document.removeEventListener("mouseup", mouseup); + }; + document.addEventListener("mousemove", mousemove); + document.addEventListener("mouseup", mouseup); + }, + onClick: _ => { + if (foundDMs.length || !category.collapsed) { + category.collapsed = !category.collapsed; + BDFDB.DataUtils.save(category, this, "dmCategories", category.id); + this.updateContainer("dmCategories"); + } + }, + onContextMenu: event => { + BDFDB.ContextMenuUtils.open(this, event, BDFDB.ContextMenuUtils.createItem(BDFDB.LibraryComponents.MenuItems.MenuGroup, { + children: [ + BDFDB.ContextMenuUtils.createItem(BDFDB.LibraryComponents.MenuItems.MenuItem, { + label: BDFDB.LanguageUtils.LanguageStrings.CATEGORY_SETTINGS, + id: BDFDB.ContextMenuUtils.createItemId(this.name, "category-settings"), + action: event2 => { + BDFDB.ContextMenuUtils.close(BDFDB.DOMUtils.getParent(BDFDB.dotCN.contextmenu, event2.target)); + this.openCategorySettingsModal(category, "dmCategories"); + } + }), + BDFDB.ContextMenuUtils.createItem(BDFDB.LibraryComponents.MenuItems.MenuItem, { + label: BDFDB.LanguageUtils.LanguageStrings.DELETE_CATEGORY, + id: BDFDB.ContextMenuUtils.createItemId(this.name, "remove-category"), + color: BDFDB.LibraryComponents.MenuItems.Colors.DANGER, + action: event2 => { + BDFDB.ContextMenuUtils.close(BDFDB.DOMUtils.getParent(BDFDB.dotCN.contextmenu, event2.target)); + BDFDB.DataUtils.remove(this, "dmCategories", category.id); + this.updateContainer("dmCategories"); + } + }) + ] + })); + }, + children: [ + BDFDB.ObjectUtils.is(color) ? BDFDB.ReactUtils.createElement("span", { + className: BDFDB.disCN.dmchannelheadertext, + children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.TextGradientElement, { + gradient: BDFDB.ColorUtils.createGradient(color), + children: category.name + }) + }) : BDFDB.ReactUtils.createElement("span", { + className: BDFDB.disCN.dmchannelheadertext, + style: {color: color}, + children: category.name, + }), + unreadAmount ? BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Badges.NumberBadge, { + className: BDFDB.disCN._pindmspinnedchannelsheaderamount, + count: unreadAmount, + style: {backgroundColor: BDFDB.DiscordConstants.Colors.STATUS_RED} + }) : null, + settings.showCategoryAmount ? BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Badges.NumberBadge, { + className: BDFDB.disCN._pindmspinnedchannelsheaderamount, + count: foundDMs.length, + style: {backgroundColor: BDFDB.DiscordConstants.Colors.BRAND} + }) : null, + BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCNS._pindmspinnedchannelsheaderarrow + BDFDB.disCNS.channelheadericonwrapper + BDFDB.disCN.channelheadericonclickable, + children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SvgIcon, { + className: BDFDB.disCNS._pindmspinnedchannelsheaderarrow + BDFDB.disCN.channelheadericon, + nativeClass: true, + iconSVG: `<svg width="24" height="24" viewBox="4 4 16 16"><path fill="currentColor" fill-rule="evenodd" clip-rule="evenodd" d="M16.59 8.59004L12 13.17L7.41 8.59004L6 10L12 16L18 10L16.59 8.59004Z"></path></svg>` + }) + }) + ].filter(n => n) + }), + hoveredChannel == "header_" + category.id && BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCNS.dmchannel + BDFDB.disCNS._pindmsdmchannelpinned + BDFDB.disCNS._pindmsdmchannelplaceholder + BDFDB.disCN.namecontainernamecontainer, + children: BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCN.namecontainerlayout + }) + }) + ].filter(n => n); + } + else e2.returnValue = null; + } + }}, {force: true, noCache: true}); + + let pinnedIds = BDFDB.ObjectUtils.toArray(e.instance.props.pinnedChannelIds).reverse(); + BDFDB.ModuleUtils.unpatch(this, e.instance, "renderDM"); + BDFDB.ModuleUtils.patch(this, e.instance, "renderDM", {before: e2 => { + if (e2.methodArguments[0] != 0) e2.methodArguments[1] += pinnedIds.slice(0, e2.methodArguments[0] - 1).flat().length; + }, after: e2 => { + if (e2.methodArguments[0] != 0) { + let id = e.instance.props.privateChannelIds[e2.methodArguments[1]]; + e2.returnValue = e.instance.props.channels[id] ? BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.PrivateChannelItems[e.instance.props.channels[id].isMultiUserDM() ? "GroupDM" : "DirectMessage"], Object.assign({ + key: id, + channel: e.instance.props.channels[id], + selected: e.instance.props.selectedChannelId == id + }, (e.instance.props.navigator || e.instance.props.listNavigator).getItemProps({ + index: e2.methodArguments[2] + }))) : null; + + let category = categories[e2.methodArguments[0] - 1]; + if (category) { + if (!id || (category.collapsed && e.instance.props.selectedChannelId != id) || !category.dms.includes(id) || draggedCategory == category.id || draggedChannel == id) e2.returnValue = null; + else if (hoveredCategory == category.id && [].concat(category.dms).reverse()[0] == id) e2.returnValue = [ + e2.returnValue, + BDFDB.ReactUtils.createElement("h2", { + className: BDFDB.disCNS.dmchannelheadercontainer + BDFDB.disCNS._pindmspinnedchannelsheadercontainer + BDFDB.disCNS._pindmsdmchannelplaceholder + BDFDB.disCN.namecontainernamecontainer + }) + ].filter(n => n); + else if (hoveredChannel == id) e2.returnValue = [ + e2.returnValue, + BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCNS.dmchannel + BDFDB.disCNS._pindmsdmchannelpinned + BDFDB.disCNS._pindmsdmchannelplaceholder + BDFDB.disCN.namecontainernamecontainer, + children: BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCN.namecontainerlayout + }) + }) + ].filter(n => n); + } + } + }}, {force: true, noCache: true}); + } + } + + processUnreadDMs (e) { + e.instance.props.pinnedPrivateChannelIds = []; + let sortedRecents = this.sortAndUpdate("pinnedRecents"); + if (sortedRecents.length) { + e.instance.props.unreadPrivateChannelIds = []; + for (let pos in sortedRecents) { + let id = sortedRecents[pos]; + if (e.instance.props.channels[id]) { + if (!e.instance.props.pinnedPrivateChannelIds.includes(id)) e.instance.props.pinnedPrivateChannelIds.push(id); + if (!e.instance.props.unreadPrivateChannelIds.includes(id)) e.instance.props.unreadPrivateChannelIds.push(id); + } + } + e.instance.props.unreadPrivateChannelIds = e.instance.props.unreadPrivateChannelIds.concat(BDFDB.LibraryModules.DirectMessageUnreadStore.getUnreadPrivateChannelIds()); + if (e.returnvalue) { + if (draggedChannel && releasedChannel) { + let pinnedPrivateChannelIds = [].concat(e.instance.props.pinnedPrivateChannelIds), newData = {}; + BDFDB.ArrayUtils.remove(pinnedPrivateChannelIds, draggedChannel, true); + pinnedPrivateChannelIds.splice(pinnedPrivateChannelIds.indexOf(releasedChannel) + 1, 0, draggedChannel); + for (let pos in pinnedPrivateChannelIds) newData[pinnedPrivateChannelIds[pos]] = parseInt(pos); + BDFDB.DataUtils.save(newData, this, "pinnedRecents"); + draggedChannel = null; + releasedChannel = null; + BDFDB.ReactUtils.forceUpdate(e.instance); + } + if (draggedChannel) { + let [children, index] = BDFDB.ReactUtils.findChildren(e.returnvalue, {filter: child => BDFDB.ReactUtils.getValue(child, "props.channel.id") == draggedChannel}); + children.splice(index, 1); + } + if (this.hoveredChannel) { + let [children, index] = BDFDB.ReactUtils.findChildren(e.returnvalue, {filter: child => BDFDB.ReactUtils.getValue(child, "props.channel.id") == this.hoveredChannel}); + children.splice(index + 1, 0, BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCNS.guildouter + BDFDB.disCN._pindmsrecentplaceholder, + children: BDFDB.ReactUtils.createElement("div", { + children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.GuildComponents.Items.DragPlaceholder, {}) + }) + })); + } + } + } + else e.instance.props.unreadPrivateChannelIds = BDFDB.LibraryModules.DirectMessageUnreadStore.getUnreadPrivateChannelIds(); + } + + processPrivateChannel (e) { + if (e.instance.props.channel) { + let category = this.getCategory(e.instance.props.channel.id, "dmCategories"); + if (category) { + if (e.node) { + BDFDB.DOMUtils.addClass(e.node, BDFDB.disCN._pindmsdmchannelpinned); + e.node.removeEventListener("mousedown", e.node.PinDMsMouseDownListener); + if (!BDFDB.DataUtils.get(this, "settings", "sortInRecentOrder")) { + e.node.setAttribute("draggable", false); + e.node.PinDMsMouseDownListener = event => { + if (!BDFDB.BDUtils.isPluginEnabled("PinDMs")) e.node.removeEventListener("mousedown", e.node.PinDMsMouseDownListener); + else { + event = event.nativeEvent || event; + let mousemove = event2 => { + if (Math.sqrt((event.pageX - event2.pageX)**2) > 20 || Math.sqrt((event.pageY - event2.pageY)**2) > 20) { + BDFDB.ListenerUtils.stopEvent(event); + draggedChannel = e.instance.props.channel.id; + this.updateContainer("dmCategories"); + let dragPreview = this.createDragPreview(e.node, event2); + document.removeEventListener("mousemove", mousemove); + document.removeEventListener("mouseup", mouseup); + let dragging = event3 => { + this.updateDragPreview(dragPreview, event3); + let maybeHoveredChannel = null; + let categoryNode = BDFDB.DOMUtils.getParent(BDFDB.dotCN._pindmspinnedchannelsheadercontainer, event3.target); + if (categoryNode) { + let hoveredCategoryId = categoryNode.getAttribute("categoryid"); + if (hoveredCategoryId && hoveredCategoryId == category.id) maybeHoveredChannel = "header_" + category.id; + } + else { + let placeholder = BDFDB.DOMUtils.getParent(BDFDB.dotCN._pindmsdmchannelplaceholder, event3.target); + maybeHoveredChannel = (BDFDB.ReactUtils.findValue(BDFDB.DOMUtils.getParent(BDFDB.dotCN._pindmsdmchannelpinned, placeholder ? placeholder.previousSibling : event3.target), "channel", {up: true}) || {}).id; + let maybeHoveredCategory = maybeHoveredChannel && this.getCategory(maybeHoveredChannel, "dmCategories"); + if (!maybeHoveredCategory || maybeHoveredCategory.id != category.id) maybeHoveredChannel = null; + }; + let update = maybeHoveredChannel != hoveredChannel; + if (maybeHoveredChannel) hoveredChannel = maybeHoveredChannel; + else hoveredChannel = null; + if (update) this.updateContainer("dmCategories"); + }; + let releasing = event3 => { + BDFDB.DOMUtils.remove(dragPreview); + if (hoveredChannel) releasedChannel = hoveredChannel; + else draggedChannel = null; + hoveredChannel = null; + this.updateContainer("dmCategories"); + document.removeEventListener("mousemove", dragging); + document.removeEventListener("mouseup", releasing); + }; + document.addEventListener("mousemove", dragging); + document.addEventListener("mouseup", releasing); + } + }; + let mouseup = _ => { + document.removeEventListener("mousemove", mousemove); + document.removeEventListener("mouseup", mouseup); + }; + document.addEventListener("mousemove", mousemove); + document.addEventListener("mouseup", mouseup); + } + }; + e.node.addEventListener("mousedown", e.node.PinDMsMouseDownListener); + } + } + if (e.returnvalue) e.returnvalue.props.children = [ + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.TooltipContainer, { + text: BDFDB.LanguageUtils.LanguageStrings.UNPIN, + children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Clickable, { + className: BDFDB.disCN._pindmsunpinbutton, + onClick: event => { + BDFDB.ListenerUtils.stopEvent(event); + this.removeFromCategory(e.instance.props.channel.id, category, "dmCategories"); + }, + children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SvgIcon, { + className: BDFDB.disCN._pindmsunpinicon, + name: BDFDB.LibraryComponents.SvgIcon.Names.PIN + }) + }) + }), + e.returnvalue.props.children + ].flat(10).filter(n => n); + } + } + } + + processDirectMessage (e) { + if (e.instance.props.channel) { + if (e.node && e.methodname == "componentDidMount") { + BDFDB.DOMUtils.removeClass(e.node, BDFDB.disCN._pindmsrecentpinned); + e.node.removeEventListener("contextmenu", e.node.PinDMsContextMenuListener); + e.node.PinDMsContextMenuListener = event => {BDFDB.DMUtils.openMenu(e.instance.props.channel.id, event);}; + e.node.addEventListener("contextmenu", e.node.PinDMsContextMenuListener); + if (this.isPinned(e.instance.props.channel.id, "pinnedRecents")) { + BDFDB.DOMUtils.addClass(e.node, BDFDB.disCN._pindmsrecentpinned); + e.node.removeEventListener("mousedown", e.node.PinDMsMouseDownListener); + if (!BDFDB.DataUtils.get(this, "settings", "sortInRecentOrderGuild")) { + for (let child of e.node.querySelectorAll("a")) child.setAttribute("draggable", false); + e.node.PinDMsMouseDownListener = event => { + let mousemove = event2 => { + if (Math.sqrt((event.pageX - event2.pageX)**2) > 20 || Math.sqrt((event.pageY - event2.pageY)**2) > 20) { + BDFDB.ListenerUtils.stopEvent(event); + draggedChannel = e.instance.props.channel.id; + BDFDB.ModuleUtils.forceAllUpdates(this, "UnreadDMs"); + let dragPreview = this.createDragPreview(e.node, event2); + document.removeEventListener("mousemove", mousemove); + document.removeEventListener("mouseup", mouseup); + let dragging = event3 => { + this.updateDragPreview(dragPreview, event3); + let placeholder = BDFDB.DOMUtils.getParent(BDFDB.dotCN._pindmsrecentplaceholder, event3.target); + let maybeHoveredChannel = (BDFDB.ReactUtils.findValue(BDFDB.DOMUtils.getParent(BDFDB.dotCN._pindmsrecentpinned, placeholder ? placeholder.previousSibling : event3.target), "channel", {up: true}) || {}).id; + let update = maybeHoveredChannel != hoveredChannel; + if (maybeHoveredChannel) hoveredChannel = maybeHoveredChannel; + else hoveredChannel = null; + if (update) BDFDB.ModuleUtils.forceAllUpdates(this, "UnreadDMs"); + }; + let releasing = event3 => { + BDFDB.DOMUtils.remove(dragPreview); + if (hoveredChannel) releasedChannel = hoveredChannel; + else draggedChannel = null; + hoveredChannel = null; + BDFDB.ModuleUtils.forceAllUpdates(this, "UnreadDMs"); + document.removeEventListener("mousemove", dragging); + document.removeEventListener("mouseup", releasing); + }; + document.addEventListener("mousemove", dragging); + document.addEventListener("mouseup", releasing); + } + }; + let mouseup = _ => { + document.removeEventListener("mousemove", mousemove); + document.removeEventListener("mouseup", mouseup); + }; + document.addEventListener("mousemove", mousemove); + document.addEventListener("mouseup", mouseup); + }; + e.node.addEventListener("mousedown", e.node.PinDMsMouseDownListener); + } + } + } + if (e.node && e.methodname == "componentWillUnmount") { + BDFDB.ModuleUtils.forceAllUpdates(this, "PrivateChannelsList"); + } + if (e.returnvalue && this.isPinned(e.instance.props.channel.id, "pinnedRecents") && BDFDB.DataUtils.get(this, "settings", "showPinIcon")) { + let [children, index] = BDFDB.ReactUtils.findChildren(e.returnvalue, {name:"BlobMask"}); + if (index > -1) children[index].props.upperLeftBadge = BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Badges.IconBadge, { + className: BDFDB.disCN.guildiconbadge, + disableColor: true, + style: {transform: "scale(-1, 1)"}, + icon: BDFDB.LibraryComponents.SvgIcon.Names.NOVA_PIN + }); + } + } + } + + generateID (type) { + if (!type) return null; + let categories = BDFDB.DataUtils.load(this, type); + let id = Math.round(Math.random() * 10000000000000000); + return categories[id] ? this.generateID() : id; + } + + filterDMs (dms) { + return dms.filter(id => BDFDB.LibraryModules.ChannelStore.getChannel(id)); + } + + addToCategory (id, category, type) { + if (!id || !category || !type) return; + let wasEmpty = !this.filterDMs(category.dms).length; + if (!category.dms.includes(id)) category.dms.unshift(id); + if (wasEmpty && category.dms.length) category.collapsed = false; + BDFDB.DataUtils.save(category, this, type, category.id); + this.updateContainer(type); + } + + removeFromCategory (id, category, type) { + if (!id || !category || !type) return; + BDFDB.ArrayUtils.remove(category.dms, id, true); + if (!this.filterDMs(category.dms).length) category.collapsed = true; + BDFDB.DataUtils.save(category, this, type, category.id); + this.updateContainer(type); + } + + getCategory (id, type) { + if (!id || !type) return null; + let categories = BDFDB.DataUtils.load(this, type); + for (let catId in categories) if (categories[catId].dms.includes(id)) return categories[catId]; + return null; + } + + sortAndUpdateCategories (type, reverse) { + let data = BDFDB.ObjectUtils.sort(BDFDB.DataUtils.load(this, type), "pos"), newData = {}; + let sorted = [], pos = 0, sort = id => { + if (sorted[pos] === undefined) { + newData[id] = Object.assign({}, data[id], {pos}); + sorted[pos] = newData[id]; + } + else { + pos++; + sort(id); + } + }; + for (let id in data) sort(id); + if (!BDFDB.equals(data, newData)) BDFDB.DataUtils.save(newData, this, type); + return (reverse ? sorted.reverse() : sorted).filter(n => n); + } + + sortDMsByTime (dms, type) { + if (dms.length > 1 && BDFDB.DataUtils.get(this, "settings", type == "dmCategories" ? "sortInRecentOrder" : "sortInRecentOrderGuild")) { + let timestamps = BDFDB.LibraryModules.DirectMessageStore.getPrivateChannelTimestamps(); + return [].concat(dms).sort(function (x, y) {return timestamps[x] > timestamps[y] ? -1 : timestamps[x] < timestamps[y] ? 1 : 0;}); + } + else return dms; + } + + openCategorySettingsModal (data, type, isNew) { + if (BDFDB.ObjectUtils.is(data) && type) BDFDB.ModalUtils.open(this, { + size: "MEDIUM", + header: BDFDB.LanguageUtils.LanguageStrings.CATEGORY_SETTINGS, + subheader: data.name, + children: [ + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.FormComponents.FormItem, { + title: BDFDB.LanguageUtils.LanguageStrings.CATEGORY_NAME, + className: BDFDB.disCN.marginbottom20 + " input-categoryname", + children: [ + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.TextInput, { + value: data.name, + placeholder: data.name, + autoFocus: true + }), + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.FormComponents.FormDivider, { + className: BDFDB.disCN.dividerdefault + }) + ] + }), + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.FormComponents.FormItem, { + title: this.labels.modal_colorpicker1_text, + className: BDFDB.disCN.marginbottom20, + children: [ + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.ColorSwatches, { + color: data.color, + number: 1 + }) + ] + }) + ], + buttons: [{ + contents: isNew ? BDFDB.LanguageUtils.LanguageStrings.CREATE : BDFDB.LanguageUtils.LanguageStrings.SAVE, + color: "BRAND", + close: true, + click: modal => { + data.name = modal.querySelector(".input-categoryname " + BDFDB.dotCN.input).value.trim() || data.name; + + data.color = BDFDB.ColorUtils.getSwatchColor(modal, 1); + if (data.color != null && !BDFDB.ObjectUtils.is(data.color)) { + if (data.color[0] < 30 && data.color[1] < 30 && data.color[2] < 30) data.color = BDFDB.ColorUtils.change(data.color, 30); + else if (data.color[0] > 225 && data.color[1] > 225 && data.color[2] > 225) data.color = BDFDB.ColorUtils.change(data.color, -30); + } + + BDFDB.DataUtils.save(data, this, type, data.id); + + this.updateContainer(type); + } + }] + }); + } + + addPin (newid, type) { + if (!newid) return; + let pinnedDMs = BDFDB.DataUtils.load(this, type); + for (let id in pinnedDMs) pinnedDMs[id] = pinnedDMs[id] + 1; + pinnedDMs[newid] = 0; + BDFDB.DataUtils.save(pinnedDMs, this, type); + this.updateContainer(type); + } + + removePin (id, type) { + if (!id) return; + BDFDB.DataUtils.remove(this, type, id); + this.updateContainer(type); + } + + isPinned (id, type) { + return BDFDB.DataUtils.load(this, type, id) != undefined; + } + + updateContainer (type) { + switch (type) { + case "dmCategories": + BDFDB.ModuleUtils.forceAllUpdates(this, "PrivateChannelsList"); + break; + case "pinnedRecents": + BDFDB.ModuleUtils.forceAllUpdates(this, "UnreadDMs"); + break; + } + } + + sortAndUpdate (type) { + let data = BDFDB.DataUtils.load(this, type), newData = {}; + delete data[""]; + delete data["null"]; + let sortedDMs = [], existingDMs = [], sortDM = (id, pos) => { + if (sortedDMs[pos] === undefined) sortedDMs[pos] = id; + else sortDM(id, pos + 1); + }; + for (let id in data) sortDM(id, data[id]); + sortedDMs = sortedDMs.filter(n => n); + for (let pos in sortedDMs) { + newData[sortedDMs[pos]] = parseInt(pos); + if (BDFDB.LibraryModules.ChannelStore.getChannel(sortedDMs[pos])) existingDMs.push(sortedDMs[pos]); + } + if (!BDFDB.equals(data, newData)) BDFDB.DataUtils.save(newData, this, type); + return this.sortDMsByTime(existingDMs, type); + } + + forceUpdateAll (stopped) { + BDFDB.ReactUtils.forceUpdate(BDFDB.ReactUtils.findOwner(document.querySelector(BDFDB.dotCN.app), {name:"FluxContainer(PrivateChannels)", all:true, unlimited:true})); + BDFDB.ModuleUtils.forceAllUpdates(this); + } + + createDragPreview (div, event) { + if (!Node.prototype.isPrototypeOf(div)) return; + let dragPreview = div.cloneNode(true); + BDFDB.DOMUtils.addClass(dragPreview, BDFDB.disCN._pindmsdragpreview); + BDFDB.DOMUtils.remove(dragPreview.querySelector(BDFDB.dotCNC.guildlowerbadge + BDFDB.dotCNC.guildupperbadge + BDFDB.dotCN.guildpillwrapper)); + document.querySelector(BDFDB.dotCN.appmount).appendChild(dragPreview); + let rects = BDFDB.DOMUtils.getRects(dragPreview); + BDFDB.DOMUtils.hide(dragPreview); + dragPreview.style.setProperty("pointer-events", "none", "important"); + dragPreview.style.setProperty("left", event.clientX - (rects.width/2) + "px", "important"); + dragPreview.style.setProperty("top", event.clientY - (rects.height/2) + "px", "important"); + return dragPreview; + } + + updateDragPreview (dragPreview, event) { + if (!Node.prototype.isPrototypeOf(dragPreview)) return; + BDFDB.DOMUtils.show(dragPreview); + let rects = BDFDB.DOMUtils.getRects(dragPreview); + dragPreview.style.setProperty("left", event.clientX - (rects.width/2) + "px", "important"); + dragPreview.style.setProperty("top", event.clientY - (rects.height/2) + "px", "important"); + } + + setLabelsByLanguage () { + switch (BDFDB.LanguageUtils.getLanguage().id) { + case "hr": //croatian + return { + context_pindm_text: "Prikljucite Izravnu Poruku", + context_pinchannel_text: "Priložite popisu kanala", + context_unpinchannel_text: "Ukloni s popisa kanala", + context_addtonewcategory_text: "Dodavanje u novu kategoriju", + context_pinguild_text: "Priložite popisu poslužitelja", + context_unpinguild_text: "Ukloni s popisa poslužitelja", + header_pinneddms_text: "Prikvačene Izravne Poruke", + modal_colorpicker1_text: "Boja kategorije" + }; + case "da": //danish + return { + context_pindm_text: "Fastgør PB", + context_pinchannel_text: "Vedhæft til kanalliste", + context_unpinchannel_text: "Fjern fra kanalliste", + context_addtonewcategory_text: "Føj til ny kategori", + context_pinguild_text: "Vedhæft til serverliste", + context_unpinguild_text: "Fjern fra serverliste", + header_pinneddms_text: "Pinned Privat Beskeder", + modal_colorpicker1_text: "Kategori farve" + }; + case "de": //german + return { + context_pindm_text: "Direktnachricht anheften", + context_pinchannel_text: "An Kanalliste anheften", + context_unpinchannel_text: "Von Kanalliste loslösen", + context_addtonewcategory_text: "Zur neuen Kategorie hinzufügen", + context_pinguild_text: "An Serverliste anheften", + context_unpinguild_text: "Von Serverliste loslösen", + header_pinneddms_text: "Gepinnte Direktnachrichten", + modal_colorpicker1_text: "Kategoriefarbe" + }; + case "es": //spanish + return { + context_pindm_text: "Anclar MD", + context_pinchannel_text: "Adjuntar a la lista de canales", + context_unpinchannel_text: "Deshazte de la lista de canales", + context_addtonewcategory_text: "Agregar a nueva categoría", + context_pinguild_text: "Adjuntar a la lista de servidores", + context_unpinguild_text: "Deshazte de la lista de servidores", + header_pinneddms_text: "Mensajes Directos Fijados", + modal_colorpicker1_text: "Color de la categoría" + }; + case "fr": //french + return { + context_pindm_text: "Épingler MP", + context_pinchannel_text: "Épingler à la liste des salons", + context_unpinchannel_text: "Détacher de la liste des salons", + context_addtonewcategory_text: "Ajouter à une nouvelle catégorie", + context_pinguild_text: "Épingler à la liste de serveurs", + context_unpinguild_text: "Détacher de la liste de serveurs", + header_pinneddms_text: "Messages Prives Épinglés", + modal_colorpicker1_text: "Couleur de la catégorie" + }; + case "it": //italian + return { + context_pindm_text: "Fissa il messaggio diretto", + context_pinchannel_text: "Allega alla lista dei canali", + context_unpinchannel_text: "Rimuovi dalla lista dei canali", + context_addtonewcategory_text: "Aggiungi a nuova categoria", + context_pinguild_text: "Allega alla lista dei server", + context_unpinguild_text: "Rimuovi dalla lista dei server", + header_pinneddms_text: "Messaggi Diretti Aggiunti", + modal_colorpicker1_text: "Colore della categoria" + }; + case "nl": //dutch + return { + context_pindm_text: "PB pinnen", + context_pinchannel_text: "Pin naar de kanalenlijst", + context_unpinchannel_text: "Losmaken van kanalenlijst", + context_addtonewcategory_text: "Toevoegen aan nieuwe categorie", + context_pinguild_text: "Pin naar de serverlijst", + context_unpinguild_text: "Losmaken van serverlijst", + header_pinneddms_text: "Vastgezette Persoonluke Berichten", + modal_colorpicker1_text: "Categorie kleur" + }; + case "no": //norwegian + return { + context_pindm_text: "Fest DM", + context_pinchannel_text: "Fest på kanalliste", + context_unpinchannel_text: "Fjern fra kanalliste", + context_addtonewcategory_text: "Legg til i ny kategori", + context_pinguild_text: "Fest på serverliste", + context_unpinguild_text: "Fjern fra serverlisten", + header_pinneddms_text: "Pinned Direktemeldinger", + modal_colorpicker1_text: "Kategorifarge" + }; + case "pl": //polish + return { + context_pindm_text: "Przypnij PW", + context_pinchannel_text: "Dołącz do listy kanałów", + context_unpinchannel_text: "Usuń z listy kanałów", + context_addtonewcategory_text: "Dodaj do nowej kategorii", + context_pinguild_text: "Dołącz do listy serwerów", + context_unpinguild_text: "Usuń z listy serwerów", + header_pinneddms_text: "Prywatne Wiadomości Bezpośrednie", + modal_colorpicker1_text: "Kolor kategorii" + }; + case "pt-BR": //portuguese (brazil) + return { + context_pindm_text: "Fixar MD", + context_pinchannel_text: "Anexar à lista de canais", + context_unpinchannel_text: "Remover da lista de canais", + context_addtonewcategory_text: "Adicionar à nova categoria", + context_pinguild_text: "Anexar à lista de servidores", + context_unpinguild_text: "Remover da lista de servidores", + header_pinneddms_text: "Mensagens diretas fixadas", + modal_colorpicker1_text: "Cor da categoria" + }; + case "fi": //finnish + return { + context_pindm_text: "Kiinnitä yksityisviestit", + context_pinchannel_text: "Liitä kanavaluetteloon", + context_unpinchannel_text: "Poista kanavaluettelosta", + context_addtonewcategory_text: "Lisää uuteen luokkaan", + context_pinguild_text: "Liitä palvelinluetteloon", + context_unpinguild_text: "Poista palvelinluettelosta", + header_pinneddms_text: "Liitetyt yksityisviestit", + modal_colorpicker1_text: "Luokan väri" + }; + case "sv": //swedish + return { + context_pindm_text: "Fäst DM", + context_pinchannel_text: "Fäst till kanallista", + context_unpinchannel_text: "Ta bort från kanallistan", + context_addtonewcategory_text: "Lägg till i ny kategori", + context_pinguild_text: "Fäst till servernlista", + context_unpinguild_text: "Ta bort från servernlista", + header_pinneddms_text: "Inlagda Direktmeddelanden", + modal_colorpicker1_text: "Kategori färg" + }; + case "tr": //turkish + return { + context_pindm_text: "DM'yi Sabitle", + context_pinchannel_text: "Kanal listesine ekle", + context_unpinchannel_text: "Kanal listesinden kaldır", + context_addtonewcategory_text: "Yeni kategoriye ekle", + context_pinguild_text: "Sunucu listesine ekle", + context_unpinguild_text: "Sunucu listesinden kaldır", + header_pinneddms_text: "Direkt Mesajlar Sabitleyin", + modal_colorpicker1_text: "Kategori rengi" + }; + case "cs": //czech + return { + context_pindm_text: "Připnout PZ", + context_pinchannel_text: "Připojení k seznamu kanálů", + context_unpinchannel_text: "Odstranit ze seznamu kanálů", + context_addtonewcategory_text: "Přidat do nové kategorie", + context_pinguild_text: "Připojit ke seznamu serverů", + context_unpinguild_text: "Odstranit ze seznamu serverů", + header_pinneddms_text: "Připojené Přímá Zpráva", + modal_colorpicker1_text: "Barva kategorie" + }; + case "bg": //bulgarian + return { + context_pindm_text: "Закачени ДС", + context_pinchannel_text: "Прикачете към списъка с канали", + context_unpinchannel_text: "Премахване от списъка с канали", + context_addtonewcategory_text: "Добавяне към нова категория", + context_pinguild_text: "Прикачване към списъка със сървъри", + context_unpinguild_text: "Премахване от списъка със сървъри", + header_pinneddms_text: "Свързани директни съобщения", + modal_colorpicker1_text: "Цвят на категорията" + }; + case "ru": //russian + return { + context_pindm_text: "Закрепить ЛС", + context_pinchannel_text: "Прикрепить к списку каналов", + context_unpinchannel_text: "Удалить из списка каналов", + context_addtonewcategory_text: "Добавить в новую категорию", + context_pinguild_text: "Присоединить к списку серверов", + context_unpinguild_text: "Удалить из списка серверов", + header_pinneddms_text: "Прикрепленные Личные Сообщения", + modal_colorpicker1_text: "Цвет категории" + }; + case "uk": //ukrainian + return { + context_pindm_text: "Закріпити ОП", + context_pinchannel_text: "Додайте до списку каналів", + context_unpinchannel_text: "Видалити зі списку каналів", + context_addtonewcategory_text: "Додати до нової категорії", + context_pinguild_text: "Додайте до списку серверів", + context_unpinguild_text: "Видалити зі списку серверів", + header_pinneddms_text: "Прикріплені oсобисті повідомлення", + modal_colorpicker1_text: "Колір категорії" + }; + case "ja": //japanese + return { + context_pindm_text: "DMピン", + context_pinchannel_text: "チャンネルリストに添付", + context_unpinchannel_text: "チャンネルリストから削除", + context_addtonewcategory_text: "新しいカテゴリに追加", + context_pinguild_text: "サーバーリストに添付", + context_unpinguild_text: "サーバーリストから削除", + header_pinneddms_text: "固定された直接メッセージ", + modal_colorpicker1_text: "カテゴリーの色" + }; + case "zh-TW": //chinese (traditional) + return { + context_pindm_text: "引腳直接留言", + context_pinchannel_text: "附加到頻道列表", + context_unpinchannel_text: "從頻道列表中刪除", + context_addtonewcategory_text: "添加到新類別", + context_pinguild_text: "附加到服務器列表", + context_unpinguild_text: "從服務器列表中刪除", + header_pinneddms_text: "固定私人信息", + modal_colorpicker1_text: "類別顏色" + }; + case "ko": //korean + return { + context_pindm_text: "비공개 메시지 고정", + context_pinchannel_text: "채널 목록에 첨부", + context_unpinchannel_text: "채널 목록에서 삭제", + context_addtonewcategory_text: "새 카테고리에 추가", + context_pinguild_text: "서버 목록에 첨부", + context_unpinguild_text: "서버 목록에서 제거", + header_pinneddms_text: "고정 된 비공개 메시지", + modal_colorpicker1_text: "카테고리 색상" + }; + default: //default: english + return { + context_pindm_text: "Pin DM", + context_pinchannel_text: "Pin to Channellist", + context_unpinchannel_text: "Unpin from Channellist", + context_addtonewcategory_text: "Add to new Category", + context_pinguild_text: "Pin to Serverlist", + context_unpinguild_text: "Unpin from Serverlist", + header_pinneddms_text: "Pinned Direct Messages", + modal_colorpicker1_text: "Categorycolor" + }; + } + } + } +})();
\ No newline at end of file diff --git a/.config/BetterDiscord/plugins/QuickMention.plugin.js b/.config/BetterDiscord/plugins/QuickMention.plugin.js new file mode 100644 index 0000000..64541e8 --- /dev/null +++ b/.config/BetterDiscord/plugins/QuickMention.plugin.js @@ -0,0 +1,78 @@ +//META{"name":"QuickMention","authorId":"278543574059057154","invite":"Jx3TjNS","donate":"https://www.paypal.me/MircoWittrien","patreon":"https://www.patreon.com/MircoWittrien","website":"https://github.com/mwittrien/BetterDiscordAddons/tree/master/Plugins/QuickMention","source":"https://raw.githubusercontent.com/mwittrien/BetterDiscordAddons/master/Plugins/QuickMention/QuickMention.plugin.js"}*// + +var QuickMention = (_ => { + return class QuickMention { + getName () {return "QuickMention";} + + getVersion () {return "1.0.0";} + + getAuthor () {return "DevilBro";} + + getDescription () {return "Adds a mention entry to the message option toolbar.";} + + // Legacy + load () {} + + start () { + if (!window.BDFDB) window.BDFDB = {myPlugins:{}}; + if (window.BDFDB && window.BDFDB.myPlugins && typeof window.BDFDB.myPlugins == "object") window.BDFDB.myPlugins[this.getName()] = this; + let libraryScript = document.querySelector("head script#BDFDBLibraryScript"); + if (!libraryScript || (performance.now() - libraryScript.getAttribute("date")) > 600000) { + if (libraryScript) libraryScript.remove(); + libraryScript = document.createElement("script"); + libraryScript.setAttribute("id", "BDFDBLibraryScript"); + libraryScript.setAttribute("type", "text/javascript"); + libraryScript.setAttribute("src", "https://mwittrien.github.io/BetterDiscordAddons/Plugins/BDFDB.min.js"); + libraryScript.setAttribute("date", performance.now()); + libraryScript.addEventListener("load", _ => {this.initialize();}); + document.head.appendChild(libraryScript); + } + else if (window.BDFDB && typeof BDFDB === "object" && BDFDB.loaded) this.initialize(); + this.startTimeout = setTimeout(_ => { + try {return this.initialize();} + catch (err) {console.error(`%c[${this.getName()}]%c`, "color: #3a71c1; font-weight: 700;", "", "Fatal Error: Could not initiate plugin! " + err);} + }, 30000); + } + + initialize () { + if (window.BDFDB && typeof BDFDB === "object" && BDFDB.loaded) { + if (this.started) return; + BDFDB.PluginUtils.init(this); + } + else { + console.error(`%c[${this.getName()}]%c`, 'color: #3a71c1; font-weight: 700;', '', 'Fatal Error: Could not load BD functions!'); + } + } + + stop () { + if (window.BDFDB && typeof BDFDB === "object" && BDFDB.loaded) { + this.stopping = true; + + BDFDB.PluginUtils.clear(this); + } + } + + + // Begin of own functions + + onMessageOptionToolbar (e) { + if (e.instance.props.message.author.id != BDFDB.UserUtils.me.id && e.instance.props.message.type == BDFDB.DiscordConstants.MessageTypes.DEFAULT && BDFDB.UserUtils.can("SEND_MESSAGES")) e.returnvalue.props.children.unshift(BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.TooltipContainer, { + key: "mention", + text: BDFDB.LanguageUtils.LanguageStrings.MENTION, + children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Clickable, { + className: BDFDB.disCN.messagetoolbarbutton, + onClick: _ => { + BDFDB.LibraryModules.DispatchUtils.ComponentDispatch.dispatchToLastSubscribed(BDFDB.DiscordConstants.ComponentActions.INSERT_TEXT, { + content: `<@!${e.instance.props.message.author.id}>` + }); + }, + children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SvgIcon, { + className: BDFDB.disCNS.messagetoolbaricon, + nativeClass: true, + name: BDFDB.LibraryComponents.SvgIcon.Names.NOVA_AT + }) + }) + })); + } + } +})();
\ No newline at end of file diff --git a/.config/BetterDiscord/plugins/RemoveNicknames.config.json b/.config/BetterDiscord/plugins/RemoveNicknames.config.json new file mode 100644 index 0000000..1818ecb --- /dev/null +++ b/.config/BetterDiscord/plugins/RemoveNicknames.config.json @@ -0,0 +1,17 @@ +{ + "changelog": { + "currentversion": "1.3.0" + }, + "settings": { + "addNickname": false, + "changeInAutoComplete": true, + "changeInChatWindow": true, + "changeInMemberList": true, + "changeInMentions": true, + "changeInTyping": true, + "changeInVoiceChat": true, + "replaceBots": true, + "replaceOwn": false, + "swapPositions": false + } +}
\ No newline at end of file diff --git a/.config/BetterDiscord/plugins/RemoveNicknames.plugin.js b/.config/BetterDiscord/plugins/RemoveNicknames.plugin.js new file mode 100644 index 0000000..0390456 --- /dev/null +++ b/.config/BetterDiscord/plugins/RemoveNicknames.plugin.js @@ -0,0 +1,201 @@ +//META{"name":"RemoveNicknames","authorId":"278543574059057154","invite":"Jx3TjNS","donate":"https://www.paypal.me/MircoWittrien","patreon":"https://www.patreon.com/MircoWittrien","website":"https://github.com/mwittrien/BetterDiscordAddons/tree/master/Plugins/RemoveNicknames","source":"https://raw.githubusercontent.com/mwittrien/BetterDiscordAddons/master/Plugins/RemoveNicknames/RemoveNicknames.plugin.js"}*// + +var RemoveNicknames = (_ => { + return class RemoveNicknames { + getName () {return "RemoveNicknames";} + + getVersion () {return "1.3.0";} + + getAuthor () {return "DevilBro";} + + getDescription () {return "Replace all nicknames with the actual accountnames.";} + + constructor () { + this.changelog = { + "fixed":[["Typing List","Works now"]] + }; + + this.patchedModules = { + before: { + AutocompleteUserResult: "render", + VoiceUser: "render", + MemberListItem: "render", + Message: "default", + MessageContent: "type", + }, + after: { + TypingUsers: "render" + } + }; + } + + initConstructor () { + this.defaults = { + settings: { + replaceOwn: {value:false, inner:false, description:"Replace your own name:"}, + replaceBots: {value:true, inner:false, description:"Replace the nickname of bots:"}, + addNickname: {value:false, inner:false, description:"Add nickname as parentheses:"}, + swapPositions: {value:false, inner:false, description:"Swap the position of username and nickname:"}, + changeInChatWindow: {value:true, inner:true, description:"Messages"}, + changeInMentions: {value:true, inner:true, description:"Mentions"}, + changeInVoiceChat: {value:true, inner:true, description:"Voice Channels"}, + changeInMemberList: {value:true, inner:true, description:"Member List"}, + changeInTyping: {value:true, inner:true, description:"Typing List"}, + changeInAutoComplete: {value:true, inner:true, description:"Autocomplete Menu"} + } + }; + } + + getSettingsPanel () { + if (!window.BDFDB || typeof BDFDB != "object" || !BDFDB.loaded || !this.started) return; + let settings = BDFDB.DataUtils.get(this, "settings"); + let settingsPanel, settingsItems = [], innerItems = []; + + for (let key in settings) (!this.defaults.settings[key].inner ? settingsItems : innerItems).push(BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SettingsSaveItem, { + className: BDFDB.disCN.marginbottom8, + type: "Switch", + plugin: this, + keys: ["settings", key], + label: this.defaults.settings[key].description, + value: settings[key] + })); + settingsItems.push(BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SettingsPanelInner, { + title: "Remove Nicknames in:", + first: settingsItems.length == 0, + last: true, + children: innerItems + })); + + return settingsPanel = BDFDB.PluginUtils.createSettingsPanel(this, settingsItems); + } + + // Legacy + load () {} + + start () { + if (!window.BDFDB) window.BDFDB = {myPlugins:{}}; + if (window.BDFDB && window.BDFDB.myPlugins && typeof window.BDFDB.myPlugins == "object") window.BDFDB.myPlugins[this.getName()] = this; + let libraryScript = document.querySelector("head script#BDFDBLibraryScript"); + if (!libraryScript || (performance.now() - libraryScript.getAttribute("date")) > 600000) { + if (libraryScript) libraryScript.remove(); + libraryScript = document.createElement("script"); + libraryScript.setAttribute("id", "BDFDBLibraryScript"); + libraryScript.setAttribute("type", "text/javascript"); + libraryScript.setAttribute("src", "https://mwittrien.github.io/BetterDiscordAddons/Plugins/BDFDB.min.js"); + libraryScript.setAttribute("date", performance.now()); + libraryScript.addEventListener("load", _ => {this.initialize();}); + document.head.appendChild(libraryScript); + } + else if (window.BDFDB && typeof BDFDB === "object" && BDFDB.loaded) this.initialize(); + this.startTimeout = setTimeout(_ => { + try {return this.initialize();} + catch (err) {console.error(`%c[${this.getName()}]%c`, "color: #3a71c1; font-weight: 700;", "", "Fatal Error: Could not initiate plugin! " + err);} + }, 30000); + } + + initialize () { + if (window.BDFDB && typeof BDFDB === "object" && BDFDB.loaded) { + if (this.started) return; + BDFDB.PluginUtils.init(this); + + this.forceUpdateAll(); + } + else console.error(`%c[${this.getName()}]%c`, "color: #3a71c1; font-weight: 700;", "", "Fatal Error: Could not load BD functions!"); + } + + + stop () { + if (window.BDFDB && typeof BDFDB === "object" && BDFDB.loaded) { + this.stopping = true; + + this.forceUpdateAll(); + + BDFDB.PluginUtils.clear(this); + } + } + + + // Begin of own functions + + onSettingsClosed (e) { + if (this.SettingsUpdated) { + delete this.SettingsUpdated; + BDFDB.ModuleUtils.forceAllUpdates(this); + } + } + + processAutocompleteUserResult (e) { + if (e.instance.props.user && e.instance.props.nick && BDFDB.DataUtils.get(this, "settings", "changeInAutoComplete")) { + let newName = this.getNewName(e.instance.props.user); + if (newName) e.instance.props.nick = newName; + } + } + + processVoiceUser (e) { + if (e.instance.props.user && e.instance.props.nick && BDFDB.DataUtils.get(this, "settings", "changeInVoiceChat")) { + let newName = this.getNewName(e.instance.props.user); + if (newName) e.instance.props.nick = newName; + } + } + + processMemberListItem (e) { + if (e.instance.props.user && e.instance.props.nick && BDFDB.DataUtils.get(this, "settings", "changeInMemberList")) { + let newName = this.getNewName(e.instance.props.user); + if (newName) e.instance.props.nick = newName; + } + } + + processTypingUsers (e) { + if (BDFDB.ObjectUtils.is(e.instance.props.typingUsers) && Object.keys(e.instance.props.typingUsers).length && BDFDB.DataUtils.get(this, "settings", "changeInTyping")) { + let users = Object.keys(e.instance.props.typingUsers).filter(id => id != BDFDB.UserUtils.me.id).filter(id => !BDFDB.LibraryModules.FriendUtils.isBlocked(id)).map(id => BDFDB.LibraryModules.UserStore.getUser(id)).filter(user => user); + if (users.length) { + let [children, index] = BDFDB.ReactUtils.findChildren(e.returnvalue, {props: [["className", BDFDB.disCN.typingtext]]}); + if (index > -1 && BDFDB.ArrayUtils.is(children[index].props.children)) for (let child of children[index].props.children) if (child.type == "strong") { + let newName = this.getNewName(users.shift()); + if (newName) BDFDB.ReactUtils.setChild(child, newName); + } + } + } + } + + processMessage (e) { + let header = e.instance.props.childrenHeader; + if (header && header.props && header.props.message && header.props.message.nick) { + let newName = this.getNewName(header.props.message.author); + if (newName) header.props.message = new BDFDB.DiscordObjects.Message(Object.assign({}, header.props.message, {nick: newName})); + } + } + + processMessageContent (e) { + if (BDFDB.ArrayUtils.is(e.instance.props.content) && BDFDB.DataUtils.get(this, "settings", "changeInMentions")) for (let ele of e.instance.props.content) { + if (BDFDB.ReactUtils.isValidElement(ele) && ele.type && (ele.type.displayName || "").toLowerCase().indexOf("popout") > -1 && typeof ele.props.render == "function") { + if (BDFDB.ReactUtils.getValue(ele, "props.children.type.displayName") == "Mention") { + let newName = this.getNewName(BDFDB.LibraryModules.UserStore.getUser(ele.props.render().props.userId)); + if (newName) ele.props.children.props.children[0] = "@" + newName; + } + } + } + if (e.instance.props.message.type != BDFDB.DiscordConstants.MessageTypes.DEFAULT && e.instance.props.message.nick && BDFDB.DataUtils.get(this, "settings", "changeInChatWindow")) { + let newName = this.getNewName(e.instance.props.message.author); + if (newName) { + e.instance.props.message = new BDFDB.DiscordObjects.Message(Object.assign({}, e.instance.props.message, {nick: newName})); + e.instance.props.children.props.message = e.instance.props.message; + } + } + } + + getNewName (user, wrapper) { + if (!user) return null; + let settings = BDFDB.DataUtils.get(this, "settings"); + let member = BDFDB.LibraryModules.MemberStore.getMember(BDFDB.LibraryModules.LastGuildStore.getGuildId(), user.id) || {}; + if (!member.nick || user.id == BDFDB.UserUtils.me.id && !settings.replaceOwn || user.bot && !settings.replaceBots) return null; + let username = (BDFDB.BDUtils.isPluginEnabled("EditUsers") && BDFDB.DataUtils.load("EditUsers", "users", user.id) || {}).name || user.username; + return settings.addNickname ? (settings.swapPositions ? (member.nick + " (" + username + ")") : (username + " (" + member.nick + ")")) : username; + } + + forceUpdateAll () { + BDFDB.ModuleUtils.forceAllUpdates(this); + BDFDB.MessageUtils.rerenderAll(); + } + } +})();
\ No newline at end of file diff --git a/.config/BetterDiscord/plugins/SendLargeMessages.plugin.js b/.config/BetterDiscord/plugins/SendLargeMessages.plugin.js new file mode 100644 index 0000000..3827ee2 --- /dev/null +++ b/.config/BetterDiscord/plugins/SendLargeMessages.plugin.js @@ -0,0 +1,259 @@ +//META{"name":"SendLargeMessages","authorId":"278543574059057154","invite":"Jx3TjNS","donate":"https://www.paypal.me/MircoWittrien","patreon":"https://www.patreon.com/MircoWittrien","website":"https://github.com/mwittrien/BetterDiscordAddons/tree/master/Plugins/SendLargeMessages","source":"https://raw.githubusercontent.com/mwittrien/BetterDiscordAddons/master/Plugins/SendLargeMessages/SendLargeMessages.plugin.js"}*// + +var SendLargeMessages = (_ => { + return class SendLargeMessages { + getName () {return "SendLargeMessages";} + + getVersion () {return "1.6.4";} + + getAuthor () {return "DevilBro";} + + getDescription () {return "Opens a popout when your message is too large, which allows you to automatically send the message in several smaller messages.";} + + constructor () { + this.patchedModules = { + before: { + ChannelTextAreaForm: "render", + ChannelEditorContainer: "render" + }, + after: { + ChannelTextAreaContainer: "render", + } + }; + } + + initConstructor () { + this.messageDelay = 1000; //changing at own risk, might result in bans or mutes + + this.css = ` + .${this.name}-modal textarea { + height: 50vh; + }`; + } + + // Legacy + load () {} + + start () { + if (!window.BDFDB) window.BDFDB = {myPlugins:{}}; + if (window.BDFDB && window.BDFDB.myPlugins && typeof window.BDFDB.myPlugins == "object") window.BDFDB.myPlugins[this.getName()] = this; + let libraryScript = document.querySelector("head script#BDFDBLibraryScript"); + if (!libraryScript || (performance.now() - libraryScript.getAttribute("date")) > 600000) { + if (libraryScript) libraryScript.remove(); + libraryScript = document.createElement("script"); + libraryScript.setAttribute("id", "BDFDBLibraryScript"); + libraryScript.setAttribute("type", "text/javascript"); + libraryScript.setAttribute("src", "https://mwittrien.github.io/BetterDiscordAddons/Plugins/BDFDB.min.js"); + libraryScript.setAttribute("date", performance.now()); + libraryScript.addEventListener("load", _ => {this.initialize();}); + document.head.appendChild(libraryScript); + } + else if (window.BDFDB && typeof BDFDB === "object" && BDFDB.loaded) this.initialize(); + this.startTimeout = setTimeout(_ => { + try {return this.initialize();} + catch (err) {console.error(`%c[${this.getName()}]%c`, "color: #3a71c1; font-weight: 700;", "", "Fatal Error: Could not initiate plugin! " + err);} + }, 30000); + } + + initialize () { + if (window.BDFDB && typeof BDFDB === "object" && BDFDB.loaded) { + if (this.started) return; + BDFDB.PluginUtils.init(this); + + BDFDB.ModuleUtils.forceAllUpdates(this); + } + else console.error(`%c[${this.getName()}]%c`, "color: #3a71c1; font-weight: 700;", "", "Fatal Error: Could not load BD functions!"); + } + + + stop () { + if (window.BDFDB && typeof BDFDB === "object" && BDFDB.loaded) { + this.stopping = true; + + BDFDB.ModuleUtils.forceAllUpdates(this); + + BDFDB.PluginUtils.clear(this); + } + } + + + // Begin of own functions + + processChannelTextAreaForm (e) { + if (!BDFDB.ModuleUtils.isPatched(this, e.instance, "handleSendMessage")) BDFDB.ModuleUtils.patch(this, e.instance, "handleSendMessage", {instead: e2 => { + if (e2.methodArguments[0].length > BDFDB.DiscordConstants.MAX_MESSAGE_LENGTH) { + e2.stopOriginalMethodCall(); + let messages = this.formatText(e2.methodArguments[0]); + messages.filter(n => n).forEach((message, i) => { + BDFDB.TimeUtils.timeout(_ => { + e2.originalMethod(message); + if (i >= messages.length-1) BDFDB.NotificationUtils.toast(this.labels.toast_allsent_text, {type:"success"}); + }, this.messageDelay * i); + }); + return Promise.resolve({ + shouldClear: true, + shouldRefocus: true + }); + } + else return e2.callOriginalMethodAfterwards(); + }}, {force: true, noCache: true}); + } + + processChannelTextAreaContainer (e) { + if (e.returnvalue.ref && e.returnvalue.ref.current && BDFDB.DOMUtils.getParent(BDFDB.dotCN.chatform, e.returnvalue.ref.current)) { + let [children, index] = BDFDB.ReactUtils.findChildren(e.returnvalue, {name: "SlateCharacterCount"}); + if (index > -1) { + let text = BDFDB.LibraryModules.SlateSelectionUtils.serialize(children[index].props.document, "raw"); + if (text.length > BDFDB.DiscordConstants.MAX_MESSAGE_LENGTH) children[index] = BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCNS.textareacharcounter + BDFDB.disCN.textareacharcountererror, + children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.TooltipContainer, { + text: Math.ceil(text.length / BDFDB.DiscordConstants.MAX_MESSAGE_LENGTH * (39/40)) + " " + BDFDB.LanguageUtils.LanguageStrings.MESSAGES, + children: BDFDB.ReactUtils.createElement("span", { + children: BDFDB.DiscordConstants.MAX_MESSAGE_LENGTH - text.length + }) + }) + }); + } + } + } + + processChannelEditorContainer (e) { + if (e.instance.props.type && e.instance.props.type == BDFDB.DiscordConstants.TextareaTypes.NORMAL) e.instance.props.shouldUploadLongMessages = false; + } + + formatText (text) { + text = text.replace(/\t/g, " "); + let longwords = text.match(/[\S]{1800,}/gm); + if (longwords) for (let longword of longwords) { + let count1 = 0; + let shortwords = []; + longword.split("").forEach(c => { + if (shortwords[count1] && shortwords[count1].length >= BDFDB.DiscordConstants.MAX_MESSAGE_LENGTH * (19/20)) count1++; + shortwords[count1] = shortwords[count1] ? shortwords[count1] + c : c; + }); + text = text.replace(longword, shortwords.join(" ")); + } + let messages = []; + let count2 = 0; + text.split(" ").forEach((word) => { + if (messages[count2] && (messages[count2] + "" + word).length > BDFDB.DiscordConstants.MAX_MESSAGE_LENGTH * (39/40)) count2++; + messages[count2] = messages[count2] ? messages[count2] + " " + word : word; + }); + + let insertCodeBlock = null, insertCodeLine = null; + for (let j = 0; j < messages.length; j++) { + if (insertCodeBlock) { + messages[j] = insertCodeBlock + messages[j]; + insertCodeBlock = null; + } + else if (insertCodeLine) { + messages[j] = insertCodeLine + messages[j]; + insertCodeLine = null; + } + + let codeBlocks = messages[j].match(/`{3,}[\S]*\n|`{3,}/gm); + let codeLines = messages[j].match(/[^`]{0,1}`{1,2}[^`]|[^`]`{1,2}[^`]{0,1}/gm); + + if (codeBlocks && codeBlocks.length % 2 == 1) { + messages[j] = messages[j] + "```"; + insertCodeBlock = codeBlocks[codeBlocks.length-1] + "\n"; + } + else if (codeLines && codeLines.length % 2 == 1) { + insertCodeLine = codeLines[codeLines.length-1].replace(/[^`]/g, ""); + messages[j] = messages[j] + insertCodeLine; + } + } + + return messages; + } + + setLabelsByLanguage () { + switch (BDFDB.LanguageUtils.getLanguage().id) { + case "hr": //croatian + return { + toast_allsent_text: "Sve veliku poslane." + }; + case "da": //danish + return { + toast_allsent_text: "Alle beskeder sendes." + }; + case "de": //german + return { + toast_allsent_text: "Alle Nachrichten versendet." + }; + case "es": //spanish + return { + toast_allsent_text: "Todos los mensajes enviados." + }; + case "fr": //french + return { + toast_allsent_text: "Tous les messages envoyés" + }; + case "it": //italian + return { + toast_allsent_text: "Tutti i messaggi inviati." + }; + case "nl": //dutch + return { + toast_allsent_text: "Alle berichten verzonden." + }; + case "no": //norwegian + return { + toast_allsent_text: "Alle meldinger sendt." + }; + case "pl": //polish + return { + toast_allsent_text: "Wszystkie wiadomości zostały wysłane." + }; + case "pt-BR": //portuguese (brazil) + return { + toast_allsent_text: "Todas as mensagens enviadas." + }; + case "fi": //finnish + return { + toast_allsent_text: "Kaikki lähetetyt viestit." + }; + case "sv": //swedish + return { + toast_allsent_text: "Alla meddelanden skickade." + }; + case "tr": //turkish + return { + toast_allsent_text: "Tüm mesajlar gönderildi." + }; + case "cs": //czech + return { + toast_allsent_text: "Všechny zprávy byly odeslány." + }; + case "bg": //bulgarian + return { + toast_allsent_text: "Всички изпратени съобщения." + }; + case "ru": //russian + return { + toast_allsent_text: "Все отправленные сообщения." + }; + case "uk": //ukrainian + return { + toast_allsent_text: "Всі повідомлення надіслано." + }; + case "ja": //japanese + return { + toast_allsent_text: "すべてのメッセージが送信されました。" + }; + case "zh-TW": //chinese (traditional) + return { + toast_allsent_text: "發送的所有消息。" + }; + case "ko": //korean + return { + toast_allsent_text: "모든 메시지가 전송되었습니다." + }; + default: //default: english + return { + toast_allsent_text: "All messages sent." + }; + } + } + } +})();
\ No newline at end of file diff --git a/.config/BetterDiscord/themes/Material-Discord.theme.css b/.config/BetterDiscord/themes/Material-Discord.theme.css new file mode 100644 index 0000000..c3f0ced --- /dev/null +++ b/.config/BetterDiscord/themes/Material-Discord.theme.css @@ -0,0 +1,3 @@ +//META{"name":"Material_Discord","description":"A theme based on Google's Material Design","author":"CapnKitten","version":"2.1.4.1"}*//{} + +@import url(https://capnkitten.github.io/BetterDiscord/Material-Discord/css/source.css?v=2.1.4.1); diff --git a/.config/BetterDiscord/themes/MinimalCord.theme.css b/.config/BetterDiscord/themes/MinimalCord.theme.css new file mode 100644 index 0000000..87e66f9 --- /dev/null +++ b/.config/BetterDiscord/themes/MinimalCord.theme.css @@ -0,0 +1,138 @@ +/** + * @name MinimalCord + * @author Gibbu#1211 + * @version 1.0.0 + * @description Changes Discord enough to give it a fresh feel while also making it darker. Supports both Light and Dark themes. + * @source https://github.com/Gibbu/BetterDiscord-Themes/tree/master/MinimalCord + * @website https://www.gibbu.me +*/ + +@import url('https://fonts.googleapis.com/css?family=Roboto:300,400,500,700,900'); +@import url("https://gibbu.github.io/BetterDiscord-Themes/MinimalCord/base.css"); + +/* Black Box user tags */ +@import url('https://monstrousdev.github.io/themes/addons/user-tags.css'); + +:root { + /* --accent: 233, 86, 120; DEFAULT: 22, 188, 249 */ + --chat-avatar-size: 48px; /* Changes size of chat avatars | DEFAULT: 40px */ + --search-results-width: 25vw; /* Width of server results. For a fixed width use px. | DEFAULT: 25vw */ + --emoji-picker-height: 260px; /* Height of Emoji picker | DEFAULT: 260px */ + --font: 'JetBrainsMono NF'; +} + +.theme-dark { + --foreground-1: var(--pywal-bg0) !important; + --foreground-2: var(--pywal-bg1) !important; + --foreground-divider: var(--pywal-color15) !important; + --background-primary: var(--pywal-bg3) !important; + --background-secondary: var(--pywal-bg2) !important; + --background-tertiary: var(--pywal-bg0) !important; + --background-floating: var(--pywal-bg0) !important; + --background-1: var(--pywal-bg0) !important; + --background-2: var(--pywal-serverside) !important; + --box-shadow: 0 3px 30px -5px #0008 !important; + --scrollbar: var(--pywal-bg1) !important; + --tooltips: var(--pywal-bg2) !important; + --pages-box: var(--message-box) !important; + --pages-box-footer: var(--pywal-bg0) !important; + --pages-separator: #ffffff0d !important; + --user-popout: var(--dropdown) !important; + --user-popout-body: var(--pywal-bg0) !important; + --user-popout-message: var(--pywal-color0) !important; + --settings-box: var(--message-box) !important; + --settings-box-hover: var(--pywal-color0) !important; + --settings-box-footer: var(--pywal-color0) !important; + --settings-input: var(--pywal-color0) !important; + --settings-paginator: #00000033 !important; + --settings-separator: #ffffff0d !important; + --dropdown: var(--pywal-bg1) !important; + --dropdown-header: var(--pywal-bg3) !important; + --dropdown-item-hover: var(--pywal-bg1) !important; + --message-box: #0000 !important; + --message-box-divider: var(--pywal-bg2) !important; + --message-embed: var(--pywal-bg2) !important; + --message-button: var(--pywal-bg3) !important; + --server-background: var(--pywal-serverside) !important; + --server-selected: var(--pywal-serverside) !important; + --search-filter-hover: var(--pywal-bg1) !important; + --search-result-header: var(--pywal-bg1) !important; + --channel-selected: var(--pywal-bg2) !important; + --channel-selected-bg: var(--channel-selected) !important; + --channel-hovered: var(--pywal-bg1) !important; + --channel-hovered-bg: var(--pywal-bg1) !important; + --modal-connection: var(--background-1) !important; + --modal-list: var(--pywal-color0) !important; + --modal-badge-invert: invert(0) !important; + --modal-bg1-search: var(--search-filter-hover) !important; + --text-1: #fff !important; + --text-2: #c9c9c9 !important; + --text-3: #999a9b !important; + --text-4: #717173 !important; + --text-dark: #565759 !important; +} + +.da-attachWrapper, .da-buttons { + width: 0; + overflow: hidden; +} + +.da-channelTextArea { + margin-top: 0 !important; + margin-bottom: 8px !important; +} + +.da-form { + margin-left: 0 !important; + margin-right: 0 !important; +} + +.da-username { + filter: saturate(0.4) brightness(2); +} + +.da-itemCard > div > div { + background: var(--background-secondary) !important; +} + +.da-channelTextArea > div { + box-shadow: none !important; + background: var(--foreground-1) !important; +} + +.da-form::before { + background: transparent !important; +} + +.da-nowPlayingColumn { + background: var(--background-1) !important; +} + +.da-videoControls { + margin: 0px !important; +} + +body { + background: var(--pywal-transparent50) !important; +} + +.da-privateChannelsHeaderContainer .da-numberBadge.da-base { + background-color: var(--pywal-color6) !important; + color: var(--pywal-readableOn-color6) !important; +} + +.da-circleIcon, +.da-circleIconButton { + color: var(--pywal-readable-color6) !important; +} + +section.da-container > .da-children > .da-tabBar > .da-item:not(.da-themed), +.bd-guild .da-item, +.da-tutorialContainer .da-pill .da-item { + background-color: var(--pywal-readable-color6) !important; + color: var(--pywal-readableOn-color6) !important; +} + +.da-actionButton { + background-color: transparent !important; +} diff --git a/.config/BetterDiscord/themes/glass.theme.css b/.config/BetterDiscord/themes/glass.theme.css new file mode 100644 index 0000000..a6dfb72 --- /dev/null +++ b/.config/BetterDiscord/themes/glass.theme.css @@ -0,0 +1,40 @@ +/** + * @name Glass + * @author Loekaars#8205 + * @version 1.0.0 + * @description Transparency required +*/ + +body #app-mount, +body #app-mount .da-app .da-app, +body #app-mount .da-app .da-app .da-layers .da-layer, +.da-scroller, +.da-bg, +.da-container > nav { + background: transparent !important; +} + +.da-sidebar .da-panels .da-container, +.da-sidebar .da-panels { + background: transparent !important; +} + +:root { + --server-selected: transparent !important; + --server-folders: var(--pywal-serverfolder-transparent) !important; + --server-background: transparent !important; +} + +.da-expandedFolderBackground { + border-radius: 16px !important; +} + +body, +.da-sidebar { + background: var(--pywal-serverfolder-transparent) !important; +} + +.da-folder { + background: transparent !important; +} + diff --git a/.config/BetterDiscord/themes/pywal.theme.css b/.config/BetterDiscord/themes/pywal.theme.css new file mode 100644 index 0000000..19b01e4 --- /dev/null +++ b/.config/BetterDiscord/themes/pywal.theme.css @@ -0,0 +1,75 @@ +/** + * @name pywal + * @author Loekaars#8205 + * @version 1.0.0 + * @description Cool beans +*/ + +:root { + --pywal-shade0: #18191C; + --pywal-shade1: #1D1E21; + --pywal-shade2: #1F2024; + --pywal-shade3: #222227; + --pywal-shade4: #1F202A; + + --accent: 102, 97, 90; + + --pywal-serverside: #121213; + --pywal-serverfolder-transparent: hsla(240, 2.4%, 7.2%, 0.55); + + --pywal-bg0: #141415; + --pywal-bg1: #181819; + --pywal-bg2: #1C1C1D; + --pywal-bg3: #202022; + + --pywal-color0: #141415; + --pywal-color1: #292b37; + --pywal-color2: #3c2a27; + --pywal-color3: #3b3033; + --pywal-color4: #3f3330; + --pywal-color5: #4b4240; + --pywal-color6: #66615a; + --pywal-color7: #c4c4c4; + --pywal-color8: #4e4e4f; + --pywal-color9: #292b37; + --pywal-color10: #3c2a27; + --pywal-color11: #3b3033; + --pywal-color12: #3f3330; + --pywal-color13: #4b4240; + --pywal-color14: #66615a; + --pywal-color15: #c4c4c4; + + --pywal-readable-color0: #6B6B70; + --pywal-readable-color1: #585B71; + --pywal-readable-color2: #745550; + --pywal-readable-color3: #67565A; + --pywal-readable-color4: #665450; + --pywal-readable-color5: #4B4240; + --pywal-readable-color6: #66615A; + --pywal-readable-color7: #C4C4C4; + --pywal-readable-color8: #4E4E4F; + --pywal-readable-color9: #585B71; + --pywal-readable-color10: #745550; + --pywal-readable-color11: #67565A; + --pywal-readable-color12: #665450; + --pywal-readable-color13: #4B4240; + --pywal-readable-color14: #66615A; + --pywal-readable-color15: #C4C4C4; + + --pywal-readableOn-color0: #c4c4c4; + --pywal-readableOn-color1: #c4c4c4; + --pywal-readableOn-color2: #c4c4c4; + --pywal-readableOn-color3: #c4c4c4; + --pywal-readableOn-color4: #c4c4c4; + --pywal-readableOn-color5: #c4c4c4; + --pywal-readableOn-color6: #c4c4c4; + --pywal-readableOn-color7: #141415; + --pywal-readableOn-color8: #c4c4c4; + --pywal-readableOn-color9: #c4c4c4; + --pywal-readableOn-color10: #c4c4c4; + --pywal-readableOn-color11: #c4c4c4; + --pywal-readableOn-color12: #c4c4c4; + --pywal-readableOn-color13: #c4c4c4; + --pywal-readableOn-color14: #c4c4c4; + --pywal-readableOn-color15: #141415; +}
\ No newline at end of file diff --git a/.config/brave-flags.conf b/.config/brave-flags.conf new file mode 100644 index 0000000..cb077db --- /dev/null +++ b/.config/brave-flags.conf @@ -0,0 +1 @@ +--force-dark-mode --load-extension=/home/loek/.cache/wal/chromium diff --git a/.config/chromium-flags.conf b/.config/chromium-flags.conf new file mode 100644 index 0000000..6fc50e8 --- /dev/null +++ b/.config/chromium-flags.conf @@ -0,0 +1 @@ +--force-dark-mode --load-extension="/home/loek/.cache/wal/chromium/" diff --git a/.config/coc/commands b/.config/coc/commands new file mode 100644 index 0000000..d173b4d --- /dev/null +++ b/.config/coc/commands @@ -0,0 +1,3 @@ +clangd.install +snippets.editSnippets +workspace.showOutput
\ No newline at end of file diff --git a/.config/coc/extensions/package.json b/.config/coc/extensions/package.json new file mode 100644 index 0000000..432cb8a --- /dev/null +++ b/.config/coc/extensions/package.json @@ -0,0 +1,14 @@ +{ + "dependencies": { + "coc-clangd": ">=0.4.10", + "coc-css": ">=1.2.3", + "coc-emmet": ">=1.1.4", + "coc-html": ">=1.2.4", + "coc-json": ">=1.2.6", + "coc-neosnippet": ">=1.2.2", + "coc-python": ">=1.2.12", + "coc-snippets": ">=2.1.28", + "coc-tsserver": ">=1.5.2", + "coc-vimtex": ">=1.0.3" + } +}
\ No newline at end of file diff --git a/.config/coc/snippets-mru b/.config/coc/snippets-mru new file mode 100644 index 0000000..b58504a --- /dev/null +++ b/.config/coc/snippets-mru @@ -0,0 +1,9 @@ +newdocument +newhtml +for +try/except/else +try/except +\begin +gerrit +nopagenumbers +snippet
\ No newline at end of file diff --git a/.config/coc/ultisnips/css.snippets b/.config/coc/ultisnips/css.snippets new file mode 100644 index 0000000..fc67c2e --- /dev/null +++ b/.config/coc/ultisnips/css.snippets @@ -0,0 +1,5 @@ +snippet resetFontWeight "reset font-weight for mobile browsers" +h1, h2, h3, h4, h5, h6 { + font-weight: normal !important; +} +endsnippet diff --git a/.config/coc/ultisnips/html.snippets b/.config/coc/ultisnips/html.snippets new file mode 100644 index 0000000..1730a7a --- /dev/null +++ b/.config/coc/ultisnips/html.snippets @@ -0,0 +1,16 @@ +snippet newhtml "HTML Starting Point" +<!DOCTYPE html> +<html> +<head> + <meta charset='utf-8'> + <meta http-equiv='X-UA-Compatible' content='IE=edge'> + <title>${1:Page Title}</title> + <meta name='viewport' content='width=device-width, initial-scale=1'> + <link rel='stylesheet' type='text/css' media='screen' href='${2:style.css}'> + <script src='${3:script.js}'></script> +</head> +<body> + ${0} +</body> +</html> +endsnippet diff --git a/.config/coc/ultisnips/tex.snippets b/.config/coc/ultisnips/tex.snippets new file mode 100644 index 0000000..056f562 --- /dev/null +++ b/.config/coc/ultisnips/tex.snippets @@ -0,0 +1,34 @@ +snippet newdocument "Starting point for a new LaTeX document" +\\documentclass[12pt, a4paper, hidelinks]{article} +\\setlength{\\marginparwidth}{2.54cm} + +% Packages +\\usepackage{fullpage} + +% Skip +\\bigskipamount=.7cm +\\medskipamount=.4cm +\\parindent=.3cm + +% Document +\\begin{document} + ${0} +\\end{document} +endsnippet + +snippet nonumberedchapters "Removes chapter numbers" +% Unnumber chapter headings +\\makeatletter +\\def\\@seccntformat#1{ + \\expandafter\\ifx\\csname c@#1\\endcsname\\c@section\\else + \\csname the#1\\endcsname\\quad + \\fi} +\\makeatother +endsnippet + +snippet beginend "begin/end snippet" +\\begin\{${1}\} +${0} +\\end\{${1}\} +endsnippet + diff --git a/.config/i3/config b/.config/i3/config new file mode 100644 index 0000000..7e6afb4 --- /dev/null +++ b/.config/i3/config @@ -0,0 +1,165 @@ +# variables +set $mod Mod4 +set $inner_gaps 10 +set $outer_gaps 0 + +# set gaps +gaps inner $inner_gaps +gaps outer $outer_gaps + +# border color +# pywal-start +client.focused #66615a #141415 #c4c4c4 #66615a #585653 +client.focused_inactive #5E5E5F #4e4e4f #c4c4c4 #181819 #141415 +client.unfocused #141415 #101011 #9D9D9D #141415 #101011 +client.urgent #141415 #e95678 #c4c4c4 #e95678 #e95678 +client.placeholder #000000 #0c0c0c #c4c4c4 #000000 #0c0c0c +client.background #c4c4c4 + +# pywal-end + +# font +font pango:Fira Code 9 + +# no idea what these do but they were in here by default +exec --no-startup-id xss-lock --transfer-sleep-lock -- i3lock --nofork +exec --no-startup-id nm-applet +set $refresh_i3status killall -SIGUSR1 i3status + +# Voulme keybinds +bindsym XF86AudioRaiseVolume exec --no-startup-id pactl set-sink-volume @DEFAULT_SINK@ +5% && $refresh_i3status +bindsym XF86AudioLowerVolume exec --no-startup-id pactl set-sink-volume @DEFAULT_SINK@ -5% && $refresh_i3status +bindsym XF86AudioMute exec --no-startup-id pactl set-sink-mute @DEFAULT_SINK@ toggle && $refresh_i3status + +# window interactions +floating_modifier $mod +bindsym $mod+q kill + +# Replace window decorations with a border +for_window [class=".*"] border pixel 1 + +# Keybinds +bindsym $mod+Escape exec "dm-tool lock" +bindsym $mod+space exec "rofi -show drun -show-icons" +bindsym $mod+Return exec konsole +bindsym $mod+p exec bwmenu +bindsym Print exec "flameshot gui" + +bindsym XF86AudioPlay exec "playerctl play-pause" +bindsym XF86AudioNext exec "playerctl next" +bindsym XF86AudioPrev exec "playerctl previous" + +# 60% keyboard media controls +bindsym Mod1+Mod4+k exec "mpc toggle" +bindsym Mod1+Mod4+l exec "mpc next" +bindsym Mod1+Mod4+j exec "mpc prev" +bindsym Mod1+Mod4+minus exec "pactl set-sink-volume @DEFAULT_SINK@ -5%" +bindsym Mod1+Mod4+equal exec "pactl set-sink-volume @DEFAULT_SINK@ +5%" + +# Gaps +bindsym $mod+i gaps inner current plus 5 +bindsym $mod+Shift+i gaps inner current minus 5 +bindsym $mod+o gaps outer current plus 5 +bindsym $mod+Shift+o gaps outer current minus 5 +bindsym $mod+n gaps inner current set -1; gaps outer current set 0 +bindsym $mod+d gaps inner current set $inner_gaps; gaps outer current set $outer_gaps; + +# Autostart +exec "polybar main -c ~/.config/polybar/config.ini &" +exec "node ~/.local/share/bin/pywal/wall.js &" +exec "exec picom --experimental-backends &" +exec "node ~/.local/share/bin/pester/index.js &" +exec "flameshot &" + +# change focus +bindsym $mod+h focus left +bindsym $mod+j focus down +bindsym $mod+k focus up +bindsym $mod+l focus right + +# move focused window +bindsym $mod+Shift+h move left +bindsym $mod+Shift+j move down +bindsym $mod+Shift+k move up +bindsym $mod+Shift+l move right + +# resize focused window +bindsym $mod+bracketright resize grow height 10 px +bindsym $mod+bracketleft resize shrink height 10 px +bindsym $mod+period resize grow width 10 px +bindsym $mod+comma resize shrink width 10 px + +# split in horizontal orientation +bindsym $mod+bar split h +bindsym $mod+minus split v + +# enter fullscreen mode for the focused container +bindsym $mod+f fullscreen toggle + +# toggle tiling / floating +bindsym $mod+Shift+space floating toggle + +# change focus between tiling / floating windows +bindsym $mod+Alt+space focus mode_toggle + +# focus the parent container +bindsym $mod+Shift+a focus parent + +# focus the child container +#bindsym $mod+d focus child + +# disable mouse teleports +mouse_warping none + +# workspaces +set $ws1 "1" +set $ws2 "2" +set $ws3 "3" +set $ws4 "4" +set $ws5 "5" +set $ws6 "6" +set $ws7 "7" +set $ws8 "8" + +# switch to workspace +bindsym $mod+1 workspace number $ws1 +bindsym $mod+2 workspace number $ws2 +bindsym $mod+3 workspace number $ws3 +bindsym $mod+4 workspace number $ws4 +bindsym $mod+5 workspace number $ws5 +bindsym $mod+6 workspace number $ws6 +bindsym $mod+7 workspace number $ws7 +bindsym $mod+8 workspace number $ws8 + +# move focused container to workspace +bindsym $mod+Shift+1 move container to workspace number $ws1 +bindsym $mod+Shift+2 move container to workspace number $ws2 +bindsym $mod+Shift+3 move container to workspace number $ws3 +bindsym $mod+Shift+4 move container to workspace number $ws4 +bindsym $mod+Shift+5 move container to workspace number $ws5 +bindsym $mod+Shift+6 move container to workspace number $ws6 +bindsym $mod+Shift+7 move container to workspace number $ws7 +bindsym $mod+Shift+8 move container to workspace number $ws8 + +# always floating windows +for_window [class="Steam"] floating enable +for_window [class="cinquo"] floating enable +for_window [title="Farge"] floating enable +for_window [window_type=notification] floating enable + +for_window [class="Unturned.x86_64"] floating disable +for_window [class="Unturned.x86_64"] fullscreen disable + +# reload the configuration file +bindsym $mod+Shift+c reload +# restart i3 inplace (preserves your layout/session, can be used to upgrade i3) +bindsym $mod+Shift+r restart +# exit i3 (logs you out of your X session) +# bindsym $mod+Shift+e exec "i3-nagbar -t warning -m 'You pressed the exit shortcut. Do you really want to exit i3? This will end your X session.' -B 'Yes, exit i3' 'i3-msg exit'" + +# bar { +# mode hide +# hidden_state hide +# modifier none +# tray_output none +# } diff --git a/.config/i3/config.backup b/.config/i3/config.backup new file mode 100644 index 0000000..4d3a098 --- /dev/null +++ b/.config/i3/config.backup @@ -0,0 +1,140 @@ +# variables +set $mod Mod4 +set $inner_gaps 10 +set $outer_gaps 0 +set $polybar_gap 30 + +# set gaps +gaps inner $inner_gaps +gaps outer $outer_gaps + +# border color +# pywal-start +client.focused #4c7899 #285577 #ffffff #2e9ef4 #285577 +client.focused_inactive #333333 #5f676a #ffffff #484e50 #5f676a +client.unfocused #333333 #222222 #888888 #292d2e #222222 +client.urgent #2f343a #900000 #ffffff #900000 #900000 +client.placeholder #000000 #0c0c0c #ffffff #000000 #0c0c0c + +client.background #ffffff +# pywal-end + +# font +font pango:Fira Code 9 + +# no idea what these do but they were in here by default +exec --no-startup-id xss-lock --transfer-sleep-lock -- i3lock --nofork +exec --no-startup-id nm-applet +set $refresh_i3status killall -SIGUSR1 i3status + +# Voulme keybinds +bindsym XF86AudioRaiseVolume exec --no-startup-id pactl set-sink-volume @DEFAULT_SINK@ +5% && $refresh_i3status +bindsym XF86AudioLowerVolume exec --no-startup-id pactl set-sink-volume @DEFAULT_SINK@ -5% && $refresh_i3status +bindsym XF86AudioMute exec --no-startup-id pactl set-sink-mute @DEFAULT_SINK@ toggle && $refresh_i3status + +# window interactions +floating_modifier $mod +bindsym $mod+q kill + +# Replace window decorations with a border +# for_window [class=".*"] border pixel 1 + +# Keybinds +bindsym $mod+Escape exec "dm-tool lock" +bindsym $mod+space exec "rofi -show drun -show-icons" +bindsym $mod+Return exec konsole +bindsym Print exec "flameshot gui" + +bindsym XF86AudioPlay exec "playerctl play-pause" +bindsym XF86AudioNext exec "playerctl next" +bindsym XF86AudioPrev exec "playerctl previous" + +# Gaps +bindsym $mod+i gaps inner current plus 5 +bindsym $mod+Shift+i gaps inner current minus 5 +bindsym $mod+o gaps outer current plus 5 +bindsym $mod+Shift+o gaps outer current minus 5 +bindsym $mod+n gaps inner current set -1; gaps outer current set 0 +bindsym $mod+d gaps inner current set $inner_gaps; gaps outer current set $outer_gaps; +bindsym $mod+p gaps top current set $polybar_gap + +# Autostart +exec "polybar main -c ~/.config/polybar/config.ini &" +exec "node ~/scripts/pywal/wall.js" +exec "exec picom &" + +exec "deadd-notification-center &" + +exec "node ~/pester/index.js &" +exec "flameshot &" +exec "dropbox &" +# exec "teams &" + +# change focus +bindsym $mod+h focus left +bindsym $mod+j focus down +bindsym $mod+k focus up +bindsym $mod+l focus right + +# move focused window +bindsym $mod+Shift+h move left +bindsym $mod+Shift+j move down +bindsym $mod+Shift+k move up +bindsym $mod+Shift+l move right + +# resize focused window +bindsym $mod+bracketright resize grow height 10 px +bindsym $mod+bracketleft resize shrink height 10 px +bindsym $mod+period resize grow width 10 px +bindsym $mod+comma resize shrink width 10 px + +# split in horizontal orientation +bindsym $mod+bar split h +bindsym $mod+minus split v + +# enter fullscreen mode for the focused container +bindsym $mod+f fullscreen toggle + +# toggle tiling / floating +bindsym $mod+Shift+space floating toggle + +# change focus between tiling / floating windows +# bindsym $mod+space focus mode_toggle + +# focus the parent container +bindsym $mod+a focus parent + +# focus the child container +#bindsym $mod+d focus child + +# workspaces +set $ws1 "1" +set $ws2 "2" +set $ws3 "3" +set $ws4 "4" + +# switch to workspace +bindsym $mod+1 workspace number $ws1 +bindsym $mod+2 workspace number $ws2 +bindsym $mod+3 workspace number $ws3 +bindsym $mod+4 workspace number $ws4 + +# move focused container to workspace +bindsym $mod+Shift+1 move container to workspace number $ws1 +bindsym $mod+Shift+2 move container to workspace number $ws2 +bindsym $mod+Shift+3 move container to workspace number $ws3 +bindsym $mod+Shift+4 move container to workspace number $ws4 + +# reload the configuration file +bindsym $mod+Shift+c reload +# restart i3 inplace (preserves your layout/session, can be used to upgrade i3) +bindsym $mod+Shift+r restart +# exit i3 (logs you out of your X session) +bindsym $mod+Shift+e exec "i3-nagbar -t warning -m 'You pressed the exit shortcut. Do you really want to exit i3? This will end your X session.' -B 'Yes, exit i3' 'i3-msg exit'" + +bar { + mode hide + hidden_state hide + modifier none + tray_output none +} diff --git a/.config/konsolerc b/.config/konsolerc new file mode 100644 index 0000000..c42e4b7 --- /dev/null +++ b/.config/konsolerc @@ -0,0 +1,25 @@ +[Desktop Entry] +DefaultProfile=Loekaars.profile + +[DownloadDialog Settings] +Height 1080=400 +Width 1920=700 + +[Favorite Profiles] +Favorites= + +[KonsoleWindow] +SaveGeometryOnExit=false +ShowMenuBarByDefault=false + +[MainWindow] +MenuBar=Disabled +State=AAAA/wAAAAD9AAAAAAAAB2oAAAQSAAAABAAAAAQAAAAIAAAACPwAAAAA +ToolBarsMovable=Disabled + +[Notification Messages] +CloseAllTabs=true +ShowPasteUnprintableWarning=false + +[Shortcut Schemes] +Current Scheme=Default diff --git a/.config/nvim/autoload/plug.vim b/.config/nvim/autoload/plug.vim new file mode 100644 index 0000000..25be27f --- /dev/null +++ b/.config/nvim/autoload/plug.vim @@ -0,0 +1,2665 @@ +" vim-plug: Vim plugin manager +" ============================ +" +" Download plug.vim and put it in ~/.vim/autoload +" +" curl -fLo ~/.vim/autoload/plug.vim --create-dirs \ +" https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim +" +" Edit your .vimrc +" +" call plug#begin('~/.vim/plugged') +" +" " Make sure you use single quotes +" +" " Shorthand notation; fetches https://github.com/junegunn/vim-easy-align +" Plug 'junegunn/vim-easy-align' +" +" " Any valid git URL is allowed +" Plug 'https://github.com/junegunn/vim-github-dashboard.git' +" +" " Multiple Plug commands can be written in a single line using | separators +" Plug 'SirVer/ultisnips' | Plug 'honza/vim-snippets' +" +" " On-demand loading +" Plug 'scrooloose/nerdtree', { 'on': 'NERDTreeToggle' } +" Plug 'tpope/vim-fireplace', { 'for': 'clojure' } +" +" " Using a non-master branch +" Plug 'rdnetto/YCM-Generator', { 'branch': 'stable' } +" +" " Using a tagged release; wildcard allowed (requires git 1.9.2 or above) +" Plug 'fatih/vim-go', { 'tag': '*' } +" +" " Plugin options +" Plug 'nsf/gocode', { 'tag': 'v.20150303', 'rtp': 'vim' } +" +" " Plugin outside ~/.vim/plugged with post-update hook +" Plug 'junegunn/fzf', { 'dir': '~/.fzf', 'do': './install --all' } +" +" " Unmanaged plugin (manually installed and updated) +" Plug '~/my-prototype-plugin' +" +" " Initialize plugin system +" call plug#end() +" +" Then reload .vimrc and :PlugInstall to install plugins. +" +" Plug options: +" +"| Option | Description | +"| ----------------------- | ------------------------------------------------ | +"| `branch`/`tag`/`commit` | Branch/tag/commit of the repository to use | +"| `rtp` | Subdirectory that contains Vim plugin | +"| `dir` | Custom directory for the plugin | +"| `as` | Use different name for the plugin | +"| `do` | Post-update hook (string or funcref) | +"| `on` | On-demand loading: Commands or `<Plug>`-mappings | +"| `for` | On-demand loading: File types | +"| `frozen` | Do not update unless explicitly specified | +" +" More information: https://github.com/junegunn/vim-plug +" +" +" Copyright (c) 2017 Junegunn Choi +" +" MIT License +" +" Permission is hereby granted, free of charge, to any person obtaining +" a copy of this software and associated documentation files (the +" "Software"), to deal in the Software without restriction, including +" without limitation the rights to use, copy, modify, merge, publish, +" distribute, sublicense, and/or sell copies of the Software, and to +" permit persons to whom the Software is furnished to do so, subject to +" the following conditions: +" +" The above copyright notice and this permission notice shall be +" included in all copies or substantial portions of the Software. +" +" THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +" EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +" MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +" NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +" LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +" OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +" WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +if exists('g:loaded_plug') + finish +endif +let g:loaded_plug = 1 + +let s:cpo_save = &cpo +set cpo&vim + +let s:plug_src = 'https://github.com/junegunn/vim-plug.git' +let s:plug_tab = get(s:, 'plug_tab', -1) +let s:plug_buf = get(s:, 'plug_buf', -1) +let s:mac_gui = has('gui_macvim') && has('gui_running') +let s:is_win = has('win32') +let s:nvim = has('nvim-0.2') || (has('nvim') && exists('*jobwait') && !s:is_win) +let s:vim8 = has('patch-8.0.0039') && exists('*job_start') +if s:is_win && &shellslash + set noshellslash + let s:me = resolve(expand('<sfile>:p')) + set shellslash +else + let s:me = resolve(expand('<sfile>:p')) +endif +let s:base_spec = { 'branch': 'master', 'frozen': 0 } +let s:TYPE = { +\ 'string': type(''), +\ 'list': type([]), +\ 'dict': type({}), +\ 'funcref': type(function('call')) +\ } +let s:loaded = get(s:, 'loaded', {}) +let s:triggers = get(s:, 'triggers', {}) + +if s:is_win + function! s:plug_call(fn, ...) + let shellslash = &shellslash + try + set noshellslash + return call(a:fn, a:000) + finally + let &shellslash = shellslash + endtry + endfunction +else + function! s:plug_call(fn, ...) + return call(a:fn, a:000) + endfunction +endif + +function! s:plug_getcwd() + return s:plug_call('getcwd') +endfunction + +function! s:plug_fnamemodify(fname, mods) + return s:plug_call('fnamemodify', a:fname, a:mods) +endfunction + +function! s:plug_expand(fmt) + return s:plug_call('expand', a:fmt, 1) +endfunction + +function! s:plug_tempname() + return s:plug_call('tempname') +endfunction + +function! plug#begin(...) + if a:0 > 0 + let s:plug_home_org = a:1 + let home = s:path(s:plug_fnamemodify(s:plug_expand(a:1), ':p')) + elseif exists('g:plug_home') + let home = s:path(g:plug_home) + elseif !empty(&rtp) + let home = s:path(split(&rtp, ',')[0]) . '/plugged' + else + return s:err('Unable to determine plug home. Try calling plug#begin() with a path argument.') + endif + if s:plug_fnamemodify(home, ':t') ==# 'plugin' && s:plug_fnamemodify(home, ':h') ==# s:first_rtp + return s:err('Invalid plug home. '.home.' is a standard Vim runtime path and is not allowed.') + endif + + let g:plug_home = home + let g:plugs = {} + let g:plugs_order = [] + let s:triggers = {} + + call s:define_commands() + return 1 +endfunction + +function! s:define_commands() + command! -nargs=+ -bar Plug call plug#(<args>) + if !executable('git') + return s:err('`git` executable not found. Most commands will not be available. To suppress this message, prepend `silent!` to `call plug#begin(...)`.') + endif + if has('win32') + \ && &shellslash + \ && (&shell =~# 'cmd\.exe' || &shell =~# 'powershell\.exe') + return s:err('vim-plug does not support shell, ' . &shell . ', when shellslash is set.') + endif + if !has('nvim') + \ && (has('win32') || has('win32unix')) + \ && !has('multi_byte') + return s:err('Vim needs +multi_byte feature on Windows to run shell commands. Enable +iconv for best results.') + endif + command! -nargs=* -bar -bang -complete=customlist,s:names PlugInstall call s:install(<bang>0, [<f-args>]) + command! -nargs=* -bar -bang -complete=customlist,s:names PlugUpdate call s:update(<bang>0, [<f-args>]) + command! -nargs=0 -bar -bang PlugClean call s:clean(<bang>0) + command! -nargs=0 -bar PlugUpgrade if s:upgrade() | execute 'source' s:esc(s:me) | endif + command! -nargs=0 -bar PlugStatus call s:status() + command! -nargs=0 -bar PlugDiff call s:diff() + command! -nargs=? -bar -bang -complete=file PlugSnapshot call s:snapshot(<bang>0, <f-args>) +endfunction + +function! s:to_a(v) + return type(a:v) == s:TYPE.list ? a:v : [a:v] +endfunction + +function! s:to_s(v) + return type(a:v) == s:TYPE.string ? a:v : join(a:v, "\n") . "\n" +endfunction + +function! s:glob(from, pattern) + return s:lines(globpath(a:from, a:pattern)) +endfunction + +function! s:source(from, ...) + let found = 0 + for pattern in a:000 + for vim in s:glob(a:from, pattern) + execute 'source' s:esc(vim) + let found = 1 + endfor + endfor + return found +endfunction + +function! s:assoc(dict, key, val) + let a:dict[a:key] = add(get(a:dict, a:key, []), a:val) +endfunction + +function! s:ask(message, ...) + call inputsave() + echohl WarningMsg + let answer = input(a:message.(a:0 ? ' (y/N/a) ' : ' (y/N) ')) + echohl None + call inputrestore() + echo "\r" + return (a:0 && answer =~? '^a') ? 2 : (answer =~? '^y') ? 1 : 0 +endfunction + +function! s:ask_no_interrupt(...) + try + return call('s:ask', a:000) + catch + return 0 + endtry +endfunction + +function! s:lazy(plug, opt) + return has_key(a:plug, a:opt) && + \ (empty(s:to_a(a:plug[a:opt])) || + \ !isdirectory(a:plug.dir) || + \ len(s:glob(s:rtp(a:plug), 'plugin')) || + \ len(s:glob(s:rtp(a:plug), 'after/plugin'))) +endfunction + +function! plug#end() + if !exists('g:plugs') + return s:err('plug#end() called without calling plug#begin() first') + endif + + if exists('#PlugLOD') + augroup PlugLOD + autocmd! + augroup END + augroup! PlugLOD + endif + let lod = { 'ft': {}, 'map': {}, 'cmd': {} } + + if exists('g:did_load_filetypes') + filetype off + endif + for name in g:plugs_order + if !has_key(g:plugs, name) + continue + endif + let plug = g:plugs[name] + if get(s:loaded, name, 0) || !s:lazy(plug, 'on') && !s:lazy(plug, 'for') + let s:loaded[name] = 1 + continue + endif + + if has_key(plug, 'on') + let s:triggers[name] = { 'map': [], 'cmd': [] } + for cmd in s:to_a(plug.on) + if cmd =~? '^<Plug>.\+' + if empty(mapcheck(cmd)) && empty(mapcheck(cmd, 'i')) + call s:assoc(lod.map, cmd, name) + endif + call add(s:triggers[name].map, cmd) + elseif cmd =~# '^[A-Z]' + let cmd = substitute(cmd, '!*$', '', '') + if exists(':'.cmd) != 2 + call s:assoc(lod.cmd, cmd, name) + endif + call add(s:triggers[name].cmd, cmd) + else + call s:err('Invalid `on` option: '.cmd. + \ '. Should start with an uppercase letter or `<Plug>`.') + endif + endfor + endif + + if has_key(plug, 'for') + let types = s:to_a(plug.for) + if !empty(types) + augroup filetypedetect + call s:source(s:rtp(plug), 'ftdetect/**/*.vim', 'after/ftdetect/**/*.vim') + augroup END + endif + for type in types + call s:assoc(lod.ft, type, name) + endfor + endif + endfor + + for [cmd, names] in items(lod.cmd) + execute printf( + \ 'command! -nargs=* -range -bang -complete=file %s call s:lod_cmd(%s, "<bang>", <line1>, <line2>, <q-args>, %s)', + \ cmd, string(cmd), string(names)) + endfor + + for [map, names] in items(lod.map) + for [mode, map_prefix, key_prefix] in + \ [['i', '<C-O>', ''], ['n', '', ''], ['v', '', 'gv'], ['o', '', '']] + execute printf( + \ '%snoremap <silent> %s %s:<C-U>call <SID>lod_map(%s, %s, %s, "%s")<CR>', + \ mode, map, map_prefix, string(map), string(names), mode != 'i', key_prefix) + endfor + endfor + + for [ft, names] in items(lod.ft) + augroup PlugLOD + execute printf('autocmd FileType %s call <SID>lod_ft(%s, %s)', + \ ft, string(ft), string(names)) + augroup END + endfor + + call s:reorg_rtp() + filetype plugin indent on + if has('vim_starting') + if has('syntax') && !exists('g:syntax_on') + syntax enable + end + else + call s:reload_plugins() + endif +endfunction + +function! s:loaded_names() + return filter(copy(g:plugs_order), 'get(s:loaded, v:val, 0)') +endfunction + +function! s:load_plugin(spec) + call s:source(s:rtp(a:spec), 'plugin/**/*.vim', 'after/plugin/**/*.vim') +endfunction + +function! s:reload_plugins() + for name in s:loaded_names() + call s:load_plugin(g:plugs[name]) + endfor +endfunction + +function! s:trim(str) + return substitute(a:str, '[\/]\+$', '', '') +endfunction + +function! s:version_requirement(val, min) + for idx in range(0, len(a:min) - 1) + let v = get(a:val, idx, 0) + if v < a:min[idx] | return 0 + elseif v > a:min[idx] | return 1 + endif + endfor + return 1 +endfunction + +function! s:git_version_requirement(...) + if !exists('s:git_version') + let s:git_version = map(split(split(s:system(['git', '--version']))[2], '\.'), 'str2nr(v:val)') + endif + return s:version_requirement(s:git_version, a:000) +endfunction + +function! s:progress_opt(base) + return a:base && !s:is_win && + \ s:git_version_requirement(1, 7, 1) ? '--progress' : '' +endfunction + +function! s:rtp(spec) + return s:path(a:spec.dir . get(a:spec, 'rtp', '')) +endfunction + +if s:is_win + function! s:path(path) + return s:trim(substitute(a:path, '/', '\', 'g')) + endfunction + + function! s:dirpath(path) + return s:path(a:path) . '\' + endfunction + + function! s:is_local_plug(repo) + return a:repo =~? '^[a-z]:\|^[%~]' + endfunction + + " Copied from fzf + function! s:wrap_cmds(cmds) + let cmds = [ + \ '@echo off', + \ 'setlocal enabledelayedexpansion'] + \ + (type(a:cmds) == type([]) ? a:cmds : [a:cmds]) + \ + ['endlocal'] + if has('iconv') + if !exists('s:codepage') + let s:codepage = libcallnr('kernel32.dll', 'GetACP', 0) + endif + return map(cmds, printf('iconv(v:val."\r", "%s", "cp%d")', &encoding, s:codepage)) + endif + return map(cmds, 'v:val."\r"') + endfunction + + function! s:batchfile(cmd) + let batchfile = s:plug_tempname().'.bat' + call writefile(s:wrap_cmds(a:cmd), batchfile) + let cmd = plug#shellescape(batchfile, {'shell': &shell, 'script': 0}) + if &shell =~# 'powershell\.exe' + let cmd = '& ' . cmd + endif + return [batchfile, cmd] + endfunction +else + function! s:path(path) + return s:trim(a:path) + endfunction + + function! s:dirpath(path) + return substitute(a:path, '[/\\]*$', '/', '') + endfunction + + function! s:is_local_plug(repo) + return a:repo[0] =~ '[/$~]' + endfunction +endif + +function! s:err(msg) + echohl ErrorMsg + echom '[vim-plug] '.a:msg + echohl None +endfunction + +function! s:warn(cmd, msg) + echohl WarningMsg + execute a:cmd 'a:msg' + echohl None +endfunction + +function! s:esc(path) + return escape(a:path, ' ') +endfunction + +function! s:escrtp(path) + return escape(a:path, ' ,') +endfunction + +function! s:remove_rtp() + for name in s:loaded_names() + let rtp = s:rtp(g:plugs[name]) + execute 'set rtp-='.s:escrtp(rtp) + let after = globpath(rtp, 'after') + if isdirectory(after) + execute 'set rtp-='.s:escrtp(after) + endif + endfor +endfunction + +function! s:reorg_rtp() + if !empty(s:first_rtp) + execute 'set rtp-='.s:first_rtp + execute 'set rtp-='.s:last_rtp + endif + + " &rtp is modified from outside + if exists('s:prtp') && s:prtp !=# &rtp + call s:remove_rtp() + unlet! s:middle + endif + + let s:middle = get(s:, 'middle', &rtp) + let rtps = map(s:loaded_names(), 's:rtp(g:plugs[v:val])') + let afters = filter(map(copy(rtps), 'globpath(v:val, "after")'), '!empty(v:val)') + let rtp = join(map(rtps, 'escape(v:val, ",")'), ',') + \ . ','.s:middle.',' + \ . join(map(afters, 'escape(v:val, ",")'), ',') + let &rtp = substitute(substitute(rtp, ',,*', ',', 'g'), '^,\|,$', '', 'g') + let s:prtp = &rtp + + if !empty(s:first_rtp) + execute 'set rtp^='.s:first_rtp + execute 'set rtp+='.s:last_rtp + endif +endfunction + +function! s:doautocmd(...) + if exists('#'.join(a:000, '#')) + execute 'doautocmd' ((v:version > 703 || has('patch442')) ? '<nomodeline>' : '') join(a:000) + endif +endfunction + +function! s:dobufread(names) + for name in a:names + let path = s:rtp(g:plugs[name]) + for dir in ['ftdetect', 'ftplugin', 'after/ftdetect', 'after/ftplugin'] + if len(finddir(dir, path)) + if exists('#BufRead') + doautocmd BufRead + endif + return + endif + endfor + endfor +endfunction + +function! plug#load(...) + if a:0 == 0 + return s:err('Argument missing: plugin name(s) required') + endif + if !exists('g:plugs') + return s:err('plug#begin was not called') + endif + let names = a:0 == 1 && type(a:1) == s:TYPE.list ? a:1 : a:000 + let unknowns = filter(copy(names), '!has_key(g:plugs, v:val)') + if !empty(unknowns) + let s = len(unknowns) > 1 ? 's' : '' + return s:err(printf('Unknown plugin%s: %s', s, join(unknowns, ', '))) + end + let unloaded = filter(copy(names), '!get(s:loaded, v:val, 0)') + if !empty(unloaded) + for name in unloaded + call s:lod([name], ['ftdetect', 'after/ftdetect', 'plugin', 'after/plugin']) + endfor + call s:dobufread(unloaded) + return 1 + end + return 0 +endfunction + +function! s:remove_triggers(name) + if !has_key(s:triggers, a:name) + return + endif + for cmd in s:triggers[a:name].cmd + execute 'silent! delc' cmd + endfor + for map in s:triggers[a:name].map + execute 'silent! unmap' map + execute 'silent! iunmap' map + endfor + call remove(s:triggers, a:name) +endfunction + +function! s:lod(names, types, ...) + for name in a:names + call s:remove_triggers(name) + let s:loaded[name] = 1 + endfor + call s:reorg_rtp() + + for name in a:names + let rtp = s:rtp(g:plugs[name]) + for dir in a:types + call s:source(rtp, dir.'/**/*.vim') + endfor + if a:0 + if !s:source(rtp, a:1) && !empty(s:glob(rtp, a:2)) + execute 'runtime' a:1 + endif + call s:source(rtp, a:2) + endif + call s:doautocmd('User', name) + endfor +endfunction + +function! s:lod_ft(pat, names) + let syn = 'syntax/'.a:pat.'.vim' + call s:lod(a:names, ['plugin', 'after/plugin'], syn, 'after/'.syn) + execute 'autocmd! PlugLOD FileType' a:pat + call s:doautocmd('filetypeplugin', 'FileType') + call s:doautocmd('filetypeindent', 'FileType') +endfunction + +function! s:lod_cmd(cmd, bang, l1, l2, args, names) + call s:lod(a:names, ['ftdetect', 'after/ftdetect', 'plugin', 'after/plugin']) + call s:dobufread(a:names) + execute printf('%s%s%s %s', (a:l1 == a:l2 ? '' : (a:l1.','.a:l2)), a:cmd, a:bang, a:args) +endfunction + +function! s:lod_map(map, names, with_prefix, prefix) + call s:lod(a:names, ['ftdetect', 'after/ftdetect', 'plugin', 'after/plugin']) + call s:dobufread(a:names) + let extra = '' + while 1 + let c = getchar(0) + if c == 0 + break + endif + let extra .= nr2char(c) + endwhile + + if a:with_prefix + let prefix = v:count ? v:count : '' + let prefix .= '"'.v:register.a:prefix + if mode(1) == 'no' + if v:operator == 'c' + let prefix = "\<esc>" . prefix + endif + let prefix .= v:operator + endif + call feedkeys(prefix, 'n') + endif + call feedkeys(substitute(a:map, '^<Plug>', "\<Plug>", '') . extra) +endfunction + +function! plug#(repo, ...) + if a:0 > 1 + return s:err('Invalid number of arguments (1..2)') + endif + + try + let repo = s:trim(a:repo) + let opts = a:0 == 1 ? s:parse_options(a:1) : s:base_spec + let name = get(opts, 'as', s:plug_fnamemodify(repo, ':t:s?\.git$??')) + let spec = extend(s:infer_properties(name, repo), opts) + if !has_key(g:plugs, name) + call add(g:plugs_order, name) + endif + let g:plugs[name] = spec + let s:loaded[name] = get(s:loaded, name, 0) + catch + return s:err(v:exception) + endtry +endfunction + +function! s:parse_options(arg) + let opts = copy(s:base_spec) + let type = type(a:arg) + if type == s:TYPE.string + let opts.tag = a:arg + elseif type == s:TYPE.dict + call extend(opts, a:arg) + if has_key(opts, 'dir') + let opts.dir = s:dirpath(s:plug_expand(opts.dir)) + endif + else + throw 'Invalid argument type (expected: string or dictionary)' + endif + return opts +endfunction + +function! s:infer_properties(name, repo) + let repo = a:repo + if s:is_local_plug(repo) + return { 'dir': s:dirpath(s:plug_expand(repo)) } + else + if repo =~ ':' + let uri = repo + else + if repo !~ '/' + throw printf('Invalid argument: %s (implicit `vim-scripts'' expansion is deprecated)', repo) + endif + let fmt = get(g:, 'plug_url_format', 'https://git::@github.com/%s.git') + let uri = printf(fmt, repo) + endif + return { 'dir': s:dirpath(g:plug_home.'/'.a:name), 'uri': uri } + endif +endfunction + +function! s:install(force, names) + call s:update_impl(0, a:force, a:names) +endfunction + +function! s:update(force, names) + call s:update_impl(1, a:force, a:names) +endfunction + +function! plug#helptags() + if !exists('g:plugs') + return s:err('plug#begin was not called') + endif + for spec in values(g:plugs) + let docd = join([s:rtp(spec), 'doc'], '/') + if isdirectory(docd) + silent! execute 'helptags' s:esc(docd) + endif + endfor + return 1 +endfunction + +function! s:syntax() + syntax clear + syntax region plug1 start=/\%1l/ end=/\%2l/ contains=plugNumber + syntax region plug2 start=/\%2l/ end=/\%3l/ contains=plugBracket,plugX + syn match plugNumber /[0-9]\+[0-9.]*/ contained + syn match plugBracket /[[\]]/ contained + syn match plugX /x/ contained + syn match plugDash /^-/ + syn match plugPlus /^+/ + syn match plugStar /^*/ + syn match plugMessage /\(^- \)\@<=.*/ + syn match plugName /\(^- \)\@<=[^ ]*:/ + syn match plugSha /\%(: \)\@<=[0-9a-f]\{4,}$/ + syn match plugTag /(tag: [^)]\+)/ + syn match plugInstall /\(^+ \)\@<=[^:]*/ + syn match plugUpdate /\(^* \)\@<=[^:]*/ + syn match plugCommit /^ \X*[0-9a-f]\{7,9} .*/ contains=plugRelDate,plugEdge,plugTag + syn match plugEdge /^ \X\+$/ + syn match plugEdge /^ \X*/ contained nextgroup=plugSha + syn match plugSha /[0-9a-f]\{7,9}/ contained + syn match plugRelDate /([^)]*)$/ contained + syn match plugNotLoaded /(not loaded)$/ + syn match plugError /^x.*/ + syn region plugDeleted start=/^\~ .*/ end=/^\ze\S/ + syn match plugH2 /^.*:\n-\+$/ + syn keyword Function PlugInstall PlugStatus PlugUpdate PlugClean + hi def link plug1 Title + hi def link plug2 Repeat + hi def link plugH2 Type + hi def link plugX Exception + hi def link plugBracket Structure + hi def link plugNumber Number + + hi def link plugDash Special + hi def link plugPlus Constant + hi def link plugStar Boolean + + hi def link plugMessage Function + hi def link plugName Label + hi def link plugInstall Function + hi def link plugUpdate Type + + hi def link plugError Error + hi def link plugDeleted Ignore + hi def link plugRelDate Comment + hi def link plugEdge PreProc + hi def link plugSha Identifier + hi def link plugTag Constant + + hi def link plugNotLoaded Comment +endfunction + +function! s:lpad(str, len) + return a:str . repeat(' ', a:len - len(a:str)) +endfunction + +function! s:lines(msg) + return split(a:msg, "[\r\n]") +endfunction + +function! s:lastline(msg) + return get(s:lines(a:msg), -1, '') +endfunction + +function! s:new_window() + execute get(g:, 'plug_window', 'vertical topleft new') +endfunction + +function! s:plug_window_exists() + let buflist = tabpagebuflist(s:plug_tab) + return !empty(buflist) && index(buflist, s:plug_buf) >= 0 +endfunction + +function! s:switch_in() + if !s:plug_window_exists() + return 0 + endif + + if winbufnr(0) != s:plug_buf + let s:pos = [tabpagenr(), winnr(), winsaveview()] + execute 'normal!' s:plug_tab.'gt' + let winnr = bufwinnr(s:plug_buf) + execute winnr.'wincmd w' + call add(s:pos, winsaveview()) + else + let s:pos = [winsaveview()] + endif + + setlocal modifiable + return 1 +endfunction + +function! s:switch_out(...) + call winrestview(s:pos[-1]) + setlocal nomodifiable + if a:0 > 0 + execute a:1 + endif + + if len(s:pos) > 1 + execute 'normal!' s:pos[0].'gt' + execute s:pos[1] 'wincmd w' + call winrestview(s:pos[2]) + endif +endfunction + +function! s:finish_bindings() + nnoremap <silent> <buffer> R :call <SID>retry()<cr> + nnoremap <silent> <buffer> D :PlugDiff<cr> + nnoremap <silent> <buffer> S :PlugStatus<cr> + nnoremap <silent> <buffer> U :call <SID>status_update()<cr> + xnoremap <silent> <buffer> U :call <SID>status_update()<cr> + nnoremap <silent> <buffer> ]] :silent! call <SID>section('')<cr> + nnoremap <silent> <buffer> [[ :silent! call <SID>section('b')<cr> +endfunction + +function! s:prepare(...) + if empty(s:plug_getcwd()) + throw 'Invalid current working directory. Cannot proceed.' + endif + + for evar in ['$GIT_DIR', '$GIT_WORK_TREE'] + if exists(evar) + throw evar.' detected. Cannot proceed.' + endif + endfor + + call s:job_abort() + if s:switch_in() + if b:plug_preview == 1 + pc + endif + enew + else + call s:new_window() + endif + + nnoremap <silent> <buffer> q :if b:plug_preview==1<bar>pc<bar>endif<bar>bd<cr> + if a:0 == 0 + call s:finish_bindings() + endif + let b:plug_preview = -1 + let s:plug_tab = tabpagenr() + let s:plug_buf = winbufnr(0) + call s:assign_name() + + for k in ['<cr>', 'L', 'o', 'X', 'd', 'dd'] + execute 'silent! unmap <buffer>' k + endfor + setlocal buftype=nofile bufhidden=wipe nobuflisted nolist noswapfile nowrap cursorline modifiable nospell + if exists('+colorcolumn') + setlocal colorcolumn= + endif + setf vim-plug + if exists('g:syntax_on') + call s:syntax() + endif +endfunction + +function! s:assign_name() + " Assign buffer name + let prefix = '[Plugins]' + let name = prefix + let idx = 2 + while bufexists(name) + let name = printf('%s (%s)', prefix, idx) + let idx = idx + 1 + endwhile + silent! execute 'f' fnameescape(name) +endfunction + +function! s:chsh(swap) + let prev = [&shell, &shellcmdflag, &shellredir] + if !s:is_win + set shell=sh + endif + if a:swap + if &shell =~# 'powershell\.exe' || &shell =~# 'pwsh$' + let &shellredir = '2>&1 | Out-File -Encoding UTF8 %s' + elseif &shell =~# 'sh' || &shell =~# 'cmd\.exe' + set shellredir=>%s\ 2>&1 + endif + endif + return prev +endfunction + +function! s:bang(cmd, ...) + let batchfile = '' + try + let [sh, shellcmdflag, shrd] = s:chsh(a:0) + " FIXME: Escaping is incomplete. We could use shellescape with eval, + " but it won't work on Windows. + let cmd = a:0 ? s:with_cd(a:cmd, a:1) : a:cmd + if s:is_win + let [batchfile, cmd] = s:batchfile(cmd) + endif + let g:_plug_bang = (s:is_win && has('gui_running') ? 'silent ' : '').'!'.escape(cmd, '#!%') + execute "normal! :execute g:_plug_bang\<cr>\<cr>" + finally + unlet g:_plug_bang + let [&shell, &shellcmdflag, &shellredir] = [sh, shellcmdflag, shrd] + if s:is_win && filereadable(batchfile) + call delete(batchfile) + endif + endtry + return v:shell_error ? 'Exit status: ' . v:shell_error : '' +endfunction + +function! s:regress_bar() + let bar = substitute(getline(2)[1:-2], '.*\zs=', 'x', '') + call s:progress_bar(2, bar, len(bar)) +endfunction + +function! s:is_updated(dir) + return !empty(s:system_chomp(['git', 'log', '--pretty=format:%h', 'HEAD...HEAD@{1}'], a:dir)) +endfunction + +function! s:do(pull, force, todo) + for [name, spec] in items(a:todo) + if !isdirectory(spec.dir) + continue + endif + let installed = has_key(s:update.new, name) + let updated = installed ? 0 : + \ (a:pull && index(s:update.errors, name) < 0 && s:is_updated(spec.dir)) + if a:force || installed || updated + execute 'cd' s:esc(spec.dir) + call append(3, '- Post-update hook for '. name .' ... ') + let error = '' + let type = type(spec.do) + if type == s:TYPE.string + if spec.do[0] == ':' + if !get(s:loaded, name, 0) + let s:loaded[name] = 1 + call s:reorg_rtp() + endif + call s:load_plugin(spec) + try + execute spec.do[1:] + catch + let error = v:exception + endtry + if !s:plug_window_exists() + cd - + throw 'Warning: vim-plug was terminated by the post-update hook of '.name + endif + else + let error = s:bang(spec.do) + endif + elseif type == s:TYPE.funcref + try + call s:load_plugin(spec) + let status = installed ? 'installed' : (updated ? 'updated' : 'unchanged') + call spec.do({ 'name': name, 'status': status, 'force': a:force }) + catch + let error = v:exception + endtry + else + let error = 'Invalid hook type' + endif + call s:switch_in() + call setline(4, empty(error) ? (getline(4) . 'OK') + \ : ('x' . getline(4)[1:] . error)) + if !empty(error) + call add(s:update.errors, name) + call s:regress_bar() + endif + cd - + endif + endfor +endfunction + +function! s:hash_match(a, b) + return stridx(a:a, a:b) == 0 || stridx(a:b, a:a) == 0 +endfunction + +function! s:checkout(spec) + let sha = a:spec.commit + let output = s:system(['git', 'rev-parse', 'HEAD'], a:spec.dir) + if !v:shell_error && !s:hash_match(sha, s:lines(output)[0]) + let output = s:system( + \ 'git fetch --depth 999999 && git checkout '.plug#shellescape(sha).' --', a:spec.dir) + endif + return output +endfunction + +function! s:finish(pull) + let new_frozen = len(filter(keys(s:update.new), 'g:plugs[v:val].frozen')) + if new_frozen + let s = new_frozen > 1 ? 's' : '' + call append(3, printf('- Installed %d frozen plugin%s', new_frozen, s)) + endif + call append(3, '- Finishing ... ') | 4 + redraw + call plug#helptags() + call plug#end() + call setline(4, getline(4) . 'Done!') + redraw + let msgs = [] + if !empty(s:update.errors) + call add(msgs, "Press 'R' to retry.") + endif + if a:pull && len(s:update.new) < len(filter(getline(5, '$'), + \ "v:val =~ '^- ' && v:val !~# 'Already up.to.date'")) + call add(msgs, "Press 'D' to see the updated changes.") + endif + echo join(msgs, ' ') + call s:finish_bindings() +endfunction + +function! s:retry() + if empty(s:update.errors) + return + endif + echo + call s:update_impl(s:update.pull, s:update.force, + \ extend(copy(s:update.errors), [s:update.threads])) +endfunction + +function! s:is_managed(name) + return has_key(g:plugs[a:name], 'uri') +endfunction + +function! s:names(...) + return sort(filter(keys(g:plugs), 'stridx(v:val, a:1) == 0 && s:is_managed(v:val)')) +endfunction + +function! s:check_ruby() + silent! ruby require 'thread'; VIM::command("let g:plug_ruby = '#{RUBY_VERSION}'") + if !exists('g:plug_ruby') + redraw! + return s:warn('echom', 'Warning: Ruby interface is broken') + endif + let ruby_version = split(g:plug_ruby, '\.') + unlet g:plug_ruby + return s:version_requirement(ruby_version, [1, 8, 7]) +endfunction + +function! s:update_impl(pull, force, args) abort + let sync = index(a:args, '--sync') >= 0 || has('vim_starting') + let args = filter(copy(a:args), 'v:val != "--sync"') + let threads = (len(args) > 0 && args[-1] =~ '^[1-9][0-9]*$') ? + \ remove(args, -1) : get(g:, 'plug_threads', 16) + + let managed = filter(copy(g:plugs), 's:is_managed(v:key)') + let todo = empty(args) ? filter(managed, '!v:val.frozen || !isdirectory(v:val.dir)') : + \ filter(managed, 'index(args, v:key) >= 0') + + if empty(todo) + return s:warn('echo', 'No plugin to '. (a:pull ? 'update' : 'install')) + endif + + if !s:is_win && s:git_version_requirement(2, 3) + let s:git_terminal_prompt = exists('$GIT_TERMINAL_PROMPT') ? $GIT_TERMINAL_PROMPT : '' + let $GIT_TERMINAL_PROMPT = 0 + for plug in values(todo) + let plug.uri = substitute(plug.uri, + \ '^https://git::@github\.com', 'https://github.com', '') + endfor + endif + + if !isdirectory(g:plug_home) + try + call mkdir(g:plug_home, 'p') + catch + return s:err(printf('Invalid plug directory: %s. '. + \ 'Try to call plug#begin with a valid directory', g:plug_home)) + endtry + endif + + if has('nvim') && !exists('*jobwait') && threads > 1 + call s:warn('echom', '[vim-plug] Update Neovim for parallel installer') + endif + + let use_job = s:nvim || s:vim8 + let python = (has('python') || has('python3')) && !use_job + let ruby = has('ruby') && !use_job && (v:version >= 703 || v:version == 702 && has('patch374')) && !(s:is_win && has('gui_running')) && threads > 1 && s:check_ruby() + + let s:update = { + \ 'start': reltime(), + \ 'all': todo, + \ 'todo': copy(todo), + \ 'errors': [], + \ 'pull': a:pull, + \ 'force': a:force, + \ 'new': {}, + \ 'threads': (python || ruby || use_job) ? min([len(todo), threads]) : 1, + \ 'bar': '', + \ 'fin': 0 + \ } + + call s:prepare(1) + call append(0, ['', '']) + normal! 2G + silent! redraw + + let s:clone_opt = [] + if get(g:, 'plug_shallow', 1) + call extend(s:clone_opt, ['--depth', '1']) + if s:git_version_requirement(1, 7, 10) + call add(s:clone_opt, '--no-single-branch') + endif + endif + + if has('win32unix') || has('wsl') + call extend(s:clone_opt, ['-c', 'core.eol=lf', '-c', 'core.autocrlf=input']) + endif + + let s:submodule_opt = s:git_version_requirement(2, 8) ? ' --jobs='.threads : '' + + " Python version requirement (>= 2.7) + if python && !has('python3') && !ruby && !use_job && s:update.threads > 1 + redir => pyv + silent python import platform; print platform.python_version() + redir END + let python = s:version_requirement( + \ map(split(split(pyv)[0], '\.'), 'str2nr(v:val)'), [2, 6]) + endif + + if (python || ruby) && s:update.threads > 1 + try + let imd = &imd + if s:mac_gui + set noimd + endif + if ruby + call s:update_ruby() + else + call s:update_python() + endif + catch + let lines = getline(4, '$') + let printed = {} + silent! 4,$d _ + for line in lines + let name = s:extract_name(line, '.', '') + if empty(name) || !has_key(printed, name) + call append('$', line) + if !empty(name) + let printed[name] = 1 + if line[0] == 'x' && index(s:update.errors, name) < 0 + call add(s:update.errors, name) + end + endif + endif + endfor + finally + let &imd = imd + call s:update_finish() + endtry + else + call s:update_vim() + while use_job && sync + sleep 100m + if s:update.fin + break + endif + endwhile + endif +endfunction + +function! s:log4(name, msg) + call setline(4, printf('- %s (%s)', a:msg, a:name)) + redraw +endfunction + +function! s:update_finish() + if exists('s:git_terminal_prompt') + let $GIT_TERMINAL_PROMPT = s:git_terminal_prompt + endif + if s:switch_in() + call append(3, '- Updating ...') | 4 + for [name, spec] in items(filter(copy(s:update.all), 'index(s:update.errors, v:key) < 0 && (s:update.force || s:update.pull || has_key(s:update.new, v:key))')) + let [pos, _] = s:logpos(name) + if !pos + continue + endif + if has_key(spec, 'commit') + call s:log4(name, 'Checking out '.spec.commit) + let out = s:checkout(spec) + elseif has_key(spec, 'tag') + let tag = spec.tag + if tag =~ '\*' + let tags = s:lines(s:system('git tag --list '.plug#shellescape(tag).' --sort -version:refname 2>&1', spec.dir)) + if !v:shell_error && !empty(tags) + let tag = tags[0] + call s:log4(name, printf('Latest tag for %s -> %s', spec.tag, tag)) + call append(3, '') + endif + endif + call s:log4(name, 'Checking out '.tag) + let out = s:system('git checkout -q '.plug#shellescape(tag).' -- 2>&1', spec.dir) + else + let branch = get(spec, 'branch', 'master') + call s:log4(name, 'Merging origin/'.s:esc(branch)) + let out = s:system('git checkout -q '.plug#shellescape(branch).' -- 2>&1' + \. (has_key(s:update.new, name) ? '' : ('&& git merge --ff-only '.plug#shellescape('origin/'.branch).' 2>&1')), spec.dir) + endif + if !v:shell_error && filereadable(spec.dir.'/.gitmodules') && + \ (s:update.force || has_key(s:update.new, name) || s:is_updated(spec.dir)) + call s:log4(name, 'Updating submodules. This may take a while.') + let out .= s:bang('git submodule update --init --recursive'.s:submodule_opt.' 2>&1', spec.dir) + endif + let msg = s:format_message(v:shell_error ? 'x': '-', name, out) + if v:shell_error + call add(s:update.errors, name) + call s:regress_bar() + silent execute pos 'd _' + call append(4, msg) | 4 + elseif !empty(out) + call setline(pos, msg[0]) + endif + redraw + endfor + silent 4 d _ + try + call s:do(s:update.pull, s:update.force, filter(copy(s:update.all), 'index(s:update.errors, v:key) < 0 && has_key(v:val, "do")')) + catch + call s:warn('echom', v:exception) + call s:warn('echo', '') + return + endtry + call s:finish(s:update.pull) + call setline(1, 'Updated. Elapsed time: ' . split(reltimestr(reltime(s:update.start)))[0] . ' sec.') + call s:switch_out('normal! gg') + endif +endfunction + +function! s:job_abort() + if (!s:nvim && !s:vim8) || !exists('s:jobs') + return + endif + + for [name, j] in items(s:jobs) + if s:nvim + silent! call jobstop(j.jobid) + elseif s:vim8 + silent! call job_stop(j.jobid) + endif + if j.new + call s:rm_rf(g:plugs[name].dir) + endif + endfor + let s:jobs = {} +endfunction + +function! s:last_non_empty_line(lines) + let len = len(a:lines) + for idx in range(len) + let line = a:lines[len-idx-1] + if !empty(line) + return line + endif + endfor + return '' +endfunction + +function! s:job_out_cb(self, data) abort + let self = a:self + let data = remove(self.lines, -1) . a:data + let lines = map(split(data, "\n", 1), 'split(v:val, "\r", 1)[-1]') + call extend(self.lines, lines) + " To reduce the number of buffer updates + let self.tick = get(self, 'tick', -1) + 1 + if !self.running || self.tick % len(s:jobs) == 0 + let bullet = self.running ? (self.new ? '+' : '*') : (self.error ? 'x' : '-') + let result = self.error ? join(self.lines, "\n") : s:last_non_empty_line(self.lines) + call s:log(bullet, self.name, result) + endif +endfunction + +function! s:job_exit_cb(self, data) abort + let a:self.running = 0 + let a:self.error = a:data != 0 + call s:reap(a:self.name) + call s:tick() +endfunction + +function! s:job_cb(fn, job, ch, data) + if !s:plug_window_exists() " plug window closed + return s:job_abort() + endif + call call(a:fn, [a:job, a:data]) +endfunction + +function! s:nvim_cb(job_id, data, event) dict abort + return (a:event == 'stdout' || a:event == 'stderr') ? + \ s:job_cb('s:job_out_cb', self, 0, join(a:data, "\n")) : + \ s:job_cb('s:job_exit_cb', self, 0, a:data) +endfunction + +function! s:spawn(name, cmd, opts) + let job = { 'name': a:name, 'running': 1, 'error': 0, 'lines': [''], + \ 'new': get(a:opts, 'new', 0) } + let s:jobs[a:name] = job + + if s:nvim + if has_key(a:opts, 'dir') + let job.cwd = a:opts.dir + endif + let argv = a:cmd + call extend(job, { + \ 'on_stdout': function('s:nvim_cb'), + \ 'on_stderr': function('s:nvim_cb'), + \ 'on_exit': function('s:nvim_cb'), + \ }) + let jid = s:plug_call('jobstart', argv, job) + if jid > 0 + let job.jobid = jid + else + let job.running = 0 + let job.error = 1 + let job.lines = [jid < 0 ? argv[0].' is not executable' : + \ 'Invalid arguments (or job table is full)'] + endif + elseif s:vim8 + let cmd = join(map(copy(a:cmd), 'plug#shellescape(v:val, {"script": 0})')) + if has_key(a:opts, 'dir') + let cmd = s:with_cd(cmd, a:opts.dir, 0) + endif + let argv = s:is_win ? ['cmd', '/s', '/c', '"'.cmd.'"'] : ['sh', '-c', cmd] + let jid = job_start(s:is_win ? join(argv, ' ') : argv, { + \ 'out_cb': function('s:job_cb', ['s:job_out_cb', job]), + \ 'err_cb': function('s:job_cb', ['s:job_out_cb', job]), + \ 'exit_cb': function('s:job_cb', ['s:job_exit_cb', job]), + \ 'err_mode': 'raw', + \ 'out_mode': 'raw' + \}) + if job_status(jid) == 'run' + let job.jobid = jid + else + let job.running = 0 + let job.error = 1 + let job.lines = ['Failed to start job'] + endif + else + let job.lines = s:lines(call('s:system', has_key(a:opts, 'dir') ? [a:cmd, a:opts.dir] : [a:cmd])) + let job.error = v:shell_error != 0 + let job.running = 0 + endif +endfunction + +function! s:reap(name) + let job = s:jobs[a:name] + if job.error + call add(s:update.errors, a:name) + elseif get(job, 'new', 0) + let s:update.new[a:name] = 1 + endif + let s:update.bar .= job.error ? 'x' : '=' + + let bullet = job.error ? 'x' : '-' + let result = job.error ? join(job.lines, "\n") : s:last_non_empty_line(job.lines) + call s:log(bullet, a:name, empty(result) ? 'OK' : result) + call s:bar() + + call remove(s:jobs, a:name) +endfunction + +function! s:bar() + if s:switch_in() + let total = len(s:update.all) + call setline(1, (s:update.pull ? 'Updating' : 'Installing'). + \ ' plugins ('.len(s:update.bar).'/'.total.')') + call s:progress_bar(2, s:update.bar, total) + call s:switch_out() + endif +endfunction + +function! s:logpos(name) + let max = line('$') + for i in range(4, max > 4 ? max : 4) + if getline(i) =~# '^[-+x*] '.a:name.':' + for j in range(i + 1, max > 5 ? max : 5) + if getline(j) !~ '^ ' + return [i, j - 1] + endif + endfor + return [i, i] + endif + endfor + return [0, 0] +endfunction + +function! s:log(bullet, name, lines) + if s:switch_in() + let [b, e] = s:logpos(a:name) + if b > 0 + silent execute printf('%d,%d d _', b, e) + if b > winheight('.') + let b = 4 + endif + else + let b = 4 + endif + " FIXME For some reason, nomodifiable is set after :d in vim8 + setlocal modifiable + call append(b - 1, s:format_message(a:bullet, a:name, a:lines)) + call s:switch_out() + endif +endfunction + +function! s:update_vim() + let s:jobs = {} + + call s:bar() + call s:tick() +endfunction + +function! s:tick() + let pull = s:update.pull + let prog = s:progress_opt(s:nvim || s:vim8) +while 1 " Without TCO, Vim stack is bound to explode + if empty(s:update.todo) + if empty(s:jobs) && !s:update.fin + call s:update_finish() + let s:update.fin = 1 + endif + return + endif + + let name = keys(s:update.todo)[0] + let spec = remove(s:update.todo, name) + let new = empty(globpath(spec.dir, '.git', 1)) + + call s:log(new ? '+' : '*', name, pull ? 'Updating ...' : 'Installing ...') + redraw + + let has_tag = has_key(spec, 'tag') + if !new + let [error, _] = s:git_validate(spec, 0) + if empty(error) + if pull + let cmd = ['git', 'fetch'] + if has_tag && !empty(globpath(spec.dir, '.git/shallow')) + call extend(cmd, ['--depth', '99999999']) + endif + if !empty(prog) + call add(cmd, prog) + endif + call s:spawn(name, cmd, { 'dir': spec.dir }) + else + let s:jobs[name] = { 'running': 0, 'lines': ['Already installed'], 'error': 0 } + endif + else + let s:jobs[name] = { 'running': 0, 'lines': s:lines(error), 'error': 1 } + endif + else + let cmd = ['git', 'clone'] + if !has_tag + call extend(cmd, s:clone_opt) + endif + if !empty(prog) + call add(cmd, prog) + endif + call s:spawn(name, extend(cmd, [spec.uri, s:trim(spec.dir)]), { 'new': 1 }) + endif + + if !s:jobs[name].running + call s:reap(name) + endif + if len(s:jobs) >= s:update.threads + break + endif +endwhile +endfunction + +function! s:update_python() +let py_exe = has('python') ? 'python' : 'python3' +execute py_exe "<< EOF" +import datetime +import functools +import os +try: + import queue +except ImportError: + import Queue as queue +import random +import re +import shutil +import signal +import subprocess +import tempfile +import threading as thr +import time +import traceback +import vim + +G_NVIM = vim.eval("has('nvim')") == '1' +G_PULL = vim.eval('s:update.pull') == '1' +G_RETRIES = int(vim.eval('get(g:, "plug_retries", 2)')) + 1 +G_TIMEOUT = int(vim.eval('get(g:, "plug_timeout", 60)')) +G_CLONE_OPT = ' '.join(vim.eval('s:clone_opt')) +G_PROGRESS = vim.eval('s:progress_opt(1)') +G_LOG_PROB = 1.0 / int(vim.eval('s:update.threads')) +G_STOP = thr.Event() +G_IS_WIN = vim.eval('s:is_win') == '1' + +class PlugError(Exception): + def __init__(self, msg): + self.msg = msg +class CmdTimedOut(PlugError): + pass +class CmdFailed(PlugError): + pass +class InvalidURI(PlugError): + pass +class Action(object): + INSTALL, UPDATE, ERROR, DONE = ['+', '*', 'x', '-'] + +class Buffer(object): + def __init__(self, lock, num_plugs, is_pull): + self.bar = '' + self.event = 'Updating' if is_pull else 'Installing' + self.lock = lock + self.maxy = int(vim.eval('winheight(".")')) + self.num_plugs = num_plugs + + def __where(self, name): + """ Find first line with name in current buffer. Return line num. """ + found, lnum = False, 0 + matcher = re.compile('^[-+x*] {0}:'.format(name)) + for line in vim.current.buffer: + if matcher.search(line) is not None: + found = True + break + lnum += 1 + + if not found: + lnum = -1 + return lnum + + def header(self): + curbuf = vim.current.buffer + curbuf[0] = self.event + ' plugins ({0}/{1})'.format(len(self.bar), self.num_plugs) + + num_spaces = self.num_plugs - len(self.bar) + curbuf[1] = '[{0}{1}]'.format(self.bar, num_spaces * ' ') + + with self.lock: + vim.command('normal! 2G') + vim.command('redraw') + + def write(self, action, name, lines): + first, rest = lines[0], lines[1:] + msg = ['{0} {1}{2}{3}'.format(action, name, ': ' if first else '', first)] + msg.extend([' ' + line for line in rest]) + + try: + if action == Action.ERROR: + self.bar += 'x' + vim.command("call add(s:update.errors, '{0}')".format(name)) + elif action == Action.DONE: + self.bar += '=' + + curbuf = vim.current.buffer + lnum = self.__where(name) + if lnum != -1: # Found matching line num + del curbuf[lnum] + if lnum > self.maxy and action in set([Action.INSTALL, Action.UPDATE]): + lnum = 3 + else: + lnum = 3 + curbuf.append(msg, lnum) + + self.header() + except vim.error: + pass + +class Command(object): + CD = 'cd /d' if G_IS_WIN else 'cd' + + def __init__(self, cmd, cmd_dir=None, timeout=60, cb=None, clean=None): + self.cmd = cmd + if cmd_dir: + self.cmd = '{0} {1} && {2}'.format(Command.CD, cmd_dir, self.cmd) + self.timeout = timeout + self.callback = cb if cb else (lambda msg: None) + self.clean = clean if clean else (lambda: None) + self.proc = None + + @property + def alive(self): + """ Returns true only if command still running. """ + return self.proc and self.proc.poll() is None + + def execute(self, ntries=3): + """ Execute the command with ntries if CmdTimedOut. + Returns the output of the command if no Exception. + """ + attempt, finished, limit = 0, False, self.timeout + + while not finished: + try: + attempt += 1 + result = self.try_command() + finished = True + return result + except CmdTimedOut: + if attempt != ntries: + self.notify_retry() + self.timeout += limit + else: + raise + + def notify_retry(self): + """ Retry required for command, notify user. """ + for count in range(3, 0, -1): + if G_STOP.is_set(): + raise KeyboardInterrupt + msg = 'Timeout. Will retry in {0} second{1} ...'.format( + count, 's' if count != 1 else '') + self.callback([msg]) + time.sleep(1) + self.callback(['Retrying ...']) + + def try_command(self): + """ Execute a cmd & poll for callback. Returns list of output. + Raises CmdFailed -> return code for Popen isn't 0 + Raises CmdTimedOut -> command exceeded timeout without new output + """ + first_line = True + + try: + tfile = tempfile.NamedTemporaryFile(mode='w+b') + preexec_fn = not G_IS_WIN and os.setsid or None + self.proc = subprocess.Popen(self.cmd, stdout=tfile, + stderr=subprocess.STDOUT, + stdin=subprocess.PIPE, shell=True, + preexec_fn=preexec_fn) + thrd = thr.Thread(target=(lambda proc: proc.wait()), args=(self.proc,)) + thrd.start() + + thread_not_started = True + while thread_not_started: + try: + thrd.join(0.1) + thread_not_started = False + except RuntimeError: + pass + + while self.alive: + if G_STOP.is_set(): + raise KeyboardInterrupt + + if first_line or random.random() < G_LOG_PROB: + first_line = False + line = '' if G_IS_WIN else nonblock_read(tfile.name) + if line: + self.callback([line]) + + time_diff = time.time() - os.path.getmtime(tfile.name) + if time_diff > self.timeout: + raise CmdTimedOut(['Timeout!']) + + thrd.join(0.5) + + tfile.seek(0) + result = [line.decode('utf-8', 'replace').rstrip() for line in tfile] + + if self.proc.returncode != 0: + raise CmdFailed([''] + result) + + return result + except: + self.terminate() + raise + + def terminate(self): + """ Terminate process and cleanup. """ + if self.alive: + if G_IS_WIN: + os.kill(self.proc.pid, signal.SIGINT) + else: + os.killpg(self.proc.pid, signal.SIGTERM) + self.clean() + +class Plugin(object): + def __init__(self, name, args, buf_q, lock): + self.name = name + self.args = args + self.buf_q = buf_q + self.lock = lock + self.tag = args.get('tag', 0) + + def manage(self): + try: + if os.path.exists(self.args['dir']): + self.update() + else: + self.install() + with self.lock: + thread_vim_command("let s:update.new['{0}'] = 1".format(self.name)) + except PlugError as exc: + self.write(Action.ERROR, self.name, exc.msg) + except KeyboardInterrupt: + G_STOP.set() + self.write(Action.ERROR, self.name, ['Interrupted!']) + except: + # Any exception except those above print stack trace + msg = 'Trace:\n{0}'.format(traceback.format_exc().rstrip()) + self.write(Action.ERROR, self.name, msg.split('\n')) + raise + + def install(self): + target = self.args['dir'] + if target[-1] == '\\': + target = target[0:-1] + + def clean(target): + def _clean(): + try: + shutil.rmtree(target) + except OSError: + pass + return _clean + + self.write(Action.INSTALL, self.name, ['Installing ...']) + callback = functools.partial(self.write, Action.INSTALL, self.name) + cmd = 'git clone {0} {1} {2} {3} 2>&1'.format( + '' if self.tag else G_CLONE_OPT, G_PROGRESS, self.args['uri'], + esc(target)) + com = Command(cmd, None, G_TIMEOUT, callback, clean(target)) + result = com.execute(G_RETRIES) + self.write(Action.DONE, self.name, result[-1:]) + + def repo_uri(self): + cmd = 'git rev-parse --abbrev-ref HEAD 2>&1 && git config -f .git/config remote.origin.url' + command = Command(cmd, self.args['dir'], G_TIMEOUT,) + result = command.execute(G_RETRIES) + return result[-1] + + def update(self): + actual_uri = self.repo_uri() + expect_uri = self.args['uri'] + regex = re.compile(r'^(?:\w+://)?(?:[^@/]*@)?([^:/]*(?::[0-9]*)?)[:/](.*?)(?:\.git)?/?$') + ma = regex.match(actual_uri) + mb = regex.match(expect_uri) + if ma is None or mb is None or ma.groups() != mb.groups(): + msg = ['', + 'Invalid URI: {0}'.format(actual_uri), + 'Expected {0}'.format(expect_uri), + 'PlugClean required.'] + raise InvalidURI(msg) + + if G_PULL: + self.write(Action.UPDATE, self.name, ['Updating ...']) + callback = functools.partial(self.write, Action.UPDATE, self.name) + fetch_opt = '--depth 99999999' if self.tag and os.path.isfile(os.path.join(self.args['dir'], '.git/shallow')) else '' + cmd = 'git fetch {0} {1} 2>&1'.format(fetch_opt, G_PROGRESS) + com = Command(cmd, self.args['dir'], G_TIMEOUT, callback) + result = com.execute(G_RETRIES) + self.write(Action.DONE, self.name, result[-1:]) + else: + self.write(Action.DONE, self.name, ['Already installed']) + + def write(self, action, name, msg): + self.buf_q.put((action, name, msg)) + +class PlugThread(thr.Thread): + def __init__(self, tname, args): + super(PlugThread, self).__init__() + self.tname = tname + self.args = args + + def run(self): + thr.current_thread().name = self.tname + buf_q, work_q, lock = self.args + + try: + while not G_STOP.is_set(): + name, args = work_q.get_nowait() + plug = Plugin(name, args, buf_q, lock) + plug.manage() + work_q.task_done() + except queue.Empty: + pass + +class RefreshThread(thr.Thread): + def __init__(self, lock): + super(RefreshThread, self).__init__() + self.lock = lock + self.running = True + + def run(self): + while self.running: + with self.lock: + thread_vim_command('noautocmd normal! a') + time.sleep(0.33) + + def stop(self): + self.running = False + +if G_NVIM: + def thread_vim_command(cmd): + vim.session.threadsafe_call(lambda: vim.command(cmd)) +else: + def thread_vim_command(cmd): + vim.command(cmd) + +def esc(name): + return '"' + name.replace('"', '\"') + '"' + +def nonblock_read(fname): + """ Read a file with nonblock flag. Return the last line. """ + fread = os.open(fname, os.O_RDONLY | os.O_NONBLOCK) + buf = os.read(fread, 100000).decode('utf-8', 'replace') + os.close(fread) + + line = buf.rstrip('\r\n') + left = max(line.rfind('\r'), line.rfind('\n')) + if left != -1: + left += 1 + line = line[left:] + + return line + +def main(): + thr.current_thread().name = 'main' + nthreads = int(vim.eval('s:update.threads')) + plugs = vim.eval('s:update.todo') + mac_gui = vim.eval('s:mac_gui') == '1' + + lock = thr.Lock() + buf = Buffer(lock, len(plugs), G_PULL) + buf_q, work_q = queue.Queue(), queue.Queue() + for work in plugs.items(): + work_q.put(work) + + start_cnt = thr.active_count() + for num in range(nthreads): + tname = 'PlugT-{0:02}'.format(num) + thread = PlugThread(tname, (buf_q, work_q, lock)) + thread.start() + if mac_gui: + rthread = RefreshThread(lock) + rthread.start() + + while not buf_q.empty() or thr.active_count() != start_cnt: + try: + action, name, msg = buf_q.get(True, 0.25) + buf.write(action, name, ['OK'] if not msg else msg) + buf_q.task_done() + except queue.Empty: + pass + except KeyboardInterrupt: + G_STOP.set() + + if mac_gui: + rthread.stop() + rthread.join() + +main() +EOF +endfunction + +function! s:update_ruby() + ruby << EOF + module PlugStream + SEP = ["\r", "\n", nil] + def get_line + buffer = '' + loop do + char = readchar rescue return + if SEP.include? char.chr + buffer << $/ + break + else + buffer << char + end + end + buffer + end + end unless defined?(PlugStream) + + def esc arg + %["#{arg.gsub('"', '\"')}"] + end + + def killall pid + pids = [pid] + if /mswin|mingw|bccwin/ =~ RUBY_PLATFORM + pids.each { |pid| Process.kill 'INT', pid.to_i rescue nil } + else + unless `which pgrep 2> /dev/null`.empty? + children = pids + until children.empty? + children = children.map { |pid| + `pgrep -P #{pid}`.lines.map { |l| l.chomp } + }.flatten + pids += children + end + end + pids.each { |pid| Process.kill 'TERM', pid.to_i rescue nil } + end + end + + def compare_git_uri a, b + regex = %r{^(?:\w+://)?(?:[^@/]*@)?([^:/]*(?::[0-9]*)?)[:/](.*?)(?:\.git)?/?$} + regex.match(a).to_a.drop(1) == regex.match(b).to_a.drop(1) + end + + require 'thread' + require 'fileutils' + require 'timeout' + running = true + iswin = VIM::evaluate('s:is_win').to_i == 1 + pull = VIM::evaluate('s:update.pull').to_i == 1 + base = VIM::evaluate('g:plug_home') + all = VIM::evaluate('s:update.todo') + limit = VIM::evaluate('get(g:, "plug_timeout", 60)') + tries = VIM::evaluate('get(g:, "plug_retries", 2)') + 1 + nthr = VIM::evaluate('s:update.threads').to_i + maxy = VIM::evaluate('winheight(".")').to_i + vim7 = VIM::evaluate('v:version').to_i <= 703 && RUBY_PLATFORM =~ /darwin/ + cd = iswin ? 'cd /d' : 'cd' + tot = VIM::evaluate('len(s:update.todo)') || 0 + bar = '' + skip = 'Already installed' + mtx = Mutex.new + take1 = proc { mtx.synchronize { running && all.shift } } + logh = proc { + cnt = bar.length + $curbuf[1] = "#{pull ? 'Updating' : 'Installing'} plugins (#{cnt}/#{tot})" + $curbuf[2] = '[' + bar.ljust(tot) + ']' + VIM::command('normal! 2G') + VIM::command('redraw') + } + where = proc { |name| (1..($curbuf.length)).find { |l| $curbuf[l] =~ /^[-+x*] #{name}:/ } } + log = proc { |name, result, type| + mtx.synchronize do + ing = ![true, false].include?(type) + bar += type ? '=' : 'x' unless ing + b = case type + when :install then '+' when :update then '*' + when true, nil then '-' else + VIM::command("call add(s:update.errors, '#{name}')") + 'x' + end + result = + if type || type.nil? + ["#{b} #{name}: #{result.lines.to_a.last || 'OK'}"] + elsif result =~ /^Interrupted|^Timeout/ + ["#{b} #{name}: #{result}"] + else + ["#{b} #{name}"] + result.lines.map { |l| " " << l } + end + if lnum = where.call(name) + $curbuf.delete lnum + lnum = 4 if ing && lnum > maxy + end + result.each_with_index do |line, offset| + $curbuf.append((lnum || 4) - 1 + offset, line.gsub(/\e\[./, '').chomp) + end + logh.call + end + } + bt = proc { |cmd, name, type, cleanup| + tried = timeout = 0 + begin + tried += 1 + timeout += limit + fd = nil + data = '' + if iswin + Timeout::timeout(timeout) do + tmp = VIM::evaluate('tempname()') + system("(#{cmd}) > #{tmp}") + data = File.read(tmp).chomp + File.unlink tmp rescue nil + end + else + fd = IO.popen(cmd).extend(PlugStream) + first_line = true + log_prob = 1.0 / nthr + while line = Timeout::timeout(timeout) { fd.get_line } + data << line + log.call name, line.chomp, type if name && (first_line || rand < log_prob) + first_line = false + end + fd.close + end + [$? == 0, data.chomp] + rescue Timeout::Error, Interrupt => e + if fd && !fd.closed? + killall fd.pid + fd.close + end + cleanup.call if cleanup + if e.is_a?(Timeout::Error) && tried < tries + 3.downto(1) do |countdown| + s = countdown > 1 ? 's' : '' + log.call name, "Timeout. Will retry in #{countdown} second#{s} ...", type + sleep 1 + end + log.call name, 'Retrying ...', type + retry + end + [false, e.is_a?(Interrupt) ? "Interrupted!" : "Timeout!"] + end + } + main = Thread.current + threads = [] + watcher = Thread.new { + if vim7 + while VIM::evaluate('getchar(1)') + sleep 0.1 + end + else + require 'io/console' # >= Ruby 1.9 + nil until IO.console.getch == 3.chr + end + mtx.synchronize do + running = false + threads.each { |t| t.raise Interrupt } unless vim7 + end + threads.each { |t| t.join rescue nil } + main.kill + } + refresh = Thread.new { + while true + mtx.synchronize do + break unless running + VIM::command('noautocmd normal! a') + end + sleep 0.2 + end + } if VIM::evaluate('s:mac_gui') == 1 + + clone_opt = VIM::evaluate('s:clone_opt').join(' ') + progress = VIM::evaluate('s:progress_opt(1)') + nthr.times do + mtx.synchronize do + threads << Thread.new { + while pair = take1.call + name = pair.first + dir, uri, tag = pair.last.values_at *%w[dir uri tag] + exists = File.directory? dir + ok, result = + if exists + chdir = "#{cd} #{iswin ? dir : esc(dir)}" + ret, data = bt.call "#{chdir} && git rev-parse --abbrev-ref HEAD 2>&1 && git config -f .git/config remote.origin.url", nil, nil, nil + current_uri = data.lines.to_a.last + if !ret + if data =~ /^Interrupted|^Timeout/ + [false, data] + else + [false, [data.chomp, "PlugClean required."].join($/)] + end + elsif !compare_git_uri(current_uri, uri) + [false, ["Invalid URI: #{current_uri}", + "Expected: #{uri}", + "PlugClean required."].join($/)] + else + if pull + log.call name, 'Updating ...', :update + fetch_opt = (tag && File.exist?(File.join(dir, '.git/shallow'))) ? '--depth 99999999' : '' + bt.call "#{chdir} && git fetch #{fetch_opt} #{progress} 2>&1", name, :update, nil + else + [true, skip] + end + end + else + d = esc dir.sub(%r{[\\/]+$}, '') + log.call name, 'Installing ...', :install + bt.call "git clone #{clone_opt unless tag} #{progress} #{uri} #{d} 2>&1", name, :install, proc { + FileUtils.rm_rf dir + } + end + mtx.synchronize { VIM::command("let s:update.new['#{name}'] = 1") } if !exists && ok + log.call name, result, ok + end + } if running + end + end + threads.each { |t| t.join rescue nil } + logh.call + refresh.kill if refresh + watcher.kill +EOF +endfunction + +function! s:shellesc_cmd(arg, script) + let escaped = substitute('"'.a:arg.'"', '[&|<>()@^!"]', '^&', 'g') + return substitute(escaped, '%', (a:script ? '%' : '^') . '&', 'g') +endfunction + +function! s:shellesc_ps1(arg) + return "'".substitute(escape(a:arg, '\"'), "'", "''", 'g')."'" +endfunction + +function! s:shellesc_sh(arg) + return "'".substitute(a:arg, "'", "'\\\\''", 'g')."'" +endfunction + +" Escape the shell argument based on the shell. +" Vim and Neovim's shellescape() are insufficient. +" 1. shellslash determines whether to use single/double quotes. +" Double-quote escaping is fragile for cmd.exe. +" 2. It does not work for powershell. +" 3. It does not work for *sh shells if the command is executed +" via cmd.exe (ie. cmd.exe /c sh -c command command_args) +" 4. It does not support batchfile syntax. +" +" Accepts an optional dictionary with the following keys: +" - shell: same as Vim/Neovim 'shell' option. +" If unset, fallback to 'cmd.exe' on Windows or 'sh'. +" - script: If truthy and shell is cmd.exe, escape for batchfile syntax. +function! plug#shellescape(arg, ...) + if a:arg =~# '^[A-Za-z0-9_/:.-]\+$' + return a:arg + endif + let opts = a:0 > 0 && type(a:1) == s:TYPE.dict ? a:1 : {} + let shell = get(opts, 'shell', s:is_win ? 'cmd.exe' : 'sh') + let script = get(opts, 'script', 1) + if shell =~# 'cmd\.exe' + return s:shellesc_cmd(a:arg, script) + elseif shell =~# 'powershell\.exe' || shell =~# 'pwsh$' + return s:shellesc_ps1(a:arg) + endif + return s:shellesc_sh(a:arg) +endfunction + +function! s:glob_dir(path) + return map(filter(s:glob(a:path, '**'), 'isdirectory(v:val)'), 's:dirpath(v:val)') +endfunction + +function! s:progress_bar(line, bar, total) + call setline(a:line, '[' . s:lpad(a:bar, a:total) . ']') +endfunction + +function! s:compare_git_uri(a, b) + " See `git help clone' + " https:// [user@] github.com[:port] / junegunn/vim-plug [.git] + " [git@] github.com[:port] : junegunn/vim-plug [.git] + " file:// / junegunn/vim-plug [/] + " / junegunn/vim-plug [/] + let pat = '^\%(\w\+://\)\='.'\%([^@/]*@\)\='.'\([^:/]*\%(:[0-9]*\)\=\)'.'[:/]'.'\(.\{-}\)'.'\%(\.git\)\=/\?$' + let ma = matchlist(a:a, pat) + let mb = matchlist(a:b, pat) + return ma[1:2] ==# mb[1:2] +endfunction + +function! s:format_message(bullet, name, message) + if a:bullet != 'x' + return [printf('%s %s: %s', a:bullet, a:name, s:lastline(a:message))] + else + let lines = map(s:lines(a:message), '" ".v:val') + return extend([printf('x %s:', a:name)], lines) + endif +endfunction + +function! s:with_cd(cmd, dir, ...) + let script = a:0 > 0 ? a:1 : 1 + return printf('cd%s %s && %s', s:is_win ? ' /d' : '', plug#shellescape(a:dir, {'script': script}), a:cmd) +endfunction + +function! s:system(cmd, ...) + let batchfile = '' + try + let [sh, shellcmdflag, shrd] = s:chsh(1) + if type(a:cmd) == s:TYPE.list + " Neovim's system() supports list argument to bypass the shell + " but it cannot set the working directory for the command. + " Assume that the command does not rely on the shell. + if has('nvim') && a:0 == 0 + return system(a:cmd) + endif + let cmd = join(map(copy(a:cmd), 'plug#shellescape(v:val, {"shell": &shell, "script": 0})')) + if &shell =~# 'powershell\.exe' + let cmd = '& ' . cmd + endif + else + let cmd = a:cmd + endif + if a:0 > 0 + let cmd = s:with_cd(cmd, a:1, type(a:cmd) != s:TYPE.list) + endif + if s:is_win && type(a:cmd) != s:TYPE.list + let [batchfile, cmd] = s:batchfile(cmd) + endif + return system(cmd) + finally + let [&shell, &shellcmdflag, &shellredir] = [sh, shellcmdflag, shrd] + if s:is_win && filereadable(batchfile) + call delete(batchfile) + endif + endtry +endfunction + +function! s:system_chomp(...) + let ret = call('s:system', a:000) + return v:shell_error ? '' : substitute(ret, '\n$', '', '') +endfunction + +function! s:git_validate(spec, check_branch) + let err = '' + if isdirectory(a:spec.dir) + let result = s:lines(s:system('git rev-parse --abbrev-ref HEAD 2>&1 && git config -f .git/config remote.origin.url', a:spec.dir)) + let remote = result[-1] + if v:shell_error + let err = join([remote, 'PlugClean required.'], "\n") + elseif !s:compare_git_uri(remote, a:spec.uri) + let err = join(['Invalid URI: '.remote, + \ 'Expected: '.a:spec.uri, + \ 'PlugClean required.'], "\n") + elseif a:check_branch && has_key(a:spec, 'commit') + let result = s:lines(s:system('git rev-parse HEAD 2>&1', a:spec.dir)) + let sha = result[-1] + if v:shell_error + let err = join(add(result, 'PlugClean required.'), "\n") + elseif !s:hash_match(sha, a:spec.commit) + let err = join([printf('Invalid HEAD (expected: %s, actual: %s)', + \ a:spec.commit[:6], sha[:6]), + \ 'PlugUpdate required.'], "\n") + endif + elseif a:check_branch + let branch = result[0] + " Check tag + if has_key(a:spec, 'tag') + let tag = s:system_chomp('git describe --exact-match --tags HEAD 2>&1', a:spec.dir) + if a:spec.tag !=# tag && a:spec.tag !~ '\*' + let err = printf('Invalid tag: %s (expected: %s). Try PlugUpdate.', + \ (empty(tag) ? 'N/A' : tag), a:spec.tag) + endif + " Check branch + elseif a:spec.branch !=# branch + let err = printf('Invalid branch: %s (expected: %s). Try PlugUpdate.', + \ branch, a:spec.branch) + endif + if empty(err) + let [ahead, behind] = split(s:lastline(s:system([ + \ 'git', 'rev-list', '--count', '--left-right', + \ printf('HEAD...origin/%s', a:spec.branch) + \ ], a:spec.dir)), '\t') + if !v:shell_error && ahead + if behind + " Only mention PlugClean if diverged, otherwise it's likely to be + " pushable (and probably not that messed up). + let err = printf( + \ "Diverged from origin/%s (%d commit(s) ahead and %d commit(s) behind!\n" + \ .'Backup local changes and run PlugClean and PlugUpdate to reinstall it.', a:spec.branch, ahead, behind) + else + let err = printf("Ahead of origin/%s by %d commit(s).\n" + \ .'Cannot update until local changes are pushed.', + \ a:spec.branch, ahead) + endif + endif + endif + endif + else + let err = 'Not found' + endif + return [err, err =~# 'PlugClean'] +endfunction + +function! s:rm_rf(dir) + if isdirectory(a:dir) + call s:system(s:is_win + \ ? 'rmdir /S /Q '.plug#shellescape(a:dir) + \ : ['rm', '-rf', a:dir]) + endif +endfunction + +function! s:clean(force) + call s:prepare() + call append(0, 'Searching for invalid plugins in '.g:plug_home) + call append(1, '') + + " List of valid directories + let dirs = [] + let errs = {} + let [cnt, total] = [0, len(g:plugs)] + for [name, spec] in items(g:plugs) + if !s:is_managed(name) + call add(dirs, spec.dir) + else + let [err, clean] = s:git_validate(spec, 1) + if clean + let errs[spec.dir] = s:lines(err)[0] + else + call add(dirs, spec.dir) + endif + endif + let cnt += 1 + call s:progress_bar(2, repeat('=', cnt), total) + normal! 2G + redraw + endfor + + let allowed = {} + for dir in dirs + let allowed[s:dirpath(s:plug_fnamemodify(dir, ':h:h'))] = 1 + let allowed[dir] = 1 + for child in s:glob_dir(dir) + let allowed[child] = 1 + endfor + endfor + + let todo = [] + let found = sort(s:glob_dir(g:plug_home)) + while !empty(found) + let f = remove(found, 0) + if !has_key(allowed, f) && isdirectory(f) + call add(todo, f) + call append(line('$'), '- ' . f) + if has_key(errs, f) + call append(line('$'), ' ' . errs[f]) + endif + let found = filter(found, 'stridx(v:val, f) != 0') + end + endwhile + + 4 + redraw + if empty(todo) + call append(line('$'), 'Already clean.') + else + let s:clean_count = 0 + call append(3, ['Directories to delete:', '']) + redraw! + if a:force || s:ask_no_interrupt('Delete all directories?') + call s:delete([6, line('$')], 1) + else + call setline(4, 'Cancelled.') + nnoremap <silent> <buffer> d :set opfunc=<sid>delete_op<cr>g@ + nmap <silent> <buffer> dd d_ + xnoremap <silent> <buffer> d :<c-u>call <sid>delete_op(visualmode(), 1)<cr> + echo 'Delete the lines (d{motion}) to delete the corresponding directories' + endif + endif + 4 + setlocal nomodifiable +endfunction + +function! s:delete_op(type, ...) + call s:delete(a:0 ? [line("'<"), line("'>")] : [line("'["), line("']")], 0) +endfunction + +function! s:delete(range, force) + let [l1, l2] = a:range + let force = a:force + while l1 <= l2 + let line = getline(l1) + if line =~ '^- ' && isdirectory(line[2:]) + execute l1 + redraw! + let answer = force ? 1 : s:ask('Delete '.line[2:].'?', 1) + let force = force || answer > 1 + if answer + call s:rm_rf(line[2:]) + setlocal modifiable + call setline(l1, '~'.line[1:]) + let s:clean_count += 1 + call setline(4, printf('Removed %d directories.', s:clean_count)) + setlocal nomodifiable + endif + endif + let l1 += 1 + endwhile +endfunction + +function! s:upgrade() + echo 'Downloading the latest version of vim-plug' + redraw + let tmp = s:plug_tempname() + let new = tmp . '/plug.vim' + + try + let out = s:system(['git', 'clone', '--depth', '1', s:plug_src, tmp]) + if v:shell_error + return s:err('Error upgrading vim-plug: '. out) + endif + + if readfile(s:me) ==# readfile(new) + echo 'vim-plug is already up-to-date' + return 0 + else + call rename(s:me, s:me . '.old') + call rename(new, s:me) + unlet g:loaded_plug + echo 'vim-plug has been upgraded' + return 1 + endif + finally + silent! call s:rm_rf(tmp) + endtry +endfunction + +function! s:upgrade_specs() + for spec in values(g:plugs) + let spec.frozen = get(spec, 'frozen', 0) + endfor +endfunction + +function! s:status() + call s:prepare() + call append(0, 'Checking plugins') + call append(1, '') + + let ecnt = 0 + let unloaded = 0 + let [cnt, total] = [0, len(g:plugs)] + for [name, spec] in items(g:plugs) + let is_dir = isdirectory(spec.dir) + if has_key(spec, 'uri') + if is_dir + let [err, _] = s:git_validate(spec, 1) + let [valid, msg] = [empty(err), empty(err) ? 'OK' : err] + else + let [valid, msg] = [0, 'Not found. Try PlugInstall.'] + endif + else + if is_dir + let [valid, msg] = [1, 'OK'] + else + let [valid, msg] = [0, 'Not found.'] + endif + endif + let cnt += 1 + let ecnt += !valid + " `s:loaded` entry can be missing if PlugUpgraded + if is_dir && get(s:loaded, name, -1) == 0 + let unloaded = 1 + let msg .= ' (not loaded)' + endif + call s:progress_bar(2, repeat('=', cnt), total) + call append(3, s:format_message(valid ? '-' : 'x', name, msg)) + normal! 2G + redraw + endfor + call setline(1, 'Finished. '.ecnt.' error(s).') + normal! gg + setlocal nomodifiable + if unloaded + echo "Press 'L' on each line to load plugin, or 'U' to update" + nnoremap <silent> <buffer> L :call <SID>status_load(line('.'))<cr> + xnoremap <silent> <buffer> L :call <SID>status_load(line('.'))<cr> + end +endfunction + +function! s:extract_name(str, prefix, suffix) + return matchstr(a:str, '^'.a:prefix.' \zs[^:]\+\ze:.*'.a:suffix.'$') +endfunction + +function! s:status_load(lnum) + let line = getline(a:lnum) + let name = s:extract_name(line, '-', '(not loaded)') + if !empty(name) + call plug#load(name) + setlocal modifiable + call setline(a:lnum, substitute(line, ' (not loaded)$', '', '')) + setlocal nomodifiable + endif +endfunction + +function! s:status_update() range + let lines = getline(a:firstline, a:lastline) + let names = filter(map(lines, 's:extract_name(v:val, "[x-]", "")'), '!empty(v:val)') + if !empty(names) + echo + execute 'PlugUpdate' join(names) + endif +endfunction + +function! s:is_preview_window_open() + silent! wincmd P + if &previewwindow + wincmd p + return 1 + endif +endfunction + +function! s:find_name(lnum) + for lnum in reverse(range(1, a:lnum)) + let line = getline(lnum) + if empty(line) + return '' + endif + let name = s:extract_name(line, '-', '') + if !empty(name) + return name + endif + endfor + return '' +endfunction + +function! s:preview_commit() + if b:plug_preview < 0 + let b:plug_preview = !s:is_preview_window_open() + endif + + let sha = matchstr(getline('.'), '^ \X*\zs[0-9a-f]\{7,9}') + if empty(sha) + return + endif + + let name = s:find_name(line('.')) + if empty(name) || !has_key(g:plugs, name) || !isdirectory(g:plugs[name].dir) + return + endif + + if exists('g:plug_pwindow') && !s:is_preview_window_open() + execute g:plug_pwindow + execute 'e' sha + else + execute 'pedit' sha + wincmd P + endif + setlocal previewwindow filetype=git buftype=nofile nobuflisted modifiable + let batchfile = '' + try + let [sh, shellcmdflag, shrd] = s:chsh(1) + let cmd = 'cd '.plug#shellescape(g:plugs[name].dir).' && git show --no-color --pretty=medium '.sha + if s:is_win + let [batchfile, cmd] = s:batchfile(cmd) + endif + execute 'silent %!' cmd + finally + let [&shell, &shellcmdflag, &shellredir] = [sh, shellcmdflag, shrd] + if s:is_win && filereadable(batchfile) + call delete(batchfile) + endif + endtry + setlocal nomodifiable + nnoremap <silent> <buffer> q :q<cr> + wincmd p +endfunction + +function! s:section(flags) + call search('\(^[x-] \)\@<=[^:]\+:', a:flags) +endfunction + +function! s:format_git_log(line) + let indent = ' ' + let tokens = split(a:line, nr2char(1)) + if len(tokens) != 5 + return indent.substitute(a:line, '\s*$', '', '') + endif + let [graph, sha, refs, subject, date] = tokens + let tag = matchstr(refs, 'tag: [^,)]\+') + let tag = empty(tag) ? ' ' : ' ('.tag.') ' + return printf('%s%s%s%s%s (%s)', indent, graph, sha, tag, subject, date) +endfunction + +function! s:append_ul(lnum, text) + call append(a:lnum, ['', a:text, repeat('-', len(a:text))]) +endfunction + +function! s:diff() + call s:prepare() + call append(0, ['Collecting changes ...', '']) + let cnts = [0, 0] + let bar = '' + let total = filter(copy(g:plugs), 's:is_managed(v:key) && isdirectory(v:val.dir)') + call s:progress_bar(2, bar, len(total)) + for origin in [1, 0] + let plugs = reverse(sort(items(filter(copy(total), (origin ? '' : '!').'(has_key(v:val, "commit") || has_key(v:val, "tag"))')))) + if empty(plugs) + continue + endif + call s:append_ul(2, origin ? 'Pending updates:' : 'Last update:') + for [k, v] in plugs + let range = origin ? '..origin/'.v.branch : 'HEAD@{1}..' + let cmd = ['git', 'log', '--graph', '--color=never'] + if s:git_version_requirement(2, 10, 0) + call add(cmd, '--no-show-signature') + endif + call extend(cmd, ['--pretty=format:%x01%h%x01%d%x01%s%x01%cr', range]) + if has_key(v, 'rtp') + call extend(cmd, ['--', v.rtp]) + endif + let diff = s:system_chomp(cmd, v.dir) + if !empty(diff) + let ref = has_key(v, 'tag') ? (' (tag: '.v.tag.')') : has_key(v, 'commit') ? (' '.v.commit) : '' + call append(5, extend(['', '- '.k.':'.ref], map(s:lines(diff), 's:format_git_log(v:val)'))) + let cnts[origin] += 1 + endif + let bar .= '=' + call s:progress_bar(2, bar, len(total)) + normal! 2G + redraw + endfor + if !cnts[origin] + call append(5, ['', 'N/A']) + endif + endfor + call setline(1, printf('%d plugin(s) updated.', cnts[0]) + \ . (cnts[1] ? printf(' %d plugin(s) have pending updates.', cnts[1]) : '')) + + if cnts[0] || cnts[1] + nnoremap <silent> <buffer> <plug>(plug-preview) :silent! call <SID>preview_commit()<cr> + if empty(maparg("\<cr>", 'n')) + nmap <buffer> <cr> <plug>(plug-preview) + endif + if empty(maparg('o', 'n')) + nmap <buffer> o <plug>(plug-preview) + endif + endif + if cnts[0] + nnoremap <silent> <buffer> X :call <SID>revert()<cr> + echo "Press 'X' on each block to revert the update" + endif + normal! gg + setlocal nomodifiable +endfunction + +function! s:revert() + if search('^Pending updates', 'bnW') + return + endif + + let name = s:find_name(line('.')) + if empty(name) || !has_key(g:plugs, name) || + \ input(printf('Revert the update of %s? (y/N) ', name)) !~? '^y' + return + endif + + call s:system('git reset --hard HEAD@{1} && git checkout '.plug#shellescape(g:plugs[name].branch).' --', g:plugs[name].dir) + setlocal modifiable + normal! "_dap + setlocal nomodifiable + echo 'Reverted' +endfunction + +function! s:snapshot(force, ...) abort + call s:prepare() + setf vim + call append(0, ['" Generated by vim-plug', + \ '" '.strftime("%c"), + \ '" :source this file in vim to restore the snapshot', + \ '" or execute: vim -S snapshot.vim', + \ '', '', 'PlugUpdate!']) + 1 + let anchor = line('$') - 3 + let names = sort(keys(filter(copy(g:plugs), + \'has_key(v:val, "uri") && !has_key(v:val, "commit") && isdirectory(v:val.dir)'))) + for name in reverse(names) + let sha = s:system_chomp(['git', 'rev-parse', '--short', 'HEAD'], g:plugs[name].dir) + if !empty(sha) + call append(anchor, printf("silent! let g:plugs['%s'].commit = '%s'", name, sha)) + redraw + endif + endfor + + if a:0 > 0 + let fn = s:plug_expand(a:1) + if filereadable(fn) && !(a:force || s:ask(a:1.' already exists. Overwrite?')) + return + endif + call writefile(getline(1, '$'), fn) + echo 'Saved as '.a:1 + silent execute 'e' s:esc(fn) + setf vim + endif +endfunction + +function! s:split_rtp() + return split(&rtp, '\\\@<!,') +endfunction + +let s:first_rtp = s:escrtp(get(s:split_rtp(), 0, '')) +let s:last_rtp = s:escrtp(get(s:split_rtp(), -1, '')) + +if exists('g:plugs') + let g:plugs_order = get(g:, 'plugs_order', keys(g:plugs)) + call s:upgrade_specs() + call s:define_commands() +endif + +let &cpo = s:cpo_save +unlet s:cpo_save diff --git a/.config/nvim/autoload/plug.vim.old b/.config/nvim/autoload/plug.vim.old new file mode 100644 index 0000000..ac14332 --- /dev/null +++ b/.config/nvim/autoload/plug.vim.old @@ -0,0 +1,2597 @@ +" vim-plug: Vim plugin manager +" ============================ +" +" Download plug.vim and put it in ~/.vim/autoload +" +" curl -fLo ~/.vim/autoload/plug.vim --create-dirs \ +" https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim +" +" Edit your .vimrc +" +" call plug#begin('~/.vim/plugged') +" +" " Make sure you use single quotes +" +" " Shorthand notation; fetches https://github.com/junegunn/vim-easy-align +" Plug 'junegunn/vim-easy-align' +" +" " Any valid git URL is allowed +" Plug 'https://github.com/junegunn/vim-github-dashboard.git' +" +" " Multiple Plug commands can be written in a single line using | separators +" Plug 'SirVer/ultisnips' | Plug 'honza/vim-snippets' +" +" " On-demand loading +" Plug 'scrooloose/nerdtree', { 'on': 'NERDTreeToggle' } +" Plug 'tpope/vim-fireplace', { 'for': 'clojure' } +" +" " Using a non-master branch +" Plug 'rdnetto/YCM-Generator', { 'branch': 'stable' } +" +" " Using a tagged release; wildcard allowed (requires git 1.9.2 or above) +" Plug 'fatih/vim-go', { 'tag': '*' } +" +" " Plugin options +" Plug 'nsf/gocode', { 'tag': 'v.20150303', 'rtp': 'vim' } +" +" " Plugin outside ~/.vim/plugged with post-update hook +" Plug 'junegunn/fzf', { 'dir': '~/.fzf', 'do': './install --all' } +" +" " Unmanaged plugin (manually installed and updated) +" Plug '~/my-prototype-plugin' +" +" " Initialize plugin system +" call plug#end() +" +" Then reload .vimrc and :PlugInstall to install plugins. +" +" Plug options: +" +"| Option | Description | +"| ----------------------- | ------------------------------------------------ | +"| `branch`/`tag`/`commit` | Branch/tag/commit of the repository to use | +"| `rtp` | Subdirectory that contains Vim plugin | +"| `dir` | Custom directory for the plugin | +"| `as` | Use different name for the plugin | +"| `do` | Post-update hook (string or funcref) | +"| `on` | On-demand loading: Commands or `<Plug>`-mappings | +"| `for` | On-demand loading: File types | +"| `frozen` | Do not update unless explicitly specified | +" +" More information: https://github.com/junegunn/vim-plug +" +" +" Copyright (c) 2017 Junegunn Choi +" +" MIT License +" +" Permission is hereby granted, free of charge, to any person obtaining +" a copy of this software and associated documentation files (the +" "Software"), to deal in the Software without restriction, including +" without limitation the rights to use, copy, modify, merge, publish, +" distribute, sublicense, and/or sell copies of the Software, and to +" permit persons to whom the Software is furnished to do so, subject to +" the following conditions: +" +" The above copyright notice and this permission notice shall be +" included in all copies or substantial portions of the Software. +" +" THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +" EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +" MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +" NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +" LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +" OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +" WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +if exists('g:loaded_plug') + finish +endif +let g:loaded_plug = 1 + +let s:cpo_save = &cpo +set cpo&vim + +let s:plug_src = 'https://github.com/junegunn/vim-plug.git' +let s:plug_tab = get(s:, 'plug_tab', -1) +let s:plug_buf = get(s:, 'plug_buf', -1) +let s:mac_gui = has('gui_macvim') && has('gui_running') +let s:is_win = has('win32') +let s:nvim = has('nvim-0.2') || (has('nvim') && exists('*jobwait') && !s:is_win) +let s:vim8 = has('patch-8.0.0039') && exists('*job_start') +if s:is_win && &shellslash + set noshellslash + let s:me = resolve(expand('<sfile>:p')) + set shellslash +else + let s:me = resolve(expand('<sfile>:p')) +endif +let s:base_spec = { 'branch': 'master', 'frozen': 0 } +let s:TYPE = { +\ 'string': type(''), +\ 'list': type([]), +\ 'dict': type({}), +\ 'funcref': type(function('call')) +\ } +let s:loaded = get(s:, 'loaded', {}) +let s:triggers = get(s:, 'triggers', {}) + +if s:is_win + function! s:plug_call(fn, ...) + let shellslash = &shellslash + try + set noshellslash + return call(a:fn, a:000) + finally + let &shellslash = shellslash + endtry + endfunction +else + function! s:plug_call(fn, ...) + return call(a:fn, a:000) + endfunction +endif + +function! s:plug_getcwd() + return s:plug_call('getcwd') +endfunction + +function! s:plug_fnamemodify(fname, mods) + return s:plug_call('fnamemodify', a:fname, a:mods) +endfunction + +function! s:plug_expand(fmt) + return s:plug_call('expand', a:fmt, 1) +endfunction + +function! s:plug_tempname() + return s:plug_call('tempname') +endfunction + +function! plug#begin(...) + if a:0 > 0 + let s:plug_home_org = a:1 + let home = s:path(s:plug_fnamemodify(s:plug_expand(a:1), ':p')) + elseif exists('g:plug_home') + let home = s:path(g:plug_home) + elseif !empty(&rtp) + let home = s:path(split(&rtp, ',')[0]) . '/plugged' + else + return s:err('Unable to determine plug home. Try calling plug#begin() with a path argument.') + endif + if s:plug_fnamemodify(home, ':t') ==# 'plugin' && s:plug_fnamemodify(home, ':h') ==# s:first_rtp + return s:err('Invalid plug home. '.home.' is a standard Vim runtime path and is not allowed.') + endif + + let g:plug_home = home + let g:plugs = {} + let g:plugs_order = [] + let s:triggers = {} + + call s:define_commands() + return 1 +endfunction + +function! s:define_commands() + command! -nargs=+ -bar Plug call plug#(<args>) + if !executable('git') + return s:err('`git` executable not found. Most commands will not be available. To suppress this message, prepend `silent!` to `call plug#begin(...)`.') + endif + if has('win32') + \ && &shellslash + \ && (&shell =~# 'cmd\.exe' || &shell =~# 'powershell\.exe') + return s:err('vim-plug does not support shell, ' . &shell . ', when shellslash is set.') + endif + if !has('nvim') + \ && (has('win32') || has('win32unix')) + \ && !has('multi_byte') + return s:err('Vim needs +multi_byte feature on Windows to run shell commands. Enable +iconv for best results.') + endif + command! -nargs=* -bar -bang -complete=customlist,s:names PlugInstall call s:install(<bang>0, [<f-args>]) + command! -nargs=* -bar -bang -complete=customlist,s:names PlugUpdate call s:update(<bang>0, [<f-args>]) + command! -nargs=0 -bar -bang PlugClean call s:clean(<bang>0) + command! -nargs=0 -bar PlugUpgrade if s:upgrade() | execute 'source' s:esc(s:me) | endif + command! -nargs=0 -bar PlugStatus call s:status() + command! -nargs=0 -bar PlugDiff call s:diff() + command! -nargs=? -bar -bang -complete=file PlugSnapshot call s:snapshot(<bang>0, <f-args>) +endfunction + +function! s:to_a(v) + return type(a:v) == s:TYPE.list ? a:v : [a:v] +endfunction + +function! s:to_s(v) + return type(a:v) == s:TYPE.string ? a:v : join(a:v, "\n") . "\n" +endfunction + +function! s:glob(from, pattern) + return s:lines(globpath(a:from, a:pattern)) +endfunction + +function! s:source(from, ...) + let found = 0 + for pattern in a:000 + for vim in s:glob(a:from, pattern) + execute 'source' s:esc(vim) + let found = 1 + endfor + endfor + return found +endfunction + +function! s:assoc(dict, key, val) + let a:dict[a:key] = add(get(a:dict, a:key, []), a:val) +endfunction + +function! s:ask(message, ...) + call inputsave() + echohl WarningMsg + let answer = input(a:message.(a:0 ? ' (y/N/a) ' : ' (y/N) ')) + echohl None + call inputrestore() + echo "\r" + return (a:0 && answer =~? '^a') ? 2 : (answer =~? '^y') ? 1 : 0 +endfunction + +function! s:ask_no_interrupt(...) + try + return call('s:ask', a:000) + catch + return 0 + endtry +endfunction + +function! s:lazy(plug, opt) + return has_key(a:plug, a:opt) && + \ (empty(s:to_a(a:plug[a:opt])) || + \ !isdirectory(a:plug.dir) || + \ len(s:glob(s:rtp(a:plug), 'plugin')) || + \ len(s:glob(s:rtp(a:plug), 'after/plugin'))) +endfunction + +function! plug#end() + if !exists('g:plugs') + return s:err('plug#end() called without calling plug#begin() first') + endif + + if exists('#PlugLOD') + augroup PlugLOD + autocmd! + augroup END + augroup! PlugLOD + endif + let lod = { 'ft': {}, 'map': {}, 'cmd': {} } + + if exists('g:did_load_filetypes') + filetype off + endif + for name in g:plugs_order + if !has_key(g:plugs, name) + continue + endif + let plug = g:plugs[name] + if get(s:loaded, name, 0) || !s:lazy(plug, 'on') && !s:lazy(plug, 'for') + let s:loaded[name] = 1 + continue + endif + + if has_key(plug, 'on') + let s:triggers[name] = { 'map': [], 'cmd': [] } + for cmd in s:to_a(plug.on) + if cmd =~? '^<Plug>.\+' + if empty(mapcheck(cmd)) && empty(mapcheck(cmd, 'i')) + call s:assoc(lod.map, cmd, name) + endif + call add(s:triggers[name].map, cmd) + elseif cmd =~# '^[A-Z]' + let cmd = substitute(cmd, '!*$', '', '') + if exists(':'.cmd) != 2 + call s:assoc(lod.cmd, cmd, name) + endif + call add(s:triggers[name].cmd, cmd) + else + call s:err('Invalid `on` option: '.cmd. + \ '. Should start with an uppercase letter or `<Plug>`.') + endif + endfor + endif + + if has_key(plug, 'for') + let types = s:to_a(plug.for) + if !empty(types) + augroup filetypedetect + call s:source(s:rtp(plug), 'ftdetect/**/*.vim', 'after/ftdetect/**/*.vim') + augroup END + endif + for type in types + call s:assoc(lod.ft, type, name) + endfor + endif + endfor + + for [cmd, names] in items(lod.cmd) + execute printf( + \ 'command! -nargs=* -range -bang -complete=file %s call s:lod_cmd(%s, "<bang>", <line1>, <line2>, <q-args>, %s)', + \ cmd, string(cmd), string(names)) + endfor + + for [map, names] in items(lod.map) + for [mode, map_prefix, key_prefix] in + \ [['i', '<C-O>', ''], ['n', '', ''], ['v', '', 'gv'], ['o', '', '']] + execute printf( + \ '%snoremap <silent> %s %s:<C-U>call <SID>lod_map(%s, %s, %s, "%s")<CR>', + \ mode, map, map_prefix, string(map), string(names), mode != 'i', key_prefix) + endfor + endfor + + for [ft, names] in items(lod.ft) + augroup PlugLOD + execute printf('autocmd FileType %s call <SID>lod_ft(%s, %s)', + \ ft, string(ft), string(names)) + augroup END + endfor + + call s:reorg_rtp() + filetype plugin indent on + if has('vim_starting') + if has('syntax') && !exists('g:syntax_on') + syntax enable + end + else + call s:reload_plugins() + endif +endfunction + +function! s:loaded_names() + return filter(copy(g:plugs_order), 'get(s:loaded, v:val, 0)') +endfunction + +function! s:load_plugin(spec) + call s:source(s:rtp(a:spec), 'plugin/**/*.vim', 'after/plugin/**/*.vim') +endfunction + +function! s:reload_plugins() + for name in s:loaded_names() + call s:load_plugin(g:plugs[name]) + endfor +endfunction + +function! s:trim(str) + return substitute(a:str, '[\/]\+$', '', '') +endfunction + +function! s:version_requirement(val, min) + for idx in range(0, len(a:min) - 1) + let v = get(a:val, idx, 0) + if v < a:min[idx] | return 0 + elseif v > a:min[idx] | return 1 + endif + endfor + return 1 +endfunction + +function! s:git_version_requirement(...) + if !exists('s:git_version') + let s:git_version = map(split(split(s:system('git --version'))[2], '\.'), 'str2nr(v:val)') + endif + return s:version_requirement(s:git_version, a:000) +endfunction + +function! s:progress_opt(base) + return a:base && !s:is_win && + \ s:git_version_requirement(1, 7, 1) ? '--progress' : '' +endfunction + +function! s:rtp(spec) + return s:path(a:spec.dir . get(a:spec, 'rtp', '')) +endfunction + +if s:is_win + function! s:path(path) + return s:trim(substitute(a:path, '/', '\', 'g')) + endfunction + + function! s:dirpath(path) + return s:path(a:path) . '\' + endfunction + + function! s:is_local_plug(repo) + return a:repo =~? '^[a-z]:\|^[%~]' + endfunction + + " Copied from fzf + function! s:wrap_cmds(cmds) + let cmds = [ + \ '@echo off', + \ 'setlocal enabledelayedexpansion'] + \ + (type(a:cmds) == type([]) ? a:cmds : [a:cmds]) + \ + ['endlocal'] + if has('iconv') + if !exists('s:codepage') + let s:codepage = libcallnr('kernel32.dll', 'GetACP', 0) + endif + return map(cmds, printf('iconv(v:val."\r", "%s", "cp%d")', &encoding, s:codepage)) + endif + return map(cmds, 'v:val."\r"') + endfunction + + function! s:batchfile(cmd) + let batchfile = s:plug_tempname().'.bat' + call writefile(s:wrap_cmds(a:cmd), batchfile) + let cmd = plug#shellescape(batchfile, {'shell': &shell, 'script': 0}) + if &shell =~# 'powershell\.exe' + let cmd = '& ' . cmd + endif + return [batchfile, cmd] + endfunction +else + function! s:path(path) + return s:trim(a:path) + endfunction + + function! s:dirpath(path) + return substitute(a:path, '[/\\]*$', '/', '') + endfunction + + function! s:is_local_plug(repo) + return a:repo[0] =~ '[/$~]' + endfunction +endif + +function! s:err(msg) + echohl ErrorMsg + echom '[vim-plug] '.a:msg + echohl None +endfunction + +function! s:warn(cmd, msg) + echohl WarningMsg + execute a:cmd 'a:msg' + echohl None +endfunction + +function! s:esc(path) + return escape(a:path, ' ') +endfunction + +function! s:escrtp(path) + return escape(a:path, ' ,') +endfunction + +function! s:remove_rtp() + for name in s:loaded_names() + let rtp = s:rtp(g:plugs[name]) + execute 'set rtp-='.s:escrtp(rtp) + let after = globpath(rtp, 'after') + if isdirectory(after) + execute 'set rtp-='.s:escrtp(after) + endif + endfor +endfunction + +function! s:reorg_rtp() + if !empty(s:first_rtp) + execute 'set rtp-='.s:first_rtp + execute 'set rtp-='.s:last_rtp + endif + + " &rtp is modified from outside + if exists('s:prtp') && s:prtp !=# &rtp + call s:remove_rtp() + unlet! s:middle + endif + + let s:middle = get(s:, 'middle', &rtp) + let rtps = map(s:loaded_names(), 's:rtp(g:plugs[v:val])') + let afters = filter(map(copy(rtps), 'globpath(v:val, "after")'), '!empty(v:val)') + let rtp = join(map(rtps, 'escape(v:val, ",")'), ',') + \ . ','.s:middle.',' + \ . join(map(afters, 'escape(v:val, ",")'), ',') + let &rtp = substitute(substitute(rtp, ',,*', ',', 'g'), '^,\|,$', '', 'g') + let s:prtp = &rtp + + if !empty(s:first_rtp) + execute 'set rtp^='.s:first_rtp + execute 'set rtp+='.s:last_rtp + endif +endfunction + +function! s:doautocmd(...) + if exists('#'.join(a:000, '#')) + execute 'doautocmd' ((v:version > 703 || has('patch442')) ? '<nomodeline>' : '') join(a:000) + endif +endfunction + +function! s:dobufread(names) + for name in a:names + let path = s:rtp(g:plugs[name]) + for dir in ['ftdetect', 'ftplugin', 'after/ftdetect', 'after/ftplugin'] + if len(finddir(dir, path)) + if exists('#BufRead') + doautocmd BufRead + endif + return + endif + endfor + endfor +endfunction + +function! plug#load(...) + if a:0 == 0 + return s:err('Argument missing: plugin name(s) required') + endif + if !exists('g:plugs') + return s:err('plug#begin was not called') + endif + let names = a:0 == 1 && type(a:1) == s:TYPE.list ? a:1 : a:000 + let unknowns = filter(copy(names), '!has_key(g:plugs, v:val)') + if !empty(unknowns) + let s = len(unknowns) > 1 ? 's' : '' + return s:err(printf('Unknown plugin%s: %s', s, join(unknowns, ', '))) + end + let unloaded = filter(copy(names), '!get(s:loaded, v:val, 0)') + if !empty(unloaded) + for name in unloaded + call s:lod([name], ['ftdetect', 'after/ftdetect', 'plugin', 'after/plugin']) + endfor + call s:dobufread(unloaded) + return 1 + end + return 0 +endfunction + +function! s:remove_triggers(name) + if !has_key(s:triggers, a:name) + return + endif + for cmd in s:triggers[a:name].cmd + execute 'silent! delc' cmd + endfor + for map in s:triggers[a:name].map + execute 'silent! unmap' map + execute 'silent! iunmap' map + endfor + call remove(s:triggers, a:name) +endfunction + +function! s:lod(names, types, ...) + for name in a:names + call s:remove_triggers(name) + let s:loaded[name] = 1 + endfor + call s:reorg_rtp() + + for name in a:names + let rtp = s:rtp(g:plugs[name]) + for dir in a:types + call s:source(rtp, dir.'/**/*.vim') + endfor + if a:0 + if !s:source(rtp, a:1) && !empty(s:glob(rtp, a:2)) + execute 'runtime' a:1 + endif + call s:source(rtp, a:2) + endif + call s:doautocmd('User', name) + endfor +endfunction + +function! s:lod_ft(pat, names) + let syn = 'syntax/'.a:pat.'.vim' + call s:lod(a:names, ['plugin', 'after/plugin'], syn, 'after/'.syn) + execute 'autocmd! PlugLOD FileType' a:pat + call s:doautocmd('filetypeplugin', 'FileType') + call s:doautocmd('filetypeindent', 'FileType') +endfunction + +function! s:lod_cmd(cmd, bang, l1, l2, args, names) + call s:lod(a:names, ['ftdetect', 'after/ftdetect', 'plugin', 'after/plugin']) + call s:dobufread(a:names) + execute printf('%s%s%s %s', (a:l1 == a:l2 ? '' : (a:l1.','.a:l2)), a:cmd, a:bang, a:args) +endfunction + +function! s:lod_map(map, names, with_prefix, prefix) + call s:lod(a:names, ['ftdetect', 'after/ftdetect', 'plugin', 'after/plugin']) + call s:dobufread(a:names) + let extra = '' + while 1 + let c = getchar(0) + if c == 0 + break + endif + let extra .= nr2char(c) + endwhile + + if a:with_prefix + let prefix = v:count ? v:count : '' + let prefix .= '"'.v:register.a:prefix + if mode(1) == 'no' + if v:operator == 'c' + let prefix = "\<esc>" . prefix + endif + let prefix .= v:operator + endif + call feedkeys(prefix, 'n') + endif + call feedkeys(substitute(a:map, '^<Plug>', "\<Plug>", '') . extra) +endfunction + +function! plug#(repo, ...) + if a:0 > 1 + return s:err('Invalid number of arguments (1..2)') + endif + + try + let repo = s:trim(a:repo) + let opts = a:0 == 1 ? s:parse_options(a:1) : s:base_spec + let name = get(opts, 'as', s:plug_fnamemodify(repo, ':t:s?\.git$??')) + let spec = extend(s:infer_properties(name, repo), opts) + if !has_key(g:plugs, name) + call add(g:plugs_order, name) + endif + let g:plugs[name] = spec + let s:loaded[name] = get(s:loaded, name, 0) + catch + return s:err(v:exception) + endtry +endfunction + +function! s:parse_options(arg) + let opts = copy(s:base_spec) + let type = type(a:arg) + if type == s:TYPE.string + let opts.tag = a:arg + elseif type == s:TYPE.dict + call extend(opts, a:arg) + if has_key(opts, 'dir') + let opts.dir = s:dirpath(s:plug_expand(opts.dir)) + endif + else + throw 'Invalid argument type (expected: string or dictionary)' + endif + return opts +endfunction + +function! s:infer_properties(name, repo) + let repo = a:repo + if s:is_local_plug(repo) + return { 'dir': s:dirpath(s:plug_expand(repo)) } + else + if repo =~ ':' + let uri = repo + else + if repo !~ '/' + throw printf('Invalid argument: %s (implicit `vim-scripts'' expansion is deprecated)', repo) + endif + let fmt = get(g:, 'plug_url_format', 'https://git::@github.com/%s.git') + let uri = printf(fmt, repo) + endif + return { 'dir': s:dirpath(g:plug_home.'/'.a:name), 'uri': uri } + endif +endfunction + +function! s:install(force, names) + call s:update_impl(0, a:force, a:names) +endfunction + +function! s:update(force, names) + call s:update_impl(1, a:force, a:names) +endfunction + +function! plug#helptags() + if !exists('g:plugs') + return s:err('plug#begin was not called') + endif + for spec in values(g:plugs) + let docd = join([s:rtp(spec), 'doc'], '/') + if isdirectory(docd) + silent! execute 'helptags' s:esc(docd) + endif + endfor + return 1 +endfunction + +function! s:syntax() + syntax clear + syntax region plug1 start=/\%1l/ end=/\%2l/ contains=plugNumber + syntax region plug2 start=/\%2l/ end=/\%3l/ contains=plugBracket,plugX + syn match plugNumber /[0-9]\+[0-9.]*/ contained + syn match plugBracket /[[\]]/ contained + syn match plugX /x/ contained + syn match plugDash /^-/ + syn match plugPlus /^+/ + syn match plugStar /^*/ + syn match plugMessage /\(^- \)\@<=.*/ + syn match plugName /\(^- \)\@<=[^ ]*:/ + syn match plugSha /\%(: \)\@<=[0-9a-f]\{4,}$/ + syn match plugTag /(tag: [^)]\+)/ + syn match plugInstall /\(^+ \)\@<=[^:]*/ + syn match plugUpdate /\(^* \)\@<=[^:]*/ + syn match plugCommit /^ \X*[0-9a-f]\{7,9} .*/ contains=plugRelDate,plugEdge,plugTag + syn match plugEdge /^ \X\+$/ + syn match plugEdge /^ \X*/ contained nextgroup=plugSha + syn match plugSha /[0-9a-f]\{7,9}/ contained + syn match plugRelDate /([^)]*)$/ contained + syn match plugNotLoaded /(not loaded)$/ + syn match plugError /^x.*/ + syn region plugDeleted start=/^\~ .*/ end=/^\ze\S/ + syn match plugH2 /^.*:\n-\+$/ + syn keyword Function PlugInstall PlugStatus PlugUpdate PlugClean + hi def link plug1 Title + hi def link plug2 Repeat + hi def link plugH2 Type + hi def link plugX Exception + hi def link plugBracket Structure + hi def link plugNumber Number + + hi def link plugDash Special + hi def link plugPlus Constant + hi def link plugStar Boolean + + hi def link plugMessage Function + hi def link plugName Label + hi def link plugInstall Function + hi def link plugUpdate Type + + hi def link plugError Error + hi def link plugDeleted Ignore + hi def link plugRelDate Comment + hi def link plugEdge PreProc + hi def link plugSha Identifier + hi def link plugTag Constant + + hi def link plugNotLoaded Comment +endfunction + +function! s:lpad(str, len) + return a:str . repeat(' ', a:len - len(a:str)) +endfunction + +function! s:lines(msg) + return split(a:msg, "[\r\n]") +endfunction + +function! s:lastline(msg) + return get(s:lines(a:msg), -1, '') +endfunction + +function! s:new_window() + execute get(g:, 'plug_window', 'vertical topleft new') +endfunction + +function! s:plug_window_exists() + let buflist = tabpagebuflist(s:plug_tab) + return !empty(buflist) && index(buflist, s:plug_buf) >= 0 +endfunction + +function! s:switch_in() + if !s:plug_window_exists() + return 0 + endif + + if winbufnr(0) != s:plug_buf + let s:pos = [tabpagenr(), winnr(), winsaveview()] + execute 'normal!' s:plug_tab.'gt' + let winnr = bufwinnr(s:plug_buf) + execute winnr.'wincmd w' + call add(s:pos, winsaveview()) + else + let s:pos = [winsaveview()] + endif + + setlocal modifiable + return 1 +endfunction + +function! s:switch_out(...) + call winrestview(s:pos[-1]) + setlocal nomodifiable + if a:0 > 0 + execute a:1 + endif + + if len(s:pos) > 1 + execute 'normal!' s:pos[0].'gt' + execute s:pos[1] 'wincmd w' + call winrestview(s:pos[2]) + endif +endfunction + +function! s:finish_bindings() + nnoremap <silent> <buffer> R :call <SID>retry()<cr> + nnoremap <silent> <buffer> D :PlugDiff<cr> + nnoremap <silent> <buffer> S :PlugStatus<cr> + nnoremap <silent> <buffer> U :call <SID>status_update()<cr> + xnoremap <silent> <buffer> U :call <SID>status_update()<cr> + nnoremap <silent> <buffer> ]] :silent! call <SID>section('')<cr> + nnoremap <silent> <buffer> [[ :silent! call <SID>section('b')<cr> +endfunction + +function! s:prepare(...) + if empty(s:plug_getcwd()) + throw 'Invalid current working directory. Cannot proceed.' + endif + + for evar in ['$GIT_DIR', '$GIT_WORK_TREE'] + if exists(evar) + throw evar.' detected. Cannot proceed.' + endif + endfor + + call s:job_abort() + if s:switch_in() + if b:plug_preview == 1 + pc + endif + enew + else + call s:new_window() + endif + + nnoremap <silent> <buffer> q :if b:plug_preview==1<bar>pc<bar>endif<bar>bd<cr> + if a:0 == 0 + call s:finish_bindings() + endif + let b:plug_preview = -1 + let s:plug_tab = tabpagenr() + let s:plug_buf = winbufnr(0) + call s:assign_name() + + for k in ['<cr>', 'L', 'o', 'X', 'd', 'dd'] + execute 'silent! unmap <buffer>' k + endfor + setlocal buftype=nofile bufhidden=wipe nobuflisted nolist noswapfile nowrap cursorline modifiable nospell + if exists('+colorcolumn') + setlocal colorcolumn= + endif + setf vim-plug + if exists('g:syntax_on') + call s:syntax() + endif +endfunction + +function! s:assign_name() + " Assign buffer name + let prefix = '[Plugins]' + let name = prefix + let idx = 2 + while bufexists(name) + let name = printf('%s (%s)', prefix, idx) + let idx = idx + 1 + endwhile + silent! execute 'f' fnameescape(name) +endfunction + +function! s:chsh(swap) + let prev = [&shell, &shellcmdflag, &shellredir] + if !s:is_win && a:swap + set shell=sh shellredir=>%s\ 2>&1 + endif + return prev +endfunction + +function! s:bang(cmd, ...) + let batchfile = '' + try + let [sh, shellcmdflag, shrd] = s:chsh(a:0) + " FIXME: Escaping is incomplete. We could use shellescape with eval, + " but it won't work on Windows. + let cmd = a:0 ? s:with_cd(a:cmd, a:1) : a:cmd + if s:is_win + let [batchfile, cmd] = s:batchfile(cmd) + endif + let g:_plug_bang = (s:is_win && has('gui_running') ? 'silent ' : '').'!'.escape(cmd, '#!%') + execute "normal! :execute g:_plug_bang\<cr>\<cr>" + finally + unlet g:_plug_bang + let [&shell, &shellcmdflag, &shellredir] = [sh, shellcmdflag, shrd] + if s:is_win && filereadable(batchfile) + call delete(batchfile) + endif + endtry + return v:shell_error ? 'Exit status: ' . v:shell_error : '' +endfunction + +function! s:regress_bar() + let bar = substitute(getline(2)[1:-2], '.*\zs=', 'x', '') + call s:progress_bar(2, bar, len(bar)) +endfunction + +function! s:is_updated(dir) + return !empty(s:system_chomp('git log --pretty=format:"%h" "HEAD...HEAD@{1}"', a:dir)) +endfunction + +function! s:do(pull, force, todo) + for [name, spec] in items(a:todo) + if !isdirectory(spec.dir) + continue + endif + let installed = has_key(s:update.new, name) + let updated = installed ? 0 : + \ (a:pull && index(s:update.errors, name) < 0 && s:is_updated(spec.dir)) + if a:force || installed || updated + execute 'cd' s:esc(spec.dir) + call append(3, '- Post-update hook for '. name .' ... ') + let error = '' + let type = type(spec.do) + if type == s:TYPE.string + if spec.do[0] == ':' + if !get(s:loaded, name, 0) + let s:loaded[name] = 1 + call s:reorg_rtp() + endif + call s:load_plugin(spec) + try + execute spec.do[1:] + catch + let error = v:exception + endtry + if !s:plug_window_exists() + cd - + throw 'Warning: vim-plug was terminated by the post-update hook of '.name + endif + else + let error = s:bang(spec.do) + endif + elseif type == s:TYPE.funcref + try + let status = installed ? 'installed' : (updated ? 'updated' : 'unchanged') + call spec.do({ 'name': name, 'status': status, 'force': a:force }) + catch + let error = v:exception + endtry + else + let error = 'Invalid hook type' + endif + call s:switch_in() + call setline(4, empty(error) ? (getline(4) . 'OK') + \ : ('x' . getline(4)[1:] . error)) + if !empty(error) + call add(s:update.errors, name) + call s:regress_bar() + endif + cd - + endif + endfor +endfunction + +function! s:hash_match(a, b) + return stridx(a:a, a:b) == 0 || stridx(a:b, a:a) == 0 +endfunction + +function! s:checkout(spec) + let sha = a:spec.commit + let output = s:system('git rev-parse HEAD', a:spec.dir) + if !v:shell_error && !s:hash_match(sha, s:lines(output)[0]) + let output = s:system( + \ 'git fetch --depth 999999 && git checkout '.plug#shellescape(sha).' --', a:spec.dir) + endif + return output +endfunction + +function! s:finish(pull) + let new_frozen = len(filter(keys(s:update.new), 'g:plugs[v:val].frozen')) + if new_frozen + let s = new_frozen > 1 ? 's' : '' + call append(3, printf('- Installed %d frozen plugin%s', new_frozen, s)) + endif + call append(3, '- Finishing ... ') | 4 + redraw + call plug#helptags() + call plug#end() + call setline(4, getline(4) . 'Done!') + redraw + let msgs = [] + if !empty(s:update.errors) + call add(msgs, "Press 'R' to retry.") + endif + if a:pull && len(s:update.new) < len(filter(getline(5, '$'), + \ "v:val =~ '^- ' && v:val !~# 'Already up.to.date'")) + call add(msgs, "Press 'D' to see the updated changes.") + endif + echo join(msgs, ' ') + call s:finish_bindings() +endfunction + +function! s:retry() + if empty(s:update.errors) + return + endif + echo + call s:update_impl(s:update.pull, s:update.force, + \ extend(copy(s:update.errors), [s:update.threads])) +endfunction + +function! s:is_managed(name) + return has_key(g:plugs[a:name], 'uri') +endfunction + +function! s:names(...) + return sort(filter(keys(g:plugs), 'stridx(v:val, a:1) == 0 && s:is_managed(v:val)')) +endfunction + +function! s:check_ruby() + silent! ruby require 'thread'; VIM::command("let g:plug_ruby = '#{RUBY_VERSION}'") + if !exists('g:plug_ruby') + redraw! + return s:warn('echom', 'Warning: Ruby interface is broken') + endif + let ruby_version = split(g:plug_ruby, '\.') + unlet g:plug_ruby + return s:version_requirement(ruby_version, [1, 8, 7]) +endfunction + +function! s:update_impl(pull, force, args) abort + let sync = index(a:args, '--sync') >= 0 || has('vim_starting') + let args = filter(copy(a:args), 'v:val != "--sync"') + let threads = (len(args) > 0 && args[-1] =~ '^[1-9][0-9]*$') ? + \ remove(args, -1) : get(g:, 'plug_threads', 16) + + let managed = filter(copy(g:plugs), 's:is_managed(v:key)') + let todo = empty(args) ? filter(managed, '!v:val.frozen || !isdirectory(v:val.dir)') : + \ filter(managed, 'index(args, v:key) >= 0') + + if empty(todo) + return s:warn('echo', 'No plugin to '. (a:pull ? 'update' : 'install')) + endif + + if !s:is_win && s:git_version_requirement(2, 3) + let s:git_terminal_prompt = exists('$GIT_TERMINAL_PROMPT') ? $GIT_TERMINAL_PROMPT : '' + let $GIT_TERMINAL_PROMPT = 0 + for plug in values(todo) + let plug.uri = substitute(plug.uri, + \ '^https://git::@github\.com', 'https://github.com', '') + endfor + endif + + if !isdirectory(g:plug_home) + try + call mkdir(g:plug_home, 'p') + catch + return s:err(printf('Invalid plug directory: %s. '. + \ 'Try to call plug#begin with a valid directory', g:plug_home)) + endtry + endif + + if has('nvim') && !exists('*jobwait') && threads > 1 + call s:warn('echom', '[vim-plug] Update Neovim for parallel installer') + endif + + let use_job = s:nvim || s:vim8 + let python = (has('python') || has('python3')) && !use_job + let ruby = has('ruby') && !use_job && (v:version >= 703 || v:version == 702 && has('patch374')) && !(s:is_win && has('gui_running')) && threads > 1 && s:check_ruby() + + let s:update = { + \ 'start': reltime(), + \ 'all': todo, + \ 'todo': copy(todo), + \ 'errors': [], + \ 'pull': a:pull, + \ 'force': a:force, + \ 'new': {}, + \ 'threads': (python || ruby || use_job) ? min([len(todo), threads]) : 1, + \ 'bar': '', + \ 'fin': 0 + \ } + + call s:prepare(1) + call append(0, ['', '']) + normal! 2G + silent! redraw + + let s:clone_opt = get(g:, 'plug_shallow', 1) ? + \ '--depth 1' . (s:git_version_requirement(1, 7, 10) ? ' --no-single-branch' : '') : '' + + if has('win32unix') || has('wsl') + let s:clone_opt .= ' -c core.eol=lf -c core.autocrlf=input' + endif + + let s:submodule_opt = s:git_version_requirement(2, 8) ? ' --jobs='.threads : '' + + " Python version requirement (>= 2.7) + if python && !has('python3') && !ruby && !use_job && s:update.threads > 1 + redir => pyv + silent python import platform; print platform.python_version() + redir END + let python = s:version_requirement( + \ map(split(split(pyv)[0], '\.'), 'str2nr(v:val)'), [2, 6]) + endif + + if (python || ruby) && s:update.threads > 1 + try + let imd = &imd + if s:mac_gui + set noimd + endif + if ruby + call s:update_ruby() + else + call s:update_python() + endif + catch + let lines = getline(4, '$') + let printed = {} + silent! 4,$d _ + for line in lines + let name = s:extract_name(line, '.', '') + if empty(name) || !has_key(printed, name) + call append('$', line) + if !empty(name) + let printed[name] = 1 + if line[0] == 'x' && index(s:update.errors, name) < 0 + call add(s:update.errors, name) + end + endif + endif + endfor + finally + let &imd = imd + call s:update_finish() + endtry + else + call s:update_vim() + while use_job && sync + sleep 100m + if s:update.fin + break + endif + endwhile + endif +endfunction + +function! s:log4(name, msg) + call setline(4, printf('- %s (%s)', a:msg, a:name)) + redraw +endfunction + +function! s:update_finish() + if exists('s:git_terminal_prompt') + let $GIT_TERMINAL_PROMPT = s:git_terminal_prompt + endif + if s:switch_in() + call append(3, '- Updating ...') | 4 + for [name, spec] in items(filter(copy(s:update.all), 'index(s:update.errors, v:key) < 0 && (s:update.force || s:update.pull || has_key(s:update.new, v:key))')) + let [pos, _] = s:logpos(name) + if !pos + continue + endif + if has_key(spec, 'commit') + call s:log4(name, 'Checking out '.spec.commit) + let out = s:checkout(spec) + elseif has_key(spec, 'tag') + let tag = spec.tag + if tag =~ '\*' + let tags = s:lines(s:system('git tag --list '.plug#shellescape(tag).' --sort -version:refname 2>&1', spec.dir)) + if !v:shell_error && !empty(tags) + let tag = tags[0] + call s:log4(name, printf('Latest tag for %s -> %s', spec.tag, tag)) + call append(3, '') + endif + endif + call s:log4(name, 'Checking out '.tag) + let out = s:system('git checkout -q '.plug#shellescape(tag).' -- 2>&1', spec.dir) + else + let branch = get(spec, 'branch', 'master') + call s:log4(name, 'Merging origin/'.s:esc(branch)) + let out = s:system('git checkout -q '.plug#shellescape(branch).' -- 2>&1' + \. (has_key(s:update.new, name) ? '' : ('&& git merge --ff-only '.plug#shellescape('origin/'.branch).' 2>&1')), spec.dir) + endif + if !v:shell_error && filereadable(spec.dir.'/.gitmodules') && + \ (s:update.force || has_key(s:update.new, name) || s:is_updated(spec.dir)) + call s:log4(name, 'Updating submodules. This may take a while.') + let out .= s:bang('git submodule update --init --recursive'.s:submodule_opt.' 2>&1', spec.dir) + endif + let msg = s:format_message(v:shell_error ? 'x': '-', name, out) + if v:shell_error + call add(s:update.errors, name) + call s:regress_bar() + silent execute pos 'd _' + call append(4, msg) | 4 + elseif !empty(out) + call setline(pos, msg[0]) + endif + redraw + endfor + silent 4 d _ + try + call s:do(s:update.pull, s:update.force, filter(copy(s:update.all), 'index(s:update.errors, v:key) < 0 && has_key(v:val, "do")')) + catch + call s:warn('echom', v:exception) + call s:warn('echo', '') + return + endtry + call s:finish(s:update.pull) + call setline(1, 'Updated. Elapsed time: ' . split(reltimestr(reltime(s:update.start)))[0] . ' sec.') + call s:switch_out('normal! gg') + endif +endfunction + +function! s:job_abort() + if (!s:nvim && !s:vim8) || !exists('s:jobs') + return + endif + + for [name, j] in items(s:jobs) + if s:nvim + silent! call jobstop(j.jobid) + elseif s:vim8 + silent! call job_stop(j.jobid) + endif + if j.new + call s:rm_rf(g:plugs[name].dir) + endif + endfor + let s:jobs = {} +endfunction + +function! s:last_non_empty_line(lines) + let len = len(a:lines) + for idx in range(len) + let line = a:lines[len-idx-1] + if !empty(line) + return line + endif + endfor + return '' +endfunction + +function! s:job_out_cb(self, data) abort + let self = a:self + let data = remove(self.lines, -1) . a:data + let lines = map(split(data, "\n", 1), 'split(v:val, "\r", 1)[-1]') + call extend(self.lines, lines) + " To reduce the number of buffer updates + let self.tick = get(self, 'tick', -1) + 1 + if !self.running || self.tick % len(s:jobs) == 0 + let bullet = self.running ? (self.new ? '+' : '*') : (self.error ? 'x' : '-') + let result = self.error ? join(self.lines, "\n") : s:last_non_empty_line(self.lines) + call s:log(bullet, self.name, result) + endif +endfunction + +function! s:job_exit_cb(self, data) abort + let a:self.running = 0 + let a:self.error = a:data != 0 + call s:reap(a:self.name) + call s:tick() +endfunction + +function! s:job_cb(fn, job, ch, data) + if !s:plug_window_exists() " plug window closed + return s:job_abort() + endif + call call(a:fn, [a:job, a:data]) +endfunction + +function! s:nvim_cb(job_id, data, event) dict abort + return a:event == 'stdout' ? + \ s:job_cb('s:job_out_cb', self, 0, join(a:data, "\n")) : + \ s:job_cb('s:job_exit_cb', self, 0, a:data) +endfunction + +function! s:spawn(name, cmd, opts) + let job = { 'name': a:name, 'running': 1, 'error': 0, 'lines': [''], + \ 'new': get(a:opts, 'new', 0) } + let s:jobs[a:name] = job + let cmd = has_key(a:opts, 'dir') ? s:with_cd(a:cmd, a:opts.dir, 0) : a:cmd + let argv = s:is_win ? ['cmd', '/s', '/c', '"'.cmd.'"'] : ['sh', '-c', cmd] + + if s:nvim + call extend(job, { + \ 'on_stdout': function('s:nvim_cb'), + \ 'on_exit': function('s:nvim_cb'), + \ }) + let jid = s:plug_call('jobstart', argv, job) + if jid > 0 + let job.jobid = jid + else + let job.running = 0 + let job.error = 1 + let job.lines = [jid < 0 ? argv[0].' is not executable' : + \ 'Invalid arguments (or job table is full)'] + endif + elseif s:vim8 + let jid = job_start(s:is_win ? join(argv, ' ') : argv, { + \ 'out_cb': function('s:job_cb', ['s:job_out_cb', job]), + \ 'exit_cb': function('s:job_cb', ['s:job_exit_cb', job]), + \ 'out_mode': 'raw' + \}) + if job_status(jid) == 'run' + let job.jobid = jid + else + let job.running = 0 + let job.error = 1 + let job.lines = ['Failed to start job'] + endif + else + let job.lines = s:lines(call('s:system', [cmd])) + let job.error = v:shell_error != 0 + let job.running = 0 + endif +endfunction + +function! s:reap(name) + let job = s:jobs[a:name] + if job.error + call add(s:update.errors, a:name) + elseif get(job, 'new', 0) + let s:update.new[a:name] = 1 + endif + let s:update.bar .= job.error ? 'x' : '=' + + let bullet = job.error ? 'x' : '-' + let result = job.error ? join(job.lines, "\n") : s:last_non_empty_line(job.lines) + call s:log(bullet, a:name, empty(result) ? 'OK' : result) + call s:bar() + + call remove(s:jobs, a:name) +endfunction + +function! s:bar() + if s:switch_in() + let total = len(s:update.all) + call setline(1, (s:update.pull ? 'Updating' : 'Installing'). + \ ' plugins ('.len(s:update.bar).'/'.total.')') + call s:progress_bar(2, s:update.bar, total) + call s:switch_out() + endif +endfunction + +function! s:logpos(name) + let max = line('$') + for i in range(4, max > 4 ? max : 4) + if getline(i) =~# '^[-+x*] '.a:name.':' + for j in range(i + 1, max > 5 ? max : 5) + if getline(j) !~ '^ ' + return [i, j - 1] + endif + endfor + return [i, i] + endif + endfor + return [0, 0] +endfunction + +function! s:log(bullet, name, lines) + if s:switch_in() + let [b, e] = s:logpos(a:name) + if b > 0 + silent execute printf('%d,%d d _', b, e) + if b > winheight('.') + let b = 4 + endif + else + let b = 4 + endif + " FIXME For some reason, nomodifiable is set after :d in vim8 + setlocal modifiable + call append(b - 1, s:format_message(a:bullet, a:name, a:lines)) + call s:switch_out() + endif +endfunction + +function! s:update_vim() + let s:jobs = {} + + call s:bar() + call s:tick() +endfunction + +function! s:tick() + let pull = s:update.pull + let prog = s:progress_opt(s:nvim || s:vim8) +while 1 " Without TCO, Vim stack is bound to explode + if empty(s:update.todo) + if empty(s:jobs) && !s:update.fin + call s:update_finish() + let s:update.fin = 1 + endif + return + endif + + let name = keys(s:update.todo)[0] + let spec = remove(s:update.todo, name) + let new = empty(globpath(spec.dir, '.git', 1)) + + call s:log(new ? '+' : '*', name, pull ? 'Updating ...' : 'Installing ...') + redraw + + let has_tag = has_key(spec, 'tag') + if !new + let [error, _] = s:git_validate(spec, 0) + if empty(error) + if pull + let fetch_opt = (has_tag && !empty(globpath(spec.dir, '.git/shallow'))) ? '--depth 99999999' : '' + call s:spawn(name, printf('git fetch %s %s 2>&1', fetch_opt, prog), { 'dir': spec.dir }) + else + let s:jobs[name] = { 'running': 0, 'lines': ['Already installed'], 'error': 0 } + endif + else + let s:jobs[name] = { 'running': 0, 'lines': s:lines(error), 'error': 1 } + endif + else + call s:spawn(name, + \ printf('git clone %s %s %s %s 2>&1', + \ has_tag ? '' : s:clone_opt, + \ prog, + \ plug#shellescape(spec.uri, {'script': 0}), + \ plug#shellescape(s:trim(spec.dir), {'script': 0})), { 'new': 1 }) + endif + + if !s:jobs[name].running + call s:reap(name) + endif + if len(s:jobs) >= s:update.threads + break + endif +endwhile +endfunction + +function! s:update_python() +let py_exe = has('python') ? 'python' : 'python3' +execute py_exe "<< EOF" +import datetime +import functools +import os +try: + import queue +except ImportError: + import Queue as queue +import random +import re +import shutil +import signal +import subprocess +import tempfile +import threading as thr +import time +import traceback +import vim + +G_NVIM = vim.eval("has('nvim')") == '1' +G_PULL = vim.eval('s:update.pull') == '1' +G_RETRIES = int(vim.eval('get(g:, "plug_retries", 2)')) + 1 +G_TIMEOUT = int(vim.eval('get(g:, "plug_timeout", 60)')) +G_CLONE_OPT = vim.eval('s:clone_opt') +G_PROGRESS = vim.eval('s:progress_opt(1)') +G_LOG_PROB = 1.0 / int(vim.eval('s:update.threads')) +G_STOP = thr.Event() +G_IS_WIN = vim.eval('s:is_win') == '1' + +class PlugError(Exception): + def __init__(self, msg): + self.msg = msg +class CmdTimedOut(PlugError): + pass +class CmdFailed(PlugError): + pass +class InvalidURI(PlugError): + pass +class Action(object): + INSTALL, UPDATE, ERROR, DONE = ['+', '*', 'x', '-'] + +class Buffer(object): + def __init__(self, lock, num_plugs, is_pull): + self.bar = '' + self.event = 'Updating' if is_pull else 'Installing' + self.lock = lock + self.maxy = int(vim.eval('winheight(".")')) + self.num_plugs = num_plugs + + def __where(self, name): + """ Find first line with name in current buffer. Return line num. """ + found, lnum = False, 0 + matcher = re.compile('^[-+x*] {0}:'.format(name)) + for line in vim.current.buffer: + if matcher.search(line) is not None: + found = True + break + lnum += 1 + + if not found: + lnum = -1 + return lnum + + def header(self): + curbuf = vim.current.buffer + curbuf[0] = self.event + ' plugins ({0}/{1})'.format(len(self.bar), self.num_plugs) + + num_spaces = self.num_plugs - len(self.bar) + curbuf[1] = '[{0}{1}]'.format(self.bar, num_spaces * ' ') + + with self.lock: + vim.command('normal! 2G') + vim.command('redraw') + + def write(self, action, name, lines): + first, rest = lines[0], lines[1:] + msg = ['{0} {1}{2}{3}'.format(action, name, ': ' if first else '', first)] + msg.extend([' ' + line for line in rest]) + + try: + if action == Action.ERROR: + self.bar += 'x' + vim.command("call add(s:update.errors, '{0}')".format(name)) + elif action == Action.DONE: + self.bar += '=' + + curbuf = vim.current.buffer + lnum = self.__where(name) + if lnum != -1: # Found matching line num + del curbuf[lnum] + if lnum > self.maxy and action in set([Action.INSTALL, Action.UPDATE]): + lnum = 3 + else: + lnum = 3 + curbuf.append(msg, lnum) + + self.header() + except vim.error: + pass + +class Command(object): + CD = 'cd /d' if G_IS_WIN else 'cd' + + def __init__(self, cmd, cmd_dir=None, timeout=60, cb=None, clean=None): + self.cmd = cmd + if cmd_dir: + self.cmd = '{0} {1} && {2}'.format(Command.CD, cmd_dir, self.cmd) + self.timeout = timeout + self.callback = cb if cb else (lambda msg: None) + self.clean = clean if clean else (lambda: None) + self.proc = None + + @property + def alive(self): + """ Returns true only if command still running. """ + return self.proc and self.proc.poll() is None + + def execute(self, ntries=3): + """ Execute the command with ntries if CmdTimedOut. + Returns the output of the command if no Exception. + """ + attempt, finished, limit = 0, False, self.timeout + + while not finished: + try: + attempt += 1 + result = self.try_command() + finished = True + return result + except CmdTimedOut: + if attempt != ntries: + self.notify_retry() + self.timeout += limit + else: + raise + + def notify_retry(self): + """ Retry required for command, notify user. """ + for count in range(3, 0, -1): + if G_STOP.is_set(): + raise KeyboardInterrupt + msg = 'Timeout. Will retry in {0} second{1} ...'.format( + count, 's' if count != 1 else '') + self.callback([msg]) + time.sleep(1) + self.callback(['Retrying ...']) + + def try_command(self): + """ Execute a cmd & poll for callback. Returns list of output. + Raises CmdFailed -> return code for Popen isn't 0 + Raises CmdTimedOut -> command exceeded timeout without new output + """ + first_line = True + + try: + tfile = tempfile.NamedTemporaryFile(mode='w+b') + preexec_fn = not G_IS_WIN and os.setsid or None + self.proc = subprocess.Popen(self.cmd, stdout=tfile, + stderr=subprocess.STDOUT, + stdin=subprocess.PIPE, shell=True, + preexec_fn=preexec_fn) + thrd = thr.Thread(target=(lambda proc: proc.wait()), args=(self.proc,)) + thrd.start() + + thread_not_started = True + while thread_not_started: + try: + thrd.join(0.1) + thread_not_started = False + except RuntimeError: + pass + + while self.alive: + if G_STOP.is_set(): + raise KeyboardInterrupt + + if first_line or random.random() < G_LOG_PROB: + first_line = False + line = '' if G_IS_WIN else nonblock_read(tfile.name) + if line: + self.callback([line]) + + time_diff = time.time() - os.path.getmtime(tfile.name) + if time_diff > self.timeout: + raise CmdTimedOut(['Timeout!']) + + thrd.join(0.5) + + tfile.seek(0) + result = [line.decode('utf-8', 'replace').rstrip() for line in tfile] + + if self.proc.returncode != 0: + raise CmdFailed([''] + result) + + return result + except: + self.terminate() + raise + + def terminate(self): + """ Terminate process and cleanup. """ + if self.alive: + if G_IS_WIN: + os.kill(self.proc.pid, signal.SIGINT) + else: + os.killpg(self.proc.pid, signal.SIGTERM) + self.clean() + +class Plugin(object): + def __init__(self, name, args, buf_q, lock): + self.name = name + self.args = args + self.buf_q = buf_q + self.lock = lock + self.tag = args.get('tag', 0) + + def manage(self): + try: + if os.path.exists(self.args['dir']): + self.update() + else: + self.install() + with self.lock: + thread_vim_command("let s:update.new['{0}'] = 1".format(self.name)) + except PlugError as exc: + self.write(Action.ERROR, self.name, exc.msg) + except KeyboardInterrupt: + G_STOP.set() + self.write(Action.ERROR, self.name, ['Interrupted!']) + except: + # Any exception except those above print stack trace + msg = 'Trace:\n{0}'.format(traceback.format_exc().rstrip()) + self.write(Action.ERROR, self.name, msg.split('\n')) + raise + + def install(self): + target = self.args['dir'] + if target[-1] == '\\': + target = target[0:-1] + + def clean(target): + def _clean(): + try: + shutil.rmtree(target) + except OSError: + pass + return _clean + + self.write(Action.INSTALL, self.name, ['Installing ...']) + callback = functools.partial(self.write, Action.INSTALL, self.name) + cmd = 'git clone {0} {1} {2} {3} 2>&1'.format( + '' if self.tag else G_CLONE_OPT, G_PROGRESS, self.args['uri'], + esc(target)) + com = Command(cmd, None, G_TIMEOUT, callback, clean(target)) + result = com.execute(G_RETRIES) + self.write(Action.DONE, self.name, result[-1:]) + + def repo_uri(self): + cmd = 'git rev-parse --abbrev-ref HEAD 2>&1 && git config -f .git/config remote.origin.url' + command = Command(cmd, self.args['dir'], G_TIMEOUT,) + result = command.execute(G_RETRIES) + return result[-1] + + def update(self): + actual_uri = self.repo_uri() + expect_uri = self.args['uri'] + regex = re.compile(r'^(?:\w+://)?(?:[^@/]*@)?([^:/]*(?::[0-9]*)?)[:/](.*?)(?:\.git)?/?$') + ma = regex.match(actual_uri) + mb = regex.match(expect_uri) + if ma is None or mb is None or ma.groups() != mb.groups(): + msg = ['', + 'Invalid URI: {0}'.format(actual_uri), + 'Expected {0}'.format(expect_uri), + 'PlugClean required.'] + raise InvalidURI(msg) + + if G_PULL: + self.write(Action.UPDATE, self.name, ['Updating ...']) + callback = functools.partial(self.write, Action.UPDATE, self.name) + fetch_opt = '--depth 99999999' if self.tag and os.path.isfile(os.path.join(self.args['dir'], '.git/shallow')) else '' + cmd = 'git fetch {0} {1} 2>&1'.format(fetch_opt, G_PROGRESS) + com = Command(cmd, self.args['dir'], G_TIMEOUT, callback) + result = com.execute(G_RETRIES) + self.write(Action.DONE, self.name, result[-1:]) + else: + self.write(Action.DONE, self.name, ['Already installed']) + + def write(self, action, name, msg): + self.buf_q.put((action, name, msg)) + +class PlugThread(thr.Thread): + def __init__(self, tname, args): + super(PlugThread, self).__init__() + self.tname = tname + self.args = args + + def run(self): + thr.current_thread().name = self.tname + buf_q, work_q, lock = self.args + + try: + while not G_STOP.is_set(): + name, args = work_q.get_nowait() + plug = Plugin(name, args, buf_q, lock) + plug.manage() + work_q.task_done() + except queue.Empty: + pass + +class RefreshThread(thr.Thread): + def __init__(self, lock): + super(RefreshThread, self).__init__() + self.lock = lock + self.running = True + + def run(self): + while self.running: + with self.lock: + thread_vim_command('noautocmd normal! a') + time.sleep(0.33) + + def stop(self): + self.running = False + +if G_NVIM: + def thread_vim_command(cmd): + vim.session.threadsafe_call(lambda: vim.command(cmd)) +else: + def thread_vim_command(cmd): + vim.command(cmd) + +def esc(name): + return '"' + name.replace('"', '\"') + '"' + +def nonblock_read(fname): + """ Read a file with nonblock flag. Return the last line. """ + fread = os.open(fname, os.O_RDONLY | os.O_NONBLOCK) + buf = os.read(fread, 100000).decode('utf-8', 'replace') + os.close(fread) + + line = buf.rstrip('\r\n') + left = max(line.rfind('\r'), line.rfind('\n')) + if left != -1: + left += 1 + line = line[left:] + + return line + +def main(): + thr.current_thread().name = 'main' + nthreads = int(vim.eval('s:update.threads')) + plugs = vim.eval('s:update.todo') + mac_gui = vim.eval('s:mac_gui') == '1' + + lock = thr.Lock() + buf = Buffer(lock, len(plugs), G_PULL) + buf_q, work_q = queue.Queue(), queue.Queue() + for work in plugs.items(): + work_q.put(work) + + start_cnt = thr.active_count() + for num in range(nthreads): + tname = 'PlugT-{0:02}'.format(num) + thread = PlugThread(tname, (buf_q, work_q, lock)) + thread.start() + if mac_gui: + rthread = RefreshThread(lock) + rthread.start() + + while not buf_q.empty() or thr.active_count() != start_cnt: + try: + action, name, msg = buf_q.get(True, 0.25) + buf.write(action, name, ['OK'] if not msg else msg) + buf_q.task_done() + except queue.Empty: + pass + except KeyboardInterrupt: + G_STOP.set() + + if mac_gui: + rthread.stop() + rthread.join() + +main() +EOF +endfunction + +function! s:update_ruby() + ruby << EOF + module PlugStream + SEP = ["\r", "\n", nil] + def get_line + buffer = '' + loop do + char = readchar rescue return + if SEP.include? char.chr + buffer << $/ + break + else + buffer << char + end + end + buffer + end + end unless defined?(PlugStream) + + def esc arg + %["#{arg.gsub('"', '\"')}"] + end + + def killall pid + pids = [pid] + if /mswin|mingw|bccwin/ =~ RUBY_PLATFORM + pids.each { |pid| Process.kill 'INT', pid.to_i rescue nil } + else + unless `which pgrep 2> /dev/null`.empty? + children = pids + until children.empty? + children = children.map { |pid| + `pgrep -P #{pid}`.lines.map { |l| l.chomp } + }.flatten + pids += children + end + end + pids.each { |pid| Process.kill 'TERM', pid.to_i rescue nil } + end + end + + def compare_git_uri a, b + regex = %r{^(?:\w+://)?(?:[^@/]*@)?([^:/]*(?::[0-9]*)?)[:/](.*?)(?:\.git)?/?$} + regex.match(a).to_a.drop(1) == regex.match(b).to_a.drop(1) + end + + require 'thread' + require 'fileutils' + require 'timeout' + running = true + iswin = VIM::evaluate('s:is_win').to_i == 1 + pull = VIM::evaluate('s:update.pull').to_i == 1 + base = VIM::evaluate('g:plug_home') + all = VIM::evaluate('s:update.todo') + limit = VIM::evaluate('get(g:, "plug_timeout", 60)') + tries = VIM::evaluate('get(g:, "plug_retries", 2)') + 1 + nthr = VIM::evaluate('s:update.threads').to_i + maxy = VIM::evaluate('winheight(".")').to_i + vim7 = VIM::evaluate('v:version').to_i <= 703 && RUBY_PLATFORM =~ /darwin/ + cd = iswin ? 'cd /d' : 'cd' + tot = VIM::evaluate('len(s:update.todo)') || 0 + bar = '' + skip = 'Already installed' + mtx = Mutex.new + take1 = proc { mtx.synchronize { running && all.shift } } + logh = proc { + cnt = bar.length + $curbuf[1] = "#{pull ? 'Updating' : 'Installing'} plugins (#{cnt}/#{tot})" + $curbuf[2] = '[' + bar.ljust(tot) + ']' + VIM::command('normal! 2G') + VIM::command('redraw') + } + where = proc { |name| (1..($curbuf.length)).find { |l| $curbuf[l] =~ /^[-+x*] #{name}:/ } } + log = proc { |name, result, type| + mtx.synchronize do + ing = ![true, false].include?(type) + bar += type ? '=' : 'x' unless ing + b = case type + when :install then '+' when :update then '*' + when true, nil then '-' else + VIM::command("call add(s:update.errors, '#{name}')") + 'x' + end + result = + if type || type.nil? + ["#{b} #{name}: #{result.lines.to_a.last || 'OK'}"] + elsif result =~ /^Interrupted|^Timeout/ + ["#{b} #{name}: #{result}"] + else + ["#{b} #{name}"] + result.lines.map { |l| " " << l } + end + if lnum = where.call(name) + $curbuf.delete lnum + lnum = 4 if ing && lnum > maxy + end + result.each_with_index do |line, offset| + $curbuf.append((lnum || 4) - 1 + offset, line.gsub(/\e\[./, '').chomp) + end + logh.call + end + } + bt = proc { |cmd, name, type, cleanup| + tried = timeout = 0 + begin + tried += 1 + timeout += limit + fd = nil + data = '' + if iswin + Timeout::timeout(timeout) do + tmp = VIM::evaluate('tempname()') + system("(#{cmd}) > #{tmp}") + data = File.read(tmp).chomp + File.unlink tmp rescue nil + end + else + fd = IO.popen(cmd).extend(PlugStream) + first_line = true + log_prob = 1.0 / nthr + while line = Timeout::timeout(timeout) { fd.get_line } + data << line + log.call name, line.chomp, type if name && (first_line || rand < log_prob) + first_line = false + end + fd.close + end + [$? == 0, data.chomp] + rescue Timeout::Error, Interrupt => e + if fd && !fd.closed? + killall fd.pid + fd.close + end + cleanup.call if cleanup + if e.is_a?(Timeout::Error) && tried < tries + 3.downto(1) do |countdown| + s = countdown > 1 ? 's' : '' + log.call name, "Timeout. Will retry in #{countdown} second#{s} ...", type + sleep 1 + end + log.call name, 'Retrying ...', type + retry + end + [false, e.is_a?(Interrupt) ? "Interrupted!" : "Timeout!"] + end + } + main = Thread.current + threads = [] + watcher = Thread.new { + if vim7 + while VIM::evaluate('getchar(1)') + sleep 0.1 + end + else + require 'io/console' # >= Ruby 1.9 + nil until IO.console.getch == 3.chr + end + mtx.synchronize do + running = false + threads.each { |t| t.raise Interrupt } unless vim7 + end + threads.each { |t| t.join rescue nil } + main.kill + } + refresh = Thread.new { + while true + mtx.synchronize do + break unless running + VIM::command('noautocmd normal! a') + end + sleep 0.2 + end + } if VIM::evaluate('s:mac_gui') == 1 + + clone_opt = VIM::evaluate('s:clone_opt') + progress = VIM::evaluate('s:progress_opt(1)') + nthr.times do + mtx.synchronize do + threads << Thread.new { + while pair = take1.call + name = pair.first + dir, uri, tag = pair.last.values_at *%w[dir uri tag] + exists = File.directory? dir + ok, result = + if exists + chdir = "#{cd} #{iswin ? dir : esc(dir)}" + ret, data = bt.call "#{chdir} && git rev-parse --abbrev-ref HEAD 2>&1 && git config -f .git/config remote.origin.url", nil, nil, nil + current_uri = data.lines.to_a.last + if !ret + if data =~ /^Interrupted|^Timeout/ + [false, data] + else + [false, [data.chomp, "PlugClean required."].join($/)] + end + elsif !compare_git_uri(current_uri, uri) + [false, ["Invalid URI: #{current_uri}", + "Expected: #{uri}", + "PlugClean required."].join($/)] + else + if pull + log.call name, 'Updating ...', :update + fetch_opt = (tag && File.exist?(File.join(dir, '.git/shallow'))) ? '--depth 99999999' : '' + bt.call "#{chdir} && git fetch #{fetch_opt} #{progress} 2>&1", name, :update, nil + else + [true, skip] + end + end + else + d = esc dir.sub(%r{[\\/]+$}, '') + log.call name, 'Installing ...', :install + bt.call "git clone #{clone_opt unless tag} #{progress} #{uri} #{d} 2>&1", name, :install, proc { + FileUtils.rm_rf dir + } + end + mtx.synchronize { VIM::command("let s:update.new['#{name}'] = 1") } if !exists && ok + log.call name, result, ok + end + } if running + end + end + threads.each { |t| t.join rescue nil } + logh.call + refresh.kill if refresh + watcher.kill +EOF +endfunction + +function! s:shellesc_cmd(arg, script) + let escaped = substitute('"'.a:arg.'"', '[&|<>()@^!"]', '^&', 'g') + return substitute(escaped, '%', (a:script ? '%' : '^') . '&', 'g') +endfunction + +function! s:shellesc_ps1(arg) + return "'".substitute(escape(a:arg, '\"'), "'", "''", 'g')."'" +endfunction + +function! s:shellesc_sh(arg) + return "'".substitute(a:arg, "'", "'\\\\''", 'g')."'" +endfunction + +function! plug#shellescape(arg, ...) + let opts = a:0 > 0 && type(a:1) == s:TYPE.dict ? a:1 : {} + let shell = get(opts, 'shell', s:is_win ? 'cmd.exe' : 'sh') + let script = get(opts, 'script', 1) + if shell =~# 'cmd\.exe' + return s:shellesc_cmd(a:arg, script) + elseif shell =~# 'powershell\.exe' || shell =~# 'pwsh$' + return s:shellesc_ps1(a:arg) + endif + return s:shellesc_sh(a:arg) +endfunction + +function! s:glob_dir(path) + return map(filter(s:glob(a:path, '**'), 'isdirectory(v:val)'), 's:dirpath(v:val)') +endfunction + +function! s:progress_bar(line, bar, total) + call setline(a:line, '[' . s:lpad(a:bar, a:total) . ']') +endfunction + +function! s:compare_git_uri(a, b) + " See `git help clone' + " https:// [user@] github.com[:port] / junegunn/vim-plug [.git] + " [git@] github.com[:port] : junegunn/vim-plug [.git] + " file:// / junegunn/vim-plug [/] + " / junegunn/vim-plug [/] + let pat = '^\%(\w\+://\)\='.'\%([^@/]*@\)\='.'\([^:/]*\%(:[0-9]*\)\=\)'.'[:/]'.'\(.\{-}\)'.'\%(\.git\)\=/\?$' + let ma = matchlist(a:a, pat) + let mb = matchlist(a:b, pat) + return ma[1:2] ==# mb[1:2] +endfunction + +function! s:format_message(bullet, name, message) + if a:bullet != 'x' + return [printf('%s %s: %s', a:bullet, a:name, s:lastline(a:message))] + else + let lines = map(s:lines(a:message), '" ".v:val') + return extend([printf('x %s:', a:name)], lines) + endif +endfunction + +function! s:with_cd(cmd, dir, ...) + let script = a:0 > 0 ? a:1 : 1 + return printf('cd%s %s && %s', s:is_win ? ' /d' : '', plug#shellescape(a:dir, {'script': script}), a:cmd) +endfunction + +function! s:system(cmd, ...) + let batchfile = '' + try + let [sh, shellcmdflag, shrd] = s:chsh(1) + let cmd = a:0 > 0 ? s:with_cd(a:cmd, a:1) : a:cmd + if s:is_win + let [batchfile, cmd] = s:batchfile(cmd) + endif + return system(cmd) + finally + let [&shell, &shellcmdflag, &shellredir] = [sh, shellcmdflag, shrd] + if s:is_win && filereadable(batchfile) + call delete(batchfile) + endif + endtry +endfunction + +function! s:system_chomp(...) + let ret = call('s:system', a:000) + return v:shell_error ? '' : substitute(ret, '\n$', '', '') +endfunction + +function! s:git_validate(spec, check_branch) + let err = '' + if isdirectory(a:spec.dir) + let result = s:lines(s:system('git rev-parse --abbrev-ref HEAD 2>&1 && git config -f .git/config remote.origin.url', a:spec.dir)) + let remote = result[-1] + if v:shell_error + let err = join([remote, 'PlugClean required.'], "\n") + elseif !s:compare_git_uri(remote, a:spec.uri) + let err = join(['Invalid URI: '.remote, + \ 'Expected: '.a:spec.uri, + \ 'PlugClean required.'], "\n") + elseif a:check_branch && has_key(a:spec, 'commit') + let result = s:lines(s:system('git rev-parse HEAD 2>&1', a:spec.dir)) + let sha = result[-1] + if v:shell_error + let err = join(add(result, 'PlugClean required.'), "\n") + elseif !s:hash_match(sha, a:spec.commit) + let err = join([printf('Invalid HEAD (expected: %s, actual: %s)', + \ a:spec.commit[:6], sha[:6]), + \ 'PlugUpdate required.'], "\n") + endif + elseif a:check_branch + let branch = result[0] + " Check tag + if has_key(a:spec, 'tag') + let tag = s:system_chomp('git describe --exact-match --tags HEAD 2>&1', a:spec.dir) + if a:spec.tag !=# tag && a:spec.tag !~ '\*' + let err = printf('Invalid tag: %s (expected: %s). Try PlugUpdate.', + \ (empty(tag) ? 'N/A' : tag), a:spec.tag) + endif + " Check branch + elseif a:spec.branch !=# branch + let err = printf('Invalid branch: %s (expected: %s). Try PlugUpdate.', + \ branch, a:spec.branch) + endif + if empty(err) + let [ahead, behind] = split(s:lastline(s:system(printf( + \ 'git rev-list --count --left-right HEAD...origin/%s', + \ a:spec.branch), a:spec.dir)), '\t') + if !v:shell_error && ahead + if behind + " Only mention PlugClean if diverged, otherwise it's likely to be + " pushable (and probably not that messed up). + let err = printf( + \ "Diverged from origin/%s (%d commit(s) ahead and %d commit(s) behind!\n" + \ .'Backup local changes and run PlugClean and PlugUpdate to reinstall it.', a:spec.branch, ahead, behind) + else + let err = printf("Ahead of origin/%s by %d commit(s).\n" + \ .'Cannot update until local changes are pushed.', + \ a:spec.branch, ahead) + endif + endif + endif + endif + else + let err = 'Not found' + endif + return [err, err =~# 'PlugClean'] +endfunction + +function! s:rm_rf(dir) + if isdirectory(a:dir) + call s:system((s:is_win ? 'rmdir /S /Q ' : 'rm -rf ') . plug#shellescape(a:dir)) + endif +endfunction + +function! s:clean(force) + call s:prepare() + call append(0, 'Searching for invalid plugins in '.g:plug_home) + call append(1, '') + + " List of valid directories + let dirs = [] + let errs = {} + let [cnt, total] = [0, len(g:plugs)] + for [name, spec] in items(g:plugs) + if !s:is_managed(name) + call add(dirs, spec.dir) + else + let [err, clean] = s:git_validate(spec, 1) + if clean + let errs[spec.dir] = s:lines(err)[0] + else + call add(dirs, spec.dir) + endif + endif + let cnt += 1 + call s:progress_bar(2, repeat('=', cnt), total) + normal! 2G + redraw + endfor + + let allowed = {} + for dir in dirs + let allowed[s:dirpath(s:plug_fnamemodify(dir, ':h:h'))] = 1 + let allowed[dir] = 1 + for child in s:glob_dir(dir) + let allowed[child] = 1 + endfor + endfor + + let todo = [] + let found = sort(s:glob_dir(g:plug_home)) + while !empty(found) + let f = remove(found, 0) + if !has_key(allowed, f) && isdirectory(f) + call add(todo, f) + call append(line('$'), '- ' . f) + if has_key(errs, f) + call append(line('$'), ' ' . errs[f]) + endif + let found = filter(found, 'stridx(v:val, f) != 0') + end + endwhile + + 4 + redraw + if empty(todo) + call append(line('$'), 'Already clean.') + else + let s:clean_count = 0 + call append(3, ['Directories to delete:', '']) + redraw! + if a:force || s:ask_no_interrupt('Delete all directories?') + call s:delete([6, line('$')], 1) + else + call setline(4, 'Cancelled.') + nnoremap <silent> <buffer> d :set opfunc=<sid>delete_op<cr>g@ + nmap <silent> <buffer> dd d_ + xnoremap <silent> <buffer> d :<c-u>call <sid>delete_op(visualmode(), 1)<cr> + echo 'Delete the lines (d{motion}) to delete the corresponding directories' + endif + endif + 4 + setlocal nomodifiable +endfunction + +function! s:delete_op(type, ...) + call s:delete(a:0 ? [line("'<"), line("'>")] : [line("'["), line("']")], 0) +endfunction + +function! s:delete(range, force) + let [l1, l2] = a:range + let force = a:force + while l1 <= l2 + let line = getline(l1) + if line =~ '^- ' && isdirectory(line[2:]) + execute l1 + redraw! + let answer = force ? 1 : s:ask('Delete '.line[2:].'?', 1) + let force = force || answer > 1 + if answer + call s:rm_rf(line[2:]) + setlocal modifiable + call setline(l1, '~'.line[1:]) + let s:clean_count += 1 + call setline(4, printf('Removed %d directories.', s:clean_count)) + setlocal nomodifiable + endif + endif + let l1 += 1 + endwhile +endfunction + +function! s:upgrade() + echo 'Downloading the latest version of vim-plug' + redraw + let tmp = s:plug_tempname() + let new = tmp . '/plug.vim' + + try + let out = s:system(printf('git clone --depth 1 %s %s', plug#shellescape(s:plug_src), plug#shellescape(tmp))) + if v:shell_error + return s:err('Error upgrading vim-plug: '. out) + endif + + if readfile(s:me) ==# readfile(new) + echo 'vim-plug is already up-to-date' + return 0 + else + call rename(s:me, s:me . '.old') + call rename(new, s:me) + unlet g:loaded_plug + echo 'vim-plug has been upgraded' + return 1 + endif + finally + silent! call s:rm_rf(tmp) + endtry +endfunction + +function! s:upgrade_specs() + for spec in values(g:plugs) + let spec.frozen = get(spec, 'frozen', 0) + endfor +endfunction + +function! s:status() + call s:prepare() + call append(0, 'Checking plugins') + call append(1, '') + + let ecnt = 0 + let unloaded = 0 + let [cnt, total] = [0, len(g:plugs)] + for [name, spec] in items(g:plugs) + let is_dir = isdirectory(spec.dir) + if has_key(spec, 'uri') + if is_dir + let [err, _] = s:git_validate(spec, 1) + let [valid, msg] = [empty(err), empty(err) ? 'OK' : err] + else + let [valid, msg] = [0, 'Not found. Try PlugInstall.'] + endif + else + if is_dir + let [valid, msg] = [1, 'OK'] + else + let [valid, msg] = [0, 'Not found.'] + endif + endif + let cnt += 1 + let ecnt += !valid + " `s:loaded` entry can be missing if PlugUpgraded + if is_dir && get(s:loaded, name, -1) == 0 + let unloaded = 1 + let msg .= ' (not loaded)' + endif + call s:progress_bar(2, repeat('=', cnt), total) + call append(3, s:format_message(valid ? '-' : 'x', name, msg)) + normal! 2G + redraw + endfor + call setline(1, 'Finished. '.ecnt.' error(s).') + normal! gg + setlocal nomodifiable + if unloaded + echo "Press 'L' on each line to load plugin, or 'U' to update" + nnoremap <silent> <buffer> L :call <SID>status_load(line('.'))<cr> + xnoremap <silent> <buffer> L :call <SID>status_load(line('.'))<cr> + end +endfunction + +function! s:extract_name(str, prefix, suffix) + return matchstr(a:str, '^'.a:prefix.' \zs[^:]\+\ze:.*'.a:suffix.'$') +endfunction + +function! s:status_load(lnum) + let line = getline(a:lnum) + let name = s:extract_name(line, '-', '(not loaded)') + if !empty(name) + call plug#load(name) + setlocal modifiable + call setline(a:lnum, substitute(line, ' (not loaded)$', '', '')) + setlocal nomodifiable + endif +endfunction + +function! s:status_update() range + let lines = getline(a:firstline, a:lastline) + let names = filter(map(lines, 's:extract_name(v:val, "[x-]", "")'), '!empty(v:val)') + if !empty(names) + echo + execute 'PlugUpdate' join(names) + endif +endfunction + +function! s:is_preview_window_open() + silent! wincmd P + if &previewwindow + wincmd p + return 1 + endif +endfunction + +function! s:find_name(lnum) + for lnum in reverse(range(1, a:lnum)) + let line = getline(lnum) + if empty(line) + return '' + endif + let name = s:extract_name(line, '-', '') + if !empty(name) + return name + endif + endfor + return '' +endfunction + +function! s:preview_commit() + if b:plug_preview < 0 + let b:plug_preview = !s:is_preview_window_open() + endif + + let sha = matchstr(getline('.'), '^ \X*\zs[0-9a-f]\{7,9}') + if empty(sha) + return + endif + + let name = s:find_name(line('.')) + if empty(name) || !has_key(g:plugs, name) || !isdirectory(g:plugs[name].dir) + return + endif + + if exists('g:plug_pwindow') && !s:is_preview_window_open() + execute g:plug_pwindow + execute 'e' sha + else + execute 'pedit' sha + wincmd P + endif + setlocal previewwindow filetype=git buftype=nofile nobuflisted modifiable + let batchfile = '' + try + let [sh, shellcmdflag, shrd] = s:chsh(1) + let cmd = 'cd '.plug#shellescape(g:plugs[name].dir).' && git show --no-color --pretty=medium '.sha + if s:is_win + let [batchfile, cmd] = s:batchfile(cmd) + endif + execute 'silent %!' cmd + finally + let [&shell, &shellcmdflag, &shellredir] = [sh, shellcmdflag, shrd] + if s:is_win && filereadable(batchfile) + call delete(batchfile) + endif + endtry + setlocal nomodifiable + nnoremap <silent> <buffer> q :q<cr> + wincmd p +endfunction + +function! s:section(flags) + call search('\(^[x-] \)\@<=[^:]\+:', a:flags) +endfunction + +function! s:format_git_log(line) + let indent = ' ' + let tokens = split(a:line, nr2char(1)) + if len(tokens) != 5 + return indent.substitute(a:line, '\s*$', '', '') + endif + let [graph, sha, refs, subject, date] = tokens + let tag = matchstr(refs, 'tag: [^,)]\+') + let tag = empty(tag) ? ' ' : ' ('.tag.') ' + return printf('%s%s%s%s%s (%s)', indent, graph, sha, tag, subject, date) +endfunction + +function! s:append_ul(lnum, text) + call append(a:lnum, ['', a:text, repeat('-', len(a:text))]) +endfunction + +function! s:diff() + call s:prepare() + call append(0, ['Collecting changes ...', '']) + let cnts = [0, 0] + let bar = '' + let total = filter(copy(g:plugs), 's:is_managed(v:key) && isdirectory(v:val.dir)') + call s:progress_bar(2, bar, len(total)) + for origin in [1, 0] + let plugs = reverse(sort(items(filter(copy(total), (origin ? '' : '!').'(has_key(v:val, "commit") || has_key(v:val, "tag"))')))) + if empty(plugs) + continue + endif + call s:append_ul(2, origin ? 'Pending updates:' : 'Last update:') + for [k, v] in plugs + let range = origin ? '..origin/'.v.branch : 'HEAD@{1}..' + let cmd = 'git log --graph --color=never ' + \ . (s:git_version_requirement(2, 10, 0) ? '--no-show-signature ' : '') + \ . join(map(['--pretty=format:%x01%h%x01%d%x01%s%x01%cr', range], 'plug#shellescape(v:val)')) + if has_key(v, 'rtp') + let cmd .= ' -- '.plug#shellescape(v.rtp) + endif + let diff = s:system_chomp(cmd, v.dir) + if !empty(diff) + let ref = has_key(v, 'tag') ? (' (tag: '.v.tag.')') : has_key(v, 'commit') ? (' '.v.commit) : '' + call append(5, extend(['', '- '.k.':'.ref], map(s:lines(diff), 's:format_git_log(v:val)'))) + let cnts[origin] += 1 + endif + let bar .= '=' + call s:progress_bar(2, bar, len(total)) + normal! 2G + redraw + endfor + if !cnts[origin] + call append(5, ['', 'N/A']) + endif + endfor + call setline(1, printf('%d plugin(s) updated.', cnts[0]) + \ . (cnts[1] ? printf(' %d plugin(s) have pending updates.', cnts[1]) : '')) + + if cnts[0] || cnts[1] + nnoremap <silent> <buffer> <plug>(plug-preview) :silent! call <SID>preview_commit()<cr> + if empty(maparg("\<cr>", 'n')) + nmap <buffer> <cr> <plug>(plug-preview) + endif + if empty(maparg('o', 'n')) + nmap <buffer> o <plug>(plug-preview) + endif + endif + if cnts[0] + nnoremap <silent> <buffer> X :call <SID>revert()<cr> + echo "Press 'X' on each block to revert the update" + endif + normal! gg + setlocal nomodifiable +endfunction + +function! s:revert() + if search('^Pending updates', 'bnW') + return + endif + + let name = s:find_name(line('.')) + if empty(name) || !has_key(g:plugs, name) || + \ input(printf('Revert the update of %s? (y/N) ', name)) !~? '^y' + return + endif + + call s:system('git reset --hard HEAD@{1} && git checkout '.plug#shellescape(g:plugs[name].branch).' --', g:plugs[name].dir) + setlocal modifiable + normal! "_dap + setlocal nomodifiable + echo 'Reverted' +endfunction + +function! s:snapshot(force, ...) abort + call s:prepare() + setf vim + call append(0, ['" Generated by vim-plug', + \ '" '.strftime("%c"), + \ '" :source this file in vim to restore the snapshot', + \ '" or execute: vim -S snapshot.vim', + \ '', '', 'PlugUpdate!']) + 1 + let anchor = line('$') - 3 + let names = sort(keys(filter(copy(g:plugs), + \'has_key(v:val, "uri") && !has_key(v:val, "commit") && isdirectory(v:val.dir)'))) + for name in reverse(names) + let sha = s:system_chomp('git rev-parse --short HEAD', g:plugs[name].dir) + if !empty(sha) + call append(anchor, printf("silent! let g:plugs['%s'].commit = '%s'", name, sha)) + redraw + endif + endfor + + if a:0 > 0 + let fn = s:plug_expand(a:1) + if filereadable(fn) && !(a:force || s:ask(a:1.' already exists. Overwrite?')) + return + endif + call writefile(getline(1, '$'), fn) + echo 'Saved as '.a:1 + silent execute 'e' s:esc(fn) + setf vim + endif +endfunction + +function! s:split_rtp() + return split(&rtp, '\\\@<!,') +endfunction + +let s:first_rtp = s:escrtp(get(s:split_rtp(), 0, '')) +let s:last_rtp = s:escrtp(get(s:split_rtp(), -1, '')) + +if exists('g:plugs') + let g:plugs_order = get(g:, 'plugs_order', keys(g:plugs)) + call s:upgrade_specs() + call s:define_commands() +endif + +let &cpo = s:cpo_save +unlet s:cpo_save diff --git a/.config/nvim/coc-settings.json b/.config/nvim/coc-settings.json new file mode 100644 index 0000000..1a58556 --- /dev/null +++ b/.config/nvim/coc-settings.json @@ -0,0 +1,3 @@ +{ + "clangd.path": "/home/loek/.config/coc/extensions/coc-clangd-data/install/10.0.0/clangd_10.0.0/bin/clangd" +} diff --git a/.config/nvim/ftplugin/tex.vim b/.config/nvim/ftplugin/tex.vim new file mode 100644 index 0000000..1c78d4b --- /dev/null +++ b/.config/nvim/ftplugin/tex.vim @@ -0,0 +1,4 @@ +setlocal cc=86 +setlocal textwidth=85 +noremap \b c\begin{<C-R>"}<CR>\end{<C-R>"} + diff --git a/.config/nvim/init.vim b/.config/nvim/init.vim new file mode 100644 index 0000000..bd53196 --- /dev/null +++ b/.config/nvim/init.vim @@ -0,0 +1,246 @@ +let mapleader = " " +set number relativenumber +set tabstop=4 +set wrap +set ai +set shiftwidth=4 +set termguicolors +set shortmess=I +set splitbelow splitright +set noshowmode +set ignorecase +set smartcase +set timeoutlen=500 +set conceallevel=0 +set mouse=a +set linebreak " set wrap but don't wrap inside words +set viminfo+='1000,n/home/loek/.local/nvim/viminfo +let g:sneak#label = 1 +let g:which_key_map = {} +let g:airline_powerline_fonts = 1 +let g:minimap_highlight='Visual' +hi! link CocFloating SneakScope +cabbrev help tab help + +if ! filereadable(expand('~/.config/nvim/autoload/plug.vim')) + echo "Downloading junegunn/vim-plug to manage plugins..." + silent !mkdir -p ~/.config/nvim/autoload/ + silent !curl "https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim" > ~/.config/nvim/autoload/plug.vim + autocmd VimEnter * PlugInstall +endif + +" plugged +call plug#begin('~/.config/nvim/plugged') +" quality of life +Plug 'jiangmiao/auto-pairs' +Plug 'tpope/vim-surround' +Plug 'Chiel92/vim-autoformat' +Plug 'itchyny/lightline.vim' +Plug 'terryma/vim-multiple-cursors' +" Plug 'ap/vim-css-color' " color name highlighter +Plug 'vim-scripts/colorizer' " better highlighter? +Plug 'aurieh/discord.nvim', { 'do': ':UpdateRemotePlugins'} +Plug 'AndrewRadev/tagalong.vim' +Plug 'tpope/vim-commentary' +Plug 'liuchengxu/vim-which-key' +Plug 'justinmk/vim-sneak' +Plug 'jbgutierrez/vim-better-comments' +Plug 'junegunn/goyo.vim' +Plug 'othree/eregex.vim' +Plug 'psliwka/vim-smoothie' + +" language plugins +Plug 'lervag/vimtex' +Plug 'pangloss/vim-javascript' +Plug 'hail2u/vim-css3-syntax' +Plug 'octol/vim-cpp-enhanced-highlight' +Plug 'vim-scripts/c.vim' + +" 'vim=ide' +Plug 'neoclide/coc.nvim', {'branch': 'release'} +Plug 'ryanoasis/vim-devicons' "Icons for filetypes +Plug 'junegunn/fzf.vim' +Plug '/usr/local/opt/fzf' + +" themes +Plug 'arzg/vim-colors-xcode' +Plug 'sainnhe/sonokai' +Plug 'bluz71/vim-nightfly-guicolors' +Plug 'Mcmartelle/vim-monokai-bold' +Plug 'ntk148v/vim-horizon' +Plug 'NLKNguyen/papercolor-theme' +Plug 'scheakur/vim-scheakur' +Plug 'mkarmona/materialbox' +Plug 'morhetz/gruvbox' +call plug#end() + +" keybinds +tnoremap <Esc> <C-\><C-n> + +nnoremap tn :tabnext<CR> +nnoremap tp :tabprevious<CR> +nnoremap tt :tabnew<CR> + +nmap <CR> o<Esc> + +nnoremap <A-j> :m +1<CR> +nnoremap <A-k> :m -2<CR> + +" leader keybindings +nnoremap <silent> <leader> :WhichKey '<space>'<CR> + +map <leader>p "+p +map <leader>y "+y +let g:which_key_map.p = 'x11-paste' +let g:which_key_map.y = 'x11-yank' + +map <leader>h :noh<cr> +let g:which_key_map.h = 'no-highlighting' + +map <leader>b :Autoformat<cr> +let g:which_key_map.b = 'format-file' + +map <leader>w /\s\+$<CR> +let g:which_key_map.w = 'trailing-whitespace' + +map <leader>dv :!opout <c-r>%<cr><cr> +map <leader>dc :w! <bar> !compiler <c-r>%<cr> +let g:which_key_map.d = { + \ 'name': '+document', + \ 'v': 'view', + \ 'c': 'compile' + \ } + +map <leader>ts :sp term://zsh<cr>i +map <leader>tv :vsp term://zsh<cr>i +map <leader>tt :tabnew term://zsh<cr>i +let g:which_key_map.t = { + \ 'name': '+term', + \ 's': 'split', + \ 'v': 'vsplit', + \ 't': 'tab' + \ } + +map <leader>.v :tabnew ~/.config/nvim/init.vim<cr> + +map <leader>.c :tabnew ~/.config/picom.conf<cr> +map <leader>.z :tabnew ~/.zshrc<cr> +map <leader>.i :tabnew ~/.config/i3/config<cr> +map <leader>.p :tabnew ~/.config/polybar/config.ini<cr> +let g:which_key_map['.'] = { + \ 'name': '+config', + \ 'v': 'vim', + \ 'z': 'zsh', + \ 'i': 'i3', + \ 'c': 'picom', + \ 'p': 'polybar' + \ } + +colorscheme xcodedark +let g:lightline = { + \ 'colorscheme': 'pywal', + \ 'separator': { 'left': '', 'right': '' }, + \ 'mode_map': { + \ 'n' : 'NORM', + \ 'i' : 'INS', + \ 'R' : 'REP', + \ 'v' : 'VIS', + \ 'V' : 'V-L', + \ "\<C-v>": 'V-B', + \ 'c' : 'CMD', + \ 's' : 'SEL', + \ 'S' : 'S-L', + \ "\<C-s>": 'S-B', + \ 't': 'TERM' + \ }, + \ 'active': { + \ 'left': [ + \ [ 'mode', 'paste' ], + \ [ 'readonly', 'filename', 'modified'] + \ ], + \ 'right': [ + \ [ 'lineinfo' ], + \ [ 'filetype' ] + \ ] + \ }, + \ } +source $HOME/.config/nvim/pywal/pywal.vim + +" vimtex config +let g:tex_flavor = 'latex' +let g:vimtex_compiler_latexmk = { + \ 'backend' : 'nvim', + \ 'background' : 1, + \ 'build_dir' : '', + \ 'callback' : 1, + \ 'continuous' : 1, + \ 'executable' : 'latexmk', + \ 'engine' : 'xelatex', + \ 'hooks' : [], + \ 'options' : [ + \ '-xelatex', + \ '-file-line-error', + \ '-synctex=1', + \ '-interaction=nonstopmode', + \ ], + \} + +" auto start compilation (!not tested!) +augroup vimtex_config + autocmd User VimtexEventInitPost silent VimtexCompile +augroup END +" TeX quotes +autocmd FileType tex let b:surround_{char2nr("q")} = "`\r'" +autocmd FileType tex let b:surround_{char2nr('Q')} = "``\r''" + +" coc.vim <tab> completion and <cr> stuffs +inoremap <silent><expr> <TAB> + \ pumvisible() ? "\<C-n>" : + \ <SID>check_back_space() ? "\<TAB>" : + \ coc#refresh() +inoremap <expr><S-TAB> pumvisible() ? "\<C-p>" : "\<C-h>" + +function! s:check_back_space() abort + let col = col('.') - 1 + return !col || getline('.')[col - 1] =~# '\s' +endfunction + +if has('patch8.1.1068') + " Use `complete_info` if your (Neo)Vim version supports it. + inoremap <expr> <cr> complete_info()["selected"] != "-1" ? "\<C-y>" : "\<C-g>u\<CR>" +else + imap <expr> <cr> pumvisible() ? "\<C-y>" : "\<C-g>u\<CR>" +endif + +" coc code navigation +map <silent> <leader>cd <Plug>(coc-definition) +map <silent> <leader>cy <Plug>(coc-type-definition) +map <silent> <leader>ci <Plug>(coc-implementation) +map <silent> <leader>cr <Plug>(coc-references) +map <leader>cn <Plug>(coc-rename) +let g:which_key_map.c = { + \ 'name': '+coc', + \ 'd': 'definition', + \ 'y': 'type-definition', + \ 'i': 'implementation', + \ 'r': 'references', + \ 'n': 'rename' + \ } + +" use <c-space>for trigger completion +inoremap <silent><expr> <c-space> coc#refresh() + +" auto-comment uit +autocmd FileType * setlocal formatoptions-=c formatoptions-=r formatoptions-=o + +" which key register dict +call which_key#register('<Space>', "g:which_key_map") + +" no line numbers in terminal +augroup TerminalStuff + " Clear old autocommands + au! + autocmd TermOpen * setlocal nonumber norelativenumber +augroup END + + diff --git a/.config/nvim/links.sh b/.config/nvim/links.sh new file mode 100644 index 0000000..0bdeb1b --- /dev/null +++ b/.config/nvim/links.sh @@ -0,0 +1,9 @@ +# https://simplyian.com/2014/04/28/how-to-have-language-specific-settings-in-vim/ +# https://vimawesome.com/ +# https://github.com/LukeSmithxyz/voidrice/blob/master/.config/nvim/init.vim +# https://github.com/neoclide/coc.nvim +# https://github.com/jiangmiao/auto-pairs +# https://github.com/ryanoasis/vim-devicons +# https://github.com/prettier/vim-prettier +# https://github.com/DarthOstrich/dotfiles/blob/master/init.vim +# https://github.com/junegunn/vim-plug/wiki/tips#automatic-installation
\ No newline at end of file diff --git a/.config/nvim/pywal/base.vim b/.config/nvim/pywal/base.vim new file mode 100644 index 0000000..c25eede --- /dev/null +++ b/.config/nvim/pywal/base.vim @@ -0,0 +1,19 @@ +let s:p = {'normal': {}, 'inactive': {}, 'insert': {}, 'replace': {}, 'visual': {}, 'tabline': {}} +let s:p.normal.left = [ [ s:color6readable, s:color6 ], [ s:color2readable, s:color2 ] ] +let s:p.normal.right = [ [ s:color1readable, s:color1 ], [ s:color2readable, s:color2 ] ] +let s:p.inactive.right = [ [ s:color1readable, s:color1 ], [ s:color2readable, s:color2 ] ] +let s:p.inactive.left = [ [ s:color6readable, s:color6 ], [ s:color2readable, s:color2 ] ] +let s:p.insert.left = [ [ s:color5readable, s:color5 ], [ s:color2readable, s:color2 ] ] +let s:p.replace.left = [ [ s:color4readable, s:color4 ], [ s:color2readable, s:color2 ] ] +let s:p.visual.left = [ [ s:color3readable, s:color3 ], [ s:color2readable, s:color2 ] ] +let s:p.normal.middle = [ [ s:none, s:none ] ] +let s:p.inactive.middle = [ [ s:none, s:none ] ] +let s:p.tabline.left = [ [ s:fg, s:bg ] ] +let s:p.tabline.tabsel = [ [ s:fg, s:bg5 ] ] +let s:p.tabline.middle = [ [ s:none, s:none ] ] +let s:p.tabline.right = copy(s:p.normal.right) +let s:p.normal.error = [ [ s:test, s:test ] ] +let s:p.normal.warning = [ [ s:test, s:test ] ] + +let g:lightline#colorscheme#pywal#palette = lightline#colorscheme#flatten(s:p) + diff --git a/.config/nvim/pywal/colors.vim b/.config/nvim/pywal/colors.vim new file mode 100644 index 0000000..36673b5 --- /dev/null +++ b/.config/nvim/pywal/colors.vim @@ -0,0 +1,46 @@ +hi! Normal guibg=#141415 ctermbg=NONE +hi! EndOfBuffer guibg=#141415 ctermbg=NONE +hi! CocInfoFloat guibg=#28282A ctermbg=NONE + +let s:bg = [ '#141415', 'NONE' ] +let s:fg = [ '#c4c4c4', 'NONE' ] +let s:bg1 = [ '#181819', 'NONE' ] +let s:bg2 = [ '#1C1C1D', 'NONE' ] +let s:bg3 = [ '#202022', 'NONE' ] +let s:bg4 = [ '#242426', 'NONE' ] +let s:bg5 = [ '#28282A', 'NONE' ] +let s:color0 = [ '#141415', 'NONE' ] +let s:color1 = [ '#292b37', 'NONE' ] +let s:color2 = [ '#3c2a27', 'NONE' ] +let s:color3 = [ '#3b3033', 'NONE' ] +let s:color4 = [ '#3f3330', 'NONE' ] +let s:color5 = [ '#4b4240', 'NONE' ] +let s:color6 = [ '#66615a', 'NONE' ] +let s:color7 = [ '#c4c4c4', 'NONE' ] +let s:color8 = [ '#4e4e4f', 'NONE' ] +let s:color9 = [ '#292b37', 'NONE' ] +let s:color10 = [ '#3c2a27', 'NONE' ] +let s:color11 = [ '#3b3033', 'NONE' ] +let s:color12 = [ '#3f3330', 'NONE' ] +let s:color13 = [ '#4b4240', 'NONE' ] +let s:color14 = [ '#66615a', 'NONE' ] +let s:color15 = [ '#c4c4c4', 'NONE' ] +let s:color0readable = [ '#c4c4c4', 'NONE' ] +let s:color1readable = [ '#c4c4c4', 'NONE' ] +let s:color2readable = [ '#c4c4c4', 'NONE' ] +let s:color3readable = [ '#c4c4c4', 'NONE' ] +let s:color4readable = [ '#c4c4c4', 'NONE' ] +let s:color5readable = [ '#c4c4c4', 'NONE' ] +let s:color6readable = [ '#c4c4c4', 'NONE' ] +let s:color7readable = [ '#141415', 'NONE' ] +let s:color8readable = [ '#c4c4c4', 'NONE' ] +let s:color9readable = [ '#c4c4c4', 'NONE' ] +let s:color10readable = [ '#c4c4c4', 'NONE' ] +let s:color11readable = [ '#c4c4c4', 'NONE' ] +let s:color12readable = [ '#c4c4c4', 'NONE' ] +let s:color13readable = [ '#c4c4c4', 'NONE' ] +let s:color14readable = [ '#c4c4c4', 'NONE' ] +let s:color15readable = [ '#141415', 'NONE' ] +let s:none = [ 'NONE', 'NONE' ] +let s:test = [ '#ff00ff', 'NONE' ] + diff --git a/.config/nvim/pywal/pywal.vim b/.config/nvim/pywal/pywal.vim new file mode 100644 index 0000000..ba4c44e --- /dev/null +++ b/.config/nvim/pywal/pywal.vim @@ -0,0 +1,65 @@ +hi! Normal guibg=#141415 ctermbg=NONE +hi! EndOfBuffer guibg=#141415 ctermbg=NONE +hi! CocInfoFloat guibg=#28282A ctermbg=NONE + +let s:bg = [ '#141415', 'NONE' ] +let s:fg = [ '#c4c4c4', 'NONE' ] +let s:bg1 = [ '#181819', 'NONE' ] +let s:bg2 = [ '#1C1C1D', 'NONE' ] +let s:bg3 = [ '#202022', 'NONE' ] +let s:bg4 = [ '#242426', 'NONE' ] +let s:bg5 = [ '#28282A', 'NONE' ] +let s:color0 = [ '#141415', 'NONE' ] +let s:color1 = [ '#292b37', 'NONE' ] +let s:color2 = [ '#3c2a27', 'NONE' ] +let s:color3 = [ '#3b3033', 'NONE' ] +let s:color4 = [ '#3f3330', 'NONE' ] +let s:color5 = [ '#4b4240', 'NONE' ] +let s:color6 = [ '#66615a', 'NONE' ] +let s:color7 = [ '#c4c4c4', 'NONE' ] +let s:color8 = [ '#4e4e4f', 'NONE' ] +let s:color9 = [ '#292b37', 'NONE' ] +let s:color10 = [ '#3c2a27', 'NONE' ] +let s:color11 = [ '#3b3033', 'NONE' ] +let s:color12 = [ '#3f3330', 'NONE' ] +let s:color13 = [ '#4b4240', 'NONE' ] +let s:color14 = [ '#66615a', 'NONE' ] +let s:color15 = [ '#c4c4c4', 'NONE' ] +let s:color0readable = [ '#c4c4c4', 'NONE' ] +let s:color1readable = [ '#c4c4c4', 'NONE' ] +let s:color2readable = [ '#c4c4c4', 'NONE' ] +let s:color3readable = [ '#c4c4c4', 'NONE' ] +let s:color4readable = [ '#c4c4c4', 'NONE' ] +let s:color5readable = [ '#c4c4c4', 'NONE' ] +let s:color6readable = [ '#c4c4c4', 'NONE' ] +let s:color7readable = [ '#141415', 'NONE' ] +let s:color8readable = [ '#c4c4c4', 'NONE' ] +let s:color9readable = [ '#c4c4c4', 'NONE' ] +let s:color10readable = [ '#c4c4c4', 'NONE' ] +let s:color11readable = [ '#c4c4c4', 'NONE' ] +let s:color12readable = [ '#c4c4c4', 'NONE' ] +let s:color13readable = [ '#c4c4c4', 'NONE' ] +let s:color14readable = [ '#c4c4c4', 'NONE' ] +let s:color15readable = [ '#141415', 'NONE' ] +let s:none = [ 'NONE', 'NONE' ] +let s:test = [ '#ff00ff', 'NONE' ] + +let s:p = {'normal': {}, 'inactive': {}, 'insert': {}, 'replace': {}, 'visual': {}, 'tabline': {}} +let s:p.normal.left = [ [ s:color6readable, s:color6 ], [ s:color2readable, s:color2 ] ] +let s:p.normal.right = [ [ s:color1readable, s:color1 ], [ s:color2readable, s:color2 ] ] +let s:p.inactive.right = [ [ s:color1readable, s:color1 ], [ s:color2readable, s:color2 ] ] +let s:p.inactive.left = [ [ s:color6readable, s:color6 ], [ s:color2readable, s:color2 ] ] +let s:p.insert.left = [ [ s:color5readable, s:color5 ], [ s:color2readable, s:color2 ] ] +let s:p.replace.left = [ [ s:color4readable, s:color4 ], [ s:color2readable, s:color2 ] ] +let s:p.visual.left = [ [ s:color3readable, s:color3 ], [ s:color2readable, s:color2 ] ] +let s:p.normal.middle = [ [ s:none, s:none ] ] +let s:p.inactive.middle = [ [ s:none, s:none ] ] +let s:p.tabline.left = [ [ s:fg, s:bg ] ] +let s:p.tabline.tabsel = [ [ s:fg, s:bg5 ] ] +let s:p.tabline.middle = [ [ s:none, s:none ] ] +let s:p.tabline.right = copy(s:p.normal.right) +let s:p.normal.error = [ [ s:test, s:test ] ] +let s:p.normal.warning = [ [ s:test, s:test ] ] + +let g:lightline#colorscheme#pywal#palette = lightline#colorscheme#flatten(s:p) + diff --git a/.config/picom.conf b/.config/picom.conf new file mode 100644 index 0000000..67afeaa --- /dev/null +++ b/.config/picom.conf @@ -0,0 +1,70 @@ +backend = "glx"; + +fading = false; +fade-delta = 10; +fade-in-step = 0.13; +fade-out-step = 0.1; +shadow = true; +shadow-radius = 48; +shadow-opacity = 0.3; +shadow-offset-y = -48; +shadow-offset-x = -48; + +blur-kern = "3x3box"; +blur-method = "kawase"; +blur-strength = 12; + +blur-background-exclude = [ + "class_g = 'Polybar'", + "class_g = 'firefox' && !I3_FLOATING_WINDOW@:c" +] + +shadow-exclude = [ + "!I3_FLOATING_WINDOW@:c && _NET_WM_WINDOW_TYPE@:32a *= '_NET_WM_WINDOW_TYPE_NORMAL'", + "class_g = 'firefox' && !I3_FLOATING_WINDOW@:c" +] + +opacity-rule = [ + "80:class_g = 'Spotify'", + "90:class_g = 'Zathura'" +] + +wintypes: { + dock = { + shadow = false; + corner-radius = 2; + opacity = 0.999; + }; + + desktop = { + shadow = false; + }; + + tooltip = { + fade = true; + shadow = false; + opacity = 1; + }; + + menu = { + fade = false; + opacity = 0.8; + }; +}; + +# combo +# desktop +# dialog +# dnd +# dock +# dropdown_menu +# menu +# normal +# notify +# popup_menu +# splash +# toolbar +# tooltip +# unknown +# utility + diff --git a/.config/polybar/config.ini b/.config/polybar/config.ini new file mode 100644 index 0000000..a24f161 --- /dev/null +++ b/.config/polybar/config.ini @@ -0,0 +1,358 @@ +[barsettings] +padding = 1.9 + +[global/wm] +margin-bottom = 50 +margin-top = 0 + +[bar/main] + +; tray-position = right +; tray-padding = ${barsettings.padding} +; tray-background = ${color.bg} +; tray-margin = 0 + +monitor = + +monitor-fallback = + +monitor-strict = false + +override-redirect = false + +bottom = false + +fixed-center = true + +width = 100% +height = 16 + +offset-x = 0 +offset-y = 0 + +background = ${color.alpha} + +foreground = ${color.fg} + +radius-top = 0.0 +radius-bottom = 0.0 + +padding = 0 + +module-margin-left = 0 +module-margin-right = 0 + +font-0 = "Scientifica:weight=regular:size=4;2" +font-1 = "Weather Icons:antialias=false:size=6;2" +font-2 = "Siji:size=8;2" +font-3 = "Material Design Icons:antialias=false:size=8;2" +font-4 = "Fira Code:size=10;2" + +modules-center = onstart time weather date alsa + +separator = + +spacing = 0 + +dim-value = 1.0 + +wm-name = + +locale = + +wm-restack = i3 + +enable-ipc = true + +click-left = +click-middle = +click-right = +scroll-up = +scroll-down = +double-click-left = +double-click-middle = +double-click-right = + +cursor-click = +cursor-scroll = + +[settings] +throttle-output = 5 +throttle-output-for = 10 + +throttle-input-for = 30 + +screenchange-reload = false + +compositing-background = source +compositing-foreground = over +compositing-overline = over +compositing-underline = over +compositing-border = over + +format-foreground = +format-background = +format-underline = +format-overline = +format-spacing = +format-padding = +format-margin = +format-offset = + +pseudo-transparency = false + +[color] + +bg = #141415 +fg = #c4c4c4 +fg-alt = #141415 + +alpha = #00000000 + +shade1 = #3F3330 +shade2 = #4C423E +shade3 = #59514C +shade4 = #66615A + +shade-fg = #c4c4c4 + +[module/alsa] +type = internal/alsa + +format-volume = <ramp-volume> <label-volume> +format-volume-background = ${color.shade4} +format-volume-foreground = ${color.shade-fg} +format-volume-padding = ${barsettings.padding} + +label-volume = %percentage%% + +format-muted-prefix = " " +format-muted-background = ${color.shade-fg} +format-muted-foreground = ${color.shade4} +format-muted-padding = ${barsettings.padding} +label-muted = "Muted" + +ramp-volume-0 = +ramp-volume-1 = +ramp-volume-2 = + +ramp-headphones-0 = +ramp-headphones-1 = + +[module/battery] +type = internal/battery + +full-at = 99 +battery = BAT1 +adapter = ACAD +poll-interval = 2 +time-format = %H:%M + +format-charging = <animation-charging> <label-charging> +format-charging-background = ${color.shade3} +format-charging-foreground = ${color.fg-alt} +format-charging-padding = ${barsettings.padding} + +format-discharging = <ramp-capacity> <label-discharging> +format-discharging-background = ${color.shade3} +format-discharging-foreground = ${color.fg-alt} +format-discharging-padding = ${barsettings.padding} + +format-full = <label-full> +format-full-background = ${color.shade3} +format-full-foreground = ${color.fg-alt} +format-full-padding = ${barsettings.padding} + +label-charging = %percentage%% +label-discharging = %percentage%% +label-full = 100% Charged + +ramp-capacity-0 = +ramp-capacity-1 = +ramp-capacity-2 = +ramp-capacity-3 = +ramp-capacity-4 = +ramp-capacity-5 = +ramp-capacity-6 = +ramp-capacity-7 = +ramp-capacity-8 = +ramp-capacity-9 = + +animation-charging-0 = +animation-charging-1 = +animation-charging-2 = +animation-charging-3 = + +animation-charging-framerate = 750 + +[module/cpu] +type = internal/cpu + +interval = 1 + +format = <label> +format-prefix = +format-background = ${color.bg} +format-foreground = ${color.shade2} +format-padding = ${barsettings.padding} + +label = " %percentage%%" + +[module/date] +type = internal/date +interval = 1.0 +time = %A, %B %d +format = <label> +format-background = ${color.shade3} +format-foreground = ${color.shade-fg} +format-padding = ${barsettings.padding} + +label = %time% + +[module/time] +type = internal/date +interval = 1.0 +time = %H:%M +format = <label> +format-background = ${color.shade1} +format-foreground = ${color.shade-fg} +format-padding = ${barsettings.padding} + +label = %time% + +[module/memory] +type = internal/memory + +interval = 3 + +format = <label> +format-prefix = +format-background = ${color.bg} +format-foreground = ${color.shade1} +format-padding = ${barsettings.padding} + +label = " %mb_used%" + +[module/packages] +type = custom/script +exec = echo " `pacman -Q | wc -l`" +format-padding = ${barsettings.padding} +interval = 60 +format-background = ${color.bg} +format-foreground = ${color.shade3} + +[module/player-mpris-simple] +type = custom/script +exec = ~/.config/polybar/player-mpris-simple.sh +interval = 3 +format-background = ${color.bg} +format-foreground = ${color.fg} +format-padding = ${barsettings.padding} +click-middle = playerctl previous & +click-right = playerctl next & +click-left = playerctl play-pause & + +[module/weather] +type = custom/script +exec = ~/.config/polybar-forecast/target/release/polybar-forecast +interval = 120 +exec-if = ping openweathermap.org -c 1 +label-font = 2 +format-background = ${color.shade2} +format-foreground = ${color.shade-fg} +format-padding = ${barsettings.padding} + +[module/whoami] +type = custom/script +exec = echo "$(whoami)@$(hostname)" +interval = 9999999 +label-font = 2 +format-background = ${color.shade1} +format-foreground = ${color.fg} +format-padding = ${barsettings.padding} + +[module/intip] +type = custom/script +exec = echo "$(ifconfig | grep -Po --color=never '(?<=inet addr:)(192\.\d+.\d+\.\d+)')" +interval = 9999999 +label-font = 2 +format-background = ${color.shade3} +format-foreground = ${color.fg-alt} +format-padding = ${barsettings.padding} +[module/extip] +type = custom/script +exec = echo "$(curl -s ifconfig.me)" +interval = 9999999 +label-font = 2 +format-background = ${color.shade3} +format-foreground = ${color.fg-alt} +format-padding = ${barsettings.padding} + +[module/network] +type = internal/network +interface = wlan0 + +interval = 1.0 +accumulate-stats = true +unknown-as-up = true + +format-connected = <ramp-signal> <label-connected> +format-connected-background = ${color.shade2} +format-connected-foreground = ${color.fg-alt} +format-connected-padding = ${barsettings.padding} + +format-disconnected = <label-disconnected> +format-disconnected-background = ${color.shade2} +format-disconnected-foreground = ${color.fg-alt} +format-disconnected-padding = ${barsettings.padding} + +label-connected = %essid% +label-disconnected = Disconnected + +ramp-signal-0 = +ramp-signal-1 = +ramp-signal-2 = +ramp-signal-3 = +ramp-signal-4 = + +; [module/i3] +; type = internal/xworkspaces + +; pin-workspaces = true + +; enable-click = true +; enable-scroll = true + +; format = <label-state> +; format-padding = 0 + +; label-monitor = %name% + +; label-active = %name% +; label-active-foreground = ${color.bg} +; label-active-background = ${color.shade5} + +; label-occupied = %icon% +; label-occupied-underline = ${color.bg} + +; label-urgent = %icon% +; label-urgent-foreground = ${color.fg} +; label-urgent-background = ${color.bg} + +; label-empty = %name% +; label-empty-background = ${color.bg} +; label-empty-foreground = ${color.fg} + +; label-active-padding = ${barsettings.padding} +; label-urgent-padding = ${barsettings.padding} +; label-occupied-padding = ${barsettings.padding} +; label-empty-padding = ${barsettings.padding} + +[module/onstart] +type = custom/script +exec = sh ~/.config/polybar/onstart.sh > /dev/null +interval = 999999999 +format-background = ${color.alpha} +format-foreground = #ff00ff +format-padding = 0 + diff --git a/.config/polybar/onstart.sh b/.config/polybar/onstart.sh new file mode 100644 index 0000000..033cec0 --- /dev/null +++ b/.config/polybar/onstart.sh @@ -0,0 +1,3 @@ +# Tray below bar :( +sleep 1 +xdo raise -n Polybar -n tray diff --git a/.config/polybar/player-mpris-simple.sh b/.config/polybar/player-mpris-simple.sh new file mode 100755 index 0000000..938ac21 --- /dev/null +++ b/.config/polybar/player-mpris-simple.sh @@ -0,0 +1,9 @@ +#!/bin/sh + +player_status=$(playerctl status 2> /dev/null) + +if [ "$player_status" = "Playing" ] || [ "$player_status" = "Paused" ]; then + echo "$(playerctl metadata artist) - $(playerctl metadata title)" | awk -v len=60 '{ if (length($0) > len) print substr($0, 1, len-3) "..."; else print; }' +else + echo "" +fi diff --git a/.config/rofi/config b/.config/rofi/config new file mode 100644 index 0000000..9aa0c48 --- /dev/null +++ b/.config/rofi/config @@ -0,0 +1,17 @@ +rofi.show-icons: false +rofi.modi: drun,run,window,ssh +rofi.lines: 7 +rofi.line-padding: 10 +rofi.matching: fuzzy +rofi.bw: 0 +rofi.padding: 0 +rofi.separator-style: none +rofi.hide-scrollbar: true +rofi.line-margin: 0 +rofi.font: sans-serif 10 +rofi.theme: /home/loek/.config/rofi/pywal.rasi +rofi.kb-row-up: Up,Control+k,Shift+Tab,Shift+ISO_Left_Tab +rofi.kb-row-down: Down,Control+j +rofi.kb-accept-entry: Control+m,Return,KP_Enter +rofi.kb-remove-to-eol: Control+Shift+e + diff --git a/.config/rofi/pywal.rasi b/.config/rofi/pywal.rasi new file mode 100644 index 0000000..7297da0 --- /dev/null +++ b/.config/rofi/pywal.rasi @@ -0,0 +1,40 @@ +* { + background-color: #14141533; + text-color: #c4c4c4; + spacing: 0; + width: 720px; +} + +inputbar { + border: 0 0 1px 0; + children: [prompt, entry]; +} + +prompt { + padding: 16px; +} + +textbox { + background-color: #141415; + border-color: #141415; + padding: 8px 16px; +} + +entry { + padding: 16px; +} + +listview { + cycle: false; + margin: 0 0 -1px 0; + scrollbar: false; +} + +element { + padding: 16px; +} + +element selected { + background-color: #66615a; + text-color: #c4c4c4; +}
\ No newline at end of file diff --git a/.config/spicetify/Themes/Loekaars/README.md b/.config/spicetify/Themes/Loekaars/README.md new file mode 100644 index 0000000..c96cdc3 --- /dev/null +++ b/.config/spicetify/Themes/Loekaars/README.md @@ -0,0 +1,11 @@ +# Black + +## Screenshots + +![Screenshot](https://i.imgur.com/HjK3Gab.png) + +## Downloads and Info + +[color.ini](https://raw.githubusercontent.com/lollilol/spicetify-themes/master/Black/color.ini) [user.css](https://raw.githubusercontent.com/lollilol/spicetify-themes/master/Black/user.css) + +Inspired by [Dark](https://github.com/morpheusthewhite/spicetify-themes/tree/master/Dark) diff --git a/.config/spicetify/Themes/Loekaars/color.ini b/.config/spicetify/Themes/Loekaars/color.ini new file mode 100644 index 0000000..92b942e --- /dev/null +++ b/.config/spicetify/Themes/Loekaars/color.ini @@ -0,0 +1,18 @@ +[Base] +Base=object Object] +main_fg=c4c4c4 +secondary_fg=B0B0B0 +main_bg=141415 +sidebar_and_player_bg=141415 +cover_overlay_and_shadow=141415 +indicator_fg_and_button_bg=66615a +pressing_fg=66615a +slider_bg=1F2024 +sidebar_indicator_and_hover_button_bg=66615a +scrollbar_fg_and_selected_row_bg=1D1E21 +pressing_button_fg=c4c4c4 +pressing_button_bg=222227 +selected_button=66615a +miscellaneous_bg=1D1E21 +miscellaneous_hover_bg=66615a +preserve_1=c4c4c4 diff --git a/.config/spicetify/Themes/Loekaars/user.css b/.config/spicetify/Themes/Loekaars/user.css new file mode 100644 index 0000000..6639898 --- /dev/null +++ b/.config/spicetify/Themes/Loekaars/user.css @@ -0,0 +1,630 @@ +:root { + --bar-height: 90px; +} +.sidebar { +--left-sidebar-item-height: 29px !important; +} +.resizer-right { + background-color: #000; +} + +body { + font-family: 'Product Sans'; +} + +/* Hide Ad banner */ +#view-leaderboard-ad { + display: none; +} + +/*Round corner cover image*/ +.card-image, +.card-placeholder-wrapper, +.card-image-content-wrapper, +.Card:not(.Card--artist) .Card__image, +.Card:not(.Card--artist) .Card__image-wrapper { + border-radius: 10px !important; + overflow: hidden !important +} + +/*Hide some annoying elements like profile name and pic, upgrade button and device connect bar at bottom, new playlist button*/ +.profile.content-top-bar__profile-link, +.upgrade-button, +.view-player .remote-playback-bar, +.LeftSidebarNewPlaylistButton__button { + display: none !important; +} + + +/*Exclude these elements from draggable property because it stops them from clickable*/ +.profile-items-container, +.profile { + -webkit-app-region: no-drag !important; +} + +/*Thinner scrollbar*/ +::-webkit-scrollbar { + height: 6px !important; + width: 6px !important; + background-color: transparent; +} + +/*Round corner scrollbar*/ +::-webkit-scrollbar-thumb { + border-radius: 3px !important; +} + +/*Hide top and bottom buttons of scrollbar */ +/*who uses those, lol*/ +::-webkit-scrollbar-button { + display: none !important; +} + +/*Hide cover image overlay*/ +.card-overlay { + visibility: hidden !important; +} + +.card-image-hit-area .card-button-add, +.card-image-hit-area .card-button-play, +.card-image-hit-area .card-button-more, +.Card__image-hit-area .card-button-add, +.Card__image-hit-area .card-button-play, +.Card__image-hit-area .card-button-more, +.Card__image-hit-area .Card__play-button, +.Card__image-hit-area .Card__add-button, +.Card__image-hit-area .Card__more-button, +.Card__image-hit-area .Card__overlay { + transition-property: all !important; + transition-duration: 0.3s !important; + transition-timing-function: cubic-bezier(.3,0,0,1) !important; + opacity: 1 !important; +} + +.glue-page-header__content .glue-page-header__image-inner { + border-radius: 10px; + box-shadow: unset !important; +} + +.glue-page-header__full-description-overlay { + box-shadow: unset !important; +} + +.card-placeholder-wrapper { + background: transparent !important; +} + +/*Spice up search input background*/ +.SearchInput { + color: var(--modspotify_main_fg); +} +.SearchInput__input { + color: var(--modspotify_secondary_fg); + background-color: var(--modspotify_slider_bg) !important; + border-radius: 4px !important; + padding-left: 34px; +} + +.sidebar:hover .sidebar-navbar.sidebar-scroll-element { + opacity: 0.4!important; +} + +.view-player .player-controls-container, +.view-player .player-controls-container .controls { + overflow: visible !important; +} + +.view-player .player-controls-container .controls .button-play{ + height:50px !important; + border-radius:50px !important; + background-color: var(--modspotify_slider_bg) !important; + box-shadow:0 0 0 0 !important; + width:50px !important; + overflow: visible !important; + box-shadow: 0 4px 15px rgba(0,0,0,0.2) !important; + transition:none 0.3s cubic-bezier(.3,0,.7,1); +} + +.view-player .player-controls-container .controls .button-play:before{ + font-size:18px !important; + padding-left: 16px !important; + padding-top: 9px !important; +} + +.view-player .player-controls-container .controls .button-play:after { + box-shadow: unset !important; +} + +.view-player .player-controls-container { + position: absolute !important; + width: 100% !important; +} + +.view-player .player-controls-container .controls { + width: 100% !important; + height: 100% !important; + align-items: center !important; + margin-top : 0px !important; +} + +/* Add round corner for Gerne and Mood cards */ +.gc-image-container, +.gc-image { + border-radius: 10px !important; +} + +/* +Collage of 3 album covers is usually seen in Browse and Chart. +*/ +.card-puff__image-wrapper, +.card-puff__info-container, +.card-puff__card-image { + border-radius: 10px !important; +} + +.card-puff__image-wrapper { + overflow: visible; +} + +.card-puff__card-image { + box-shadow: 5px 0 30px rgba(0,0,0,0.7); + overflow: visible; +} + +.card-puff__title-container { + background-color: transparent !important; +} + +.card-puff.pressed .card-puff__image-wrapper, +.card-puff.pressed .card-puff__info-container { + opacity: 0.7 !important; +} + +.card-puff__title { + padding: 5px 10px 5px 10px !important; + background-color: var(--modspotify_main_bg) !important; + border-radius: 4px; + border: 2px solid var(--modspotify_main_fg); +} + +/* +We use round corner on cover so they look weird in original +form, so I move last cover to the right 20px and first one to the left 20px +*/ +.card-puff__card-image:nth-child(1) { + right: 20px; + box-shadow: 0 0 0 0 !important; +} + +.card-puff__card-image:nth-child(3) { + left: 20px; +} + +.grid-overlay-label { + top: 140px !important; +} + +/**/ +.glue-page-header__background-color { + background-image: none !important; + background: var(--modspotify_main_bg); +} + +/* .glue-page-header__sticky { + padding-top: 60px !important; +} */ + +/* +Remove those title, cringy description and +meaningless followers number +*/ + +.carousel .card-info-subtitle-description, +.carousel .card-info-subtitle-metadata, +.carousel .card:not(.card-type-station).card-info-title, +.carousel .card.card-type-playlist.image-loaded .Card__info-subtitle-description, +.carousel .card.card-type-playlist.image-loaded .Card__info-subtitle-metadata { + display: none !important; +} + + +/* +In top of Browse usually has bunch of Playlist or Album cards, +and they has .carousel as a wrapper and it hides anything that +overflows from its zone, aka our shadow and lifting animation. +*/ +.carousel { + overflow: visible !important; +} + +/* +Button with text Play +*/ +.button.button-green, +.GlueButton.GlueButton--style-green { + color: var(--modspotify_main_fg) !important; +} + +/* +Change text color in playlist +*/ +.tl-explicit .label, +.tl-premium .label, +.tl-cell:not(.tl-number), +.tl-cell a:link, +.tl-highlight { + color: var(--modspotify_secondary_fg); +} + +.card-type-album .card-info-title, +.card-type-track .card-info-title, +.card-type-collection-album .card-info-title, +.card-type-episode .card-info-title { + font-size: 15px; + font-weight: 900 !important; + text-align: center !important; + width: 100% !important; +} + +.card-type-album .card-info-subtitle-links, +.card-type-track .card-info-subtitle-links, +.card-type-collection-album .card-info-subtitle-links, +.card-type-episode .card-info-subtitle-links { + text-align: center !important; + width: 100% !important; +} + +.tracklist-station-container::after { + background: transparent !important; +} + +.GlueHeader__background-overlay { + background: var(--modspotify_main_bg) !important; +} + +/* Move navigation buttons and search field to the right and down */ +.browser-navigation-top-bar { + margin-left: 40px !important; + margin-top: 15px !important; +} + +.SearchInput__input, +.SearchInput__searchIcon, +.SearchInput__clearButton { + margin-top: 15px !important; +} + +.content-top-bar__profile-menu-button { + margin-top: 15px !important; +} + +.body-container--windows:not(.with-buddy-list):not(.messagebar) .content-top-bar__profile { + margin-right: 110px !important; + margin-top: -5px; +} + +/* Spice up Fullscreen mode */ +#view-player .album-art .album-art__image { + border-radius: 30px !important; + box-shadow: 0 10px 70px rgba(var(--modspotify_rgb_cover_overlay_and_shadow),.5) !important; +} + +#view-player .album-art .album-art__image .card-image-content-wrapper, +#view-player .album-art .album-art__image .card-image-content-wrapper .card-image { + border-radius: 30px !important; +} + +#video-player .album-art__foreground { + flex-direction: row; + text-align: left; +} + +#video-player .album-art__background { + background-color: initial; +} + +#video-player .album-art__track-details { + padding-left: 50px; + line-height: initial; +} + +#video-player .album-art__track-title { + font-size: 84px; + margin-top: 0; + line-height: initial; +} + +#video-player .album-art__artist-name { + font-size: 54px; + margin-top: 0; + line-height: initial; +} + +/* Daily mixes */ +.carousel .card-info-wrapper.card-info-with-description.card-info-with-metadata { + height: 50px !important; +} + +/* Remove section divider */ +.section-divider { + border-bottom: 0 !important; +} + +/* Adjust Position of border active tab in Nav bar at top +and add little glowing effect +*/ +.nav.navbar-nav { + overflow: hidden !important; +} + +.nav.navbar-nav a { + overflow: visible !important; +} + +.nav.navbar-nav a::after { + bottom: 0px !important; + width: 100% !important; +} + +.nav.navbar-nav a:focus:not(.button):active::after{ + background-color: var(--modspotify_pressing_fg) !important; +} + +/* Notification bar */ +#content-wrapper #view-message-bar { + position: absolute !important; + width: calc(100% - 160px) !important; + margin-left: 80px !important; + border-radius: 0 0 10px 10px !important; +} + +/* Small cover Big cover mechanism */ +.now-playing.cover-size-transition.active.image-expanded #now-playing-image-small { + display: none; +} + +.now-playing.cover-size-transition.active.image-expanded .cover-image-link-wrapper { + flex: 0 1 10px; +} + +#view-now-playing a.image { + overflow: visible !important; +} + +/* Profile arrow in top left */ +.content-top-bar__profile-menu-button .dropdown { + position: fixed !important; + top: 10px !important; + -webkit-app-region: no-drag !important; +} + +/* [WINDOWS] Change Profile menu horizontal position */ +body.body-container--windows .content-top-bar__profile-menu-button .dropdown { + right: 190px !important; +} + +body:not(.body-container--windows) .content-top-bar__profile-menu-button .dropdown { + right: 20px !important; +} + +/* Small tooltip */ +#tooltip { + box-shadow: 0 0 10px rgba(0,0,0,0.2) !important; + border-radius: 5px !important; + border: 2px solid var(--modspotify_main_fg); + padding: 10px 10px; +} + +.tooltip-arrow-top, .tooltip-arrow-bottom { + display: none !important; +} + +.lyrics-lines-container, +.message-container { + color: var(--modspotify_main_fg) !important; +} + +/* Home page */ +.GlueCarousel__grid-wrapper::-webkit-scrollbar-thumb { + display: none; +} + +.GlueCard__info-wrapper, +.Card__info-wrapper { + margin-bottom: 30px; +} + +.card-horizontal-interior-wrapper .card-info- { + text-align: start !important; +} + +.tl-row.selected:hover .tl-cell { + background: var(--modspotify_scrollbar_fg_and_selected_row_bg) !important; +} + +.GlueTableRow--is-selected { + background-color: var(--modspotify_scrollbar_fg_and_selected_row_bg) !important; +} + +.tracklist-podcast .tl-progress .row-progress__bar { + background-color: var(--modspotify_main_fg); +} + +.Header__background-color{ + background-color: var(--modspotify_main_bg) !important; +} + +.Button--style-green, +.button.button-green, .button.button-white { + /* border-radius: 4px; */ + color: var(--modspotify_main_fg) !important; +} + +.glue-page-header:not(.glue-page-header--album):not(.glue-page-header--playlist):not(.glue-page-header--artist):not(.glue-page-header--dailymix):not(.glue-page-header--user):not(.glue-page-header--show) + .glue-page-header__content-inner .glue-page-header__title-text, +.HomeHeader .Header__content-inner .Header__title-text-inner, +.MadeForYouHeader .Header__content-inner .Header__title-text-inner, +.RecentlyPlayedPage__header .Header__content-inner .Header__title-text-inner { + background-color: var(--modspotify_main_bg); + /* padding: 5px 20px; + border: 5px solid var(--modspotify_main_fg) !important; + border-radius: 6px; + box-shadow: 0 4px 12px 0 rgba(var(--modspotify_rgb_cover_overlay_and_shadow),.2); */ + text-transform: uppercase; +} + +.glue-page-header.glue-page-header--album .glue-page-header__content-inner .glue-page-header__title, +.glue-page-header.glue-page-header--artist .glue-page-header__content-inner .glue-page-header__title, +.glue-page-header.glue-page-header--dailymix .glue-page-header__content-inner .glue-page-header__title, +.glue-page-header.glue-page-header--playlist .glue-page-header__content-inner .glue-page-header__title { + margin-top: 10px; +} + +span.glue-page-header__title-text { + color: var(--modspotify_main_fg); +} + +.glue-page-header .glue-page-header__content-inner .glue-page-header__button { + margin-top: 40px; +} + +.glue-page-header__content-inner, +.glue-page-header__data, +.glue-page-header__title, +.Header__content-inner, +.Header__data, +.Header__title, +.Header__title-text, +.Header__title-text-inner { + overflow: visible !important; +} + +/*Force player bar to has fixed height*/ +.view-player { + height: var(--bar-height) !important; + border-top: 0; +} + +.view-player .now-playing { + overflow: unset; +} + +.view-player .cover-image-container { + position: fixed !important; + left: 0; + bottom: 0; +} + +.view-player .now-playing .cover-image-link, +.view-player .now-playing .cover-image-link figure { + width: var(--bar-height); + height: var(--bar-height); +} + +#now-playing-image-small .cover-image { + width: var(--bar-height); + height: var(--bar-height); +} + +.view-player .now-playing .cover-image-link-wrapper { + flex: 0 1 calc(var(--bar-height) + 8px); +} + +.text-container { + z-index: 3; +} + +.view-player .now-playing-container .button-add { + color: var(--modspotify_main_fg) !important; +} +/* +.progress-container .progress-bar, +.progress-container .inner { + top: 0 !important; + margin-top: 0 !important; + height: 5px; +} + +.progress-container .progress-bar-wrapper { + top: 0 !important; + height: 5px; +} +*/ +.progress-container { + /*position: fixed !important;*/ + width: 55% !important; + /*bottom: var(--bar-height) !important;*/ + /*margin : 0 !important;*/ + margin-left: auto; + margin-right: auto; +} + +.glue-page-header__p2s-details, +.glue-page-header__p2s-followers { + display: none; +} + +.context-menu { + border: none !important; + box-shadow: 0px 3px 30px -5px #0008 !important; + border-radius: 7px !important; + overflow: hidden; +} + +#menu-wrapper ::-webkit-scrollbar { + display: none; +} + +.resizer-right { + background-color: var(--modspotify_main_bg); +} + +.main-view-wrapper { + overflow: unset; +} + +.Button--style-icon-stroke:after, +.Button--style-icon-stroke:hover:after, +.Button--style-icon-stroke, +.glue-page-header__button .button-icon-with-stroke, +.glue-page-header__button .button-icon-with-stroke::after { + box-shadow: unset; +} + +.glue-page-header.glue-page-header--artist .glue-page-header__label { + padding-top: 10px; +} + +.glue-page-header.glue-page-header--artist.has-custom-image .glue-page-header__label { + padding-top: 8px; +} + +.glue-page-header__content .glue-page-header__label { + margin-left: -2px; + z-index: 2; +} + +/* .glue-page-header__label span, +.Header__label span { + background-color: var(--modspotify_main_fg); + color: var(--modspotify_main_bg); + padding: 2px 10px; +} */ + +.glue-page-header__label .header-verified-check { + background-color: transparent; +} + +body.remotebar .view-player .player-bar-wrapper { + height: 100%; +} + + +.Header__image-inner { + box-shadow: unset; +} + +.Button:not(.Button--style-stroke) * , +.button:not(.button-with-stroke) * { + color: var(--modspotify_main_bg) !important; +}
\ No newline at end of file diff --git a/.config/spicetify/config.ini b/.config/spicetify/config.ini new file mode 100644 index 0000000..c554077 --- /dev/null +++ b/.config/spicetify/config.ini @@ -0,0 +1,36 @@ +[AdditionalOptions] +made_for_you_hub = 0 +song_page = 0 +extensions = +fastUser_switching = 0 +lyric_force_no_sync = 0 +new_feedback_ui = 0 +search_in_sidebar = 0 +custom_apps = +home = 0 +radio = 0 +tastebuds = 0 +visualization_high_framerate = 0 +experimental_features = 0 +lyric_always_show = 0 +minimal_ui = 0 + +[Setting] +replace_colors = 1 +overwrite_assets = 0 +spotify_path = /opt/spotify +prefs_path = /home/loek/.config/spotify/prefs +current_theme = Loekaars +color_scheme = +inject_css = 1 + +[Preprocesses] +remove_rtl_rule = 1 +expose_apis = 1 +disable_sentry = 1 +disable_ui_logging = 1 + +; DO NOT CHANGE! +[Backup] +version = 1.1.10.546.ge08ef575 + diff --git a/.config/startpage/index.html b/.config/startpage/index.html new file mode 100644 index 0000000..2de34cd --- /dev/null +++ b/.config/startpage/index.html @@ -0,0 +1,45 @@ +<!DOCTYPE html> +<html> +<head> + <meta charset='utf-8'> + <meta http-equiv='X-UA-Compatible' content='IE=edge'> + <title>New Tab</title> + <meta name='viewport' content='width=device-width, initial-scale=1'> + <link rel='stylesheet' type='text/css' media='screen' href='style.css'> + <script src="jquery.min.js"></script> + <script src="script.js" defer></script> +</head> +<body> + <div class="center"> + <h1 class="time"> + </h1> + + <div class="term"> + <div class="columns"> + <div class="column"> + <h3 style="color: var(--pywal-readable-color2)">school</h3> + <a href="https://www.montiplaza.nl/">montiplaza</a> + <a href="https://somtoday.nl/">somtoday</a> + <a href="https://calendar.google.com">google calendar</a> + <a href="https://client.etesync.com/pim">etesync calendar</a> + </div> + + <div class="column"> + <h3 style="color: var(--pywal-readable-color3)">social</h3> + <a href="https://www.reddit.com/new">reddit</a> + <a href="https://www.twitter.com/">twitter</a> + <a href="https://www.twitch.com/directory/following">twitch</a> + <a href="https://www.youtube.com/">youtube</a> + </div> + + <div class="column"> + <h3 style="color: var(--pywal-readable-color4)">nerd shit</h3> + <a href="https://github.com/lonkaars">github</a> + <a href="https://10fastfingers.com/typing-test/dutch">typing test</a> + <a href="https://frikandelbroodje:3000/">private git</a> + </div> + </div> + </div> + </div> +</body> +</html> diff --git a/.config/startpage/jquery.min.js b/.config/startpage/jquery.min.js new file mode 100644 index 0000000..b061403 --- /dev/null +++ b/.config/startpage/jquery.min.js @@ -0,0 +1,2 @@ +/*! jQuery v3.5.1 | (c) JS Foundation and other contributors | jquery.org/license */ +!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(C,e){"use strict";var t=[],r=Object.getPrototypeOf,s=t.slice,g=t.flat?function(e){return t.flat.call(e)}:function(e){return t.concat.apply([],e)},u=t.push,i=t.indexOf,n={},o=n.toString,v=n.hasOwnProperty,a=v.toString,l=a.call(Object),y={},m=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType},x=function(e){return null!=e&&e===e.window},E=C.document,c={type:!0,src:!0,nonce:!0,noModule:!0};function b(e,t,n){var r,i,o=(n=n||E).createElement("script");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function w(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[o.call(e)]||"object":typeof e}var f="3.5.1",S=function(e,t){return new S.fn.init(e,t)};function p(e){var t=!!e&&"length"in e&&e.length,n=w(e);return!m(e)&&!x(e)&&("array"===n||0===t||"number"==typeof t&&0<t&&t-1 in e)}S.fn=S.prototype={jquery:f,constructor:S,length:0,toArray:function(){return s.call(this)},get:function(e){return null==e?s.call(this):e<0?this[e+this.length]:this[e]},pushStack:function(e){var t=S.merge(this.constructor(),e);return t.prevObject=this,t},each:function(e){return S.each(this,e)},map:function(n){return this.pushStack(S.map(this,function(e,t){return n.call(e,t,e)}))},slice:function(){return this.pushStack(s.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},even:function(){return this.pushStack(S.grep(this,function(e,t){return(t+1)%2}))},odd:function(){return this.pushStack(S.grep(this,function(e,t){return t%2}))},eq:function(e){var t=this.length,n=+e+(e<0?t:0);return this.pushStack(0<=n&&n<t?[this[n]]:[])},end:function(){return this.prevObject||this.constructor()},push:u,sort:t.sort,splice:t.splice},S.extend=S.fn.extend=function(){var e,t,n,r,i,o,a=arguments[0]||{},s=1,u=arguments.length,l=!1;for("boolean"==typeof a&&(l=a,a=arguments[s]||{},s++),"object"==typeof a||m(a)||(a={}),s===u&&(a=this,s--);s<u;s++)if(null!=(e=arguments[s]))for(t in e)r=e[t],"__proto__"!==t&&a!==r&&(l&&r&&(S.isPlainObject(r)||(i=Array.isArray(r)))?(n=a[t],o=i&&!Array.isArray(n)?[]:i||S.isPlainObject(n)?n:{},i=!1,a[t]=S.extend(l,o,r)):void 0!==r&&(a[t]=r));return a},S.extend({expando:"jQuery"+(f+Math.random()).replace(/\D/g,""),isReady:!0,error:function(e){throw new Error(e)},noop:function(){},isPlainObject:function(e){var t,n;return!(!e||"[object Object]"!==o.call(e))&&(!(t=r(e))||"function"==typeof(n=v.call(t,"constructor")&&t.constructor)&&a.call(n)===l)},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},globalEval:function(e,t,n){b(e,{nonce:t&&t.nonce},n)},each:function(e,t){var n,r=0;if(p(e)){for(n=e.length;r<n;r++)if(!1===t.call(e[r],r,e[r]))break}else for(r in e)if(!1===t.call(e[r],r,e[r]))break;return e},makeArray:function(e,t){var n=t||[];return null!=e&&(p(Object(e))?S.merge(n,"string"==typeof e?[e]:e):u.call(n,e)),n},inArray:function(e,t,n){return null==t?-1:i.call(t,e,n)},merge:function(e,t){for(var n=+t.length,r=0,i=e.length;r<n;r++)e[i++]=t[r];return e.length=i,e},grep:function(e,t,n){for(var r=[],i=0,o=e.length,a=!n;i<o;i++)!t(e[i],i)!==a&&r.push(e[i]);return r},map:function(e,t,n){var r,i,o=0,a=[];if(p(e))for(r=e.length;o<r;o++)null!=(i=t(e[o],o,n))&&a.push(i);else for(o in e)null!=(i=t(e[o],o,n))&&a.push(i);return g(a)},guid:1,support:y}),"function"==typeof Symbol&&(S.fn[Symbol.iterator]=t[Symbol.iterator]),S.each("Boolean Number String Function Array Date RegExp Object Error Symbol".split(" "),function(e,t){n["[object "+t+"]"]=t.toLowerCase()});var d=function(n){var e,d,b,o,i,h,f,g,w,u,l,T,C,a,E,v,s,c,y,S="sizzle"+1*new Date,p=n.document,k=0,r=0,m=ue(),x=ue(),A=ue(),N=ue(),D=function(e,t){return e===t&&(l=!0),0},j={}.hasOwnProperty,t=[],q=t.pop,L=t.push,H=t.push,O=t.slice,P=function(e,t){for(var n=0,r=e.length;n<r;n++)if(e[n]===t)return n;return-1},R="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",M="[\\x20\\t\\r\\n\\f]",I="(?:\\\\[\\da-fA-F]{1,6}"+M+"?|\\\\[^\\r\\n\\f]|[\\w-]|[^\0-\\x7f])+",W="\\["+M+"*("+I+")(?:"+M+"*([*^$|!~]?=)"+M+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+I+"))|)"+M+"*\\]",F=":("+I+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+W+")*)|.*)\\)|)",B=new RegExp(M+"+","g"),$=new RegExp("^"+M+"+|((?:^|[^\\\\])(?:\\\\.)*)"+M+"+$","g"),_=new RegExp("^"+M+"*,"+M+"*"),z=new RegExp("^"+M+"*([>+~]|"+M+")"+M+"*"),U=new RegExp(M+"|>"),X=new RegExp(F),V=new RegExp("^"+I+"$"),G={ID:new RegExp("^#("+I+")"),CLASS:new RegExp("^\\.("+I+")"),TAG:new RegExp("^("+I+"|[*])"),ATTR:new RegExp("^"+W),PSEUDO:new RegExp("^"+F),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+R+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,Q=/^(?:input|select|textarea|button)$/i,J=/^h\d$/i,K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\[\\da-fA-F]{1,6}"+M+"?|\\\\([^\\r\\n\\f])","g"),ne=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){T()},ae=be(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{H.apply(t=O.call(p.childNodes),p.childNodes),t[p.childNodes.length].nodeType}catch(e){H={apply:t.length?function(e,t){L.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&(T(e),e=e||C,E)){if(11!==p&&(u=Z.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return H.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&d.getElementsByClassName&&e.getElementsByClassName)return H.apply(n,e.getElementsByClassName(i)),n}if(d.qsa&&!N[t+" "]&&(!v||!v.test(t))&&(1!==p||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&(U.test(t)||z.test(t))){(f=ee.test(t)&&ye(e.parentNode)||e)===e&&d.scope||((s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=S)),o=(l=h(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+xe(l[o]);c=l.join(",")}try{return H.apply(n,f.querySelectorAll(c)),n}catch(e){N(t,!0)}finally{s===S&&e.removeAttribute("id")}}}return g(t.replace($,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[S]=!0,e}function ce(e){var t=C.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)b.attrHandle[n[r]]=t}function pe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function de(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e.namespaceURI,n=(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},T=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:p;return r!=C&&9===r.nodeType&&r.documentElement&&(a=(C=r).documentElement,E=!i(C),p!=C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),d.scope=ce(function(e){return a.appendChild(e).appendChild(C.createElement("div")),"undefined"!=typeof e.querySelectorAll&&!e.querySelectorAll(":scope fieldset div").length}),d.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),d.getElementsByTagName=ce(function(e){return e.appendChild(C.createComment("")),!e.getElementsByTagName("*").length}),d.getElementsByClassName=K.test(C.getElementsByClassName),d.getById=ce(function(e){return a.appendChild(e).id=S,!C.getElementsByName||!C.getElementsByName(S).length}),d.getById?(b.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=d.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):d.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},b.find.CLASS=d.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){var t;a.appendChild(e).innerHTML="<a id='"+S+"'></a><select id='"+S+"-\r\\' msallowcapture=''><option selected=''></option></select>",e.querySelectorAll("[msallowcapture^='']").length&&v.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||v.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll("[id~="+S+"-]").length||v.push("~="),(t=C.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||v.push("\\["+M+"*name"+M+"*="+M+"*(?:''|\"\")"),e.querySelectorAll(":checked").length||v.push(":checked"),e.querySelectorAll("a#"+S+"+*").length||v.push(".#.+[+~]"),e.querySelectorAll("\\\f"),v.push("[\\r\\n\\f]")}),ce(function(e){e.innerHTML="<a href='' disabled='disabled'></a><select disabled='disabled'><option/></select>";var t=C.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&v.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&v.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&v.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),v.push(",.*:")})),(d.matchesSelector=K.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){d.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",F)}),v=v.length&&new RegExp(v.join("|")),s=s.length&&new RegExp(s.join("|")),t=K.test(a.compareDocumentPosition),y=t||K.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},D=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e==C||e.ownerDocument==p&&y(p,e)?-1:t==C||t.ownerDocument==p&&y(p,t)?1:u?P(u,e)-P(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e==C?-1:t==C?1:i?-1:o?1:u?P(u,e)-P(u,t):0;if(i===o)return pe(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?pe(a[r],s[r]):a[r]==p?-1:s[r]==p?1:0}),C},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if(T(e),d.matchesSelector&&E&&!N[t+" "]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){N(t,!0)}return 0<se(t,C,null,[e]).length},se.contains=function(e,t){return(e.ownerDocument||e)!=C&&T(e),y(e,t)},se.attr=function(e,t){(e.ownerDocument||e)!=C&&T(e);var n=b.attrHandle[t.toLowerCase()],r=n&&j.call(b.attrHandle,t.toLowerCase())?n(e,t,!E):void 0;return void 0!==r?r:d.attributes||!E?e.getAttribute(t):(r=e.getAttributeNode(t))&&r.specified?r.value:null},se.escape=function(e){return(e+"").replace(re,ie)},se.error=function(e){throw new Error("Syntax error, unrecognized expression: "+e)},se.uniqueSort=function(e){var t,n=[],r=0,i=0;if(l=!d.detectDuplicates,u=!d.sortStable&&e.slice(0),e.sort(D),l){while(t=e[i++])t===e[i]&&(r=n.push(i));while(r--)e.splice(n[r],1)}return u=null,e},o=se.getText=function(e){var t,n="",r=0,i=e.nodeType;if(i){if(1===i||9===i||11===i){if("string"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=o(e)}else if(3===i||4===i)return e.nodeValue}else while(t=e[r++])n+=o(t);return n},(b=se.selectors={cacheLength:50,createPseudo:le,match:G,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return G.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=m[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&m(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1<t.indexOf(i):"$="===r?i&&t.slice(-i.length)===i:"~="===r?-1<(" "+t.replace(B," ")+" ").indexOf(i):"|="===r&&(t===i||t.slice(0,i.length+1)===i+"-"))}},CHILD:function(h,e,t,g,v){var y="nth"!==h.slice(0,3),m="last"!==h.slice(-4),x="of-type"===e;return 1===g&&0===v?function(e){return!!e.parentNode}:function(e,t,n){var r,i,o,a,s,u,l=y!==m?"nextSibling":"previousSibling",c=e.parentNode,f=x&&e.nodeName.toLowerCase(),p=!n&&!x,d=!1;if(c){if(y){while(l){a=e;while(a=a[l])if(x?a.nodeName.toLowerCase()===f:1===a.nodeType)return!1;u=l="only"===h&&!u&&"nextSibling"}return!0}if(u=[m?c.firstChild:c.lastChild],m&&p){d=(s=(r=(i=(o=(a=c)[S]||(a[S]={}))[a.uniqueID]||(o[a.uniqueID]={}))[h]||[])[0]===k&&r[1])&&r[2],a=s&&c.childNodes[s];while(a=++s&&a&&a[l]||(d=s=0)||u.pop())if(1===a.nodeType&&++d&&a===e){i[h]=[k,s,d];break}}else if(p&&(d=s=(r=(i=(o=(a=e)[S]||(a[S]={}))[a.uniqueID]||(o[a.uniqueID]={}))[h]||[])[0]===k&&r[1]),!1===d)while(a=++s&&a&&a[l]||(d=s=0)||u.pop())if((x?a.nodeName.toLowerCase()===f:1===a.nodeType)&&++d&&(p&&((i=(o=a[S]||(a[S]={}))[a.uniqueID]||(o[a.uniqueID]={}))[h]=[k,d]),a===e))break;return(d-=v)===g||d%g==0&&0<=d/g}}},PSEUDO:function(e,o){var t,a=b.pseudos[e]||b.setFilters[e.toLowerCase()]||se.error("unsupported pseudo: "+e);return a[S]?a(o):1<a.length?(t=[e,e,"",o],b.setFilters.hasOwnProperty(e.toLowerCase())?le(function(e,t){var n,r=a(e,o),i=r.length;while(i--)e[n=P(e,r[i])]=!(t[n]=r[i])}):function(e){return a(e,0,t)}):a}},pseudos:{not:le(function(e){var r=[],i=[],s=f(e.replace($,"$1"));return s[S]?le(function(e,t,n,r){var i,o=s(e,null,r,[]),a=e.length;while(a--)(i=o[a])&&(e[a]=!(t[a]=i))}):function(e,t,n){return r[0]=e,s(r,null,n,i),r[0]=null,!i.pop()}}),has:le(function(t){return function(e){return 0<se(t,e).length}}),contains:le(function(t){return t=t.replace(te,ne),function(e){return-1<(e.textContent||o(e)).indexOf(t)}}),lang:le(function(n){return V.test(n||"")||se.error("unsupported lang: "+n),n=n.replace(te,ne).toLowerCase(),function(e){var t;do{if(t=E?e.lang:e.getAttribute("xml:lang")||e.getAttribute("lang"))return(t=t.toLowerCase())===n||0===t.indexOf(n+"-")}while((e=e.parentNode)&&1===e.nodeType);return!1}}),target:function(e){var t=n.location&&n.location.hash;return t&&t.slice(1)===e.id},root:function(e){return e===a},focus:function(e){return e===C.activeElement&&(!C.hasFocus||C.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:ge(!1),disabled:ge(!0),checked:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&!!e.checked||"option"===t&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,!0===e.selected},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeType<6)return!1;return!0},parent:function(e){return!b.pseudos.empty(e)},header:function(e){return J.test(e.nodeName)},input:function(e){return Q.test(e.nodeName)},button:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&"button"===e.type||"button"===t},text:function(e){var t;return"input"===e.nodeName.toLowerCase()&&"text"===e.type&&(null==(t=e.getAttribute("type"))||"text"===t.toLowerCase())},first:ve(function(){return[0]}),last:ve(function(e,t){return[t-1]}),eq:ve(function(e,t,n){return[n<0?n+t:n]}),even:ve(function(e,t){for(var n=0;n<t;n+=2)e.push(n);return e}),odd:ve(function(e,t){for(var n=1;n<t;n+=2)e.push(n);return e}),lt:ve(function(e,t,n){for(var r=n<0?n+t:t<n?t:n;0<=--r;)e.push(r);return e}),gt:ve(function(e,t,n){for(var r=n<0?n+t:n;++r<t;)e.push(r);return e})}}).pseudos.nth=b.pseudos.eq,{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})b.pseudos[e]=de(e);for(e in{submit:!0,reset:!0})b.pseudos[e]=he(e);function me(){}function xe(e){for(var t=0,n=e.length,r="";t<n;t++)r+=e[t].value;return r}function be(s,e,t){var u=e.dir,l=e.next,c=l||u,f=t&&"parentNode"===c,p=r++;return e.first?function(e,t,n){while(e=e[u])if(1===e.nodeType||f)return s(e,t,n);return!1}:function(e,t,n){var r,i,o,a=[k,p];if(n){while(e=e[u])if((1===e.nodeType||f)&&s(e,t,n))return!0}else while(e=e[u])if(1===e.nodeType||f)if(i=(o=e[S]||(e[S]={}))[e.uniqueID]||(o[e.uniqueID]={}),l&&l===e.nodeName.toLowerCase())e=e[u]||e;else{if((r=i[c])&&r[0]===k&&r[1]===p)return a[2]=r[2];if((i[c]=a)[2]=s(e,t,n))return!0}return!1}}function we(i){return 1<i.length?function(e,t,n){var r=i.length;while(r--)if(!i[r](e,t,n))return!1;return!0}:i[0]}function Te(e,t,n,r,i){for(var o,a=[],s=0,u=e.length,l=null!=t;s<u;s++)(o=e[s])&&(n&&!n(o,r,i)||(a.push(o),l&&t.push(s)));return a}function Ce(d,h,g,v,y,e){return v&&!v[S]&&(v=Ce(v)),y&&!y[S]&&(y=Ce(y,e)),le(function(e,t,n,r){var i,o,a,s=[],u=[],l=t.length,c=e||function(e,t,n){for(var r=0,i=t.length;r<i;r++)se(e,t[r],n);return n}(h||"*",n.nodeType?[n]:n,[]),f=!d||!e&&h?c:Te(c,s,d,n,r),p=g?y||(e?d:l||v)?[]:t:f;if(g&&g(f,p,n,r),v){i=Te(p,u),v(i,[],n,r),o=i.length;while(o--)(a=i[o])&&(p[u[o]]=!(f[u[o]]=a))}if(e){if(y||d){if(y){i=[],o=p.length;while(o--)(a=p[o])&&i.push(f[o]=a);y(null,p=[],i,r)}o=p.length;while(o--)(a=p[o])&&-1<(i=y?P(e,a):s[o])&&(e[i]=!(t[i]=a))}}else p=Te(p===t?p.splice(l,p.length):p),y?y(null,t,p,r):H.apply(t,p)})}function Ee(e){for(var i,t,n,r=e.length,o=b.relative[e[0].type],a=o||b.relative[" "],s=o?1:0,u=be(function(e){return e===i},a,!0),l=be(function(e){return-1<P(i,e)},a,!0),c=[function(e,t,n){var r=!o&&(n||t!==w)||((i=t).nodeType?u(e,t,n):l(e,t,n));return i=null,r}];s<r;s++)if(t=b.relative[e[s].type])c=[be(we(c),t)];else{if((t=b.filter[e[s].type].apply(null,e[s].matches))[S]){for(n=++s;n<r;n++)if(b.relative[e[n].type])break;return Ce(1<s&&we(c),1<s&&xe(e.slice(0,s-1).concat({value:" "===e[s-2].type?"*":""})).replace($,"$1"),t,s<n&&Ee(e.slice(s,n)),n<r&&Ee(e=e.slice(n)),n<r&&xe(e))}c.push(t)}return we(c)}return me.prototype=b.filters=b.pseudos,b.setFilters=new me,h=se.tokenize=function(e,t){var n,r,i,o,a,s,u,l=x[e+" "];if(l)return t?0:l.slice(0);a=e,s=[],u=b.preFilter;while(a){for(o in n&&!(r=_.exec(a))||(r&&(a=a.slice(r[0].length)||a),s.push(i=[])),n=!1,(r=z.exec(a))&&(n=r.shift(),i.push({value:n,type:r[0].replace($," ")}),a=a.slice(n.length)),b.filter)!(r=G[o].exec(a))||u[o]&&!(r=u[o](r))||(n=r.shift(),i.push({value:n,type:o,matches:r}),a=a.slice(n.length));if(!n)break}return t?a.length:a?se.error(e):x(e,s).slice(0)},f=se.compile=function(e,t){var n,v,y,m,x,r,i=[],o=[],a=A[e+" "];if(!a){t||(t=h(e)),n=t.length;while(n--)(a=Ee(t[n]))[S]?i.push(a):o.push(a);(a=A(e,(v=o,m=0<(y=i).length,x=0<v.length,r=function(e,t,n,r,i){var o,a,s,u=0,l="0",c=e&&[],f=[],p=w,d=e||x&&b.find.TAG("*",i),h=k+=null==p?1:Math.random()||.1,g=d.length;for(i&&(w=t==C||t||i);l!==g&&null!=(o=d[l]);l++){if(x&&o){a=0,t||o.ownerDocument==C||(T(o),n=!E);while(s=v[a++])if(s(o,t||C,n)){r.push(o);break}i&&(k=h)}m&&((o=!s&&o)&&u--,e&&c.push(o))}if(u+=l,m&&l!==u){a=0;while(s=y[a++])s(c,f,t,n);if(e){if(0<u)while(l--)c[l]||f[l]||(f[l]=q.call(r));f=Te(f)}H.apply(r,f),i&&!e&&0<f.length&&1<u+y.length&&se.uniqueSort(r)}return i&&(k=h,w=p),c},m?le(r):r))).selector=e}return a},g=se.select=function(e,t,n,r){var i,o,a,s,u,l="function"==typeof e&&e,c=!r&&h(e=l.selector||e);if(n=n||[],1===c.length){if(2<(o=c[0]=c[0].slice(0)).length&&"ID"===(a=o[0]).type&&9===t.nodeType&&E&&b.relative[o[1].type]){if(!(t=(b.find.ID(a.matches[0].replace(te,ne),t)||[])[0]))return n;l&&(t=t.parentNode),e=e.slice(o.shift().value.length)}i=G.needsContext.test(e)?0:o.length;while(i--){if(a=o[i],b.relative[s=a.type])break;if((u=b.find[s])&&(r=u(a.matches[0].replace(te,ne),ee.test(o[0].type)&&ye(t.parentNode)||t))){if(o.splice(i,1),!(e=r.length&&xe(o)))return H.apply(n,r),n;break}}}return(l||f(e,c))(r,t,!E,n,!t||ee.test(e)&&ye(t.parentNode)||t),n},d.sortStable=S.split("").sort(D).join("")===S,d.detectDuplicates=!!l,T(),d.sortDetached=ce(function(e){return 1&e.compareDocumentPosition(C.createElement("fieldset"))}),ce(function(e){return e.innerHTML="<a href='#'></a>","#"===e.firstChild.getAttribute("href")})||fe("type|href|height|width",function(e,t,n){if(!n)return e.getAttribute(t,"type"===t.toLowerCase()?1:2)}),d.attributes&&ce(function(e){return e.innerHTML="<input/>",e.firstChild.setAttribute("value",""),""===e.firstChild.getAttribute("value")})||fe("value",function(e,t,n){if(!n&&"input"===e.nodeName.toLowerCase())return e.defaultValue}),ce(function(e){return null==e.getAttribute("disabled")})||fe(R,function(e,t,n){var r;if(!n)return!0===e[t]?t.toLowerCase():(r=e.getAttributeNode(t))&&r.specified?r.value:null}),se}(C);S.find=d,S.expr=d.selectors,S.expr[":"]=S.expr.pseudos,S.uniqueSort=S.unique=d.uniqueSort,S.text=d.getText,S.isXMLDoc=d.isXML,S.contains=d.contains,S.escapeSelector=d.escape;var h=function(e,t,n){var r=[],i=void 0!==n;while((e=e[t])&&9!==e.nodeType)if(1===e.nodeType){if(i&&S(e).is(n))break;r.push(e)}return r},T=function(e,t){for(var n=[];e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n},k=S.expr.match.needsContext;function A(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()}var N=/^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function D(e,n,r){return m(n)?S.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?S.grep(e,function(e){return e===n!==r}):"string"!=typeof n?S.grep(e,function(e){return-1<i.call(n,e)!==r}):S.filter(n,e,r)}S.filter=function(e,t,n){var r=t[0];return n&&(e=":not("+e+")"),1===t.length&&1===r.nodeType?S.find.matchesSelector(r,e)?[r]:[]:S.find.matches(e,S.grep(t,function(e){return 1===e.nodeType}))},S.fn.extend({find:function(e){var t,n,r=this.length,i=this;if("string"!=typeof e)return this.pushStack(S(e).filter(function(){for(t=0;t<r;t++)if(S.contains(i[t],this))return!0}));for(n=this.pushStack([]),t=0;t<r;t++)S.find(e,i[t],n);return 1<r?S.uniqueSort(n):n},filter:function(e){return this.pushStack(D(this,e||[],!1))},not:function(e){return this.pushStack(D(this,e||[],!0))},is:function(e){return!!D(this,"string"==typeof e&&k.test(e)?S(e):e||[],!1).length}});var j,q=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/;(S.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||j,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:q.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof S?t[0]:t,S.merge(this,S.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:E,!0)),N.test(r[1])&&S.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=E.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):m(e)?void 0!==n.ready?n.ready(e):e(S):S.makeArray(e,this)}).prototype=S.fn,j=S(E);var L=/^(?:parents|prev(?:Until|All))/,H={children:!0,contents:!0,next:!0,prev:!0};function O(e,t){while((e=e[t])&&1!==e.nodeType);return e}S.fn.extend({has:function(e){var t=S(e,this),n=t.length;return this.filter(function(){for(var e=0;e<n;e++)if(S.contains(this,t[e]))return!0})},closest:function(e,t){var n,r=0,i=this.length,o=[],a="string"!=typeof e&&S(e);if(!k.test(e))for(;r<i;r++)for(n=this[r];n&&n!==t;n=n.parentNode)if(n.nodeType<11&&(a?-1<a.index(n):1===n.nodeType&&S.find.matchesSelector(n,e))){o.push(n);break}return this.pushStack(1<o.length?S.uniqueSort(o):o)},index:function(e){return e?"string"==typeof e?i.call(S(e),this[0]):i.call(this,e.jquery?e[0]:e):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){return this.pushStack(S.uniqueSort(S.merge(this.get(),S(e,t))))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}}),S.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return h(e,"parentNode")},parentsUntil:function(e,t,n){return h(e,"parentNode",n)},next:function(e){return O(e,"nextSibling")},prev:function(e){return O(e,"previousSibling")},nextAll:function(e){return h(e,"nextSibling")},prevAll:function(e){return h(e,"previousSibling")},nextUntil:function(e,t,n){return h(e,"nextSibling",n)},prevUntil:function(e,t,n){return h(e,"previousSibling",n)},siblings:function(e){return T((e.parentNode||{}).firstChild,e)},children:function(e){return T(e.firstChild)},contents:function(e){return null!=e.contentDocument&&r(e.contentDocument)?e.contentDocument:(A(e,"template")&&(e=e.content||e),S.merge([],e.childNodes))}},function(r,i){S.fn[r]=function(e,t){var n=S.map(this,i,e);return"Until"!==r.slice(-5)&&(t=e),t&&"string"==typeof t&&(n=S.filter(t,n)),1<this.length&&(H[r]||S.uniqueSort(n),L.test(r)&&n.reverse()),this.pushStack(n)}});var P=/[^\x20\t\r\n\f]+/g;function R(e){return e}function M(e){throw e}function I(e,t,n,r){var i;try{e&&m(i=e.promise)?i.call(e).done(t).fail(n):e&&m(i=e.then)?i.call(e,t,n):t.apply(void 0,[e].slice(r))}catch(e){n.apply(void 0,[e])}}S.Callbacks=function(r){var e,n;r="string"==typeof r?(e=r,n={},S.each(e.match(P)||[],function(e,t){n[t]=!0}),n):S.extend({},r);var i,t,o,a,s=[],u=[],l=-1,c=function(){for(a=a||r.once,o=i=!0;u.length;l=-1){t=u.shift();while(++l<s.length)!1===s[l].apply(t[0],t[1])&&r.stopOnFalse&&(l=s.length,t=!1)}r.memory||(t=!1),i=!1,a&&(s=t?[]:"")},f={add:function(){return s&&(t&&!i&&(l=s.length-1,u.push(t)),function n(e){S.each(e,function(e,t){m(t)?r.unique&&f.has(t)||s.push(t):t&&t.length&&"string"!==w(t)&&n(t)})}(arguments),t&&!i&&c()),this},remove:function(){return S.each(arguments,function(e,t){var n;while(-1<(n=S.inArray(t,s,n)))s.splice(n,1),n<=l&&l--}),this},has:function(e){return e?-1<S.inArray(e,s):0<s.length},empty:function(){return s&&(s=[]),this},disable:function(){return a=u=[],s=t="",this},disabled:function(){return!s},lock:function(){return a=u=[],t||i||(s=t=""),this},locked:function(){return!!a},fireWith:function(e,t){return a||(t=[e,(t=t||[]).slice?t.slice():t],u.push(t),i||c()),this},fire:function(){return f.fireWith(this,arguments),this},fired:function(){return!!o}};return f},S.extend({Deferred:function(e){var o=[["notify","progress",S.Callbacks("memory"),S.Callbacks("memory"),2],["resolve","done",S.Callbacks("once memory"),S.Callbacks("once memory"),0,"resolved"],["reject","fail",S.Callbacks("once memory"),S.Callbacks("once memory"),1,"rejected"]],i="pending",a={state:function(){return i},always:function(){return s.done(arguments).fail(arguments),this},"catch":function(e){return a.then(null,e)},pipe:function(){var i=arguments;return S.Deferred(function(r){S.each(o,function(e,t){var n=m(i[t[4]])&&i[t[4]];s[t[1]](function(){var e=n&&n.apply(this,arguments);e&&m(e.promise)?e.promise().progress(r.notify).done(r.resolve).fail(r.reject):r[t[0]+"With"](this,n?[e]:arguments)})}),i=null}).promise()},then:function(t,n,r){var u=0;function l(i,o,a,s){return function(){var n=this,r=arguments,e=function(){var e,t;if(!(i<u)){if((e=a.apply(n,r))===o.promise())throw new TypeError("Thenable self-resolution");t=e&&("object"==typeof e||"function"==typeof e)&&e.then,m(t)?s?t.call(e,l(u,o,R,s),l(u,o,M,s)):(u++,t.call(e,l(u,o,R,s),l(u,o,M,s),l(u,o,R,o.notifyWith))):(a!==R&&(n=void 0,r=[e]),(s||o.resolveWith)(n,r))}},t=s?e:function(){try{e()}catch(e){S.Deferred.exceptionHook&&S.Deferred.exceptionHook(e,t.stackTrace),u<=i+1&&(a!==M&&(n=void 0,r=[e]),o.rejectWith(n,r))}};i?t():(S.Deferred.getStackHook&&(t.stackTrace=S.Deferred.getStackHook()),C.setTimeout(t))}}return S.Deferred(function(e){o[0][3].add(l(0,e,m(r)?r:R,e.notifyWith)),o[1][3].add(l(0,e,m(t)?t:R)),o[2][3].add(l(0,e,m(n)?n:M))}).promise()},promise:function(e){return null!=e?S.extend(e,a):a}},s={};return S.each(o,function(e,t){var n=t[2],r=t[5];a[t[1]]=n.add,r&&n.add(function(){i=r},o[3-e][2].disable,o[3-e][3].disable,o[0][2].lock,o[0][3].lock),n.add(t[3].fire),s[t[0]]=function(){return s[t[0]+"With"](this===s?void 0:this,arguments),this},s[t[0]+"With"]=n.fireWith}),a.promise(s),e&&e.call(s,s),s},when:function(e){var n=arguments.length,t=n,r=Array(t),i=s.call(arguments),o=S.Deferred(),a=function(t){return function(e){r[t]=this,i[t]=1<arguments.length?s.call(arguments):e,--n||o.resolveWith(r,i)}};if(n<=1&&(I(e,o.done(a(t)).resolve,o.reject,!n),"pending"===o.state()||m(i[t]&&i[t].then)))return o.then();while(t--)I(i[t],a(t),o.reject);return o.promise()}});var W=/^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;S.Deferred.exceptionHook=function(e,t){C.console&&C.console.warn&&e&&W.test(e.name)&&C.console.warn("jQuery.Deferred exception: "+e.message,e.stack,t)},S.readyException=function(e){C.setTimeout(function(){throw e})};var F=S.Deferred();function B(){E.removeEventListener("DOMContentLoaded",B),C.removeEventListener("load",B),S.ready()}S.fn.ready=function(e){return F.then(e)["catch"](function(e){S.readyException(e)}),this},S.extend({isReady:!1,readyWait:1,ready:function(e){(!0===e?--S.readyWait:S.isReady)||(S.isReady=!0)!==e&&0<--S.readyWait||F.resolveWith(E,[S])}}),S.ready.then=F.then,"complete"===E.readyState||"loading"!==E.readyState&&!E.documentElement.doScroll?C.setTimeout(S.ready):(E.addEventListener("DOMContentLoaded",B),C.addEventListener("load",B));var $=function(e,t,n,r,i,o,a){var s=0,u=e.length,l=null==n;if("object"===w(n))for(s in i=!0,n)$(e,t,s,n[s],!0,o,a);else if(void 0!==r&&(i=!0,m(r)||(a=!0),l&&(a?(t.call(e,r),t=null):(l=t,t=function(e,t,n){return l.call(S(e),n)})),t))for(;s<u;s++)t(e[s],n,a?r:r.call(e[s],s,t(e[s],n)));return i?e:l?t.call(e):u?t(e[0],n):o},_=/^-ms-/,z=/-([a-z])/g;function U(e,t){return t.toUpperCase()}function X(e){return e.replace(_,"ms-").replace(z,U)}var V=function(e){return 1===e.nodeType||9===e.nodeType||!+e.nodeType};function G(){this.expando=S.expando+G.uid++}G.uid=1,G.prototype={cache:function(e){var t=e[this.expando];return t||(t={},V(e)&&(e.nodeType?e[this.expando]=t:Object.defineProperty(e,this.expando,{value:t,configurable:!0}))),t},set:function(e,t,n){var r,i=this.cache(e);if("string"==typeof t)i[X(t)]=n;else for(r in t)i[X(r)]=t[r];return i},get:function(e,t){return void 0===t?this.cache(e):e[this.expando]&&e[this.expando][X(t)]},access:function(e,t,n){return void 0===t||t&&"string"==typeof t&&void 0===n?this.get(e,t):(this.set(e,t,n),void 0!==n?n:t)},remove:function(e,t){var n,r=e[this.expando];if(void 0!==r){if(void 0!==t){n=(t=Array.isArray(t)?t.map(X):(t=X(t))in r?[t]:t.match(P)||[]).length;while(n--)delete r[t[n]]}(void 0===t||S.isEmptyObject(r))&&(e.nodeType?e[this.expando]=void 0:delete e[this.expando])}},hasData:function(e){var t=e[this.expando];return void 0!==t&&!S.isEmptyObject(t)}};var Y=new G,Q=new G,J=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,K=/[A-Z]/g;function Z(e,t,n){var r,i;if(void 0===n&&1===e.nodeType)if(r="data-"+t.replace(K,"-$&").toLowerCase(),"string"==typeof(n=e.getAttribute(r))){try{n="true"===(i=n)||"false"!==i&&("null"===i?null:i===+i+""?+i:J.test(i)?JSON.parse(i):i)}catch(e){}Q.set(e,t,n)}else n=void 0;return n}S.extend({hasData:function(e){return Q.hasData(e)||Y.hasData(e)},data:function(e,t,n){return Q.access(e,t,n)},removeData:function(e,t){Q.remove(e,t)},_data:function(e,t,n){return Y.access(e,t,n)},_removeData:function(e,t){Y.remove(e,t)}}),S.fn.extend({data:function(n,e){var t,r,i,o=this[0],a=o&&o.attributes;if(void 0===n){if(this.length&&(i=Q.get(o),1===o.nodeType&&!Y.get(o,"hasDataAttrs"))){t=a.length;while(t--)a[t]&&0===(r=a[t].name).indexOf("data-")&&(r=X(r.slice(5)),Z(o,r,i[r]));Y.set(o,"hasDataAttrs",!0)}return i}return"object"==typeof n?this.each(function(){Q.set(this,n)}):$(this,function(e){var t;if(o&&void 0===e)return void 0!==(t=Q.get(o,n))?t:void 0!==(t=Z(o,n))?t:void 0;this.each(function(){Q.set(this,n,e)})},null,e,1<arguments.length,null,!0)},removeData:function(e){return this.each(function(){Q.remove(this,e)})}}),S.extend({queue:function(e,t,n){var r;if(e)return t=(t||"fx")+"queue",r=Y.get(e,t),n&&(!r||Array.isArray(n)?r=Y.access(e,t,S.makeArray(n)):r.push(n)),r||[]},dequeue:function(e,t){t=t||"fx";var n=S.queue(e,t),r=n.length,i=n.shift(),o=S._queueHooks(e,t);"inprogress"===i&&(i=n.shift(),r--),i&&("fx"===t&&n.unshift("inprogress"),delete o.stop,i.call(e,function(){S.dequeue(e,t)},o)),!r&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return Y.get(e,n)||Y.access(e,n,{empty:S.Callbacks("once memory").add(function(){Y.remove(e,[t+"queue",n])})})}}),S.fn.extend({queue:function(t,n){var e=2;return"string"!=typeof t&&(n=t,t="fx",e--),arguments.length<e?S.queue(this[0],t):void 0===n?this:this.each(function(){var e=S.queue(this,t,n);S._queueHooks(this,t),"fx"===t&&"inprogress"!==e[0]&&S.dequeue(this,t)})},dequeue:function(e){return this.each(function(){S.dequeue(this,e)})},clearQueue:function(e){return this.queue(e||"fx",[])},promise:function(e,t){var n,r=1,i=S.Deferred(),o=this,a=this.length,s=function(){--r||i.resolveWith(o,[o])};"string"!=typeof e&&(t=e,e=void 0),e=e||"fx";while(a--)(n=Y.get(o[a],e+"queueHooks"))&&n.empty&&(r++,n.empty.add(s));return s(),i.promise(t)}});var ee=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,te=new RegExp("^(?:([+-])=|)("+ee+")([a-z%]*)$","i"),ne=["Top","Right","Bottom","Left"],re=E.documentElement,ie=function(e){return S.contains(e.ownerDocument,e)},oe={composed:!0};re.getRootNode&&(ie=function(e){return S.contains(e.ownerDocument,e)||e.getRootNode(oe)===e.ownerDocument});var ae=function(e,t){return"none"===(e=t||e).style.display||""===e.style.display&&ie(e)&&"none"===S.css(e,"display")};function se(e,t,n,r){var i,o,a=20,s=r?function(){return r.cur()}:function(){return S.css(e,t,"")},u=s(),l=n&&n[3]||(S.cssNumber[t]?"":"px"),c=e.nodeType&&(S.cssNumber[t]||"px"!==l&&+u)&&te.exec(S.css(e,t));if(c&&c[3]!==l){u/=2,l=l||c[3],c=+u||1;while(a--)S.style(e,t,c+l),(1-o)*(1-(o=s()/u||.5))<=0&&(a=0),c/=o;c*=2,S.style(e,t,c+l),n=n||[]}return n&&(c=+c||+u||0,i=n[1]?c+(n[1]+1)*n[2]:+n[2],r&&(r.unit=l,r.start=c,r.end=i)),i}var ue={};function le(e,t){for(var n,r,i,o,a,s,u,l=[],c=0,f=e.length;c<f;c++)(r=e[c]).style&&(n=r.style.display,t?("none"===n&&(l[c]=Y.get(r,"display")||null,l[c]||(r.style.display="")),""===r.style.display&&ae(r)&&(l[c]=(u=a=o=void 0,a=(i=r).ownerDocument,s=i.nodeName,(u=ue[s])||(o=a.body.appendChild(a.createElement(s)),u=S.css(o,"display"),o.parentNode.removeChild(o),"none"===u&&(u="block"),ue[s]=u)))):"none"!==n&&(l[c]="none",Y.set(r,"display",n)));for(c=0;c<f;c++)null!=l[c]&&(e[c].style.display=l[c]);return e}S.fn.extend({show:function(){return le(this,!0)},hide:function(){return le(this)},toggle:function(e){return"boolean"==typeof e?e?this.show():this.hide():this.each(function(){ae(this)?S(this).show():S(this).hide()})}});var ce,fe,pe=/^(?:checkbox|radio)$/i,de=/<([a-z][^\/\0>\x20\t\r\n\f]*)/i,he=/^$|^module$|\/(?:java|ecma)script/i;ce=E.createDocumentFragment().appendChild(E.createElement("div")),(fe=E.createElement("input")).setAttribute("type","radio"),fe.setAttribute("checked","checked"),fe.setAttribute("name","t"),ce.appendChild(fe),y.checkClone=ce.cloneNode(!0).cloneNode(!0).lastChild.checked,ce.innerHTML="<textarea>x</textarea>",y.noCloneChecked=!!ce.cloneNode(!0).lastChild.defaultValue,ce.innerHTML="<option></option>",y.option=!!ce.lastChild;var ge={thead:[1,"<table>","</table>"],col:[2,"<table><colgroup>","</colgroup></table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],_default:[0,"",""]};function ve(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&A(e,t)?S.merge([e],n):n}function ye(e,t){for(var n=0,r=e.length;n<r;n++)Y.set(e[n],"globalEval",!t||Y.get(t[n],"globalEval"))}ge.tbody=ge.tfoot=ge.colgroup=ge.caption=ge.thead,ge.th=ge.td,y.option||(ge.optgroup=ge.option=[1,"<select multiple='multiple'>","</select>"]);var me=/<|&#?\w+;/;function xe(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d<h;d++)if((o=e[d])||0===o)if("object"===w(o))S.merge(p,o.nodeType?[o]:o);else if(me.test(o)){a=a||f.appendChild(t.createElement("div")),s=(de.exec(o)||["",""])[1].toLowerCase(),u=ge[s]||ge._default,a.innerHTML=u[1]+S.htmlPrefilter(o)+u[2],c=u[0];while(c--)a=a.lastChild;S.merge(p,a.childNodes),(a=f.firstChild).textContent=""}else p.push(t.createTextNode(o));f.textContent="",d=0;while(o=p[d++])if(r&&-1<S.inArray(o,r))i&&i.push(o);else if(l=ie(o),a=ve(f.appendChild(o),"script"),l&&ye(a),n){c=0;while(o=a[c++])he.test(o.type||"")&&n.push(o)}return f}var be=/^key/,we=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,Te=/^([^.]*)(?:\.(.+)|)/;function Ce(){return!0}function Ee(){return!1}function Se(e,t){return e===function(){try{return E.activeElement}catch(e){}}()==("focus"===t)}function ke(e,t,n,r,i,o){var a,s;if("object"==typeof t){for(s in"string"!=typeof n&&(r=r||n,n=void 0),t)ke(e,s,n,r,t[s],o);return e}if(null==r&&null==i?(i=n,r=n=void 0):null==i&&("string"==typeof n?(i=r,r=void 0):(i=r,r=n,n=void 0)),!1===i)i=Ee;else if(!i)return e;return 1===o&&(a=i,(i=function(e){return S().off(e),a.apply(this,arguments)}).guid=a.guid||(a.guid=S.guid++)),e.each(function(){S.event.add(this,t,i,r,n)})}function Ae(e,i,o){o?(Y.set(e,i,!1),S.event.add(e,i,{namespace:!1,handler:function(e){var t,n,r=Y.get(this,i);if(1&e.isTrigger&&this[i]){if(r.length)(S.event.special[i]||{}).delegateType&&e.stopPropagation();else if(r=s.call(arguments),Y.set(this,i,r),t=o(this,i),this[i](),r!==(n=Y.get(this,i))||t?Y.set(this,i,!1):n={},r!==n)return e.stopImmediatePropagation(),e.preventDefault(),n.value}else r.length&&(Y.set(this,i,{value:S.event.trigger(S.extend(r[0],S.Event.prototype),r.slice(1),this)}),e.stopImmediatePropagation())}})):void 0===Y.get(e,i)&&S.event.add(e,i,Ce)}S.event={global:{},add:function(t,e,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,v=Y.get(t);if(V(t)){n.handler&&(n=(o=n).handler,i=o.selector),i&&S.find.matchesSelector(re,i),n.guid||(n.guid=S.guid++),(u=v.events)||(u=v.events=Object.create(null)),(a=v.handle)||(a=v.handle=function(e){return"undefined"!=typeof S&&S.event.triggered!==e.type?S.event.dispatch.apply(t,arguments):void 0}),l=(e=(e||"").match(P)||[""]).length;while(l--)d=g=(s=Te.exec(e[l])||[])[1],h=(s[2]||"").split(".").sort(),d&&(f=S.event.special[d]||{},d=(i?f.delegateType:f.bindType)||d,f=S.event.special[d]||{},c=S.extend({type:d,origType:g,data:r,handler:n,guid:n.guid,selector:i,needsContext:i&&S.expr.match.needsContext.test(i),namespace:h.join(".")},o),(p=u[d])||((p=u[d]=[]).delegateCount=0,f.setup&&!1!==f.setup.call(t,r,h,a)||t.addEventListener&&t.addEventListener(d,a)),f.add&&(f.add.call(t,c),c.handler.guid||(c.handler.guid=n.guid)),i?p.splice(p.delegateCount++,0,c):p.push(c),S.event.global[d]=!0)}},remove:function(e,t,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,v=Y.hasData(e)&&Y.get(e);if(v&&(u=v.events)){l=(t=(t||"").match(P)||[""]).length;while(l--)if(d=g=(s=Te.exec(t[l])||[])[1],h=(s[2]||"").split(".").sort(),d){f=S.event.special[d]||{},p=u[d=(r?f.delegateType:f.bindType)||d]||[],s=s[2]&&new RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"),a=o=p.length;while(o--)c=p[o],!i&&g!==c.origType||n&&n.guid!==c.guid||s&&!s.test(c.namespace)||r&&r!==c.selector&&("**"!==r||!c.selector)||(p.splice(o,1),c.selector&&p.delegateCount--,f.remove&&f.remove.call(e,c));a&&!p.length&&(f.teardown&&!1!==f.teardown.call(e,h,v.handle)||S.removeEvent(e,d,v.handle),delete u[d])}else for(d in u)S.event.remove(e,d+t[l],n,r,!0);S.isEmptyObject(u)&&Y.remove(e,"handle events")}},dispatch:function(e){var t,n,r,i,o,a,s=new Array(arguments.length),u=S.event.fix(e),l=(Y.get(this,"events")||Object.create(null))[u.type]||[],c=S.event.special[u.type]||{};for(s[0]=u,t=1;t<arguments.length;t++)s[t]=arguments[t];if(u.delegateTarget=this,!c.preDispatch||!1!==c.preDispatch.call(this,u)){a=S.event.handlers.call(this,u,l),t=0;while((i=a[t++])&&!u.isPropagationStopped()){u.currentTarget=i.elem,n=0;while((o=i.handlers[n++])&&!u.isImmediatePropagationStopped())u.rnamespace&&!1!==o.namespace&&!u.rnamespace.test(o.namespace)||(u.handleObj=o,u.data=o.data,void 0!==(r=((S.event.special[o.origType]||{}).handle||o.handler).apply(i.elem,s))&&!1===(u.result=r)&&(u.preventDefault(),u.stopPropagation()))}return c.postDispatch&&c.postDispatch.call(this,u),u.result}},handlers:function(e,t){var n,r,i,o,a,s=[],u=t.delegateCount,l=e.target;if(u&&l.nodeType&&!("click"===e.type&&1<=e.button))for(;l!==this;l=l.parentNode||this)if(1===l.nodeType&&("click"!==e.type||!0!==l.disabled)){for(o=[],a={},n=0;n<u;n++)void 0===a[i=(r=t[n]).selector+" "]&&(a[i]=r.needsContext?-1<S(i,this).index(l):S.find(i,this,null,[l]).length),a[i]&&o.push(r);o.length&&s.push({elem:l,handlers:o})}return l=this,u<t.length&&s.push({elem:l,handlers:t.slice(u)}),s},addProp:function(t,e){Object.defineProperty(S.Event.prototype,t,{enumerable:!0,configurable:!0,get:m(e)?function(){if(this.originalEvent)return e(this.originalEvent)}:function(){if(this.originalEvent)return this.originalEvent[t]},set:function(e){Object.defineProperty(this,t,{enumerable:!0,configurable:!0,writable:!0,value:e})}})},fix:function(e){return e[S.expando]?e:new S.Event(e)},special:{load:{noBubble:!0},click:{setup:function(e){var t=this||e;return pe.test(t.type)&&t.click&&A(t,"input")&&Ae(t,"click",Ce),!1},trigger:function(e){var t=this||e;return pe.test(t.type)&&t.click&&A(t,"input")&&Ae(t,"click"),!0},_default:function(e){var t=e.target;return pe.test(t.type)&&t.click&&A(t,"input")&&Y.get(t,"click")||A(t,"a")}},beforeunload:{postDispatch:function(e){void 0!==e.result&&e.originalEvent&&(e.originalEvent.returnValue=e.result)}}}},S.removeEvent=function(e,t,n){e.removeEventListener&&e.removeEventListener(t,n)},S.Event=function(e,t){if(!(this instanceof S.Event))return new S.Event(e,t);e&&e.type?(this.originalEvent=e,this.type=e.type,this.isDefaultPrevented=e.defaultPrevented||void 0===e.defaultPrevented&&!1===e.returnValue?Ce:Ee,this.target=e.target&&3===e.target.nodeType?e.target.parentNode:e.target,this.currentTarget=e.currentTarget,this.relatedTarget=e.relatedTarget):this.type=e,t&&S.extend(this,t),this.timeStamp=e&&e.timeStamp||Date.now(),this[S.expando]=!0},S.Event.prototype={constructor:S.Event,isDefaultPrevented:Ee,isPropagationStopped:Ee,isImmediatePropagationStopped:Ee,isSimulated:!1,preventDefault:function(){var e=this.originalEvent;this.isDefaultPrevented=Ce,e&&!this.isSimulated&&e.preventDefault()},stopPropagation:function(){var e=this.originalEvent;this.isPropagationStopped=Ce,e&&!this.isSimulated&&e.stopPropagation()},stopImmediatePropagation:function(){var e=this.originalEvent;this.isImmediatePropagationStopped=Ce,e&&!this.isSimulated&&e.stopImmediatePropagation(),this.stopPropagation()}},S.each({altKey:!0,bubbles:!0,cancelable:!0,changedTouches:!0,ctrlKey:!0,detail:!0,eventPhase:!0,metaKey:!0,pageX:!0,pageY:!0,shiftKey:!0,view:!0,"char":!0,code:!0,charCode:!0,key:!0,keyCode:!0,button:!0,buttons:!0,clientX:!0,clientY:!0,offsetX:!0,offsetY:!0,pointerId:!0,pointerType:!0,screenX:!0,screenY:!0,targetTouches:!0,toElement:!0,touches:!0,which:function(e){var t=e.button;return null==e.which&&be.test(e.type)?null!=e.charCode?e.charCode:e.keyCode:!e.which&&void 0!==t&&we.test(e.type)?1&t?1:2&t?3:4&t?2:0:e.which}},S.event.addProp),S.each({focus:"focusin",blur:"focusout"},function(e,t){S.event.special[e]={setup:function(){return Ae(this,e,Se),!1},trigger:function(){return Ae(this,e),!0},delegateType:t}}),S.each({mouseenter:"mouseover",mouseleave:"mouseout",pointerenter:"pointerover",pointerleave:"pointerout"},function(e,i){S.event.special[e]={delegateType:i,bindType:i,handle:function(e){var t,n=e.relatedTarget,r=e.handleObj;return n&&(n===this||S.contains(this,n))||(e.type=r.origType,t=r.handler.apply(this,arguments),e.type=i),t}}}),S.fn.extend({on:function(e,t,n,r){return ke(this,e,t,n,r)},one:function(e,t,n,r){return ke(this,e,t,n,r,1)},off:function(e,t,n){var r,i;if(e&&e.preventDefault&&e.handleObj)return r=e.handleObj,S(e.delegateTarget).off(r.namespace?r.origType+"."+r.namespace:r.origType,r.selector,r.handler),this;if("object"==typeof e){for(i in e)this.off(i,t,e[i]);return this}return!1!==t&&"function"!=typeof t||(n=t,t=void 0),!1===n&&(n=Ee),this.each(function(){S.event.remove(this,e,n,t)})}});var Ne=/<script|<style|<link/i,De=/checked\s*(?:[^=]|=\s*.checked.)/i,je=/^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g;function qe(e,t){return A(e,"table")&&A(11!==t.nodeType?t:t.firstChild,"tr")&&S(e).children("tbody")[0]||e}function Le(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function He(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Oe(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(Y.hasData(e)&&(s=Y.get(e).events))for(i in Y.remove(t,"handle events"),s)for(n=0,r=s[i].length;n<r;n++)S.event.add(t,i,s[i][n]);Q.hasData(e)&&(o=Q.access(e),a=S.extend({},o),Q.set(t,a))}}function Pe(n,r,i,o){r=g(r);var e,t,a,s,u,l,c=0,f=n.length,p=f-1,d=r[0],h=m(d);if(h||1<f&&"string"==typeof d&&!y.checkClone&&De.test(d))return n.each(function(e){var t=n.eq(e);h&&(r[0]=d.call(this,e,t.html())),Pe(t,r,i,o)});if(f&&(t=(e=xe(r,n[0].ownerDocument,!1,n,o)).firstChild,1===e.childNodes.length&&(e=t),t||o)){for(s=(a=S.map(ve(e,"script"),Le)).length;c<f;c++)u=e,c!==p&&(u=S.clone(u,!0,!0),s&&S.merge(a,ve(u,"script"))),i.call(n[c],u,c);if(s)for(l=a[a.length-1].ownerDocument,S.map(a,He),c=0;c<s;c++)u=a[c],he.test(u.type||"")&&!Y.access(u,"globalEval")&&S.contains(l,u)&&(u.src&&"module"!==(u.type||"").toLowerCase()?S._evalUrl&&!u.noModule&&S._evalUrl(u.src,{nonce:u.nonce||u.getAttribute("nonce")},l):b(u.textContent.replace(je,""),u,l))}return n}function Re(e,t,n){for(var r,i=t?S.filter(t,e):e,o=0;null!=(r=i[o]);o++)n||1!==r.nodeType||S.cleanData(ve(r)),r.parentNode&&(n&&ie(r)&&ye(ve(r,"script")),r.parentNode.removeChild(r));return e}S.extend({htmlPrefilter:function(e){return e},clone:function(e,t,n){var r,i,o,a,s,u,l,c=e.cloneNode(!0),f=ie(e);if(!(y.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||S.isXMLDoc(e)))for(a=ve(c),r=0,i=(o=ve(e)).length;r<i;r++)s=o[r],u=a[r],void 0,"input"===(l=u.nodeName.toLowerCase())&&pe.test(s.type)?u.checked=s.checked:"input"!==l&&"textarea"!==l||(u.defaultValue=s.defaultValue);if(t)if(n)for(o=o||ve(e),a=a||ve(c),r=0,i=o.length;r<i;r++)Oe(o[r],a[r]);else Oe(e,c);return 0<(a=ve(c,"script")).length&&ye(a,!f&&ve(e,"script")),c},cleanData:function(e){for(var t,n,r,i=S.event.special,o=0;void 0!==(n=e[o]);o++)if(V(n)){if(t=n[Y.expando]){if(t.events)for(r in t.events)i[r]?S.event.remove(n,r):S.removeEvent(n,r,t.handle);n[Y.expando]=void 0}n[Q.expando]&&(n[Q.expando]=void 0)}}}),S.fn.extend({detach:function(e){return Re(this,e,!0)},remove:function(e){return Re(this,e)},text:function(e){return $(this,function(e){return void 0===e?S.text(this):this.empty().each(function(){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||(this.textContent=e)})},null,e,arguments.length)},append:function(){return Pe(this,arguments,function(e){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||qe(this,e).appendChild(e)})},prepend:function(){return Pe(this,arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=qe(this,e);t.insertBefore(e,t.firstChild)}})},before:function(){return Pe(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return Pe(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)})},empty:function(){for(var e,t=0;null!=(e=this[t]);t++)1===e.nodeType&&(S.cleanData(ve(e,!1)),e.textContent="");return this},clone:function(e,t){return e=null!=e&&e,t=null==t?e:t,this.map(function(){return S.clone(this,e,t)})},html:function(e){return $(this,function(e){var t=this[0]||{},n=0,r=this.length;if(void 0===e&&1===t.nodeType)return t.innerHTML;if("string"==typeof e&&!Ne.test(e)&&!ge[(de.exec(e)||["",""])[1].toLowerCase()]){e=S.htmlPrefilter(e);try{for(;n<r;n++)1===(t=this[n]||{}).nodeType&&(S.cleanData(ve(t,!1)),t.innerHTML=e);t=0}catch(e){}}t&&this.empty().append(e)},null,e,arguments.length)},replaceWith:function(){var n=[];return Pe(this,arguments,function(e){var t=this.parentNode;S.inArray(this,n)<0&&(S.cleanData(ve(this)),t&&t.replaceChild(e,this))},n)}}),S.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(e,a){S.fn[e]=function(e){for(var t,n=[],r=S(e),i=r.length-1,o=0;o<=i;o++)t=o===i?this:this.clone(!0),S(r[o])[a](t),u.apply(n,t.get());return this.pushStack(n)}});var Me=new RegExp("^("+ee+")(?!px)[a-z%]+$","i"),Ie=function(e){var t=e.ownerDocument.defaultView;return t&&t.opener||(t=C),t.getComputedStyle(e)},We=function(e,t,n){var r,i,o={};for(i in t)o[i]=e.style[i],e.style[i]=t[i];for(i in r=n.call(e),t)e.style[i]=o[i];return r},Fe=new RegExp(ne.join("|"),"i");function Be(e,t,n){var r,i,o,a,s=e.style;return(n=n||Ie(e))&&(""!==(a=n.getPropertyValue(t)||n[t])||ie(e)||(a=S.style(e,t)),!y.pixelBoxStyles()&&Me.test(a)&&Fe.test(t)&&(r=s.width,i=s.minWidth,o=s.maxWidth,s.minWidth=s.maxWidth=s.width=a,a=n.width,s.width=r,s.minWidth=i,s.maxWidth=o)),void 0!==a?a+"":a}function $e(e,t){return{get:function(){if(!e())return(this.get=t).apply(this,arguments);delete this.get}}}!function(){function e(){if(l){u.style.cssText="position:absolute;left:-11111px;width:60px;margin-top:1px;padding:0;border:0",l.style.cssText="position:relative;display:block;box-sizing:border-box;overflow:scroll;margin:auto;border:1px;padding:1px;width:60%;top:1%",re.appendChild(u).appendChild(l);var e=C.getComputedStyle(l);n="1%"!==e.top,s=12===t(e.marginLeft),l.style.right="60%",o=36===t(e.right),r=36===t(e.width),l.style.position="absolute",i=12===t(l.offsetWidth/3),re.removeChild(u),l=null}}function t(e){return Math.round(parseFloat(e))}var n,r,i,o,a,s,u=E.createElement("div"),l=E.createElement("div");l.style&&(l.style.backgroundClip="content-box",l.cloneNode(!0).style.backgroundClip="",y.clearCloneStyle="content-box"===l.style.backgroundClip,S.extend(y,{boxSizingReliable:function(){return e(),r},pixelBoxStyles:function(){return e(),o},pixelPosition:function(){return e(),n},reliableMarginLeft:function(){return e(),s},scrollboxSize:function(){return e(),i},reliableTrDimensions:function(){var e,t,n,r;return null==a&&(e=E.createElement("table"),t=E.createElement("tr"),n=E.createElement("div"),e.style.cssText="position:absolute;left:-11111px",t.style.height="1px",n.style.height="9px",re.appendChild(e).appendChild(t).appendChild(n),r=C.getComputedStyle(t),a=3<parseInt(r.height),re.removeChild(e)),a}}))}();var _e=["Webkit","Moz","ms"],ze=E.createElement("div").style,Ue={};function Xe(e){var t=S.cssProps[e]||Ue[e];return t||(e in ze?e:Ue[e]=function(e){var t=e[0].toUpperCase()+e.slice(1),n=_e.length;while(n--)if((e=_e[n]+t)in ze)return e}(e)||e)}var Ve=/^(none|table(?!-c[ea]).+)/,Ge=/^--/,Ye={position:"absolute",visibility:"hidden",display:"block"},Qe={letterSpacing:"0",fontWeight:"400"};function Je(e,t,n){var r=te.exec(t);return r?Math.max(0,r[2]-(n||0))+(r[3]||"px"):t}function Ke(e,t,n,r,i,o){var a="width"===t?1:0,s=0,u=0;if(n===(r?"border":"content"))return 0;for(;a<4;a+=2)"margin"===n&&(u+=S.css(e,n+ne[a],!0,i)),r?("content"===n&&(u-=S.css(e,"padding"+ne[a],!0,i)),"margin"!==n&&(u-=S.css(e,"border"+ne[a]+"Width",!0,i))):(u+=S.css(e,"padding"+ne[a],!0,i),"padding"!==n?u+=S.css(e,"border"+ne[a]+"Width",!0,i):s+=S.css(e,"border"+ne[a]+"Width",!0,i));return!r&&0<=o&&(u+=Math.max(0,Math.ceil(e["offset"+t[0].toUpperCase()+t.slice(1)]-o-u-s-.5))||0),u}function Ze(e,t,n){var r=Ie(e),i=(!y.boxSizingReliable()||n)&&"border-box"===S.css(e,"boxSizing",!1,r),o=i,a=Be(e,t,r),s="offset"+t[0].toUpperCase()+t.slice(1);if(Me.test(a)){if(!n)return a;a="auto"}return(!y.boxSizingReliable()&&i||!y.reliableTrDimensions()&&A(e,"tr")||"auto"===a||!parseFloat(a)&&"inline"===S.css(e,"display",!1,r))&&e.getClientRects().length&&(i="border-box"===S.css(e,"boxSizing",!1,r),(o=s in e)&&(a=e[s])),(a=parseFloat(a)||0)+Ke(e,t,n||(i?"border":"content"),o,r,a)+"px"}function et(e,t,n,r,i){return new et.prototype.init(e,t,n,r,i)}S.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=Be(e,"opacity");return""===n?"1":n}}}},cssNumber:{animationIterationCount:!0,columnCount:!0,fillOpacity:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,gridArea:!0,gridColumn:!0,gridColumnEnd:!0,gridColumnStart:!0,gridRow:!0,gridRowEnd:!0,gridRowStart:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{},style:function(e,t,n,r){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var i,o,a,s=X(t),u=Ge.test(t),l=e.style;if(u||(t=Xe(s)),a=S.cssHooks[t]||S.cssHooks[s],void 0===n)return a&&"get"in a&&void 0!==(i=a.get(e,!1,r))?i:l[t];"string"===(o=typeof n)&&(i=te.exec(n))&&i[1]&&(n=se(e,t,i),o="number"),null!=n&&n==n&&("number"!==o||u||(n+=i&&i[3]||(S.cssNumber[s]?"":"px")),y.clearCloneStyle||""!==n||0!==t.indexOf("background")||(l[t]="inherit"),a&&"set"in a&&void 0===(n=a.set(e,n,r))||(u?l.setProperty(t,n):l[t]=n))}},css:function(e,t,n,r){var i,o,a,s=X(t);return Ge.test(t)||(t=Xe(s)),(a=S.cssHooks[t]||S.cssHooks[s])&&"get"in a&&(i=a.get(e,!0,n)),void 0===i&&(i=Be(e,t,r)),"normal"===i&&t in Qe&&(i=Qe[t]),""===n||n?(o=parseFloat(i),!0===n||isFinite(o)?o||0:i):i}}),S.each(["height","width"],function(e,u){S.cssHooks[u]={get:function(e,t,n){if(t)return!Ve.test(S.css(e,"display"))||e.getClientRects().length&&e.getBoundingClientRect().width?Ze(e,u,n):We(e,Ye,function(){return Ze(e,u,n)})},set:function(e,t,n){var r,i=Ie(e),o=!y.scrollboxSize()&&"absolute"===i.position,a=(o||n)&&"border-box"===S.css(e,"boxSizing",!1,i),s=n?Ke(e,u,n,a,i):0;return a&&o&&(s-=Math.ceil(e["offset"+u[0].toUpperCase()+u.slice(1)]-parseFloat(i[u])-Ke(e,u,"border",!1,i)-.5)),s&&(r=te.exec(t))&&"px"!==(r[3]||"px")&&(e.style[u]=t,t=S.css(e,u)),Je(0,t,s)}}}),S.cssHooks.marginLeft=$e(y.reliableMarginLeft,function(e,t){if(t)return(parseFloat(Be(e,"marginLeft"))||e.getBoundingClientRect().left-We(e,{marginLeft:0},function(){return e.getBoundingClientRect().left}))+"px"}),S.each({margin:"",padding:"",border:"Width"},function(i,o){S.cssHooks[i+o]={expand:function(e){for(var t=0,n={},r="string"==typeof e?e.split(" "):[e];t<4;t++)n[i+ne[t]+o]=r[t]||r[t-2]||r[0];return n}},"margin"!==i&&(S.cssHooks[i+o].set=Je)}),S.fn.extend({css:function(e,t){return $(this,function(e,t,n){var r,i,o={},a=0;if(Array.isArray(t)){for(r=Ie(e),i=t.length;a<i;a++)o[t[a]]=S.css(e,t[a],!1,r);return o}return void 0!==n?S.style(e,t,n):S.css(e,t)},e,t,1<arguments.length)}}),((S.Tween=et).prototype={constructor:et,init:function(e,t,n,r,i,o){this.elem=e,this.prop=n,this.easing=i||S.easing._default,this.options=t,this.start=this.now=this.cur(),this.end=r,this.unit=o||(S.cssNumber[n]?"":"px")},cur:function(){var e=et.propHooks[this.prop];return e&&e.get?e.get(this):et.propHooks._default.get(this)},run:function(e){var t,n=et.propHooks[this.prop];return this.options.duration?this.pos=t=S.easing[this.easing](e,this.options.duration*e,0,1,this.options.duration):this.pos=t=e,this.now=(this.end-this.start)*t+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),n&&n.set?n.set(this):et.propHooks._default.set(this),this}}).init.prototype=et.prototype,(et.propHooks={_default:{get:function(e){var t;return 1!==e.elem.nodeType||null!=e.elem[e.prop]&&null==e.elem.style[e.prop]?e.elem[e.prop]:(t=S.css(e.elem,e.prop,""))&&"auto"!==t?t:0},set:function(e){S.fx.step[e.prop]?S.fx.step[e.prop](e):1!==e.elem.nodeType||!S.cssHooks[e.prop]&&null==e.elem.style[Xe(e.prop)]?e.elem[e.prop]=e.now:S.style(e.elem,e.prop,e.now+e.unit)}}}).scrollTop=et.propHooks.scrollLeft={set:function(e){e.elem.nodeType&&e.elem.parentNode&&(e.elem[e.prop]=e.now)}},S.easing={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2},_default:"swing"},S.fx=et.prototype.init,S.fx.step={};var tt,nt,rt,it,ot=/^(?:toggle|show|hide)$/,at=/queueHooks$/;function st(){nt&&(!1===E.hidden&&C.requestAnimationFrame?C.requestAnimationFrame(st):C.setTimeout(st,S.fx.interval),S.fx.tick())}function ut(){return C.setTimeout(function(){tt=void 0}),tt=Date.now()}function lt(e,t){var n,r=0,i={height:e};for(t=t?1:0;r<4;r+=2-t)i["margin"+(n=ne[r])]=i["padding"+n]=e;return t&&(i.opacity=i.width=e),i}function ct(e,t,n){for(var r,i=(ft.tweeners[t]||[]).concat(ft.tweeners["*"]),o=0,a=i.length;o<a;o++)if(r=i[o].call(n,t,e))return r}function ft(o,e,t){var n,a,r=0,i=ft.prefilters.length,s=S.Deferred().always(function(){delete u.elem}),u=function(){if(a)return!1;for(var e=tt||ut(),t=Math.max(0,l.startTime+l.duration-e),n=1-(t/l.duration||0),r=0,i=l.tweens.length;r<i;r++)l.tweens[r].run(n);return s.notifyWith(o,[l,n,t]),n<1&&i?t:(i||s.notifyWith(o,[l,1,0]),s.resolveWith(o,[l]),!1)},l=s.promise({elem:o,props:S.extend({},e),opts:S.extend(!0,{specialEasing:{},easing:S.easing._default},t),originalProperties:e,originalOptions:t,startTime:tt||ut(),duration:t.duration,tweens:[],createTween:function(e,t){var n=S.Tween(o,l.opts,e,t,l.opts.specialEasing[e]||l.opts.easing);return l.tweens.push(n),n},stop:function(e){var t=0,n=e?l.tweens.length:0;if(a)return this;for(a=!0;t<n;t++)l.tweens[t].run(1);return e?(s.notifyWith(o,[l,1,0]),s.resolveWith(o,[l,e])):s.rejectWith(o,[l,e]),this}}),c=l.props;for(!function(e,t){var n,r,i,o,a;for(n in e)if(i=t[r=X(n)],o=e[n],Array.isArray(o)&&(i=o[1],o=e[n]=o[0]),n!==r&&(e[r]=o,delete e[n]),(a=S.cssHooks[r])&&"expand"in a)for(n in o=a.expand(o),delete e[r],o)n in e||(e[n]=o[n],t[n]=i);else t[r]=i}(c,l.opts.specialEasing);r<i;r++)if(n=ft.prefilters[r].call(l,o,c,l.opts))return m(n.stop)&&(S._queueHooks(l.elem,l.opts.queue).stop=n.stop.bind(n)),n;return S.map(c,ct,l),m(l.opts.start)&&l.opts.start.call(o,l),l.progress(l.opts.progress).done(l.opts.done,l.opts.complete).fail(l.opts.fail).always(l.opts.always),S.fx.timer(S.extend(u,{elem:o,anim:l,queue:l.opts.queue})),l}S.Animation=S.extend(ft,{tweeners:{"*":[function(e,t){var n=this.createTween(e,t);return se(n.elem,e,te.exec(t),n),n}]},tweener:function(e,t){m(e)?(t=e,e=["*"]):e=e.match(P);for(var n,r=0,i=e.length;r<i;r++)n=e[r],ft.tweeners[n]=ft.tweeners[n]||[],ft.tweeners[n].unshift(t)},prefilters:[function(e,t,n){var r,i,o,a,s,u,l,c,f="width"in t||"height"in t,p=this,d={},h=e.style,g=e.nodeType&&ae(e),v=Y.get(e,"fxshow");for(r in n.queue||(null==(a=S._queueHooks(e,"fx")).unqueued&&(a.unqueued=0,s=a.empty.fire,a.empty.fire=function(){a.unqueued||s()}),a.unqueued++,p.always(function(){p.always(function(){a.unqueued--,S.queue(e,"fx").length||a.empty.fire()})})),t)if(i=t[r],ot.test(i)){if(delete t[r],o=o||"toggle"===i,i===(g?"hide":"show")){if("show"!==i||!v||void 0===v[r])continue;g=!0}d[r]=v&&v[r]||S.style(e,r)}if((u=!S.isEmptyObject(t))||!S.isEmptyObject(d))for(r in f&&1===e.nodeType&&(n.overflow=[h.overflow,h.overflowX,h.overflowY],null==(l=v&&v.display)&&(l=Y.get(e,"display")),"none"===(c=S.css(e,"display"))&&(l?c=l:(le([e],!0),l=e.style.display||l,c=S.css(e,"display"),le([e]))),("inline"===c||"inline-block"===c&&null!=l)&&"none"===S.css(e,"float")&&(u||(p.done(function(){h.display=l}),null==l&&(c=h.display,l="none"===c?"":c)),h.display="inline-block")),n.overflow&&(h.overflow="hidden",p.always(function(){h.overflow=n.overflow[0],h.overflowX=n.overflow[1],h.overflowY=n.overflow[2]})),u=!1,d)u||(v?"hidden"in v&&(g=v.hidden):v=Y.access(e,"fxshow",{display:l}),o&&(v.hidden=!g),g&&le([e],!0),p.done(function(){for(r in g||le([e]),Y.remove(e,"fxshow"),d)S.style(e,r,d[r])})),u=ct(g?v[r]:0,r,p),r in v||(v[r]=u.start,g&&(u.end=u.start,u.start=0))}],prefilter:function(e,t){t?ft.prefilters.unshift(e):ft.prefilters.push(e)}}),S.speed=function(e,t,n){var r=e&&"object"==typeof e?S.extend({},e):{complete:n||!n&&t||m(e)&&e,duration:e,easing:n&&t||t&&!m(t)&&t};return S.fx.off?r.duration=0:"number"!=typeof r.duration&&(r.duration in S.fx.speeds?r.duration=S.fx.speeds[r.duration]:r.duration=S.fx.speeds._default),null!=r.queue&&!0!==r.queue||(r.queue="fx"),r.old=r.complete,r.complete=function(){m(r.old)&&r.old.call(this),r.queue&&S.dequeue(this,r.queue)},r},S.fn.extend({fadeTo:function(e,t,n,r){return this.filter(ae).css("opacity",0).show().end().animate({opacity:t},e,n,r)},animate:function(t,e,n,r){var i=S.isEmptyObject(t),o=S.speed(e,n,r),a=function(){var e=ft(this,S.extend({},t),o);(i||Y.get(this,"finish"))&&e.stop(!0)};return a.finish=a,i||!1===o.queue?this.each(a):this.queue(o.queue,a)},stop:function(i,e,o){var a=function(e){var t=e.stop;delete e.stop,t(o)};return"string"!=typeof i&&(o=e,e=i,i=void 0),e&&this.queue(i||"fx",[]),this.each(function(){var e=!0,t=null!=i&&i+"queueHooks",n=S.timers,r=Y.get(this);if(t)r[t]&&r[t].stop&&a(r[t]);else for(t in r)r[t]&&r[t].stop&&at.test(t)&&a(r[t]);for(t=n.length;t--;)n[t].elem!==this||null!=i&&n[t].queue!==i||(n[t].anim.stop(o),e=!1,n.splice(t,1));!e&&o||S.dequeue(this,i)})},finish:function(a){return!1!==a&&(a=a||"fx"),this.each(function(){var e,t=Y.get(this),n=t[a+"queue"],r=t[a+"queueHooks"],i=S.timers,o=n?n.length:0;for(t.finish=!0,S.queue(this,a,[]),r&&r.stop&&r.stop.call(this,!0),e=i.length;e--;)i[e].elem===this&&i[e].queue===a&&(i[e].anim.stop(!0),i.splice(e,1));for(e=0;e<o;e++)n[e]&&n[e].finish&&n[e].finish.call(this);delete t.finish})}}),S.each(["toggle","show","hide"],function(e,r){var i=S.fn[r];S.fn[r]=function(e,t,n){return null==e||"boolean"==typeof e?i.apply(this,arguments):this.animate(lt(r,!0),e,t,n)}}),S.each({slideDown:lt("show"),slideUp:lt("hide"),slideToggle:lt("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(e,r){S.fn[e]=function(e,t,n){return this.animate(r,e,t,n)}}),S.timers=[],S.fx.tick=function(){var e,t=0,n=S.timers;for(tt=Date.now();t<n.length;t++)(e=n[t])()||n[t]!==e||n.splice(t--,1);n.length||S.fx.stop(),tt=void 0},S.fx.timer=function(e){S.timers.push(e),S.fx.start()},S.fx.interval=13,S.fx.start=function(){nt||(nt=!0,st())},S.fx.stop=function(){nt=null},S.fx.speeds={slow:600,fast:200,_default:400},S.fn.delay=function(r,e){return r=S.fx&&S.fx.speeds[r]||r,e=e||"fx",this.queue(e,function(e,t){var n=C.setTimeout(e,r);t.stop=function(){C.clearTimeout(n)}})},rt=E.createElement("input"),it=E.createElement("select").appendChild(E.createElement("option")),rt.type="checkbox",y.checkOn=""!==rt.value,y.optSelected=it.selected,(rt=E.createElement("input")).value="t",rt.type="radio",y.radioValue="t"===rt.value;var pt,dt=S.expr.attrHandle;S.fn.extend({attr:function(e,t){return $(this,S.attr,e,t,1<arguments.length)},removeAttr:function(e){return this.each(function(){S.removeAttr(this,e)})}}),S.extend({attr:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return"undefined"==typeof e.getAttribute?S.prop(e,t,n):(1===o&&S.isXMLDoc(e)||(i=S.attrHooks[t.toLowerCase()]||(S.expr.match.bool.test(t)?pt:void 0)),void 0!==n?null===n?void S.removeAttr(e,t):i&&"set"in i&&void 0!==(r=i.set(e,n,t))?r:(e.setAttribute(t,n+""),n):i&&"get"in i&&null!==(r=i.get(e,t))?r:null==(r=S.find.attr(e,t))?void 0:r)},attrHooks:{type:{set:function(e,t){if(!y.radioValue&&"radio"===t&&A(e,"input")){var n=e.value;return e.setAttribute("type",t),n&&(e.value=n),t}}}},removeAttr:function(e,t){var n,r=0,i=t&&t.match(P);if(i&&1===e.nodeType)while(n=i[r++])e.removeAttribute(n)}}),pt={set:function(e,t,n){return!1===t?S.removeAttr(e,n):e.setAttribute(n,n),n}},S.each(S.expr.match.bool.source.match(/\w+/g),function(e,t){var a=dt[t]||S.find.attr;dt[t]=function(e,t,n){var r,i,o=t.toLowerCase();return n||(i=dt[o],dt[o]=r,r=null!=a(e,t,n)?o:null,dt[o]=i),r}});var ht=/^(?:input|select|textarea|button)$/i,gt=/^(?:a|area)$/i;function vt(e){return(e.match(P)||[]).join(" ")}function yt(e){return e.getAttribute&&e.getAttribute("class")||""}function mt(e){return Array.isArray(e)?e:"string"==typeof e&&e.match(P)||[]}S.fn.extend({prop:function(e,t){return $(this,S.prop,e,t,1<arguments.length)},removeProp:function(e){return this.each(function(){delete this[S.propFix[e]||e]})}}),S.extend({prop:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return 1===o&&S.isXMLDoc(e)||(t=S.propFix[t]||t,i=S.propHooks[t]),void 0!==n?i&&"set"in i&&void 0!==(r=i.set(e,n,t))?r:e[t]=n:i&&"get"in i&&null!==(r=i.get(e,t))?r:e[t]},propHooks:{tabIndex:{get:function(e){var t=S.find.attr(e,"tabindex");return t?parseInt(t,10):ht.test(e.nodeName)||gt.test(e.nodeName)&&e.href?0:-1}}},propFix:{"for":"htmlFor","class":"className"}}),y.optSelected||(S.propHooks.selected={get:function(e){var t=e.parentNode;return t&&t.parentNode&&t.parentNode.selectedIndex,null},set:function(e){var t=e.parentNode;t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex)}}),S.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){S.propFix[this.toLowerCase()]=this}),S.fn.extend({addClass:function(t){var e,n,r,i,o,a,s,u=0;if(m(t))return this.each(function(e){S(this).addClass(t.call(this,e,yt(this)))});if((e=mt(t)).length)while(n=this[u++])if(i=yt(n),r=1===n.nodeType&&" "+vt(i)+" "){a=0;while(o=e[a++])r.indexOf(" "+o+" ")<0&&(r+=o+" ");i!==(s=vt(r))&&n.setAttribute("class",s)}return this},removeClass:function(t){var e,n,r,i,o,a,s,u=0;if(m(t))return this.each(function(e){S(this).removeClass(t.call(this,e,yt(this)))});if(!arguments.length)return this.attr("class","");if((e=mt(t)).length)while(n=this[u++])if(i=yt(n),r=1===n.nodeType&&" "+vt(i)+" "){a=0;while(o=e[a++])while(-1<r.indexOf(" "+o+" "))r=r.replace(" "+o+" "," ");i!==(s=vt(r))&&n.setAttribute("class",s)}return this},toggleClass:function(i,t){var o=typeof i,a="string"===o||Array.isArray(i);return"boolean"==typeof t&&a?t?this.addClass(i):this.removeClass(i):m(i)?this.each(function(e){S(this).toggleClass(i.call(this,e,yt(this),t),t)}):this.each(function(){var e,t,n,r;if(a){t=0,n=S(this),r=mt(i);while(e=r[t++])n.hasClass(e)?n.removeClass(e):n.addClass(e)}else void 0!==i&&"boolean"!==o||((e=yt(this))&&Y.set(this,"__className__",e),this.setAttribute&&this.setAttribute("class",e||!1===i?"":Y.get(this,"__className__")||""))})},hasClass:function(e){var t,n,r=0;t=" "+e+" ";while(n=this[r++])if(1===n.nodeType&&-1<(" "+vt(yt(n))+" ").indexOf(t))return!0;return!1}});var xt=/\r/g;S.fn.extend({val:function(n){var r,e,i,t=this[0];return arguments.length?(i=m(n),this.each(function(e){var t;1===this.nodeType&&(null==(t=i?n.call(this,e,S(this).val()):n)?t="":"number"==typeof t?t+="":Array.isArray(t)&&(t=S.map(t,function(e){return null==e?"":e+""})),(r=S.valHooks[this.type]||S.valHooks[this.nodeName.toLowerCase()])&&"set"in r&&void 0!==r.set(this,t,"value")||(this.value=t))})):t?(r=S.valHooks[t.type]||S.valHooks[t.nodeName.toLowerCase()])&&"get"in r&&void 0!==(e=r.get(t,"value"))?e:"string"==typeof(e=t.value)?e.replace(xt,""):null==e?"":e:void 0}}),S.extend({valHooks:{option:{get:function(e){var t=S.find.attr(e,"value");return null!=t?t:vt(S.text(e))}},select:{get:function(e){var t,n,r,i=e.options,o=e.selectedIndex,a="select-one"===e.type,s=a?null:[],u=a?o+1:i.length;for(r=o<0?u:a?o:0;r<u;r++)if(((n=i[r]).selected||r===o)&&!n.disabled&&(!n.parentNode.disabled||!A(n.parentNode,"optgroup"))){if(t=S(n).val(),a)return t;s.push(t)}return s},set:function(e,t){var n,r,i=e.options,o=S.makeArray(t),a=i.length;while(a--)((r=i[a]).selected=-1<S.inArray(S.valHooks.option.get(r),o))&&(n=!0);return n||(e.selectedIndex=-1),o}}}}),S.each(["radio","checkbox"],function(){S.valHooks[this]={set:function(e,t){if(Array.isArray(t))return e.checked=-1<S.inArray(S(e).val(),t)}},y.checkOn||(S.valHooks[this].get=function(e){return null===e.getAttribute("value")?"on":e.value})}),y.focusin="onfocusin"in C;var bt=/^(?:focusinfocus|focusoutblur)$/,wt=function(e){e.stopPropagation()};S.extend(S.event,{trigger:function(e,t,n,r){var i,o,a,s,u,l,c,f,p=[n||E],d=v.call(e,"type")?e.type:e,h=v.call(e,"namespace")?e.namespace.split("."):[];if(o=f=a=n=n||E,3!==n.nodeType&&8!==n.nodeType&&!bt.test(d+S.event.triggered)&&(-1<d.indexOf(".")&&(d=(h=d.split(".")).shift(),h.sort()),u=d.indexOf(":")<0&&"on"+d,(e=e[S.expando]?e:new S.Event(d,"object"==typeof e&&e)).isTrigger=r?2:3,e.namespace=h.join("."),e.rnamespace=e.namespace?new RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,e.result=void 0,e.target||(e.target=n),t=null==t?[e]:S.makeArray(t,[e]),c=S.event.special[d]||{},r||!c.trigger||!1!==c.trigger.apply(n,t))){if(!r&&!c.noBubble&&!x(n)){for(s=c.delegateType||d,bt.test(s+d)||(o=o.parentNode);o;o=o.parentNode)p.push(o),a=o;a===(n.ownerDocument||E)&&p.push(a.defaultView||a.parentWindow||C)}i=0;while((o=p[i++])&&!e.isPropagationStopped())f=o,e.type=1<i?s:c.bindType||d,(l=(Y.get(o,"events")||Object.create(null))[e.type]&&Y.get(o,"handle"))&&l.apply(o,t),(l=u&&o[u])&&l.apply&&V(o)&&(e.result=l.apply(o,t),!1===e.result&&e.preventDefault());return e.type=d,r||e.isDefaultPrevented()||c._default&&!1!==c._default.apply(p.pop(),t)||!V(n)||u&&m(n[d])&&!x(n)&&((a=n[u])&&(n[u]=null),S.event.triggered=d,e.isPropagationStopped()&&f.addEventListener(d,wt),n[d](),e.isPropagationStopped()&&f.removeEventListener(d,wt),S.event.triggered=void 0,a&&(n[u]=a)),e.result}},simulate:function(e,t,n){var r=S.extend(new S.Event,n,{type:e,isSimulated:!0});S.event.trigger(r,null,t)}}),S.fn.extend({trigger:function(e,t){return this.each(function(){S.event.trigger(e,t,this)})},triggerHandler:function(e,t){var n=this[0];if(n)return S.event.trigger(e,t,n,!0)}}),y.focusin||S.each({focus:"focusin",blur:"focusout"},function(n,r){var i=function(e){S.event.simulate(r,e.target,S.event.fix(e))};S.event.special[r]={setup:function(){var e=this.ownerDocument||this.document||this,t=Y.access(e,r);t||e.addEventListener(n,i,!0),Y.access(e,r,(t||0)+1)},teardown:function(){var e=this.ownerDocument||this.document||this,t=Y.access(e,r)-1;t?Y.access(e,r,t):(e.removeEventListener(n,i,!0),Y.remove(e,r))}}});var Tt=C.location,Ct={guid:Date.now()},Et=/\?/;S.parseXML=function(e){var t;if(!e||"string"!=typeof e)return null;try{t=(new C.DOMParser).parseFromString(e,"text/xml")}catch(e){t=void 0}return t&&!t.getElementsByTagName("parsererror").length||S.error("Invalid XML: "+e),t};var St=/\[\]$/,kt=/\r?\n/g,At=/^(?:submit|button|image|reset|file)$/i,Nt=/^(?:input|select|textarea|keygen)/i;function Dt(n,e,r,i){var t;if(Array.isArray(e))S.each(e,function(e,t){r||St.test(n)?i(n,t):Dt(n+"["+("object"==typeof t&&null!=t?e:"")+"]",t,r,i)});else if(r||"object"!==w(e))i(n,e);else for(t in e)Dt(n+"["+t+"]",e[t],r,i)}S.param=function(e,t){var n,r=[],i=function(e,t){var n=m(t)?t():t;r[r.length]=encodeURIComponent(e)+"="+encodeURIComponent(null==n?"":n)};if(null==e)return"";if(Array.isArray(e)||e.jquery&&!S.isPlainObject(e))S.each(e,function(){i(this.name,this.value)});else for(n in e)Dt(n,e[n],t,i);return r.join("&")},S.fn.extend({serialize:function(){return S.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var e=S.prop(this,"elements");return e?S.makeArray(e):this}).filter(function(){var e=this.type;return this.name&&!S(this).is(":disabled")&&Nt.test(this.nodeName)&&!At.test(e)&&(this.checked||!pe.test(e))}).map(function(e,t){var n=S(this).val();return null==n?null:Array.isArray(n)?S.map(n,function(e){return{name:t.name,value:e.replace(kt,"\r\n")}}):{name:t.name,value:n.replace(kt,"\r\n")}}).get()}});var jt=/%20/g,qt=/#.*$/,Lt=/([?&])_=[^&]*/,Ht=/^(.*?):[ \t]*([^\r\n]*)$/gm,Ot=/^(?:GET|HEAD)$/,Pt=/^\/\//,Rt={},Mt={},It="*/".concat("*"),Wt=E.createElement("a");function Ft(o){return function(e,t){"string"!=typeof e&&(t=e,e="*");var n,r=0,i=e.toLowerCase().match(P)||[];if(m(t))while(n=i[r++])"+"===n[0]?(n=n.slice(1)||"*",(o[n]=o[n]||[]).unshift(t)):(o[n]=o[n]||[]).push(t)}}function Bt(t,i,o,a){var s={},u=t===Mt;function l(e){var r;return s[e]=!0,S.each(t[e]||[],function(e,t){var n=t(i,o,a);return"string"!=typeof n||u||s[n]?u?!(r=n):void 0:(i.dataTypes.unshift(n),l(n),!1)}),r}return l(i.dataTypes[0])||!s["*"]&&l("*")}function $t(e,t){var n,r,i=S.ajaxSettings.flatOptions||{};for(n in t)void 0!==t[n]&&((i[n]?e:r||(r={}))[n]=t[n]);return r&&S.extend(!0,e,r),e}Wt.href=Tt.href,S.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:Tt.href,type:"GET",isLocal:/^(?:about|app|app-storage|.+-extension|file|res|widget):$/.test(Tt.protocol),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":It,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/\bxml\b/,html:/\bhtml/,json:/\bjson\b/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":JSON.parse,"text xml":S.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(e,t){return t?$t($t(e,S.ajaxSettings),t):$t(S.ajaxSettings,e)},ajaxPrefilter:Ft(Rt),ajaxTransport:Ft(Mt),ajax:function(e,t){"object"==typeof e&&(t=e,e=void 0),t=t||{};var c,f,p,n,d,r,h,g,i,o,v=S.ajaxSetup({},t),y=v.context||v,m=v.context&&(y.nodeType||y.jquery)?S(y):S.event,x=S.Deferred(),b=S.Callbacks("once memory"),w=v.statusCode||{},a={},s={},u="canceled",T={readyState:0,getResponseHeader:function(e){var t;if(h){if(!n){n={};while(t=Ht.exec(p))n[t[1].toLowerCase()+" "]=(n[t[1].toLowerCase()+" "]||[]).concat(t[2])}t=n[e.toLowerCase()+" "]}return null==t?null:t.join(", ")},getAllResponseHeaders:function(){return h?p:null},setRequestHeader:function(e,t){return null==h&&(e=s[e.toLowerCase()]=s[e.toLowerCase()]||e,a[e]=t),this},overrideMimeType:function(e){return null==h&&(v.mimeType=e),this},statusCode:function(e){var t;if(e)if(h)T.always(e[T.status]);else for(t in e)w[t]=[w[t],e[t]];return this},abort:function(e){var t=e||u;return c&&c.abort(t),l(0,t),this}};if(x.promise(T),v.url=((e||v.url||Tt.href)+"").replace(Pt,Tt.protocol+"//"),v.type=t.method||t.type||v.method||v.type,v.dataTypes=(v.dataType||"*").toLowerCase().match(P)||[""],null==v.crossDomain){r=E.createElement("a");try{r.href=v.url,r.href=r.href,v.crossDomain=Wt.protocol+"//"+Wt.host!=r.protocol+"//"+r.host}catch(e){v.crossDomain=!0}}if(v.data&&v.processData&&"string"!=typeof v.data&&(v.data=S.param(v.data,v.traditional)),Bt(Rt,v,t,T),h)return T;for(i in(g=S.event&&v.global)&&0==S.active++&&S.event.trigger("ajaxStart"),v.type=v.type.toUpperCase(),v.hasContent=!Ot.test(v.type),f=v.url.replace(qt,""),v.hasContent?v.data&&v.processData&&0===(v.contentType||"").indexOf("application/x-www-form-urlencoded")&&(v.data=v.data.replace(jt,"+")):(o=v.url.slice(f.length),v.data&&(v.processData||"string"==typeof v.data)&&(f+=(Et.test(f)?"&":"?")+v.data,delete v.data),!1===v.cache&&(f=f.replace(Lt,"$1"),o=(Et.test(f)?"&":"?")+"_="+Ct.guid+++o),v.url=f+o),v.ifModified&&(S.lastModified[f]&&T.setRequestHeader("If-Modified-Since",S.lastModified[f]),S.etag[f]&&T.setRequestHeader("If-None-Match",S.etag[f])),(v.data&&v.hasContent&&!1!==v.contentType||t.contentType)&&T.setRequestHeader("Content-Type",v.contentType),T.setRequestHeader("Accept",v.dataTypes[0]&&v.accepts[v.dataTypes[0]]?v.accepts[v.dataTypes[0]]+("*"!==v.dataTypes[0]?", "+It+"; q=0.01":""):v.accepts["*"]),v.headers)T.setRequestHeader(i,v.headers[i]);if(v.beforeSend&&(!1===v.beforeSend.call(y,T,v)||h))return T.abort();if(u="abort",b.add(v.complete),T.done(v.success),T.fail(v.error),c=Bt(Mt,v,t,T)){if(T.readyState=1,g&&m.trigger("ajaxSend",[T,v]),h)return T;v.async&&0<v.timeout&&(d=C.setTimeout(function(){T.abort("timeout")},v.timeout));try{h=!1,c.send(a,l)}catch(e){if(h)throw e;l(-1,e)}}else l(-1,"No Transport");function l(e,t,n,r){var i,o,a,s,u,l=t;h||(h=!0,d&&C.clearTimeout(d),c=void 0,p=r||"",T.readyState=0<e?4:0,i=200<=e&&e<300||304===e,n&&(s=function(e,t,n){var r,i,o,a,s=e.contents,u=e.dataTypes;while("*"===u[0])u.shift(),void 0===r&&(r=e.mimeType||t.getResponseHeader("Content-Type"));if(r)for(i in s)if(s[i]&&s[i].test(r)){u.unshift(i);break}if(u[0]in n)o=u[0];else{for(i in n){if(!u[0]||e.converters[i+" "+u[0]]){o=i;break}a||(a=i)}o=o||a}if(o)return o!==u[0]&&u.unshift(o),n[o]}(v,T,n)),!i&&-1<S.inArray("script",v.dataTypes)&&(v.converters["text script"]=function(){}),s=function(e,t,n,r){var i,o,a,s,u,l={},c=e.dataTypes.slice();if(c[1])for(a in e.converters)l[a.toLowerCase()]=e.converters[a];o=c.shift();while(o)if(e.responseFields[o]&&(n[e.responseFields[o]]=t),!u&&r&&e.dataFilter&&(t=e.dataFilter(t,e.dataType)),u=o,o=c.shift())if("*"===o)o=u;else if("*"!==u&&u!==o){if(!(a=l[u+" "+o]||l["* "+o]))for(i in l)if((s=i.split(" "))[1]===o&&(a=l[u+" "+s[0]]||l["* "+s[0]])){!0===a?a=l[i]:!0!==l[i]&&(o=s[0],c.unshift(s[1]));break}if(!0!==a)if(a&&e["throws"])t=a(t);else try{t=a(t)}catch(e){return{state:"parsererror",error:a?e:"No conversion from "+u+" to "+o}}}return{state:"success",data:t}}(v,s,T,i),i?(v.ifModified&&((u=T.getResponseHeader("Last-Modified"))&&(S.lastModified[f]=u),(u=T.getResponseHeader("etag"))&&(S.etag[f]=u)),204===e||"HEAD"===v.type?l="nocontent":304===e?l="notmodified":(l=s.state,o=s.data,i=!(a=s.error))):(a=l,!e&&l||(l="error",e<0&&(e=0))),T.status=e,T.statusText=(t||l)+"",i?x.resolveWith(y,[o,l,T]):x.rejectWith(y,[T,l,a]),T.statusCode(w),w=void 0,g&&m.trigger(i?"ajaxSuccess":"ajaxError",[T,v,i?o:a]),b.fireWith(y,[T,l]),g&&(m.trigger("ajaxComplete",[T,v]),--S.active||S.event.trigger("ajaxStop")))}return T},getJSON:function(e,t,n){return S.get(e,t,n,"json")},getScript:function(e,t){return S.get(e,void 0,t,"script")}}),S.each(["get","post"],function(e,i){S[i]=function(e,t,n,r){return m(t)&&(r=r||n,n=t,t=void 0),S.ajax(S.extend({url:e,type:i,dataType:r,data:t,success:n},S.isPlainObject(e)&&e))}}),S.ajaxPrefilter(function(e){var t;for(t in e.headers)"content-type"===t.toLowerCase()&&(e.contentType=e.headers[t]||"")}),S._evalUrl=function(e,t,n){return S.ajax({url:e,type:"GET",dataType:"script",cache:!0,async:!1,global:!1,converters:{"text script":function(){}},dataFilter:function(e){S.globalEval(e,t,n)}})},S.fn.extend({wrapAll:function(e){var t;return this[0]&&(m(e)&&(e=e.call(this[0])),t=S(e,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstElementChild)e=e.firstElementChild;return e}).append(this)),this},wrapInner:function(n){return m(n)?this.each(function(e){S(this).wrapInner(n.call(this,e))}):this.each(function(){var e=S(this),t=e.contents();t.length?t.wrapAll(n):e.append(n)})},wrap:function(t){var n=m(t);return this.each(function(e){S(this).wrapAll(n?t.call(this,e):t)})},unwrap:function(e){return this.parent(e).not("body").each(function(){S(this).replaceWith(this.childNodes)}),this}}),S.expr.pseudos.hidden=function(e){return!S.expr.pseudos.visible(e)},S.expr.pseudos.visible=function(e){return!!(e.offsetWidth||e.offsetHeight||e.getClientRects().length)},S.ajaxSettings.xhr=function(){try{return new C.XMLHttpRequest}catch(e){}};var _t={0:200,1223:204},zt=S.ajaxSettings.xhr();y.cors=!!zt&&"withCredentials"in zt,y.ajax=zt=!!zt,S.ajaxTransport(function(i){var o,a;if(y.cors||zt&&!i.crossDomain)return{send:function(e,t){var n,r=i.xhr();if(r.open(i.type,i.url,i.async,i.username,i.password),i.xhrFields)for(n in i.xhrFields)r[n]=i.xhrFields[n];for(n in i.mimeType&&r.overrideMimeType&&r.overrideMimeType(i.mimeType),i.crossDomain||e["X-Requested-With"]||(e["X-Requested-With"]="XMLHttpRequest"),e)r.setRequestHeader(n,e[n]);o=function(e){return function(){o&&(o=a=r.onload=r.onerror=r.onabort=r.ontimeout=r.onreadystatechange=null,"abort"===e?r.abort():"error"===e?"number"!=typeof r.status?t(0,"error"):t(r.status,r.statusText):t(_t[r.status]||r.status,r.statusText,"text"!==(r.responseType||"text")||"string"!=typeof r.responseText?{binary:r.response}:{text:r.responseText},r.getAllResponseHeaders()))}},r.onload=o(),a=r.onerror=r.ontimeout=o("error"),void 0!==r.onabort?r.onabort=a:r.onreadystatechange=function(){4===r.readyState&&C.setTimeout(function(){o&&a()})},o=o("abort");try{r.send(i.hasContent&&i.data||null)}catch(e){if(o)throw e}},abort:function(){o&&o()}}}),S.ajaxPrefilter(function(e){e.crossDomain&&(e.contents.script=!1)}),S.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/\b(?:java|ecma)script\b/},converters:{"text script":function(e){return S.globalEval(e),e}}}),S.ajaxPrefilter("script",function(e){void 0===e.cache&&(e.cache=!1),e.crossDomain&&(e.type="GET")}),S.ajaxTransport("script",function(n){var r,i;if(n.crossDomain||n.scriptAttrs)return{send:function(e,t){r=S("<script>").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),E.head.appendChild(r[0])},abort:function(){i&&i()}}});var Ut,Xt=[],Vt=/(=)\?(?=&|$)|\?\?/;S.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Xt.pop()||S.expando+"_"+Ct.guid++;return this[e]=!0,e}}),S.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Vt.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Vt.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=m(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Vt,"$1"+r):!1!==e.jsonp&&(e.url+=(Et.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||S.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=C[r],C[r]=function(){o=arguments},n.always(function(){void 0===i?S(C).removeProp(r):C[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,Xt.push(r)),o&&m(i)&&i(o[0]),o=i=void 0}),"script"}),y.createHTMLDocument=((Ut=E.implementation.createHTMLDocument("").body).innerHTML="<form></form><form></form>",2===Ut.childNodes.length),S.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(y.createHTMLDocument?((r=(t=E.implementation.createHTMLDocument("")).createElement("base")).href=E.location.href,t.head.appendChild(r)):t=E),o=!n&&[],(i=N.exec(e))?[t.createElement(i[1])]:(i=xe([e],t,o),o&&o.length&&S(o).remove(),S.merge([],i.childNodes)));var r,i,o},S.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1<s&&(r=vt(e.slice(s)),e=e.slice(0,s)),m(t)?(n=t,t=void 0):t&&"object"==typeof t&&(i="POST"),0<a.length&&S.ajax({url:e,type:i||"GET",dataType:"html",data:t}).done(function(e){o=arguments,a.html(r?S("<div>").append(S.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},S.expr.pseudos.animated=function(t){return S.grep(S.timers,function(e){return t===e.elem}).length},S.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=S.css(e,"position"),c=S(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=S.css(e,"top"),u=S.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),m(t)&&(t=t.call(e,n,S.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):("number"==typeof f.top&&(f.top+="px"),"number"==typeof f.left&&(f.left+="px"),c.css(f))}},S.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){S.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===S.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===S.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=S(e).offset()).top+=S.css(e,"borderTopWidth",!0),i.left+=S.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-S.css(r,"marginTop",!0),left:t.left-i.left-S.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===S.css(e,"position"))e=e.offsetParent;return e||re})}}),S.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;S.fn[t]=function(e){return $(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),S.each(["top","left"],function(e,n){S.cssHooks[n]=$e(y.pixelPosition,function(e,t){if(t)return t=Be(e,n),Me.test(t)?S(e).position()[n]+"px":t})}),S.each({Height:"height",Width:"width"},function(a,s){S.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){S.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return $(this,function(e,t,n){var r;return x(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?S.css(e,t,i):S.style(e,t,n,i)},s,n?e:void 0,n)}})}),S.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){S.fn[t]=function(e){return this.on(t,e)}}),S.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),S.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){S.fn[n]=function(e,t){return 0<arguments.length?this.on(n,null,e,t):this.trigger(n)}});var Gt=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g;S.proxy=function(e,t){var n,r,i;if("string"==typeof t&&(n=e[t],t=e,e=n),m(e))return r=s.call(arguments,2),(i=function(){return e.apply(t||this,r.concat(s.call(arguments)))}).guid=e.guid=e.guid||S.guid++,i},S.holdReady=function(e){e?S.readyWait++:S.ready(!0)},S.isArray=Array.isArray,S.parseJSON=JSON.parse,S.nodeName=A,S.isFunction=m,S.isWindow=x,S.camelCase=X,S.type=w,S.now=Date.now,S.isNumeric=function(e){var t=S.type(e);return("number"===t||"string"===t)&&!isNaN(e-parseFloat(e))},S.trim=function(e){return null==e?"":(e+"").replace(Gt,"")},"function"==typeof define&&define.amd&&define("jquery",[],function(){return S});var Yt=C.jQuery,Qt=C.$;return S.noConflict=function(e){return C.$===S&&(C.$=Qt),e&&C.jQuery===S&&(C.jQuery=Yt),S},"undefined"==typeof e&&(C.jQuery=C.$=S),S}); diff --git a/.config/startpage/pywal.css b/.config/startpage/pywal.css new file mode 100644 index 0000000..de2f510 --- /dev/null +++ b/.config/startpage/pywal.css @@ -0,0 +1,63 @@ +:root { + --pywal-shade0: #18191C; + --pywal-shade1: #1D1E21; + --pywal-shade2: #1F2024; + --pywal-shade3: #222227; + --pywal-shade4: #1F202A; + + --pywal-bg0: #141415; + --pywal-bg1: #181819; + --pywal-bg2: #1C1C1D; + --pywal-bg3: #202022; + + --pywal-color0: #141415; + --pywal-color1: #292b37; + --pywal-color2: #3c2a27; + --pywal-color3: #3b3033; + --pywal-color4: #3f3330; + --pywal-color5: #4b4240; + --pywal-color6: #66615a; + --pywal-color7: #c4c4c4; + --pywal-color8: #4e4e4f; + --pywal-color9: #292b37; + --pywal-color10: #3c2a27; + --pywal-color11: #3b3033; + --pywal-color12: #3f3330; + --pywal-color13: #4b4240; + --pywal-color14: #66615a; + --pywal-color15: #c4c4c4; + + --pywal-readable-color0: #6B6B70; + --pywal-readable-color1: #585B71; + --pywal-readable-color2: #745550; + --pywal-readable-color3: #67565A; + --pywal-readable-color4: #665450; + --pywal-readable-color5: #4B4240; + --pywal-readable-color6: #66615A; + --pywal-readable-color7: #C4C4C4; + --pywal-readable-color8: #4E4E4F; + --pywal-readable-color9: #585B71; + --pywal-readable-color10: #745550; + --pywal-readable-color11: #67565A; + --pywal-readable-color12: #665450; + --pywal-readable-color13: #4B4240; + --pywal-readable-color14: #66615A; + --pywal-readable-color15: #C4C4C4; + + --pywal-readableOn-color0: #c4c4c4; + --pywal-readableOn-color1: #c4c4c4; + --pywal-readableOn-color2: #c4c4c4; + --pywal-readableOn-color3: #c4c4c4; + --pywal-readableOn-color4: #c4c4c4; + --pywal-readableOn-color5: #c4c4c4; + --pywal-readableOn-color6: #c4c4c4; + --pywal-readableOn-color7: #141415; + --pywal-readableOn-color8: #c4c4c4; + --pywal-readableOn-color9: #c4c4c4; + --pywal-readableOn-color10: #c4c4c4; + --pywal-readableOn-color11: #c4c4c4; + --pywal-readableOn-color12: #c4c4c4; + --pywal-readableOn-color13: #c4c4c4; + --pywal-readableOn-color14: #c4c4c4; + --pywal-readableOn-color15: #141415; +}
\ No newline at end of file diff --git a/.config/startpage/script.js b/.config/startpage/script.js new file mode 100644 index 0000000..c735e78 --- /dev/null +++ b/.config/startpage/script.js @@ -0,0 +1,7 @@ +// Time +$('.time').text(new Date().toLocaleTimeString('nl').substr(0, 5)) +setInterval(() => { + $('.time').text(new Date().toLocaleTimeString('nl').substr(0, 5)) +}, 500); + + diff --git a/.config/startpage/style.css b/.config/startpage/style.css new file mode 100644 index 0000000..f6eea2d --- /dev/null +++ b/.config/startpage/style.css @@ -0,0 +1,91 @@ +@import url(file:///home/loek/.config/startpage/pywal.css); + +html, body { + margin: 0; + padding: 0; + background: var(--pywal-color0); + color: var(--pywal-color15); + font-family: "JetBrainsMono NF"; +} + +* { + cursor: normal; + user-select: none; +} + +h1 { + margin: 0; +} + +.center { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + white-space: nowrap; +} + +.term { + width: 500px; + padding: 16px; + position: relative; +} + +.term::before { + content: ''; + width: 100%; + height: 100%; + position: absolute; + top: 0; + left: 0; + background-color: var(--pywal-color8); + opacity: 0.2; + z-index: -2; + border-radius: 8px; +} + +h3 { + font-size: 14px; + font-weight: 800; + margin: 0 0 8px 0; +} + +.columns { + display: grid; + grid-template-columns: repeat(3, 1fr); +} + +.columns .column { + display: inline-block; +} + +.columns .column * { + display: block; +} + +a { + font-size: 14px; + font-weight: normal; + text-decoration: none; + color: var(--pywal-color15); + position: relative; + left: 0; + transition: left .3s; +} + +a::before { + content: '➜'; + position: absolute; + left: -30px; + opacity: 0; + transition: left .3s, opacity .3s; +} + +a:hover { + left: 15px; +} + +a:hover::before { + left: -15px; + opacity: 1; +} diff --git a/.config/user-dirs.dirs b/.config/user-dirs.dirs new file mode 100644 index 0000000..f7c6dec --- /dev/null +++ b/.config/user-dirs.dirs @@ -0,0 +1,15 @@ +# This file is written by xdg-user-dirs-update +# If you want to change or add directories, just edit the line you're +# interested in. All local changes will be retained on the next run. +# Format is XDG_xxx_DIR="$HOME/yyy", where yyy is a shell-escaped +# homedir-relative path, or XDG_xxx_DIR="/yyy", where /yyy is an +# absolute path. No other format is supported. +# +XDG_DOWNLOAD_DIR="$HOME/dl" +XDG_DOCUMENTS_DIR="$HOME/docs" +XDG_MUSIC_DIR="$HOME/music" +XDG_DESKTOP_DIR="$HOME/" +XDG_TEMPLATES_DIR="$HOME/" +XDG_PUBLICSHARE_DIR="$HOME/" +XDG_PICTURES_DIR="$HOME/" +XDG_VIDEOS_DIR="$HOME/" diff --git a/.config/user-dirs.locale b/.config/user-dirs.locale new file mode 100644 index 0000000..3e0b419 --- /dev/null +++ b/.config/user-dirs.locale @@ -0,0 +1 @@ +en_US
\ No newline at end of file diff --git a/.config/zathura/zathurarc b/.config/zathura/zathurarc new file mode 100644 index 0000000..2e94927 --- /dev/null +++ b/.config/zathura/zathurarc @@ -0,0 +1,13 @@ +set scroll-page-aware "true" +set smooth-scroll "true" +set scroll-full-overlap 0.01 +set scroll-step 100 +set font "Fira Code 10" + +# recolor (dark mode) +map <C-i> recolor +set recolor "true" +set recolor-lightcolor "#141415" +set recolor-darkcolor "#c4c4c4" +set recolor-reverse-video "true" +set recolor-keephue "true" diff --git a/.local/share/bin/brave b/.local/share/bin/brave new file mode 100755 index 0000000..c645f54 --- /dev/null +++ b/.local/share/bin/brave @@ -0,0 +1,9 @@ +#!/bin/sh + +XDG_CONFIG_HOME="${XDG_CONFIG_HOME:-$HOME/.config}" +BRAVE_USER_FLAGS_FILE="$XDG_CONFIG_HOME/brave-flags.conf" +if [[ -f $BRAVE_USER_FLAGS_FILE ]]; then + USER_FLAGS="$(cat $BRAVE_USER_FLAGS_FILE | sed 's/#.*//')" +fi + +/usr/bin/brave $@ $USER_FLAGS diff --git a/.local/share/bin/loadwall b/.local/share/bin/loadwall new file mode 100755 index 0000000..e419667 --- /dev/null +++ b/.local/share/bin/loadwall @@ -0,0 +1,5 @@ +#!/bin/node +var args = process.argv; +var image = args.find(a => a.match(/\.(png|jpeg|jpg)/g)); +var wal = require(__dirname + "/pywal/jswal.js"); +wal(["--bg-fill", image]); diff --git a/.local/share/bin/m3uprefix b/.local/share/bin/m3uprefix new file mode 100755 index 0000000..c5ab206 --- /dev/null +++ b/.local/share/bin/m3uprefix @@ -0,0 +1,9 @@ +#!/bin/bash + +fullfile=$1 + +filename=$(basename -- "$fullfile") +filename="${filename%.*}" + +nvim "+%s/^[^#]/$filename\/&/g" "+wq" "$fullfile" + diff --git a/.local/share/konsole/Loekaars.profile b/.local/share/konsole/Loekaars.profile new file mode 100644 index 0000000..ce1eadd --- /dev/null +++ b/.local/share/konsole/Loekaars.profile @@ -0,0 +1,35 @@ +[Appearance] +AntiAliasFonts=true +BoldIntense=true +ColorScheme=colors-konsole +Font=JetBrainsMono Nerd Font,10,-1,5,57,0,0,0,0,0,Medium +LineSpacing=0 +UseFontLineChararacters=true + +[Cursor Options] +CustomCursorColor=213,216,218 +UseCustomCursorColor=true + +[General] +DimWhenInactive=false +LocalTabTitleFormat=%n +Name=Loekaars +Parent=FALLBACK/ +ShowTerminalSizeHint=false +TerminalCenter=false +TerminalColumns=150 +TerminalMargin=0 +TerminalRows=44 + +[Interaction Options] +AutoCopySelectedText=true +CopyTextAsHTML=false +MiddleClickPasteMode=1 +OpenLinksByDirectClickEnabled=true +UnderlineLinksEnabled=true + +[Scrolling] +ScrollBarPosition=2 + +[Terminal Features] +UrlHintsModifiers=268435456 diff --git a/.local/share/konsole/colors-konsole.colorscheme b/.local/share/konsole/colors-konsole.colorscheme new file mode 120000 index 0000000..76c0d26 --- /dev/null +++ b/.local/share/konsole/colors-konsole.colorscheme @@ -0,0 +1 @@ +/home/loek/.cache/wal/colors-konsole.colorscheme
\ No newline at end of file diff --git a/.xprofile b/.xprofile new file mode 100755 index 0000000..1cdf34a --- /dev/null +++ b/.xprofile @@ -0,0 +1,9 @@ +export _JAVA_AWT_WM_NONREPARENTING=1 +export TZ='Europe/Amsterdam' + +/usr/lib/polkit-gnome/polkit-gnome-authentication-agent-1 & +exec xrdb /home/loek/.config/X11/Xresources & +autocutsel & + +i3 + @@ -0,0 +1,117 @@ +# xdg to be safe :) +XDG_CONFIG_HOME="$HOME"/.config +XDG_CACHE_HOME="$HOME"/.cache +XDG_DATA_HOME="$HOME"/.local/share + +ZSH_THEME="agnoster" + +export ZSH="/home/loek/.local/share/oh-my-zsh" +export ADOTDIR="$XDG_CONFIG_HOME"/antigen + +source ~/.config/antigen.zsh +antigen use oh-my-zsh +antigen bundle git +antigen bundle zsh-users/zsh-syntax-highlighting +antigen bundle zsh-users/zsh-autosuggestions +antigen theme agnoster +antigen bundle arzzen/calc.plugin.zsh +antigen apply + +source $ZSH/oh-my-zsh.sh + +# scripts +export PATH=~/.local/share/bin:$PATH +export PATH=~/.local/go/bin:$PATH + +# restic +export RESTIC_PASSWORD_FILE=/mnt/g/resticpass +export RESTIC_REPOSITORY=/mnt/g + +# environment variables +export EDITOR='nvim' +export FZF_DEFAULT_COMMAND='find .' +export XCURSOR_PATH=${XCURSOR_PATH}:~/.local/share/icons +export GOPATH=$HOME/.local/go +export ETESYNC_URL="https://superesc:9443" + +# js-beautify +export jsbeautify_end_with_newline=true +export jsbeautify_brace_style="preserve-inline" +export jsbeautify_indent_with_tabs=true + +# node certificate settings +export NODE_EXTRA_CA_CERTS=/usr/share/ca-certificates/bitwarden.crt + +# NVM +export NVM_DIR="$([ -z "${XDG_CONFIG_HOME-}" ] && printf %s "${HOME}/.nvm" || printf %s "${XDG_CONFIG_HOME}/nvm")" +[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm + +# mkcd +function mkcd { + mkdir "$1" && cd "$1" +} + +# clone +function clone { + git clone https://github.com/$1 && cd "${1#*/}" +} + +# gitignore +function gi() { curl -sL https://www.toptal.com/developers/gitignore/api/$@ ;} + +# ueberzug +source "`ueberzug library`" + +# aliases +alias chrome="chromium" +alias l="live-server" +alias r='ranger --choosedir=$HOME/.cache/rangerdir; LASTDIR=`cat $HOME/.cache/rangerdir`; cd "$LASTDIR"' +alias wacom="xsetwacom set $(xsetwacom list devices | grep stylus | grep -oP --color=never "(?<=id\:\s)([0-9]*)") area 0 0 15200 4275" +alias reload="sudo systemctl restart lightdm" +alias rwall="node ~/.local/share/bin/pywal/wall.js" +alias patchmc="node /home/loek/.local/share/bin/patch_minecraft_profiles.js" +alias cls="clear" +alias lowerpolybar="xdo lower -n Polybar -n tray && xdo lower -N Polybar" +alias timesync="sudo ntpd -qg && sudo hwclock --systohc" +alias v="nvim" +alias vim="nvim" +alias copy="xclip -selection c" +alias sdl="spotifydl" +alias sctl="systemctl" +alias ncp="ncmpcpp" +alias xsiv="i3-swallow sxiv" +alias scrcpy="i3-swallow scrcpy" +alias dnd="dragon-drag-and-drop" +alias adda="git add -A" +alias first="git commit -m \"first commit\"" + +# cursors +alias cursorbl="printf '\033[1 q'" +alias cursorul="printf '\033[4 q'" +alias cursorbar="printf '\033[6 q'" + +# dircolors +eval "`dircolors ~/.config/dircolors`" + +# cleanup +rm -rf ~/.Wurst\ encryption ~/.xsession-errors ~/.xsession-errors.old ~/.zcompdump* ~/.zshrc.zwc ~/.lesshst ~/.lyrics ~/.android ~/.zcalc_history .git-credentials .node_repl_history .python_history +export ANDROID_SDK_HOME="$XDG_CONFIG_HOME"/android +export ADB_VENDOR_KEY="$XDG_CONFIG_HOME"/android +export CARGO_HOME="$XDG_DATA_HOME"/cargo +alias nvidia-settings=nvidia-settings --config="$XDG_CONFIG_HOME"/nvidia/settings +export gnome_user_dir="$HOME"/.config/gnome/apps +export GNUPGHOME="$XDG_DATA_HOME"/gnupg +alias gpg2="gpg2 --homedir $XDG_DATA_HOME/gnupg" +export GRADLE_USER_HOME="$XDG_DATA_HOME"/gradle +export _JAVA_OPTIONS=-Djava.util.prefs.userRoot="$XDG_CONFIG_HOME"/java +export NPM_CONFIG_USERCONFIG=$XDG_CONFIG_HOME/npm/npmrc +export NVM_DIR="$XDG_DATA_HOME"/nvm +export PARALLEL_HOME="$XDG_CONFIG_HOME"/parallel +export PYLINTHOME="$XDG_CACHE_HOME"/pylint +export STACK_ROOT="$XDG_DATA_HOME"/stack +export WINEPREFIX="$XDG_DATA_HOME"/wineprefixes/default +export HISTFILE="$XDG_DATA_HOME"/zsh/history +export CUDA_CACHE_PATH="$XDG_CACHE_HOME"/nv +alias gpg2="gpg2 --homedir $XDG_DATA_HOME/gnupg" +export CONAN_USER_HOME="$XDG_CONFIG_HOME/conan" + diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..fdb474d --- /dev/null +++ b/readme.md @@ -0,0 +1,24 @@ +# dottydots + +these are dotfiles + +- discord +- spotify +- zsh +- nvim +- i3 +- polybar +- zathura +- chromium +- brave +- rofi +- konsole + +also includes jswal, my shitty inefficient wrapper for wal that adds readable colors and more things to theme and such + +# screenshots + +![](1.png) +![](2.png) +![](3.png) + |