7023c500dd7a

More
[view raw] [browse files]
author Steve Losh <steve@stevelosh.com>
date Mon, 23 Aug 2021 11:51:18 -0400
parents d4ff2322e2ab
children 1720a1e79e8b
branches/tags (none)
files gitconfig lispwords psqlrc stumpwmrc weechat/alias.conf weechat/autosort.conf weechat/buflist.conf weechat/charset.conf weechat/exec.conf weechat/fifo.conf weechat/fset.conf weechat/logger.conf weechat/python.conf weechat/python/autoload/autosort.py weechat/python/autoload/brows.py weechat/python/autoload/colon_complete.py weechat/python/autoload/editor.py weechat/python/autoload/quotes.py weechat/python/autoload/sanitize_jira.py weechat/python/autosort.py weechat/python/colon_complete.py weechat/python/sanitize_jira.py weechat/relay.conf weechat/ruby.conf weechat/script.conf weechat/trigger.conf weechat/urlgrab.conf weechat/weechat.conf weechat/xfer.conf

Changes

--- a/gitconfig	Tue Aug 17 15:20:33 2021 -0400
+++ b/gitconfig	Mon Aug 23 11:51:18 2021 -0400
@@ -8,6 +8,7 @@
     excludesfile = ~/.gitignore
 
 [alias]
+    mainbranch = "!f() { git branch | grep -P ' (master|main)$' | sed -Ee 's/.* //'; }; f"
     tags = tag -l
     branches = branch -a
     remotes = remote -v
@@ -33,9 +34,6 @@
     ci = commit
     cm = commit -m
 
-    rom = rebase origin/master
-    rec = rebase --continue
-
     d = diff
     di = diff --cached
     dl = "!f() { git diff \"$@\" | nvim -R -c 'set ft=diff' -; }; f"
@@ -84,7 +82,7 @@
 
     fuu = "!sh -c 'git fu && git uu' -"
     fuo = "!sh -c 'git fo && git uo' -"
-    fuom = "!sh -c 'git co master && git fo && git uo' -"
+    fuom = "!sh -c 'git co $(git mainbranch) && git fo && git uo' -"
 
     addremove = !git add . && git add -u
     addrem = !git addremove
--- a/lispwords	Tue Aug 17 15:20:33 2021 -0400
+++ b/lispwords	Mon Aug 23 11:51:18 2021 -0400
@@ -121,6 +121,7 @@
 
 ; stumpwm
 (3 defcommand)
+(1 when-let-window)
 
 ; adopt
 (2 define-interface)
@@ -140,3 +141,4 @@
 
 ; boots
 (1 event-case)
+
--- a/psqlrc	Tue Aug 17 15:20:33 2021 -0400
+++ b/psqlrc	Mon Aug 23 11:51:18 2021 -0400
@@ -10,3 +10,4 @@
 
 \setenv PAGER less
 \setenv LESS -iS
+
--- a/stumpwmrc	Tue Aug 17 15:20:33 2021 -0400
+++ b/stumpwmrc	Mon Aug 23 11:51:18 2021 -0400
@@ -7,7 +7,7 @@
 ;;;; Config -------------------------------------------------------------------
 (set-prefix-key (kbd "C-space"))
 
-(redirect-all-output (data-dir-file "debug" "log"))
+(defvar *redirected* (redirect-all-output (data-dir-file "debug" "log")))
 
 (setf *mouse-focus-policy* :click
       *message-window-gravity* :center
@@ -144,6 +144,10 @@
   "Find and return a fresh list of all windows that match `query` under `window-match-p`."
   (remove-if-not (lambda (w) (window-match-p query w)) (all-windows)))
 
+(defmacro when-let-window ((symbol title-query) &body body)
+  `(when-let ((,symbol (find-window `(:title ,(ppcre:create-scanner ,title-query)))))
+     ,@body))
+
 
 ;;;; Posture ------------------------------------------------------------------
 (defparameter *posture-thread* nil)
@@ -402,10 +406,17 @@
   (run-shell-command (format nil "mark ~A" thing)))
 
 (defcommand toggle-zoom-mute () ()
-  (when-let ((win (find-window `(:title ,(ppcre:create-scanner "^Zoom Meeting.*")))))
+  (when-let-window (win "^Zoom Meeting.*")
     (focus-window win t) ; Zoom stupidly won't accept the shortcut unless it's in focus
     (meta (kbd "M-a"))))
 
+(defcommand end-zoom () ()
+  (when-let-window (win "^Zoom Meeting.*")
+    (kill-window win))
+  (sleep 2)
+  (when-let-window (win "^Zoom -.*")
+    (kill-window win)))
+
 
 ;;;; Terminal Fonts -----------------------------------------------------------
 (defcommand reload-terminal-font-size ()
@@ -473,8 +484,8 @@
   (run-or-raise "gcontrol" '(:class "Gnome-control-center")))
 
 (defcommand zoom () ()
-  (when-let ((window (find-window `(:title ,(ppcre:create-scanner "^Zoom Meeting.*")))))
-    (focus-window window t)))
+  (when-let-window (w "^Zoom Meeting.*")
+    (focus-window w t)))
 
 
 ;;;; Timers -------------------------------------------------------------------
@@ -547,6 +558,7 @@
   ("H-o" "files")
   ("H-z" "zoom")
   ("XF86Launch8" "toggle-zoom-mute")
+  ("H-XF86Launch8" "end-zoom")
   ("H-q" "exec lock-screen")
   ("H-y" "screenshot")
   ("H-g" "gcontrol")
--- a/weechat/alias.conf	Tue Aug 17 15:20:33 2021 -0400
+++ b/weechat/alias.conf	Mon Aug 23 11:51:18 2021 -0400
@@ -1,10 +1,10 @@
 #
-# weechat -- alias.conf
+# WeeChat -- alias.conf
 #
 # WARNING: It is NOT recommended to edit this file by hand,
 # especially if WeeChat is running.
 #
-# Use /set or similar command to change settings in WeeChat.
+# Use commands like /set or /fset to change settings in WeeChat.
 #
 # For more info, see: https://weechat.org/doc/quickstart
 #
--- a/weechat/autosort.conf	Tue Aug 17 15:20:33 2021 -0400
+++ b/weechat/autosort.conf	Mon Aug 23 11:51:18 2021 -0400
@@ -1,18 +1,24 @@
 #
-# weechat -- autosort.conf
+# WeeChat -- autosort.conf
 #
 # WARNING: It is NOT recommended to edit this file by hand,
 # especially if WeeChat is running.
 #
-# Use /set or similar command to change settings in WeeChat.
+# Use commands like /set or /fset to change settings in WeeChat.
 #
 # For more info, see: https://weechat.org/doc/quickstart
 #
 
 [sorting]
 case_sensitive = off
-group_irc = on
+debug_log = off
 replacements = "[]"
 rules = "[["core", 0], ["irc", 2], ["*", 1], ["irc.irc_raw", 0], ["irc.server", 1]]"
+signal_delay = 5
 signals = "buffer_opened buffer_merged buffer_unmerged buffer_renamed"
+sort_limit = 100
 sort_on_config_change = on
+
+[v3]
+helpers = "{"core_first": "${if:${buffer.full_name}!=core.weechat}", "irc_raw_first": "${if:${buffer.full_name}!=irc.irc_raw}", "irc_raw_last": "${if:${buffer.full_name}==irc.irc_raw}", "hashless_name": "${info:autosort_replace,#,,${info:autosort_escape,${buffer.name}}}", "script_or_plugin": "${if:${script_name}?${script_name}:${plugin}}"}"
+rules = "["${core_first}", "${info:autosort_order,${info:autosort_escape,${script_or_plugin}},core,*,irc,bitlbee,matrix,slack}", "${script_or_plugin}", "${irc_raw_first}", "${server}", "${info:autosort_order,${type},server,*,channel,private}", "${hashless_name}", "${buffer.full_name}"]"
--- a/weechat/buflist.conf	Tue Aug 17 15:20:33 2021 -0400
+++ b/weechat/buflist.conf	Mon Aug 23 11:51:18 2021 -0400
@@ -1,10 +1,10 @@
 #
-# weechat -- buflist.conf
+# WeeChat -- buflist.conf
 #
 # WARNING: It is NOT recommended to edit this file by hand,
 # especially if WeeChat is running.
 #
-# Use /set or similar command to change settings in WeeChat.
+# Use commands like /set or /fset to change settings in WeeChat.
 #
 # For more info, see: https://weechat.org/doc/quickstart
 #
@@ -21,6 +21,7 @@
 nick_prefix_empty = on
 signals_refresh = ""
 sort = "number,-active"
+use_items = 1
 
 [format]
 buffer = "${format_number}${indent}${format_nick_prefix}${color_hotlist}${format_name}"
@@ -37,3 +38,4 @@
 name = "${name}"
 nick_prefix = "${color_nick_prefix}${nick_prefix}"
 number = "${color:green}${number}${if:${number_displayed}?.: }"
+tls_version = " ${color:default}(${if:${tls_version}==TLS1.3?${color:green}:${if:${tls_version}==TLS1.2?${color:yellow}:${color:red}}}${translate:${tls_version}}${color:default})"
--- a/weechat/charset.conf	Tue Aug 17 15:20:33 2021 -0400
+++ b/weechat/charset.conf	Mon Aug 23 11:51:18 2021 -0400
@@ -1,10 +1,10 @@
 #
-# weechat -- charset.conf
+# WeeChat -- charset.conf
 #
 # WARNING: It is NOT recommended to edit this file by hand,
 # especially if WeeChat is running.
 #
-# Use /set or similar command to change settings in WeeChat.
+# Use commands like /set or /fset to change settings in WeeChat.
 #
 # For more info, see: https://weechat.org/doc/quickstart
 #
--- a/weechat/exec.conf	Tue Aug 17 15:20:33 2021 -0400
+++ b/weechat/exec.conf	Mon Aug 23 11:51:18 2021 -0400
@@ -1,10 +1,10 @@
 #
-# weechat -- exec.conf
+# WeeChat -- exec.conf
 #
 # WARNING: It is NOT recommended to edit this file by hand,
 # especially if WeeChat is running.
 #
-# Use /set or similar command to change settings in WeeChat.
+# Use commands like /set or /fset to change settings in WeeChat.
 #
 # For more info, see: https://weechat.org/doc/quickstart
 #
@@ -12,6 +12,7 @@
 [command]
 default_options = ""
 purge_delay = 0
+shell = "${env:SHELL}"
 
 [color]
 flag_finished = lightred
--- a/weechat/fifo.conf	Tue Aug 17 15:20:33 2021 -0400
+++ b/weechat/fifo.conf	Mon Aug 23 11:51:18 2021 -0400
@@ -1,10 +1,10 @@
 #
-# weechat -- fifo.conf
+# WeeChat -- fifo.conf
 #
 # WARNING: It is NOT recommended to edit this file by hand,
 # especially if WeeChat is running.
 #
-# Use /set or similar command to change settings in WeeChat.
+# Use commands like /set or /fset to change settings in WeeChat.
 #
 # For more info, see: https://weechat.org/doc/quickstart
 #
--- a/weechat/fset.conf	Tue Aug 17 15:20:33 2021 -0400
+++ b/weechat/fset.conf	Mon Aug 23 11:51:18 2021 -0400
@@ -1,15 +1,16 @@
 #
-# weechat -- fset.conf
+# WeeChat -- fset.conf
 #
 # WARNING: It is NOT recommended to edit this file by hand,
 # especially if WeeChat is running.
 #
-# Use /set or similar command to change settings in WeeChat.
+# Use commands like /set or /fset to change settings in WeeChat.
 #
 # For more info, see: https://weechat.org/doc/quickstart
 #
 
 [look]
+auto_refresh = "*"
 auto_unmark = off
 condition_catch_set = "${count} >= 1"
 export_help_default = on
--- a/weechat/logger.conf	Tue Aug 17 15:20:33 2021 -0400
+++ b/weechat/logger.conf	Mon Aug 23 11:51:18 2021 -0400
@@ -1,10 +1,10 @@
 #
-# weechat -- logger.conf
+# WeeChat -- logger.conf
 #
 # WARNING: It is NOT recommended to edit this file by hand,
 # especially if WeeChat is running.
 #
-# Use /set or similar command to change settings in WeeChat.
+# Use commands like /set or /fset to change settings in WeeChat.
 #
 # For more info, see: https://weechat.org/doc/quickstart
 #
@@ -19,6 +19,7 @@
 
 [file]
 auto_log = on
+color_lines = off
 flush_delay = 120
 fsync = off
 info_lines = off
--- a/weechat/python.conf	Tue Aug 17 15:20:33 2021 -0400
+++ b/weechat/python.conf	Mon Aug 23 11:51:18 2021 -0400
@@ -1,10 +1,10 @@
 #
-# weechat -- python.conf
+# WeeChat -- python.conf
 #
 # WARNING: It is NOT recommended to edit this file by hand,
 # especially if WeeChat is running.
 #
-# Use /set or similar command to change settings in WeeChat.
+# Use commands like /set or /fset to change settings in WeeChat.
 #
 # For more info, see: https://weechat.org/doc/quickstart
 #
--- a/weechat/python/autoload/autosort.py	Tue Aug 17 15:20:33 2021 -0400
+++ b/weechat/python/autoload/autosort.py	Mon Aug 23 11:51:18 2021 -0400
@@ -1,860 +1,1 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright (C) 2013-2014 Maarten de Vries <maarten@de-vri.es>
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program.  If not, see <http://www.gnu.org/licenses/>.
-#
-
-#
-# Autosort automatically keeps your buffers sorted and grouped by server.
-# You can define your own sorting rules. See /help autosort for more details.
-#
-# http://github.com/de-vri.es/weechat-autosort
-#
-
-#
-# Changelog:
-# 2.5:
-#   * Fix handling unicode buffer names.
-#   * Add hint to set irc.look.server_buffer to independent and buffers.look.indenting to on.
-# 2.4:
-#   * Make script python3 compatible.
-# 2.3:
-#   * Fix sorting items without score last (regressed in 2.2).
-# 2.2:
-#   * Add configuration option for signals that trigger a sort.
-#   * Add command to manually trigger a sort (/autosort sort).
-#   * Add replacement patterns to apply before sorting.
-# 2.1:
-#   * Fix some minor style issues.
-# 2.0:
-#   * Allow for custom sort rules.
-#
-
-
-import weechat
-import re
-import json
-
-SCRIPT_NAME     = 'autosort'
-SCRIPT_AUTHOR   = 'Maarten de Vries <maarten@de-vri.es>'
-SCRIPT_VERSION  = '2.5'
-SCRIPT_LICENSE  = 'GPL3'
-SCRIPT_DESC     = 'Automatically or manually keep your buffers sorted and grouped by server.'
-
-
-config = None
-hooks  = []
-
-class HumanReadableError(Exception):
-	pass
-
-
-def parse_int(arg, arg_name = 'argument'):
-	''' Parse an integer and provide a more human readable error. '''
-	arg = arg.strip()
-	try:
-		return int(arg)
-	except ValueError:
-		raise HumanReadableError('Invalid {0}: expected integer, got "{1}".'.format(arg_name, arg))
-
-
-class Pattern:
-	''' A simple glob-like pattern for matching buffer names. '''
-
-	def __init__(self, pattern):
-		''' Construct a pattern from a string. '''
-		escaped    = False
-		char_class = 0
-		chars      = ''
-		regex      = ''
-		for c in pattern:
-			if escaped and char_class:
-				escaped = False
-				chars += re.escape(c)
-			elif escaped:
-				escaped = False
-				regex += re.escape(c)
-			elif c == '\\':
-				escaped = True
-			elif c == '*' and not char_class:
-				regex += '[^.]*'
-			elif c == '?' and not char_class:
-				regex += '[^.]'
-			elif c == '[' and not char_class:
-				char_class = 1
-				chars    = ''
-			elif c == '^' and char_class and not chars:
-				chars += '^'
-			elif c == ']' and char_class and chars not in ('', '^'):
-				char_class = False
-				regex += '[' + chars + ']'
-			elif c == '-' and char_class:
-				chars += '-'
-			elif char_class:
-				chars += re.escape(c)
-			else:
-				regex += re.escape(c)
-
-		if char_class:
-			raise ValueError("unmatched opening '['")
-		if escaped:
-			raise ValueError("unexpected trailing '\\'")
-
-		self.regex   = re.compile('^' + regex + '$')
-		self.pattern = pattern
-
-	def match(self, input):
-		''' Match the pattern against a string. '''
-		return self.regex.match(input)
-
-
-class FriendlyList(object):
-	''' A list with human readable errors. '''
-
-	def __init__(self):
-		self.__data = []
-
-	def raw(self):
-		return self.__data
-
-	def append(self, value):
-		''' Add a rule to the list. '''
-		self.__data.append(value)
-
-	def insert(self, index, value):
-		''' Add a rule to the list. '''
-		if not 0 <= index <= len(self): raise HumanReadableError('Index out of range: expected an integer in the range [0, {0}], got {1}.'.format(len(self), index))
-		self.__data.insert(index, value)
-
-	def pop(self, index):
-		''' Remove a rule from the list and return it. '''
-		if not 0 <= index < len(self): raise HumanReadableError('Index out of range: expected an integer in the range [0, {0}), got {1}.'.format(len(self), index))
-		return self.__data.pop(index)
-
-	def move(self, index_a, index_b):
-		''' Move a rule to a new position in the list. '''
-		self.insert(index_b, self.pop(index_a))
-
-	def swap(self, index_a, index_b):
-		''' Swap two elements in the list. '''
-		self[index_a], self[index_b] = self[index_b], self[index_a]
-
-	def __len__(self):
-		return len(self.__data)
-
-	def __getitem__(self, index):
-		if not 0 <= index < len(self): raise HumanReadableError('Index out of range: expected an integer in the range [0, {0}), got {1}.'.format(len(self), index))
-		return self.__data[index]
-
-	def __setitem__(self, index, value):
-		if not 0 <= index < len(self): raise HumanReadableError('Index out of range: expected an integer in the range [0, {0}), got {1}.'.format(len(self), index))
-		self.__data[index] = value
-
-	def __iter__(self):
-		return iter(self.__data)
-
-
-class RuleList(FriendlyList):
-	''' A list of rules to test buffer names against. '''
-	rule_regex = re.compile(r'^(.*)=\s*([+-]?[^=]*)$')
-
-	def __init__(self, rules):
-		''' Construct a RuleList from a list of rules. '''
-		super(RuleList, self).__init__()
-		for rule in rules: self.append(rule)
-
-	def get_score(self, name, rules):
-		''' Get the sort score of a partial name according to a rule list. '''
-		for rule in self:
-			if rule[0].match(name): return rule[1]
-		return 999999999
-
-	def encode(self):
-		''' Encode the rules for storage. '''
-		return json.dumps(list(map(lambda x: (x[0].pattern, x[1]), self)))
-
-	@staticmethod
-	def decode(blob):
-		''' Parse rules from a string blob. '''
-		result = []
-
-		try:
-			decoded = json.loads(blob)
-		except ValueError:
-			log('Invalid rules: expected JSON encoded list of pairs, got "{0}".'.format(blob))
-			return [], 0
-
-		for rule in decoded:
-			# Rules must be a pattern,score pair.
-			if len(rule) != 2:
-				log('Invalid rule: expected (pattern, score), got "{0}". Rule ignored.'.format(rule))
-				continue
-
-			# Rules must have a valid pattern.
-			try:
-				pattern = Pattern(rule[0])
-			except ValueError as e:
-				log('Invalid pattern: {0} in "{1}". Rule ignored.'.format(e, rule[0]))
-				continue
-
-			# Rules must have a valid score.
-			try:
-				score = int(rule[1])
-			except ValueError as e:
-				log('Invalid score: expected an integer, got "{0}". Rule ignored.'.format(score))
-				continue
-
-			result.append((pattern, score))
-
-		return RuleList(result)
-
-	@staticmethod
-	def parse_rule(arg):
-		''' Parse a rule argument. '''
-		arg = arg.strip()
-		match = RuleList.rule_regex.match(arg)
-		if not match:
-			raise HumanReadableError('Invalid rule: expected "<pattern> = <score>", got "{0}".'.format(arg))
-
-		pattern = match.group(1).strip()
-		try:
-			pattern = Pattern(pattern)
-		except ValueError as e:
-			raise HumanReadableError('Invalid pattern: {0} in "{1}".'.format(e, pattern))
-
-		score   = parse_int(match.group(2), 'score')
-		return (pattern, score)
-
-
-def decode_replacements(blob):
-	''' Decode a replacement list encoded as JSON. '''
-	result = FriendlyList()
-	try:
-		decoded = json.loads(blob)
-	except ValueError:
-		log('Invalid replacement list: expected JSON encoded list of pairs, got "{0}".'.format(blob))
-		return [], 0
-
-	for replacement in decoded:
-		# Replacements must be a (string, string) pair.
-		if len(replacement) != 2:
-			log('Invalid replacement pattern: expected (pattern, replacement), got "{0}". Replacement ignored.'.format(rule))
-			continue
-		result.append(replacement)
-
-	return result
-
-
-def encode_replacements(replacements):
-	''' Encode a list of replacement patterns as JSON. '''
-	return json.dumps(replacements.raw())
-
-
-class Config:
-	''' The autosort configuration. '''
-
-	default_rules = json.dumps([
-		('core', 0),
-		('irc',  2),
-		('*',    1),
-
-		('irc.irc_raw', 0),
-		('irc.server',  1),
-	])
-
-	default_replacements = '[]'
-	default_signals      = 'buffer_opened buffer_merged buffer_unmerged buffer_renamed'
-
-	def __init__(self, filename):
-		''' Initialize the configuration. '''
-
-		self.filename         = filename
-		self.config_file      = weechat.config_new(self.filename, '', '')
-		self.sorting_section  = None
-
-		self.case_sensitive   = False
-		self.group_irc        = True
-		self.rules            = []
-		self.replacements     = []
-		self.signals          = []
-		self.sort_on_config   = True
-
-		self.__case_sensitive = None
-		self.__group_irc      = None
-		self.__rules          = None
-		self.__replacements   = None
-		self.__signals        = None
-		self.__sort_on_config = None
-
-		if not self.config_file:
-			log('Failed to initialize configuration file "{0}".'.format(self.filename))
-			return
-
-		self.sorting_section = weechat.config_new_section(self.config_file, 'sorting', False, False, '', '', '', '', '', '', '', '', '', '')
-
-		if not self.sorting_section:
-			log('Failed to initialize section "sorting" of configuration file.')
-			weechat.config_free(self.config_file)
-			return
-
-		self.__case_sensitive = weechat.config_new_option(
-			self.config_file, self.sorting_section,
-			'case_sensitive', 'boolean',
-			'If this option is on, sorting is case sensitive.',
-			'', 0, 0, 'off', 'off', 0,
-			'', '', '', '', '', ''
-		)
-
-		self.__group_irc = weechat.config_new_option(
-			self.config_file, self.sorting_section,
-			'group_irc', 'boolean',
-			'If this option is on, the script pretends that IRC channel/private buffers are renamed to "irc.server.{network}.{channel}" rather than "irc.{network}.{channel}".' +
-			'This ensures that these buffers are grouped with their respective server buffer.',
-			'', 0, 0, 'on', 'on', 0,
-			'', '', '', '', '', ''
-		)
-
-		self.__rules = weechat.config_new_option(
-			self.config_file, self.sorting_section,
-			'rules', 'string',
-			'An ordered list of sorting rules encoded as JSON. See /help autosort for commands to manipulate these rules.',
-			'', 0, 0, Config.default_rules, Config.default_rules, 0,
-			'', '', '', '', '', ''
-		)
-
-		self.__replacements = weechat.config_new_option(
-			self.config_file, self.sorting_section,
-			'replacements', 'string',
-			'An ordered list of replacement patterns to use on buffer name components, encoded as JSON. See /help autosort for commands to manipulate these replacements.',
-			'', 0, 0, Config.default_replacements, Config.default_replacements, 0,
-			'', '', '', '', '', ''
-		)
-
-		self.__signals = weechat.config_new_option(
-			self.config_file, self.sorting_section,
-			'signals', 'string',
-			'The signals that will cause autosort to resort your buffer list. Seperate signals with spaces.',
-			'', 0, 0, Config.default_signals, Config.default_signals, 0,
-			'', '', '', '', '', ''
-		)
-
-		self.__sort_on_config = weechat.config_new_option(
-			self.config_file, self.sorting_section,
-			'sort_on_config_change', 'boolean',
-			'Decides if the buffer list should be sorted when autosort configuration changes.',
-			'', 0, 0, 'on', 'on', 0,
-			'', '', '', '', '', ''
-		)
-
-		if weechat.config_read(self.config_file) != weechat.WEECHAT_RC_OK:
-			log('Failed to load configuration file.')
-
-		if weechat.config_write(self.config_file) != weechat.WEECHAT_RC_OK:
-			log('Failed to write configuration file.')
-
-		self.reload()
-
-	def reload(self):
-		''' Load configuration variables. '''
-
-		self.case_sensitive = weechat.config_boolean(self.__case_sensitive)
-		self.group_irc      = weechat.config_boolean(self.__group_irc)
-
-		rules_blob          = weechat.config_string(self.__rules)
-		replacements_blob   = weechat.config_string(self.__replacements)
-		signals_blob        = weechat.config_string(self.__signals)
-
-		self.rules          = RuleList.decode(rules_blob)
-		self.replacements   = decode_replacements(replacements_blob)
-		self.signals        = signals_blob.split()
-		self.sort_on_config = weechat.config_boolean(self.__sort_on_config)
-
-	def save_rules(self, run_callback = True):
-		''' Save the current rules to the configuration. '''
-		weechat.config_option_set(self.__rules, RuleList.encode(self.rules), run_callback)
-
-	def save_replacements(self, run_callback = True):
-		''' Save the current replacement patterns to the configuration. '''
-		weechat.config_option_set(self.__replacements, encode_replacements(self.replacements), run_callback)
-
-
-def pad(sequence, length, padding = None):
-	''' Pad a list until is has a certain length. '''
-	return sequence + [padding] * max(0, (length - len(sequence)))
-
-
-def log(message, buffer = 'NULL'):
-	weechat.prnt(buffer, 'autosort: {0}'.format(message))
-
-
-def get_buffers():
-	''' Get a list of all the buffers in weechat. '''
-	buffers = []
-
-	buffer_list = weechat.infolist_get('buffer', '', '')
-
-	while weechat.infolist_next(buffer_list):
-		name   = weechat.infolist_string (buffer_list, 'full_name')
-		number = weechat.infolist_integer(buffer_list, 'number')
-
-		# Buffer is merged with one we already have in the list, skip it.
-		if number <= len(buffers):
-			continue
-		buffers.append(name)
-
-	weechat.infolist_free(buffer_list)
-	return buffers
-
-
-def preprocess(buffer, config):
-	'''
-	Preprocess a buffers names.
-	'''
-	if not config.case_sensitive:
-		buffer = buffer.lower()
-
-	for replacement in config.replacements:
-		buffer = buffer.replace(replacement[0], replacement[1])
-
-	buffer = buffer.split('.')
-	if config.group_irc and len(buffer) >= 2 and buffer[0] == 'irc' and buffer[1] not in ('server', 'irc_raw'):
-		buffer.insert(1, 'server')
-
-	return buffer
-
-
-def buffer_sort_key(rules):
-	''' Create a sort key function for a buffer list from a rule list. '''
-	def key(buffer):
-		result  = []
-		name    = ''
-		for word in preprocess(buffer.decode('utf-8'), config):
-			name += ('.' if name else '') + word
-			result.append((rules.get_score(name, rules), word))
-		return result
-
-	return key
-
-
-def apply_buffer_order(buffers):
-	''' Sort the buffers in weechat according to the order in the input list.  '''
-	for i, buffer in enumerate(buffers):
-		weechat.command('', '/buffer swap {0} {1}'.format(buffer, i + 1))
-
-
-def split_args(args, expected, optional = 0):
-	''' Split an argument string in the desired number of arguments. '''
-	split = args.split(' ', expected - 1)
-	if (len(split) < expected):
-		raise HumanReadableError('Expected at least {0} arguments, got {1}.'.format(expected, len(split)))
-	return split[:-1] + pad(split[-1].split(' ', optional), optional + 1, '')
-
-
-def command_sort(buffer, command, args):
-	''' Sort the buffers and print a confirmation. '''
-	on_buffers_changed()
-	log("Finished sorting buffers.", buffer)
-	return weechat.WEECHAT_RC_OK
-
-
-def command_rule_list(buffer, command, args):
-	''' Show the list of sorting rules. '''
-	output = 'Sorting rules:\n'
-	for i, rule in enumerate(config.rules):
-		output += '    {0}: {1} = {2}\n'.format(i, rule[0].pattern, rule[1])
-	if not len(config.rules):
-		output += '    No sorting rules configured.\n'
-	log(output, buffer)
-
-	return weechat.WEECHAT_RC_OK
-
-
-def command_rule_add(buffer, command, args):
-	''' Add a rule to the rule list. '''
-	rule = RuleList.parse_rule(args)
-
-	config.rules.append(rule)
-	config.save_rules()
-	command_rule_list(buffer, command, '')
-
-	return weechat.WEECHAT_RC_OK
-
-
-def command_rule_insert(buffer, command, args):
-	''' Insert a rule at the desired position in the rule list. '''
-	index, rule = split_args(args, 2)
-	index = parse_int(index, 'index')
-	rule  = RuleList.parse_rule(rule)
-
-	config.rules.insert(index, rule)
-	config.save_rules()
-	command_rule_list(buffer, command, '')
-	return weechat.WEECHAT_RC_OK
-
-
-def command_rule_update(buffer, command, args):
-	''' Update a rule in the rule list. '''
-	index, rule = split_args(args, 2)
-	index = parse_int(index, 'index')
-	rule  = RuleList.parse_rule(rule)
-
-	config.rules[index] = rule
-	config.save_rules()
-	command_rule_list(buffer, command, '')
-	return weechat.WEECHAT_RC_OK
-
-
-def command_rule_delete(buffer, command, args):
-	''' Delete a rule from the rule list. '''
-	index = args.strip()
-	index = parse_int(index, 'index')
-
-	config.rules.pop(index)
-	config.save_rules()
-	command_rule_list(buffer, command, '')
-	return weechat.WEECHAT_RC_OK
-
-
-def command_rule_move(buffer, command, args):
-	''' Move a rule to a new position. '''
-	index_a, index_b = split_args(args, 2)
-	index_a = parse_int(index_a, 'index')
-	index_b = parse_int(index_b, 'index')
-
-	config.rules.move(index_a, index_b)
-	config.save_rules()
-	command_rule_list(buffer, command, '')
-	return weechat.WEECHAT_RC_OK
-
-
-def command_rule_swap(buffer, command, args):
-	''' Swap two rules. '''
-	index_a, index_b = split_args(args, 2)
-	index_a = parse_int(index_a, 'index')
-	index_b = parse_int(index_b, 'index')
-
-	config.rules.swap(index_a, index_b)
-	config.save_rules()
-	command_rule_list(buffer, command, '')
-	return weechat.WEECHAT_RC_OK
-
-
-def command_replacement_list(buffer, command, args):
-	''' Show the list of sorting rules. '''
-	output = 'Replacement patterns:\n'
-	for i, pattern in enumerate(config.replacements):
-		output += '    {0}: {1} -> {2}\n'.format(i, pattern[0], pattern[1])
-	if not len(config.replacements):
-		output += '    No replacement patterns configured.'
-	log(output, buffer)
-
-	return weechat.WEECHAT_RC_OK
-
-
-def command_replacement_add(buffer, command, args):
-	''' Add a rule to the rule list. '''
-	pattern, replacement = split_args(args, 1, 1)
-
-	config.replacements.append((pattern, replacement))
-	config.save_replacements()
-	command_replacement_list(buffer, command, '')
-
-	return weechat.WEECHAT_RC_OK
-
-
-def command_replacement_insert(buffer, command, args):
-	''' Insert a rule at the desired position in the rule list. '''
-	index, pattern, replacement = split_args(args, 2, 1)
-	index = parse_int(index, 'index')
-
-	config.replacements.insert(index, (pattern, replacement))
-	config.save_replacements()
-	command_replacement_list(buffer, command, '')
-	return weechat.WEECHAT_RC_OK
-
-
-def command_replacement_update(buffer, command, args):
-	''' Update a rule in the rule list. '''
-	index, pattern, replacement = split_args(args, 2, 1)
-	index = parse_int(index, 'index')
-
-	config.replacements[index] = (pattern, replacement)
-	config.save_replacements()
-	command_replacement_list(buffer, command, '')
-	return weechat.WEECHAT_RC_OK
-
-
-def command_replacement_delete(buffer, command, args):
-	''' Delete a rule from the rule list. '''
-	index = args.strip()
-	index = parse_int(index, 'index')
-
-	config.replacements.pop(index)
-	config.save_replacements()
-	command_replacement_list(buffer, command, '')
-	return weechat.WEECHAT_RC_OK
-
-
-def command_replacement_move(buffer, command, args):
-	''' Move a rule to a new position. '''
-	index_a, index_b = split_args(args, 2)
-	index_a = parse_int(index_a, 'index')
-	index_b = parse_int(index_b, 'index')
-
-	config.replacements.move(index_a, index_b)
-	config.save_replacements()
-	command_replacement_list(buffer, command, '')
-	return weechat.WEECHAT_RC_OK
-
-
-def command_replacement_swap(buffer, command, args):
-	''' Swap two rules. '''
-	index_a, index_b = split_args(args, 2)
-	index_a = parse_int(index_a, 'index')
-	index_b = parse_int(index_b, 'index')
-
-	config.replacements.swap(index_a, index_b)
-	config.save_replacements()
-	command_replacement_list(buffer, command, '')
-	return weechat.WEECHAT_RC_OK
-
-
-
-
-def call_command(buffer, command, args, subcommands):
-	''' Call a subccommand from a dictionary. '''
-	subcommand, tail = pad(args.split(' ', 1), 2, '')
-	subcommand = subcommand.strip()
-	if (subcommand == ''):
-		child   = subcommands.get(' ')
-	else:
-		command = command + [subcommand]
-		child   = subcommands.get(subcommand)
-
-	if isinstance(child, dict):
-		return call_command(buffer, command, tail, child)
-	elif callable(child):
-		return child(buffer, command, tail)
-
-	log('{0}: command not found'.format(' '.join(command)))
-	return weechat.WEECHAT_RC_ERROR
-
-
-def on_buffers_changed(*args, **kwargs):
-	''' Called whenever the buffer list changes. '''
-	buffers = get_buffers()
-	buffers.sort(key=buffer_sort_key(config.rules))
-	apply_buffer_order(buffers)
-	return weechat.WEECHAT_RC_OK
-
-
-def on_config_changed(*args, **kwargs):
-	''' Called whenever the configuration changes. '''
-	config.reload()
-
-	# Unhook all signals and hook the new ones.
-	for hook in hooks:
-		weechat.unhook(hook)
-	for signal in config.signals:
-		hooks.append(weechat.hook_signal(signal, 'on_buffers_changed', ''))
-
-	if config.sort_on_config:
-		on_buffers_changed()
-
-	return weechat.WEECHAT_RC_OK
-
-
-def on_autosort_command(data, buffer, args):
-	''' Called when the autosort command is invoked. '''
-	try:
-		return call_command(buffer, ['/autosort'], args, {
-			' ':      command_sort,
-			'sort':   command_sort,
-
-			'rules': {
-				' ':         command_rule_list,
-				'list':      command_rule_list,
-				'add':       command_rule_add,
-				'insert':    command_rule_insert,
-				'update':    command_rule_update,
-				'delete':    command_rule_delete,
-				'move':      command_rule_move,
-				'swap':      command_rule_swap,
-			},
-			'replacements': {
-				' ':      command_replacement_list,
-				'list':   command_replacement_list,
-				'add':    command_replacement_add,
-				'insert': command_replacement_insert,
-				'update': command_replacement_update,
-				'delete': command_replacement_delete,
-				'move':   command_replacement_move,
-				'swap':   command_replacement_swap,
-			},
-			'sort':   on_buffers_changed,
-		})
-	except HumanReadableError as e:
-		log(e, buffer)
-		return weechat.WEECHAT_RC_ERROR
-
-
-command_description = r'''
-NOTE: For the best effect, you may want to consider setting the option irc.look.server_buffer to independent and buffers.look.indenting to on.
-
-# Commands
-
-## Miscellaneous
-/autosort sort
-Manually trigger the buffer sorting.
-
-
-## Sorting rules
-
-/autosort rules list
-Print the list of sort rules.
-
-/autosort rules add <pattern> = <score>
-Add a new rule at the end of the list.
-
-/autosort rules insert <index> <pattern> = <score>
-Insert a new rule at the given index in the list.
-
-/autosort rules update <index> <pattern> = <score>
-Update a rule in the list with a new pattern and score.
-
-/autosort rules delete <index>
-Delete a rule from the list.
-
-/autosort rules move <index_from> <index_to>
-Move a rule from one position in the list to another.
-
-/autosort rules swap <index_a> <index_b>
-Swap two rules in the list
-
-
-## Replacement patterns
-
-/autosort replacements list
-Print the list of replacement patterns.
-
-/autosort replacements add <pattern> <replacement>
-Add a new replacement pattern at the end of the list.
-
-/autosort replacements insert <index> <pattern> <replacement>
-Insert a new replacement pattern at the given index in the list.
-
-/autosort replacements update <index> <pattern> <replacement>
-Update a replacement pattern in the list.
-
-/autosort replacements delete <index>
-Delete a replacement pattern from the list.
-
-/autosort replacements move <index_from> <index_to>
-Move a replacement pattern from one position in the list to another.
-
-/autosort replacements swap <index_a> <index_b>
-Swap two replacement pattern in the list
-
-
-# Introduction
-Autosort is a weechat script to automatically keep your buffers sorted.
-The sort order can be customized by defining your own sort rules,
-but the default should be sane enough for most people.
-It can also group IRC channel/private buffers under their server buffer if you like.
-
-Autosort first turns buffer names into a list of their components by splitting on them on the period character.
-For example, the buffer name "irc.server.freenode" is turned into ['irc', 'server', 'freenode'].
-The list of buffers is then lexicographically sorted.
-
-To facilitate custom sort orders, it is possible to assign a score to each component individually before the sorting is done.
-Any name component that did not get a score assigned will be sorted after those that did receive a score.
-Components are always sorted on their score first and on their name second.
-Lower scores are sorted first.
-
-## Automatic or manual sorting
-By default, autosort will automatically sort your buffer list whenever a buffer is opened, merged, unmerged or renamed.
-This should keep your buffers sorted in almost all situations.
-However, you may wish to change the list of signals that cause your buffer list to be sorted.
-Simply edit the "autosort.sorting.signals" option to add or remove any signal you like.
-If you remove all signals you can still sort your buffers manually with the "/autosort sort" command.
-To prevent all automatic sorting, "autosort.sorting.sort_on_config_change" should also be set to off.
-
-## Grouping IRC buffers
-In weechat, IRC channel/private buffers are named "irc.<network>.<#channel>",
-and IRC server buffers are named "irc.server.<network>".
-This does not work very well with lexicographical sorting if you want all buffers for one network grouped together.
-That is why autosort comes with the "autosort.sorting.group_irc" option,
-which secretly pretends IRC channel/private buffers are called "irc.server.<network>.<#channel>".
-The buffers are not actually renamed, autosort simply pretends they are for sorting purposes.
-
-## Replacement patterns
-Sometimes you may want to ignore some characters for sorting purposes.
-On Freenode for example, you may wish to ignore the difference between channels starting with a double or a single hash sign.
-To do so, simply add a replacement pattern that replaces ## with # with the following command:
-/autosort replacements add ## #
-
-Replacement patterns do not support wildcards or special characters at the moment.
-
-## Sort rules
-You can assign scores to name components by defining sort rules.
-The first rule that matches a component decides the score.
-Further rules are not examined.
-Sort rules use the following syntax:
-<glob-pattern> = <score>
-
-You can use the "/autosort rules" command to show and manipulate the list of sort rules.
-
-
-Allowed special characters in the glob patterns are:
-
-Pattern | Meaning
---------|--------
-*       | Matches a sequence of any characters except for periods.
-?       | Matches a single character, but not a period.
-[a-z]   | Matches a single character in the given regex-like character class.
-[^ab]   | A negated regex-like character class.
-\*      | A backslash escapes the next characters and removes its special meaning.
-\\      | A literal backslash.
-
-
-## Example
-As an example, consider the following rule list:
-0: core            = 0
-1: irc             = 2
-2: *               = 1
-
-3: irc.server.*.#* = 1
-4: irc.server.*.*  = 0
-
-Rule 0 ensures the core buffer is always sorted first.
-Rule 1 sorts IRC buffers last and rule 2 puts all remaining buffers in between the two.
-
-Rule 3 and 4 would make no sense with the group_irc option off.
-With the option on though, these rules will sort private buffers before regular channel buffers.
-Rule 3 matches channel buffers and assigns them a higher score,
-while rule 4 matches the buffers that remain and assigns them a lower score.
-The same effect could also be achieved with a single rule:
-irc.server.*.[^#]* = 0
-'''
-
-command_completion = 'sort||rules list|add|insert|update|delete|move|swap||replacements list|add|insert|update|delete|move|swap'
-
-
-if weechat.register(SCRIPT_NAME, SCRIPT_AUTHOR, SCRIPT_VERSION, SCRIPT_LICENSE, SCRIPT_DESC, "", ""):
-	config = Config('autosort')
-
-	weechat.hook_config('autosort.*',      'on_config_changed',  '')
-	weechat.hook_command('autosort', command_description, '', '', command_completion, 'on_autosort_command', 'NULL')
-	on_config_changed()
+../autosort.py
\ No newline at end of file
--- a/weechat/python/autoload/brows.py	Tue Aug 17 15:20:33 2021 -0400
+++ b/weechat/python/autoload/brows.py	Mon Aug 23 11:51:18 2021 -0400
@@ -15,7 +15,7 @@
 try:
     import weechat
 except ImportError:
-    print 'This is a weechat script, what are you doing, run it in weechat, jesus'
+    print('This is a weechat script, what are you doing, run it in weechat, jesus')
     import_ok = False
 
 weechat_version = 0
--- a/weechat/python/autoload/colon_complete.py	Tue Aug 17 15:20:33 2021 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,69 +0,0 @@
-SCRIPT_NAME='coloncomplete'
-SCRIPT_AUTHOR='Steve Losh <steve@stevelosh.com>'
-SCRIPT_VERSION='1.0'
-SCRIPT_LICENSE='MIT/X11'
-SCRIPT_DESC='Add a colon after nick completion when all the previous words in the input are also nicks.'
-
-EXTRA_NICKS = ['all', 'backend', 'clojerks', 'ops', 'support']
-
-import_ok=True
-
-try:
-    import weechat
-except ImportError:
-    print 'This script must be run under WeeChat'
-    print 'You can obtain a copy of WeeChat, for free, at http://www.weechat.org'
-    import_ok=False
-
-weechat_version=0
-
-def get_nicks(buffer, prefix=''):
-    channel = weechat.buffer_get_string(buffer, 'localvar_channel')
-    server = weechat.buffer_get_string(buffer, 'localvar_server')
-    prefix = prefix.lower()
-
-    matches = []
-
-    infolist = weechat.infolist_get('irc_nick', '', '%s,%s' % (server, channel))
-    while weechat.infolist_next(infolist):
-        nick = weechat.infolist_string(infolist, 'name')
-        if nick != 'localhost' and nick.lower().startswith(prefix):
-            matches.append(nick)
-    weechat.infolist_free(infolist)
-
-    for nick in EXTRA_NICKS:
-        if nick.lower().startswith(prefix):
-            matches.append(nick)
-
-    return matches
-
-def completer(data, buffer, command):
-    cb = weechat.current_buffer()
-    if command == "/input complete_next":
-        line = weechat.buffer_get_string(cb, "input")
-        words = line.split(' ')
-        prefix = words[-1]
-        if prefix and words and all([s.endswith(':') for s in words[:-1] if s]):
-            nicks = get_nicks(cb, prefix)
-            if len(nicks) == 1:
-                for _ in range(len(prefix)):
-                    weechat.command(buffer, "/input delete_previous_char")
-                weechat.command(buffer, "/input insert " + nicks[-1] + ":\\x20")
-            elif len(nicks) > 1:
-                l = min(len(nick) for nick in nicks)
-                for i in range(len(prefix), l):
-                    if len(set(nick[i] for nick in nicks)) > 1:
-                        break
-                    else:
-                        weechat.command(buffer, "/input insert " + nicks[0][i])
-
-                for nick in nicks:
-                    weechat.prnt(cb, "==> " + nick)
-                return weechat.WEECHAT_RC_OK_EAT
-
-    return weechat.WEECHAT_RC_OK
-
-if __name__ == "__main__" and import_ok:
-    if weechat.register(SCRIPT_NAME, SCRIPT_AUTHOR, SCRIPT_VERSION, SCRIPT_LICENSE, SCRIPT_DESC, "", ""):
-        weechat_version = weechat.info_get("version_number", "") or 0
-        weechat.hook_command_run('/input complete*', 'completer', '')
--- a/weechat/python/autoload/editor.py	Tue Aug 17 15:20:33 2021 -0400
+++ b/weechat/python/autoload/editor.py	Mon Aug 23 11:51:18 2021 -0400
@@ -16,7 +16,7 @@
 try:
     import weechat
 except ImportError:
-    print 'This is a weechat script, what are you doing, run it in weechat, jesus'
+    print('This is a weechat script, what are you doing, run it in weechat, jesus')
     import_ok = False
 
 weechat_version = 0
@@ -33,9 +33,8 @@
         # Reopen, because most editors do atomic write-tmp+rename saves which
         # fucks with Python here.
         tf.file.close()
-        tf = file(tf.name)
-
-        return tf.read()
+        with open(tf.name) as tf2:
+            return tf2.read()
 
 def editor(data, buffer, args):
     suffix = args or "tmp"
--- a/weechat/python/autoload/quotes.py	Tue Aug 17 15:20:33 2021 -0400
+++ b/weechat/python/autoload/quotes.py	Mon Aug 23 11:51:18 2021 -0400
@@ -18,7 +18,7 @@
 try:
     import weechat
 except ImportError:
-    print 'This is a weechat script, what are you doing, run it in weechat, jesus'
+    print('This is a weechat script, what are you doing, run it in weechat, jesus')
     import_ok = False
 
 weechat_version = 0
--- a/weechat/python/autoload/sanitize_jira.py	Tue Aug 17 15:20:33 2021 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,33 +0,0 @@
-import re, weechat, subprocess
-
-SCRIPT_NAME = 'sanitize_jira'
-SCRIPT_AUTHOR = 'Steve Losh <steve@stevelosh.com>'
-SCRIPT_VERSION = '0.0.1'
-SCRIPT_LICENSE = 'MIT'
-SCRIPT_DESC = 'clean up the garbage jirabot sends to channels into something readable'
-
-weechat.register(SCRIPT_NAME, SCRIPT_AUTHOR, SCRIPT_VERSION, SCRIPT_LICENSE, SCRIPT_DESC, '', '')
-
-weechat.hook_line('*', '', 'nick_Jira_Cloud', 'sanitize_jira', '')
-
-first_line_re = re.compile(
-    r'(?P<link>https://[^/]+/browse/[^?]+)[?]atlOrigin=[^ ]+ [(](?P<title>.+)[)]'
-)
-
-detail_line_re = re.compile(
-    r'''Status: \x1a\x01[*](?P<status>[^*]+)[*]\x1b\x01.*Type: \x1a\x01[*](?P<type>[^*]+)[*]\x1b\x01.*Assignee: \x1a\x01[*](?P<assignee>[^*]+)[*]\x1b\x01.*Priority: \x1a\x01[*](?P<priority>[^*]+)[*]\x1b\x01'''
-)
-
-def sanitize_jira(data, line):
-    if 'sign up for an Atlassian account to view this link' in line['message']:
-        return {'message': ' '}
-
-    m = first_line_re.search(line['message'])
-    if m:
-        return {'message': '%s | %s' % (m.group('title'), m.group('link'))}
-
-    m = detail_line_re.search(line['message'])
-    if m:
-        return {'message': '%s / %s / %s' % (m.group('type'), m.group('status'), m.group('assignee'))}
-
-    return {}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/weechat/python/autosort.py	Mon Aug 23 11:51:18 2021 -0400
@@ -0,0 +1,1075 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2013-2017 Maarten de Vries <maarten@de-vri.es>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+#
+# Autosort automatically keeps your buffers sorted and grouped by server.
+# You can define your own sorting rules. See /help autosort for more details.
+#
+# https://github.com/de-vri-es/weechat-autosort
+#
+
+#
+# Changelog:
+# 3.9:
+#   * Remove `buffers.pl` from recommended settings.
+# 3,8:
+#   * Fix relative sorting on script name in default rules.
+#   * Document a useful property of stable sort algorithms.
+# 3.7:
+#   * Make default rules work with bitlbee, matrix and slack.
+# 3.6:
+#   * Add more documentation on provided info hooks.
+# 3.5:
+#   * Add ${info:autosort_escape,...} to escape arguments for other info hooks.
+# 3.4:
+#   * Fix rate-limit of sorting to prevent high CPU load and lock-ups.
+#   * Fix bug in parsing empty arguments for info hooks.
+#   * Add debug_log option to aid with debugging.
+#   * Correct a few typos.
+# 3.3:
+#   * Fix the /autosort debug command for unicode.
+#   * Update the default rules to work better with Slack.
+# 3.2:
+#   * Fix python3 compatiblity.
+# 3.1:
+#   * Use colors to format the help text.
+# 3.0:
+#   * Switch to evaluated expressions for sorting.
+#   * Add `/autosort debug` command.
+#   * Add ${info:autosort_replace,from,to,text} to replace substrings in sort rules.
+#   * Add ${info:autosort_order,value,first,second,third} to ease writing sort rules.
+#   * Make tab completion context aware.
+# 2.8:
+#   * Fix compatibility with python 3 regarding unicode handling.
+# 2.7:
+#   * Fix sorting of buffers with spaces in their name.
+# 2.6:
+#   * Ignore case in rules when doing case insensitive sorting.
+# 2.5:
+#   * Fix handling unicode buffer names.
+#   * Add hint to set irc.look.server_buffer to independent and buffers.look.indenting to on.
+# 2.4:
+#   * Make script python3 compatible.
+# 2.3:
+#   * Fix sorting items without score last (regressed in 2.2).
+# 2.2:
+#   * Add configuration option for signals that trigger a sort.
+#   * Add command to manually trigger a sort (/autosort sort).
+#   * Add replacement patterns to apply before sorting.
+# 2.1:
+#   * Fix some minor style issues.
+# 2.0:
+#   * Allow for custom sort rules.
+#
+
+
+import json
+import math
+import re
+import sys
+import time
+import weechat
+
+SCRIPT_NAME     = 'autosort'
+SCRIPT_AUTHOR   = 'Maarten de Vries <maarten@de-vri.es>'
+SCRIPT_VERSION  = '3.9'
+SCRIPT_LICENSE  = 'GPL3'
+SCRIPT_DESC     = 'Flexible automatic (or manual) buffer sorting based on eval expressions.'
+
+
+config             = None
+hooks              = []
+signal_delay_timer = None
+sort_limit_timer   = None
+sort_queued        = False
+
+
+# Make sure that unicode, bytes and str are always available in python2 and 3.
+# For python 2, str == bytes
+# For python 3, str == unicode
+if sys.version_info[0] >= 3:
+	unicode = str
+
+def ensure_str(input):
+	'''
+	Make sure the given type if the correct string type for the current python version.
+	That means bytes for python2 and unicode for python3.
+	'''
+	if not isinstance(input, str):
+		if isinstance(input, bytes):
+			return input.encode('utf-8')
+		if isinstance(input, unicode):
+			return input.decode('utf-8')
+	return input
+
+
+if hasattr(time, 'perf_counter'):
+	perf_counter = time.perf_counter
+else:
+	perf_counter = time.clock
+
+def casefold(string):
+	if hasattr(string, 'casefold'): return string.casefold()
+	# Fall back to lowercasing for python2.
+	return string.lower()
+
+def list_swap(values, a, b):
+	values[a], values[b] = values[b], values[a]
+
+def list_move(values, old_index, new_index):
+	values.insert(new_index, values.pop(old_index))
+
+def list_find(collection, value):
+	for i, elem in enumerate(collection):
+		if elem == value: return i
+	return None
+
+class HumanReadableError(Exception):
+	pass
+
+def parse_int(arg, arg_name = 'argument'):
+	''' Parse an integer and provide a more human readable error. '''
+	arg = arg.strip()
+	try:
+		return int(arg)
+	except ValueError:
+		raise HumanReadableError('Invalid {0}: expected integer, got "{1}".'.format(arg_name, arg))
+
+def decode_rules(blob):
+	parsed = json.loads(blob)
+	if not isinstance(parsed, list):
+		log('Malformed rules, expected a JSON encoded list of strings, but got a {0}. No rules have been loaded. Please fix the setting manually.'.format(type(parsed)))
+		return []
+
+	for i, entry in enumerate(parsed):
+		if not isinstance(entry, (str, unicode)):
+			log('Rule #{0} is not a string but a {1}. No rules have been loaded. Please fix the setting manually.'.format(i, type(entry)))
+			return []
+
+	return parsed
+
+def decode_helpers(blob):
+	parsed = json.loads(blob)
+	if not isinstance(parsed, dict):
+		log('Malformed helpers, expected a JSON encoded dictionary but got a {0}. No helpers have been loaded. Please fix the setting manually.'.format(type(parsed)))
+		return {}
+
+	for key, value in parsed.items():
+		if not isinstance(value, (str, unicode)):
+			log('Helper "{0}" is not a string but a {1}. No helpers have been loaded. Please fix setting manually.'.format(key, type(value)))
+			return {}
+	return parsed
+
+class Config:
+	''' The autosort configuration. '''
+
+	default_rules = json.dumps([
+		'${core_first}',
+		'${info:autosort_order,${info:autosort_escape,${script_or_plugin}},core,*,irc,bitlbee,matrix,slack}',
+		'${script_or_plugin}',
+		'${irc_raw_first}',
+		'${server}',
+		'${info:autosort_order,${type},server,*,channel,private}',
+		'${hashless_name}',
+		'${buffer.full_name}',
+	])
+
+	default_helpers = json.dumps({
+		'core_first':       '${if:${buffer.full_name}!=core.weechat}',
+		'irc_raw_first':    '${if:${buffer.full_name}!=irc.irc_raw}',
+		'irc_raw_last':     '${if:${buffer.full_name}==irc.irc_raw}',
+		'hashless_name':    '${info:autosort_replace,#,,${info:autosort_escape,${buffer.name}}}',
+		'script_or_plugin': '${if:${script_name}?${script_name}:${plugin}}',
+	})
+
+	default_signal_delay = 5
+	default_sort_limit   = 100
+
+	default_signals = 'buffer_opened buffer_merged buffer_unmerged buffer_renamed'
+
+	def __init__(self, filename):
+		''' Initialize the configuration. '''
+
+		self.filename         = filename
+		self.config_file      = weechat.config_new(self.filename, '', '')
+		self.sorting_section  = None
+		self.v3_section       = None
+
+		self.case_sensitive   = False
+		self.rules            = []
+		self.helpers          = {}
+		self.signals          = []
+		self.signal_delay     = Config.default_signal_delay,
+		self.sort_limit       = Config.default_sort_limit,
+		self.sort_on_config   = True
+		self.debug_log        = False
+
+		self.__case_sensitive = None
+		self.__rules          = None
+		self.__helpers        = None
+		self.__signals        = None
+		self.__signal_delay   = None
+		self.__sort_limit     = None
+		self.__sort_on_config = None
+		self.__debug_log      = None
+
+		if not self.config_file:
+			log('Failed to initialize configuration file "{0}".'.format(self.filename))
+			return
+
+		self.sorting_section = weechat.config_new_section(self.config_file, 'sorting', False, False, '', '', '', '', '', '', '', '', '', '')
+		self.v3_section      = weechat.config_new_section(self.config_file, 'v3',      False, False, '', '', '', '', '', '', '', '', '', '')
+
+		if not self.sorting_section:
+			log('Failed to initialize section "sorting" of configuration file.')
+			weechat.config_free(self.config_file)
+			return
+
+		self.__case_sensitive = weechat.config_new_option(
+			self.config_file, self.sorting_section,
+			'case_sensitive', 'boolean',
+			'If this option is on, sorting is case sensitive.',
+			'', 0, 0, 'off', 'off', 0,
+			'', '', '', '', '', ''
+		)
+
+		weechat.config_new_option(
+			self.config_file, self.sorting_section,
+			'rules', 'string',
+			'Sort rules used by autosort v2.x and below. Not used by autosort anymore.',
+			'', 0, 0, '', '', 0,
+			'', '', '', '', '', ''
+		)
+
+		weechat.config_new_option(
+			self.config_file, self.sorting_section,
+			'replacements', 'string',
+			'Replacement patterns used by autosort v2.x and below. Not used by autosort anymore.',
+			'', 0, 0, '', '', 0,
+			'', '', '', '', '', ''
+		)
+
+		self.__rules = weechat.config_new_option(
+			self.config_file, self.v3_section,
+			'rules', 'string',
+			'An ordered list of sorting rules encoded as JSON. See /help autosort for commands to manipulate these rules.',
+			'', 0, 0, Config.default_rules, Config.default_rules, 0,
+			'', '', '', '', '', ''
+		)
+
+		self.__helpers = weechat.config_new_option(
+			self.config_file, self.v3_section,
+			'helpers', 'string',
+			'A dictionary helper variables to use in the sorting rules, encoded as JSON. See /help autosort for commands to manipulate these helpers.',
+			'', 0, 0, Config.default_helpers, Config.default_helpers, 0,
+			'', '', '', '', '', ''
+		)
+
+		self.__signals = weechat.config_new_option(
+			self.config_file, self.sorting_section,
+			'signals', 'string',
+			'A space separated list of signals that will cause autosort to resort your buffer list.',
+			'', 0, 0, Config.default_signals, Config.default_signals, 0,
+			'', '', '', '', '', ''
+		)
+
+		self.__signal_delay = weechat.config_new_option(
+			self.config_file, self.sorting_section,
+			'signal_delay', 'integer',
+			'Delay in milliseconds to wait after a signal before sorting the buffer list. This prevents triggering many times if multiple signals arrive in a short time. It can also be needed to wait for buffer localvars to be available.',
+			'', 0, 1000, str(Config.default_signal_delay), str(Config.default_signal_delay), 0,
+			'', '', '', '', '', ''
+		)
+
+		self.__sort_limit = weechat.config_new_option(
+			self.config_file, self.sorting_section,
+			'sort_limit', 'integer',
+			'Minimum delay in milliseconds to wait after sorting before signals can trigger a sort again. This is effectively a rate limit on sorting. Keeping signal_delay low while setting this higher can reduce excessive sorting without a long initial delay.',
+			'', 0, 1000, str(Config.default_sort_limit), str(Config.default_sort_limit), 0,
+			'', '', '', '', '', ''
+		)
+
+		self.__sort_on_config = weechat.config_new_option(
+			self.config_file, self.sorting_section,
+			'sort_on_config_change', 'boolean',
+			'Decides if the buffer list should be sorted when autosort configuration changes.',
+			'', 0, 0, 'on', 'on', 0,
+			'', '', '', '', '', ''
+		)
+
+		self.__debug_log = weechat.config_new_option(
+			self.config_file, self.sorting_section,
+			'debug_log', 'boolean',
+			'If enabled, print more debug messages. Not recommended for normal usage.',
+			'', 0, 0, 'off', 'off', 0,
+			'', '', '', '', '', ''
+		)
+
+		if weechat.config_read(self.config_file) != weechat.WEECHAT_RC_OK:
+			log('Failed to load configuration file.')
+
+		if weechat.config_write(self.config_file) != weechat.WEECHAT_RC_OK:
+			log('Failed to write configuration file.')
+
+		self.reload()
+
+	def reload(self):
+		''' Load configuration variables. '''
+
+		self.case_sensitive = weechat.config_boolean(self.__case_sensitive)
+
+		rules_blob    = weechat.config_string(self.__rules)
+		helpers_blob  = weechat.config_string(self.__helpers)
+		signals_blob  = weechat.config_string(self.__signals)
+
+		self.rules          = decode_rules(rules_blob)
+		self.helpers        = decode_helpers(helpers_blob)
+		self.signals        = signals_blob.split()
+		self.signal_delay   = weechat.config_integer(self.__signal_delay)
+		self.sort_limit     = weechat.config_integer(self.__sort_limit)
+		self.sort_on_config = weechat.config_boolean(self.__sort_on_config)
+		self.debug_log      = weechat.config_boolean(self.__debug_log)
+
+	def save_rules(self, run_callback = True):
+		''' Save the current rules to the configuration. '''
+		weechat.config_option_set(self.__rules, json.dumps(self.rules), run_callback)
+
+	def save_helpers(self, run_callback = True):
+		''' Save the current helpers to the configuration. '''
+		weechat.config_option_set(self.__helpers, json.dumps(self.helpers), run_callback)
+
+
+def pad(sequence, length, padding = None):
+	''' Pad a list until is has a certain length. '''
+	return sequence + [padding] * max(0, (length - len(sequence)))
+
+def log(message, buffer = 'NULL'):
+	weechat.prnt(buffer, 'autosort: {0}'.format(message))
+
+def debug(message, buffer = 'NULL'):
+	if config.debug_log:
+		weechat.prnt(buffer, 'autosort: debug: {0}'.format(message))
+
+def get_buffers():
+	''' Get a list of all the buffers in weechat. '''
+	hdata  = weechat.hdata_get('buffer')
+	buffer = weechat.hdata_get_list(hdata, "gui_buffers");
+
+	result = []
+	while buffer:
+		number = weechat.hdata_integer(hdata, buffer, 'number')
+		result.append((number, buffer))
+		buffer = weechat.hdata_pointer(hdata, buffer, 'next_buffer')
+	return hdata, result
+
+class MergedBuffers(list):
+	""" A list of merged buffers, possibly of size 1. """
+	def __init__(self, number):
+		super(MergedBuffers, self).__init__()
+		self.number = number
+
+def merge_buffer_list(buffers):
+	'''
+	Group merged buffers together.
+	The output is a list of MergedBuffers.
+	'''
+	if not buffers: return []
+	result = {}
+	for number, buffer in buffers:
+		if number not in result: result[number] = MergedBuffers(number)
+		result[number].append(buffer)
+	return result.values()
+
+def sort_buffers(hdata, buffers, rules, helpers, case_sensitive):
+	for merged in buffers:
+		for buffer in merged:
+			name = weechat.hdata_string(hdata, buffer, 'name')
+
+	return sorted(buffers, key=merged_sort_key(rules, helpers, case_sensitive))
+
+def buffer_sort_key(rules, helpers, case_sensitive):
+	''' Create a sort key function for a list of lists of merged buffers. '''
+	def key(buffer):
+		extra_vars = {}
+		for helper_name, helper in sorted(helpers.items()):
+			expanded = weechat.string_eval_expression(helper, {"buffer": buffer}, {}, {})
+			extra_vars[helper_name] = expanded if case_sensitive else casefold(expanded)
+		result = []
+		for rule in rules:
+			expanded = weechat.string_eval_expression(rule, {"buffer": buffer}, extra_vars, {})
+			result.append(expanded if case_sensitive else casefold(expanded))
+		return result
+
+	return key
+
+def merged_sort_key(rules, helpers, case_sensitive):
+	buffer_key = buffer_sort_key(rules, helpers, case_sensitive)
+	def key(merged):
+		best = None
+		for buffer in merged:
+			this = buffer_key(buffer)
+			if best is None or this < best: best = this
+		return best
+	return key
+
+def apply_buffer_order(buffers):
+	''' Sort the buffers in weechat according to the given order. '''
+	for i, buffer in enumerate(buffers):
+		weechat.buffer_set(buffer[0], "number", str(i + 1))
+
+def split_args(args, expected, optional = 0):
+	''' Split an argument string in the desired number of arguments. '''
+	split = args.split(' ', expected - 1)
+	if (len(split) < expected):
+		raise HumanReadableError('Expected at least {0} arguments, got {1}.'.format(expected, len(split)))
+	return split[:-1] + pad(split[-1].split(' ', optional), optional + 1, '')
+
+def do_sort(verbose = False):
+	start = perf_counter()
+
+	hdata, buffers = get_buffers()
+	buffers = merge_buffer_list(buffers)
+	buffers = sort_buffers(hdata, buffers, config.rules, config.helpers, config.case_sensitive)
+	apply_buffer_order(buffers)
+
+	elapsed = perf_counter() - start
+	if verbose:
+		log("Finished sorting buffers in {0:.4f} seconds.".format(elapsed))
+	else:
+		debug("Finished sorting buffers in {0:.4f} seconds.".format(elapsed))
+
+def command_sort(buffer, command, args):
+	''' Sort the buffers and print a confirmation. '''
+	do_sort(True)
+	return weechat.WEECHAT_RC_OK
+
+def command_debug(buffer, command, args):
+	hdata, buffers = get_buffers()
+	buffers = merge_buffer_list(buffers)
+
+	# Show evaluation results.
+	log('Individual evaluation results:')
+	start = perf_counter()
+	key = buffer_sort_key(config.rules, config.helpers, config.case_sensitive)
+	results = []
+	for merged in buffers:
+		for buffer in merged:
+			fullname = weechat.hdata_string(hdata, buffer, 'full_name')
+			results.append((fullname, key(buffer)))
+	elapsed = perf_counter() - start
+
+	for fullname, result in results:
+		fullname = ensure_str(fullname)
+		result = [ensure_str(x) for x in result]
+		log('{0}: {1}'.format(fullname, result))
+	log('Computing evaluation results took {0:.4f} seconds.'.format(elapsed))
+
+	return weechat.WEECHAT_RC_OK
+
+def command_rule_list(buffer, command, args):
+	''' Show the list of sorting rules. '''
+	output = 'Sorting rules:\n'
+	for i, rule in enumerate(config.rules):
+		output += '    {0}: {1}\n'.format(i, rule)
+	if not len(config.rules):
+		output += '    No sorting rules configured.\n'
+	log(output )
+
+	return weechat.WEECHAT_RC_OK
+
+
+def command_rule_add(buffer, command, args):
+	''' Add a rule to the rule list. '''
+	config.rules.append(args)
+	config.save_rules()
+	command_rule_list(buffer, command, '')
+
+	return weechat.WEECHAT_RC_OK
+
+
+def command_rule_insert(buffer, command, args):
+	''' Insert a rule at the desired position in the rule list. '''
+	index, rule = split_args(args, 2)
+	index = parse_int(index, 'index')
+
+	config.rules.insert(index, rule)
+	config.save_rules()
+	command_rule_list(buffer, command, '')
+	return weechat.WEECHAT_RC_OK
+
+
+def command_rule_update(buffer, command, args):
+	''' Update a rule in the rule list. '''
+	index, rule = split_args(args, 2)
+	index = parse_int(index, 'index')
+
+	config.rules[index] = rule
+	config.save_rules()
+	command_rule_list(buffer, command, '')
+	return weechat.WEECHAT_RC_OK
+
+
+def command_rule_delete(buffer, command, args):
+	''' Delete a rule from the rule list. '''
+	index = args.strip()
+	index = parse_int(index, 'index')
+
+	config.rules.pop(index)
+	config.save_rules()
+	command_rule_list(buffer, command, '')
+	return weechat.WEECHAT_RC_OK
+
+
+def command_rule_move(buffer, command, args):
+	''' Move a rule to a new position. '''
+	index_a, index_b = split_args(args, 2)
+	index_a = parse_int(index_a, 'index')
+	index_b = parse_int(index_b, 'index')
+
+	list_move(config.rules, index_a, index_b)
+	config.save_rules()
+	command_rule_list(buffer, command, '')
+	return weechat.WEECHAT_RC_OK
+
+
+def command_rule_swap(buffer, command, args):
+	''' Swap two rules. '''
+	index_a, index_b = split_args(args, 2)
+	index_a = parse_int(index_a, 'index')
+	index_b = parse_int(index_b, 'index')
+
+	list_swap(config.rules, index_a, index_b)
+	config.save_rules()
+	command_rule_list(buffer, command, '')
+	return weechat.WEECHAT_RC_OK
+
+
+def command_helper_list(buffer, command, args):
+	''' Show the list of helpers. '''
+	output = 'Helper variables:\n'
+
+	width = max(map(lambda x: len(x) if len(x) <= 30 else 0, config.helpers.keys()))
+
+	for name, expression in sorted(config.helpers.items()):
+		output += '    {0:>{width}}: {1}\n'.format(name, expression, width=width)
+	if not len(config.helpers):
+		output += '    No helper variables configured.'
+	log(output)
+
+	return weechat.WEECHAT_RC_OK
+
+
+def command_helper_set(buffer, command, args):
+	''' Add/update a helper to the helper list. '''
+	name, expression = split_args(args, 2)
+
+	config.helpers[name] = expression
+	config.save_helpers()
+	command_helper_list(buffer, command, '')
+
+	return weechat.WEECHAT_RC_OK
+
+def command_helper_delete(buffer, command, args):
+	''' Delete a helper from the helper list. '''
+	name = args.strip()
+
+	del config.helpers[name]
+	config.save_helpers()
+	command_helper_list(buffer, command, '')
+	return weechat.WEECHAT_RC_OK
+
+
+def command_helper_rename(buffer, command, args):
+	''' Rename a helper to a new position. '''
+	old_name, new_name = split_args(args, 2)
+
+	try:
+		config.helpers[new_name] = config.helpers[old_name]
+		del config.helpers[old_name]
+	except KeyError:
+		raise HumanReadableError('No such helper: {0}'.format(old_name))
+	config.save_helpers()
+	command_helper_list(buffer, command, '')
+	return weechat.WEECHAT_RC_OK
+
+
+def command_helper_swap(buffer, command, args):
+	''' Swap two helpers. '''
+	a, b = split_args(args, 2)
+	try:
+		config.helpers[b], config.helpers[a] = config.helpers[a], config.helpers[b]
+	except KeyError as e:
+		raise HumanReadableError('No such helper: {0}'.format(e.args[0]))
+
+	config.helpers.swap(index_a, index_b)
+	config.save_helpers()
+	command_helper_list(buffer, command, '')
+	return weechat.WEECHAT_RC_OK
+
+def call_command(buffer, command, args, subcommands):
+	''' Call a subcommand from a dictionary. '''
+	subcommand, tail = pad(args.split(' ', 1), 2, '')
+	subcommand = subcommand.strip()
+	if (subcommand == ''):
+		child   = subcommands.get(' ')
+	else:
+		command = command + [subcommand]
+		child   = subcommands.get(subcommand)
+
+	if isinstance(child, dict):
+		return call_command(buffer, command, tail, child)
+	elif callable(child):
+		return child(buffer, command, tail)
+
+	log('{0}: command not found'.format(' '.join(command)))
+	return weechat.WEECHAT_RC_ERROR
+
+def on_signal(data, signal, signal_data):
+	global signal_delay_timer
+	global sort_queued
+
+	# If the sort limit timeout is started, we're in the hold-off time after sorting, just queue a sort.
+	if sort_limit_timer is not None:
+		if sort_queued:
+			debug('Signal {0} ignored, sort limit timeout is active and sort is already queued.'.format(signal))
+		else:
+			debug('Signal {0} received but sort limit timeout is active, sort is now queued.'.format(signal))
+		sort_queued = True
+		return weechat.WEECHAT_RC_OK
+
+	# If the signal delay timeout is started, a signal was recently received, so ignore this signal.
+	if signal_delay_timer is not None:
+		debug('Signal {0} ignored, signal delay timeout active.'.format(signal))
+		return weechat.WEECHAT_RC_OK
+
+	# Otherwise, start the signal delay timeout.
+	debug('Signal {0} received, starting signal delay timeout of {1} ms.'.format(signal, config.signal_delay))
+	weechat.hook_timer(config.signal_delay, 0, 1, "on_signal_delay_timeout", "")
+	return weechat.WEECHAT_RC_OK
+
+def on_signal_delay_timeout(pointer, remaining_calls):
+	""" Called when the signal_delay_timer triggers. """
+	global signal_delay_timer
+	global sort_limit_timer
+	global sort_queued
+
+	signal_delay_timer = None
+
+	# If the sort limit timeout was started, we're still in the no-sort period, so just queue a sort.
+	if sort_limit_timer is not None:
+		debug('Signal delay timeout expired, but sort limit timeout is active, sort is now queued.')
+		sort_queued = True
+		return weechat.WEECHAT_RC_OK
+
+	# Time to sort!
+	debug('Signal delay timeout expired, starting sort.')
+	do_sort()
+
+	# Start the sort limit timeout if not disabled.
+	if config.sort_limit > 0:
+		debug('Starting sort limit timeout of {0} ms.'.format(config.sort_limit))
+		sort_limit_timer = weechat.hook_timer(config.sort_limit, 0, 1, "on_sort_limit_timeout", "")
+
+	return weechat.WEECHAT_RC_OK
+
+def on_sort_limit_timeout(pointer, remainin_calls):
+	""" Called when de sort_limit_timer triggers. """
+	global sort_limit_timer
+	global sort_queued
+
+	# If no signal was received during the timeout, we're done.
+	if not sort_queued:
+		debug('Sort limit timeout expired without receiving a signal.')
+		sort_limit_timer = None
+		return weechat.WEECHAT_RC_OK
+
+	# Otherwise it's time to sort.
+	debug('Signal received during sort limit timeout, starting queued sort.')
+	do_sort()
+	sort_queued = False
+
+	# Start the sort limit timeout again if not disabled.
+	if config.sort_limit > 0:
+		debug('Starting sort limit timeout of {0} ms.'.format(config.sort_limit))
+		sort_limit_timer = weechat.hook_timer(config.sort_limit, 0, 1, "on_sort_limit_timeout", "")
+
+	return weechat.WEECHAT_RC_OK
+
+
+def apply_config():
+	# Unhook all signals and hook the new ones.
+	for hook in hooks:
+		weechat.unhook(hook)
+	for signal in config.signals:
+		hooks.append(weechat.hook_signal(signal, 'on_signal', ''))
+
+	if config.sort_on_config:
+		debug('Sorting because configuration changed.')
+		do_sort()
+
+def on_config_changed(*args, **kwargs):
+	''' Called whenever the configuration changes. '''
+	config.reload()
+	apply_config()
+
+	return weechat.WEECHAT_RC_OK
+
+def parse_arg(args):
+	if not args: return '', None
+
+	result  = ''
+	escaped = False
+	for i, c in enumerate(args):
+		if not escaped:
+			if c == '\\':
+				escaped = True
+				continue
+			elif c == ',':
+				return result, args[i+1:]
+		result  += c
+		escaped  = False
+	return result, None
+
+def parse_args(args, max = None):
+	result = []
+	i = 0
+	while max is None or i < max:
+		i += 1
+		arg, args = parse_arg(args)
+		if arg is None: break
+		result.append(arg)
+		if args is None: break
+	return result, args
+
+def on_info_escape(pointer, name, arguments):
+	result = ''
+	for c in arguments:
+		if c == '\\':
+			result += '\\\\'
+		elif c == ',':
+			result += '\\,'
+		else:
+			result +=c
+	return result
+
+def on_info_replace(pointer, name, arguments):
+	arguments, rest = parse_args(arguments, 3)
+	if rest or len(arguments) < 3:
+		log('usage: ${{info:{0},old,new,text}}'.format(name))
+		return ''
+	old, new, text = arguments
+
+	return text.replace(old, new)
+
+def on_info_order(pointer, name, arguments):
+	arguments, rest = parse_args(arguments)
+	if len(arguments) < 1:
+		log('usage: ${{info:{0},value,first,second,third,...}}'.format(name))
+		return ''
+
+	value = arguments[0]
+	keys  = arguments[1:]
+	if not keys: return '0'
+
+	# Find the value in the keys (or '*' if we can't find it)
+	result = list_find(keys, value)
+	if result is None: result = list_find(keys, '*')
+	if result is None: result = len(keys)
+
+	# Pad result with leading zero to make sure string sorting works.
+	width = int(math.log10(len(keys))) + 1
+	return '{0:0{1}}'.format(result, width)
+
+
+def on_autosort_command(data, buffer, args):
+	''' Called when the autosort command is invoked. '''
+	try:
+		return call_command(buffer, ['/autosort'], args, {
+			' ':      command_sort,
+			'sort':   command_sort,
+			'debug':  command_debug,
+
+			'rules': {
+				' ':         command_rule_list,
+				'list':      command_rule_list,
+				'add':       command_rule_add,
+				'insert':    command_rule_insert,
+				'update':    command_rule_update,
+				'delete':    command_rule_delete,
+				'move':      command_rule_move,
+				'swap':      command_rule_swap,
+			},
+			'helpers': {
+				' ':      command_helper_list,
+				'list':   command_helper_list,
+				'set':    command_helper_set,
+				'delete': command_helper_delete,
+				'rename': command_helper_rename,
+				'swap':   command_helper_swap,
+			},
+		})
+	except HumanReadableError as e:
+		log(e)
+		return weechat.WEECHAT_RC_ERROR
+
+def add_completions(completion, words):
+	for word in words:
+		weechat.hook_completion_list_add(completion, word, 0, weechat.WEECHAT_LIST_POS_END)
+
+def autosort_complete_rules(words, completion):
+	if len(words) == 0:
+		add_completions(completion, ['add', 'delete', 'insert', 'list', 'move', 'swap', 'update'])
+	if len(words) == 1 and words[0] in ('delete', 'insert', 'move', 'swap', 'update'):
+		add_completions(completion, map(str, range(len(config.rules))))
+	if len(words) == 2 and words[0] in ('move', 'swap'):
+		add_completions(completion, map(str, range(len(config.rules))))
+	if len(words) == 2 and words[0] in ('update'):
+		try:
+			add_completions(completion, [config.rules[int(words[1])]])
+		except KeyError: pass
+		except ValueError: pass
+	else:
+		add_completions(completion, [''])
+	return weechat.WEECHAT_RC_OK
+
+def autosort_complete_helpers(words, completion):
+	if len(words) == 0:
+		add_completions(completion, ['delete', 'list', 'rename', 'set', 'swap'])
+	elif len(words) == 1 and words[0] in ('delete', 'rename', 'set', 'swap'):
+		add_completions(completion, sorted(config.helpers.keys()))
+	elif len(words) == 2 and words[0] == 'swap':
+		add_completions(completion, sorted(config.helpers.keys()))
+	elif len(words) == 2 and words[0] == 'rename':
+		add_completions(completion, sorted(config.helpers.keys()))
+	elif len(words) == 2 and words[0] == 'set':
+		try:
+			add_completions(completion, [config.helpers[words[1]]])
+		except KeyError: pass
+	return weechat.WEECHAT_RC_OK
+
+def on_autosort_complete(data, name, buffer, completion):
+	cmdline = weechat.buffer_get_string(buffer, "input")
+	cursor  = weechat.buffer_get_integer(buffer, "input_pos")
+	prefix  = cmdline[:cursor]
+	words   = prefix.split()[1:]
+
+	# If the current word isn't finished yet,
+	# ignore it for coming up with completion suggestions.
+	if prefix[-1] != ' ': words = words[:-1]
+
+	if len(words) == 0:
+		add_completions(completion, ['debug', 'helpers', 'rules', 'sort'])
+	elif words[0] == 'rules':
+		return autosort_complete_rules(words[1:], completion)
+	elif words[0] == 'helpers':
+		return autosort_complete_helpers(words[1:], completion)
+	return weechat.WEECHAT_RC_OK
+
+command_description = r'''{*white}# General commands{reset}
+
+{*white}/autosort {brown}sort{reset}
+Manually trigger the buffer sorting.
+
+{*white}/autosort {brown}debug{reset}
+Show the evaluation results of the sort rules for each buffer.
+
+
+{*white}# Sorting rule commands{reset}
+
+{*white}/autosort{brown} rules list{reset}
+Print the list of sort rules.
+
+{*white}/autosort {brown}rules add {cyan}<expression>{reset}
+Add a new rule at the end of the list.
+
+{*white}/autosort {brown}rules insert {cyan}<index> <expression>{reset}
+Insert a new rule at the given index in the list.
+
+{*white}/autosort {brown}rules update {cyan}<index> <expression>{reset}
+Update a rule in the list with a new expression.
+
+{*white}/autosort {brown}rules delete {cyan}<index>
+Delete a rule from the list.
+
+{*white}/autosort {brown}rules move {cyan}<index_from> <index_to>{reset}
+Move a rule from one position in the list to another.
+
+{*white}/autosort {brown}rules swap {cyan}<index_a> <index_b>{reset}
+Swap two rules in the list
+
+
+{*white}# Helper variable commands{reset}
+
+{*white}/autosort {brown}helpers list
+Print the list of helper variables.
+
+{*white}/autosort {brown}helpers set {cyan}<name> <expression>
+Add or update a helper variable with the given name.
+
+{*white}/autosort {brown}helpers delete {cyan}<name>
+Delete a helper variable.
+
+{*white}/autosort {brown}helpers rename {cyan}<old_name> <new_name>
+Rename a helper variable.
+
+{*white}/autosort {brown}helpers swap {cyan}<name_a> <name_b>
+Swap the expressions of two helper variables in the list.
+
+
+{*white}# Info hooks{reset}
+Autosort comes with a number of info hooks to add some extra functionality to regular weechat eval strings.
+Info hooks can be used in eval strings in the form of {cyan}${{info:some_hook,arguments}}{reset}.
+
+Commas and backslashes in arguments to autosort info hooks (except for {cyan}${{info:autosort_escape}}{reset}) must be escaped with a backslash.
+
+{*white}${{info:{brown}autosort_replace{white},{cyan}pattern{white},{cyan}replacement{white},{cyan}source{white}}}{reset}
+Replace all occurrences of {cyan}pattern{reset} with {cyan}replacement{reset} in the string {cyan}source{reset}.
+Can be used to ignore certain strings when sorting by replacing them with an empty string.
+
+For example: {cyan}${{info:autosort_replace,cat,dog,the dog is meowing}}{reset} expands to "the cat is meowing".
+
+{*white}${{info:{brown}autosort_order{white},{cyan}value{white},{cyan}option0{white},{cyan}option1{white},{cyan}option2{white},{cyan}...{white}}}
+Generate a zero-padded number that corresponds to the index of {cyan}value{reset} in the list of options.
+If one of the options is the special value {brown}*{reset}, then any value not explicitly mentioned will be sorted at that position.
+Otherwise, any value that does not match an option is assigned the highest number available.
+Can be used to easily sort buffers based on a manual sequence.
+
+For example: {cyan}${{info:autosort_order,${{server}},freenode,oftc,efnet}}{reset} will sort freenode before oftc, followed by efnet and then any remaining servers.
+Alternatively, {cyan}${{info:autosort_order,${{server}},freenode,oftc,*,efnet}}{reset} will sort any unlisted servers after freenode and oftc, but before efnet.
+
+{*white}${{info:{brown}autosort_escape{white},{cyan}text{white}}}{reset}
+Escape commas and backslashes in {cyan}text{reset} by prepending them with a backslash.
+This is mainly useful to pass arbitrary eval strings as arguments to other autosort info hooks.
+Otherwise, an eval string that expands to something with a comma would be interpreted as multiple arguments.
+
+For example, it can be used to safely pass buffer names to {cyan}${{info:autosort_replace}}{reset} like so:
+{cyan}${{info:autosort_replace,##,#,${{info:autosort_escape,${{buffer.name}}}}}}{reset}.
+
+
+{*white}# Description
+Autosort is a weechat script to automatically keep your buffers sorted. The sort
+order can be customized by defining your own sort rules, but the default should
+be sane enough for most people. It can also group IRC channel/private buffers
+under their server buffer if you like.
+
+Autosort uses a stable sorting algorithm, meaning that you can manually move buffers
+to change their relative order, if they sort equal with your rule set.
+
+{*white}# Sort rules{reset}
+Autosort evaluates a list of eval expressions (see {*default}/help eval{reset}) and sorts the
+buffers based on evaluated result. Earlier rules will be considered first. Only
+if earlier rules produced identical results is the result of the next rule
+considered for sorting purposes.
+
+You can debug your sort rules with the `{*default}/autosort debug{reset}` command, which will
+print the evaluation results of each rule for each buffer.
+
+{*brown}NOTE:{reset} The sort rules for version 3 are not compatible with version 2 or vice
+versa. You will have to manually port your old rules to version 3 if you have any.
+
+{*white}# Helper variables{reset}
+You may define helper variables for the main sort rules to keep your rules
+readable. They can be used in the main sort rules as variables. For example,
+a helper variable named `{cyan}foo{reset}` can be accessed in a main rule with the
+string `{cyan}${{foo}}{reset}`.
+
+{*white}# Automatic or manual sorting{reset}
+By default, autosort will automatically sort your buffer list whenever a buffer
+is opened, merged, unmerged or renamed. This should keep your buffers sorted in
+almost all situations. However, you may wish to change the list of signals that
+cause your buffer list to be sorted. Simply edit the `{cyan}autosort.sorting.signals{reset}`
+option to add or remove any signal you like.
+
+If you remove all signals you can still sort your buffers manually with the
+`{*default}/autosort sort{reset}` command. To prevent all automatic sorting, the option
+`{cyan}autosort.sorting.sort_on_config_change{reset}` should also be disabled.
+
+{*white}# Recommended settings
+For the best visual effect, consider setting the following options:
+  {*white}/set {cyan}irc.look.server_buffer{reset} {brown}independent{reset}
+
+This setting allows server buffers to be sorted independently, which is
+needed to create a hierarchical tree view of the server and channel buffers.
+
+If you are using the {*default}buflist{reset} plugin you can (ab)use Unicode to draw a tree
+structure with the following setting (modify to suit your need):
+  {*white}/set {cyan}buflist.format.indent {brown}"${{color:237}}${{if:${{buffer.next_buffer.local_variables.type}}=~^(channel|private)$?├─:└─}}"{reset}
+'''
+
+command_completion = '%(plugin_autosort) %(plugin_autosort) %(plugin_autosort) %(plugin_autosort) %(plugin_autosort)'
+
+info_replace_description = (
+	'Replace all occurrences of `pattern` with `replacement` in the string `source`. '
+	'Can be used to ignore certain strings when sorting by replacing them with an empty string. '
+	'See /help autosort for examples.'
+)
+info_replace_arguments = 'pattern,replacement,source'
+
+info_order_description = (
+	'Generate a zero-padded number that corresponds to the index of `value` in the list of options. '
+	'If one of the options is the special value `*`, then any value not explicitly mentioned will be sorted at that position. '
+	'Otherwise, any value that does not match an option is assigned the highest number available. '
+	'Can be used to easily sort buffers based on a manual sequence. '
+	'See /help autosort for examples.'
+)
+info_order_arguments = 'value,first,second,third,...'
+
+info_escape_description = (
+	'Escape commas and backslashes in `text` by prepending them with a backslash. '
+	'This is mainly useful to pass arbitrary eval strings as arguments to other autosort info hooks. '
+	'Otherwise, an eval string that expands to something with a comma would be interpreted as multiple arguments.'
+	'See /help autosort for examples.'
+)
+info_escape_arguments = 'text'
+
+
+if weechat.register(SCRIPT_NAME, SCRIPT_AUTHOR, SCRIPT_VERSION, SCRIPT_LICENSE, SCRIPT_DESC, "", ""):
+	config = Config('autosort')
+
+	colors = {
+		'default':  weechat.color('default'),
+		'reset':    weechat.color('reset'),
+		'black':    weechat.color('black'),
+		'red':      weechat.color('red'),
+		'green':    weechat.color('green'),
+		'brown':    weechat.color('brown'),
+		'yellow':   weechat.color('yellow'),
+		'blue':     weechat.color('blue'),
+		'magenta':  weechat.color('magenta'),
+		'cyan':     weechat.color('cyan'),
+		'white':    weechat.color('white'),
+		'*default': weechat.color('*default'),
+		'*black':   weechat.color('*black'),
+		'*red':     weechat.color('*red'),
+		'*green':   weechat.color('*green'),
+		'*brown':   weechat.color('*brown'),
+		'*yellow':  weechat.color('*yellow'),
+		'*blue':    weechat.color('*blue'),
+		'*magenta': weechat.color('*magenta'),
+		'*cyan':    weechat.color('*cyan'),
+		'*white':   weechat.color('*white'),
+	}
+
+	weechat.hook_config('autosort.*', 'on_config_changed',  '')
+	weechat.hook_completion('plugin_autosort', '', 'on_autosort_complete', '')
+	weechat.hook_command('autosort', command_description.format(**colors), '', '', command_completion, 'on_autosort_command', '')
+	weechat.hook_info('autosort_escape',  info_escape_description,  info_escape_arguments,  'on_info_escape', '')
+	weechat.hook_info('autosort_replace', info_replace_description, info_replace_arguments, 'on_info_replace', '')
+	weechat.hook_info('autosort_order',   info_order_description,   info_order_arguments,   'on_info_order',   '')
+
+	apply_config()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/weechat/python/colon_complete.py	Mon Aug 23 11:51:18 2021 -0400
@@ -0,0 +1,69 @@
+SCRIPT_NAME='coloncomplete'
+SCRIPT_AUTHOR='Steve Losh <steve@stevelosh.com>'
+SCRIPT_VERSION='1.0'
+SCRIPT_LICENSE='MIT/X11'
+SCRIPT_DESC='Add a colon after nick completion when all the previous words in the input are also nicks.'
+
+EXTRA_NICKS = ['all', 'backend', 'clojerks', 'ops', 'support']
+
+import_ok=True
+
+try:
+    import weechat
+except ImportError:
+    print 'This script must be run under WeeChat'
+    print 'You can obtain a copy of WeeChat, for free, at http://www.weechat.org'
+    import_ok=False
+
+weechat_version=0
+
+def get_nicks(buffer, prefix=''):
+    channel = weechat.buffer_get_string(buffer, 'localvar_channel')
+    server = weechat.buffer_get_string(buffer, 'localvar_server')
+    prefix = prefix.lower()
+
+    matches = []
+
+    infolist = weechat.infolist_get('irc_nick', '', '%s,%s' % (server, channel))
+    while weechat.infolist_next(infolist):
+        nick = weechat.infolist_string(infolist, 'name')
+        if nick != 'localhost' and nick.lower().startswith(prefix):
+            matches.append(nick)
+    weechat.infolist_free(infolist)
+
+    for nick in EXTRA_NICKS:
+        if nick.lower().startswith(prefix):
+            matches.append(nick)
+
+    return matches
+
+def completer(data, buffer, command):
+    cb = weechat.current_buffer()
+    if command == "/input complete_next":
+        line = weechat.buffer_get_string(cb, "input")
+        words = line.split(' ')
+        prefix = words[-1]
+        if prefix and words and all([s.endswith(':') for s in words[:-1] if s]):
+            nicks = get_nicks(cb, prefix)
+            if len(nicks) == 1:
+                for _ in range(len(prefix)):
+                    weechat.command(buffer, "/input delete_previous_char")
+                weechat.command(buffer, "/input insert " + nicks[-1] + ":\\x20")
+            elif len(nicks) > 1:
+                l = min(len(nick) for nick in nicks)
+                for i in range(len(prefix), l):
+                    if len(set(nick[i] for nick in nicks)) > 1:
+                        break
+                    else:
+                        weechat.command(buffer, "/input insert " + nicks[0][i])
+
+                for nick in nicks:
+                    weechat.prnt(cb, "==> " + nick)
+                return weechat.WEECHAT_RC_OK_EAT
+
+    return weechat.WEECHAT_RC_OK
+
+if __name__ == "__main__" and import_ok:
+    if weechat.register(SCRIPT_NAME, SCRIPT_AUTHOR, SCRIPT_VERSION, SCRIPT_LICENSE, SCRIPT_DESC, "", ""):
+        weechat_version = weechat.info_get("version_number", "") or 0
+        weechat.hook_command_run('/input complete*', 'completer', '')
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/weechat/python/sanitize_jira.py	Mon Aug 23 11:51:18 2021 -0400
@@ -0,0 +1,33 @@
+import re, weechat, subprocess
+
+SCRIPT_NAME = 'sanitize_jira'
+SCRIPT_AUTHOR = 'Steve Losh <steve@stevelosh.com>'
+SCRIPT_VERSION = '0.0.1'
+SCRIPT_LICENSE = 'MIT'
+SCRIPT_DESC = 'clean up the garbage jirabot sends to channels into something readable'
+
+weechat.register(SCRIPT_NAME, SCRIPT_AUTHOR, SCRIPT_VERSION, SCRIPT_LICENSE, SCRIPT_DESC, '', '')
+
+weechat.hook_line('*', '', 'nick_Jira_Cloud', 'sanitize_jira', '')
+
+first_line_re = re.compile(
+    r'(?P<link>https://[^/]+/browse/[^?]+)[?]atlOrigin=[^ ]+ [(](?P<title>.+)[)]'
+)
+
+detail_line_re = re.compile(
+    r'''Status: \x1a\x01[*](?P<status>[^*]+)[*]\x1b\x01.*Type: \x1a\x01[*](?P<type>[^*]+)[*]\x1b\x01.*Assignee: \x1a\x01[*](?P<assignee>[^*]+)[*]\x1b\x01.*Priority: \x1a\x01[*](?P<priority>[^*]+)[*]\x1b\x01'''
+)
+
+def sanitize_jira(data, line):
+    if 'sign up for an Atlassian account to view this link' in line['message']:
+        return {'message': ' '}
+
+    m = first_line_re.search(line['message'])
+    if m:
+        return {'message': '%s | %s' % (m.group('title'), m.group('link'))}
+
+    m = detail_line_re.search(line['message'])
+    if m:
+        return {'message': '%s / %s / %s' % (m.group('type'), m.group('status'), m.group('assignee'))}
+
+    return {}
--- a/weechat/relay.conf	Tue Aug 17 15:20:33 2021 -0400
+++ b/weechat/relay.conf	Mon Aug 23 11:51:18 2021 -0400
@@ -1,10 +1,10 @@
 #
-# weechat -- relay.conf
+# WeeChat -- relay.conf
 #
 # WARNING: It is NOT recommended to edit this file by hand,
 # especially if WeeChat is running.
 #
-# Use /set or similar command to change settings in WeeChat.
+# Use commands like /set or /fset to change settings in WeeChat.
 #
 # For more info, see: https://weechat.org/doc/quickstart
 #
@@ -27,14 +27,20 @@
 [network]
 allow_empty_password = off
 allowed_ips = ""
+auth_timeout = 60
 bind_address = ""
 clients_purge_delay = 0
 compression_level = 6
 ipv6 = on
 max_clients = 5
+nonce_size = 16
 password = ""
+password_hash_algo = "*"
+password_hash_iterations = 100000
 ssl_cert_key = "%h/ssl/relay.pem"
 ssl_priorities = "NORMAL:-VERS-SSL3.0"
+totp_secret = ""
+totp_window = 0
 websocket_allowed_origins = ""
 
 [irc]
@@ -45,4 +51,9 @@
 backlog_tags = "irc_privmsg"
 backlog_time_format = "[%H:%M] "
 
+[weechat]
+commands = ""
+
 [port]
+
+[path]
--- a/weechat/ruby.conf	Tue Aug 17 15:20:33 2021 -0400
+++ b/weechat/ruby.conf	Mon Aug 23 11:51:18 2021 -0400
@@ -1,10 +1,10 @@
 #
-# weechat -- ruby.conf
+# WeeChat -- ruby.conf
 #
 # WARNING: It is NOT recommended to edit this file by hand,
 # especially if WeeChat is running.
 #
-# Use /set or similar command to change settings in WeeChat.
+# Use commands like /set or /fset to change settings in WeeChat.
 #
 # For more info, see: https://weechat.org/doc/quickstart
 #
--- a/weechat/script.conf	Tue Aug 17 15:20:33 2021 -0400
+++ b/weechat/script.conf	Mon Aug 23 11:51:18 2021 -0400
@@ -1,10 +1,10 @@
 #
-# weechat -- script.conf
+# WeeChat -- script.conf
 #
 # WARNING: It is NOT recommended to edit this file by hand,
 # especially if WeeChat is running.
 #
-# Use /set or similar command to change settings in WeeChat.
+# Use commands like /set or /fset to change settings in WeeChat.
 #
 # For more info, see: https://weechat.org/doc/quickstart
 #
@@ -50,6 +50,7 @@
 [scripts]
 autoload = on
 cache_expire = 60
+download_enabled = on
 download_timeout = 30
 hold = ""
 path = "%h/script"
--- a/weechat/trigger.conf	Tue Aug 17 15:20:33 2021 -0400
+++ b/weechat/trigger.conf	Mon Aug 23 11:51:18 2021 -0400
@@ -1,10 +1,10 @@
 #
-# weechat -- trigger.conf
+# WeeChat -- trigger.conf
 #
 # WARNING: It is NOT recommended to edit this file by hand,
 # especially if WeeChat is running.
 #
-# Use /set or similar command to change settings in WeeChat.
+# Use commands like /set or /fset to change settings in WeeChat.
 #
 # For more info, see: https://weechat.org/doc/quickstart
 #
--- a/weechat/urlgrab.conf	Tue Aug 17 15:20:33 2021 -0400
+++ b/weechat/urlgrab.conf	Mon Aug 23 11:51:18 2021 -0400
@@ -1,10 +1,10 @@
 #
-# weechat -- urlgrab.conf
+# WeeChat -- urlgrab.conf
 #
 # WARNING: It is NOT recommended to edit this file by hand,
 # especially if WeeChat is running.
 #
-# Use /set or similar command to change settings in WeeChat.
+# Use commands like /set or /fset to change settings in WeeChat.
 #
 # For more info, see: https://weechat.org/doc/quickstart
 #
--- a/weechat/weechat.conf	Tue Aug 17 15:20:33 2021 -0400
+++ b/weechat/weechat.conf	Mon Aug 23 11:51:18 2021 -0400
@@ -1,10 +1,10 @@
 #
-# weechat -- weechat.conf
+# WeeChat -- weechat.conf
 #
 # WARNING: It is NOT recommended to edit this file by hand,
 # especially if WeeChat is running.
 #
-# Use /set or similar command to change settings in WeeChat.
+# Use commands like /set or /fset to change settings in WeeChat.
 #
 # For more info, see: https://weechat.org/doc/quickstart
 #
@@ -35,6 +35,7 @@
 buffer_search_regex = off
 buffer_search_where = prefix_message
 buffer_time_format = "%H:%M"
+buffer_time_same = ""
 color_basic_force_bold = off
 color_inactive_buffer = off
 color_inactive_message = on
@@ -71,6 +72,7 @@
 hotlist_sort = group_time_asc
 hotlist_suffix = ""
 hotlist_unique_numbers = on
+hotlist_update_on_buffer_switch = on
 input_cursor_scroll = 20
 input_share = none
 input_share_overwrite = off
@@ -89,6 +91,7 @@
 mouse_timer_delay = 100
 nick_color_force = ""
 nick_color_hash = djb2
+nick_color_hash_salt = ""
 nick_color_stop_chars = "_|["
 nick_prefix = ""
 nick_suffix = ""
@@ -111,6 +114,7 @@
 prefix_network = "--"
 prefix_quit = "✘"
 prefix_same_nick = ""
+prefix_same_nick_middle = ""
 prefix_suffix = "|"
 quote_nick_prefix = "<"
 quote_nick_suffix = ">"
@@ -118,6 +122,7 @@
 read_marker = line
 read_marker_always_show = on
 read_marker_string = "─"
+read_marker_update_on_buffer_switch = on
 save_config_on_exit = off
 save_config_with_fsync = off
 save_layout_on_exit = all
@@ -231,7 +236,8 @@
 
 [network]
 connection_timeout = 60
-gnutls_ca_file = "/etc/ssl/certs/ca-certificates.crt"
+gnutls_ca_system = on
+gnutls_ca_user = ""
 gnutls_handshake_timeout = 30
 proxy_curl = ""
 
@@ -242,8 +248,16 @@
 path = "%h/plugins"
 save_config_on_unload = on
 
+[signal]
+sighup = "${if:${info:weechat_headless}?/reload:/quit -yes}"
+sigquit = "/quit -yes"
+sigterm = "/quit -yes"
+sigusr1 = ""
+sigusr2 = ""
+
 [bar]
 buffers.color_bg = default
+buffers.color_bg_inactive = default
 buffers.color_delim = default
 buffers.color_fg = default
 buffers.conditions = ""
@@ -258,6 +272,7 @@
 buffers.size_max = 0
 buffers.type = root
 buflist.color_bg = default
+buflist.color_bg_inactive = default
 buflist.color_delim = default
 buflist.color_fg = default
 buflist.conditions = ""
@@ -272,6 +287,7 @@
 buflist.size_max = 25
 buflist.type = root
 fset.color_bg = default
+fset.color_bg_inactive = default
 fset.color_delim = cyan
 fset.color_fg = default
 fset.conditions = "${buffer.full_name} == fset.fset"
@@ -286,6 +302,7 @@
 fset.size_max = 3
 fset.type = window
 input.color_bg = default
+input.color_bg_inactive = default
 input.color_delim = green
 input.color_fg = default
 input.conditions = ""
@@ -300,6 +317,7 @@
 input.size_max = 0
 input.type = window
 nicklist.color_bg = default
+nicklist.color_bg_inactive = default
 nicklist.color_delim = cyan
 nicklist.color_fg = default
 nicklist.conditions = "nicklist"
@@ -314,6 +332,7 @@
 nicklist.size_max = 0
 nicklist.type = window
 status.color_bg = green
+status.color_bg_inactive = default
 status.color_delim = 0
 status.color_fg = 0
 status.conditions = ""
@@ -328,6 +347,7 @@
 status.size_max = 0
 status.type = window
 title.color_bg = green
+title.color_bg_inactive = default
 title.color_delim = cyan
 title.color_fg = 16
 title.conditions = ""
@@ -345,6 +365,11 @@
 [layout]
 
 [notify]
+python.slack.10xgenomics.&cloud-alerts-pagerduty = highlight
+python.slack.10xgenomics.&cloud-sumo-prod-support-alerts = highlight
+python.slack.10xgenomics.&lacework-10xdev = highlight
+python.slack.10xgenomics.&lacework-10xprod = highlight
+python.slack.10xgenomics.&testing1234 = highlight
 
 [filter]
 irc_smart = on;*;irc_smart_filter;*
@@ -381,6 +406,8 @@
 ctrl-Y = "/input clipboard_paste"
 meta-meta-OP = "/bar scroll buflist * b"
 meta-meta-OQ = "/bar scroll buflist * e"
+meta-meta2-11~ = "/bar scroll buflist * b"
+meta-meta2-12~ = "/bar scroll buflist * e"
 meta-meta2-1~ = "/window scroll_top"
 meta-meta2-23~ = "/bar scroll nicklist * yb"
 meta-meta2-24~ = "/bar scroll nicklist * ye"
@@ -406,6 +433,7 @@
 meta-< = "/input jump_previously_visited_buffer"
 meta-= = "/filter toggle"
 meta-> = "/input jump_next_visited_buffer"
+meta-B = "/buflist toggle"
 meta-OA = "/input history_global_previous"
 meta-OB = "/input history_global_next"
 meta-OC = "/input move_next_word"
@@ -418,6 +446,10 @@
 meta-Ob = "/input history_global_next"
 meta-Oc = "/input move_next_word"
 meta-Od = "/input move_previous_word"
+meta2-11^ = "/bar scroll buflist * -100%"
+meta2-11~ = "/bar scroll buflist * -100%"
+meta2-12^ = "/bar scroll buflist * +100%"
+meta2-12~ = "/bar scroll buflist * +100%"
 meta2-15~ = "/bar scroll nicklist * y-100%"
 meta2-17~ = "/bar scroll nicklist * y+100%"
 meta2-18~ = "/window -1"
@@ -426,8 +458,12 @@
 meta2-1;3B = "/buffer +1"
 meta2-1;3C = "/buffer +1"
 meta2-1;3D = "/buffer -1"
+meta2-1;3P = "/bar scroll buflist * b"
+meta2-1;3Q = "/bar scroll buflist * e"
 meta2-1;5A = "/input history_global_previous"
 meta2-1;5B = "/input history_global_next"
+meta2-1;5P = "/bar scroll buflist * -100%"
+meta2-1;5Q = "/bar scroll buflist * +100%"
 meta2-1;9A = "/buffer move -1"
 meta2-1;9B = "/buffer move +1"
 meta2-1~ = "/input move_beginning_of_line"
@@ -601,6 +637,11 @@
 meta2-B = "/cursor move down"
 meta2-C = "/cursor move right"
 meta2-D = "/cursor move left"
+@chat(python.*):D = "hsignal:slack_cursor_delete"
+@chat(python.*):L = "hsignal:slack_cursor_linkarchive"
+@chat(python.*):M = "hsignal:slack_cursor_message"
+@chat(python.*):R = "hsignal:slack_cursor_reply"
+@chat(python.*):T = "hsignal:slack_cursor_thread"
 @item(buffer_nicklist):K = "/window ${_window_number};/kickban ${nick}"
 @item(buffer_nicklist):b = "/window ${_window_number};/ban ${nick}"
 @item(buffer_nicklist):k = "/window ${_window_number};/kick ${nick}"
@@ -622,6 +663,7 @@
 @chat(fset.fset):button2* = "hsignal:fset_mouse"
 @chat(fset.fset):wheeldown = "/fset -down 5"
 @chat(fset.fset):wheelup = "/fset -up 5"
+@chat(python.*):button2 = "hsignal:slack_mouse"
 @chat(script.scripts):button1 = "/window ${_window_number};/script go ${_chat_line_y}"
 @chat(script.scripts):button2 = "/window ${_window_number};/script go ${_chat_line_y};/script installremove -q ${script_name_with_extension}"
 @chat(script.scripts):wheeldown = "/script down 5"
--- a/weechat/xfer.conf	Tue Aug 17 15:20:33 2021 -0400
+++ b/weechat/xfer.conf	Mon Aug 23 11:51:18 2021 -0400
@@ -1,10 +1,10 @@
 #
-# weechat -- xfer.conf
+# WeeChat -- xfer.conf
 #
 # WARNING: It is NOT recommended to edit this file by hand,
 # especially if WeeChat is running.
 #
-# Use /set or similar command to change settings in WeeChat.
+# Use commands like /set or /fset to change settings in WeeChat.
 #
 # For more info, see: https://weechat.org/doc/quickstart
 #
@@ -31,7 +31,8 @@
 own_ip = ""
 port_range = ""
 send_ack = on
-speed_limit = 0
+speed_limit_recv = 0
+speed_limit_send = 0
 timeout = 300
 
 [file]
@@ -43,5 +44,6 @@
 auto_resume = on
 convert_spaces = on
 download_path = "%h/xfer"
+download_temporary_suffix = ".part"
 upload_path = "~"
 use_nick_in_filename = on