diff --git a/.gitattributes b/.gitattributes
index b47749b4fa1e237526365f5ad35a5d7ce1d7422b..c46330192cbbdcc3b97b5c1caba896d51f8cf8e0 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -4,6 +4,7 @@
 *.cpp      text diff=cpp
 *.h        text diff=cpp
 *.py       text diff=python
+indra/newview/llimprocessing.cpp -text
 
 # Visual Studio
 *.sln text eol=crlf
diff --git a/build.sh b/build.sh
index 545c913f92c90694b38fb0b1d38f0371badfaa0a..f480825be7e921a40256243adf77262b801263af 100755
--- a/build.sh
+++ b/build.sh
@@ -28,7 +28,7 @@ build_dir_Linux()
 
 build_dir_CYGWIN()
 {
-  echo build-vc${AUTOBUILD_VSVER:-120}-${AUTOBUILD_ADDRSIZE}
+  echo build-vc${AUTOBUILD_VSVER}-${AUTOBUILD_ADDRSIZE}
 }
 
 viewer_channel_suffix()
diff --git a/indra/cmake/FindWindowsSDK.cmake b/indra/cmake/FindWindowsSDK.cmake
deleted file mode 100644
index 32991ea66c9d6a7d47aafe7e45a00b5eccc99867..0000000000000000000000000000000000000000
--- a/indra/cmake/FindWindowsSDK.cmake
+++ /dev/null
@@ -1,631 +0,0 @@
-# - Find the Windows SDK aka Platform SDK
-#
-# Relevant Wikipedia article: http://en.wikipedia.org/wiki/Microsoft_Windows_SDK
-#
-# Pass "COMPONENTS tools" to ignore Visual Studio version checks: in case
-# you just want the tool binaries to run, rather than the libraries and headers
-# for compiling.
-#
-# Variables:
-#  WINDOWSSDK_FOUND - if any version of the windows or platform SDK was found that is usable with the current version of visual studio
-#  WINDOWSSDK_LATEST_DIR
-#  WINDOWSSDK_LATEST_NAME
-#  WINDOWSSDK_FOUND_PREFERENCE - if we found an entry indicating a "preferred" SDK listed for this visual studio version
-#  WINDOWSSDK_PREFERRED_DIR
-#  WINDOWSSDK_PREFERRED_NAME
-#
-#  WINDOWSSDK_DIRS - contains no duplicates, ordered most recent first.
-#  WINDOWSSDK_PREFERRED_FIRST_DIRS - contains no duplicates, ordered with preferred first, followed by the rest in descending recency
-#
-# Functions:
-#  windowssdk_name_lookup(<directory> <output variable>) - Find the name corresponding with the SDK directory you pass in, or
-#     NOTFOUND if not recognized. Your directory must be one of WINDOWSSDK_DIRS for this to work.
-#
-#  windowssdk_build_lookup(<directory> <output variable>) - Find the build version number corresponding with the SDK directory you pass in, or
-#     NOTFOUND if not recognized. Your directory must be one of WINDOWSSDK_DIRS for this to work.
-#
-#  get_windowssdk_from_component(<file or dir> <output variable>) - Given a library or include dir,
-#     find the Windows SDK root dir corresponding to it, or NOTFOUND if unrecognized.
-#
-#  get_windowssdk_library_dirs(<directory> <output variable>) - Find the architecture-appropriate
-#     library directories corresponding to the SDK directory you pass in (or NOTFOUND if none)
-#
-#  get_windowssdk_library_dirs_multiple(<output variable> <directory> ...) - Find the architecture-appropriate
-#     library directories corresponding to the SDK directories you pass in, in order, skipping those not found. NOTFOUND if none at all.
-#     Good for passing WINDOWSSDK_DIRS or WINDOWSSDK_DIRS to if you really just want a file and don't care where from.
-#
-#  get_windowssdk_include_dirs(<directory> <output variable>) - Find the
-#     include directories corresponding to the SDK directory you pass in (or NOTFOUND if none)
-#
-#  get_windowssdk_include_dirs_multiple(<output variable> <directory> ...) - Find the
-#     include directories corresponding to the SDK directories you pass in, in order, skipping those not found. NOTFOUND if none at all.
-#     Good for passing WINDOWSSDK_DIRS or WINDOWSSDK_DIRS to if you really just want a file and don't care where from.
-#
-# Requires these CMake modules:
-#  FindPackageHandleStandardArgs (known included with CMake >=2.6.2)
-#
-# Original Author:
-# 2012 Ryan Pavlik <rpavlik@iastate.edu> <abiryan@ryand.net>
-# http://academic.cleardefinition.com
-# Iowa State University HCI Graduate Program/VRAC
-#
-# Copyright Iowa State University 2012.
-# Distributed under the Boost Software License, Version 1.0.
-# (See accompanying file LICENSE_1_0.txt or copy at
-# http://www.boost.org/LICENSE_1_0.txt)
-
-set(_preferred_sdk_dirs) # pre-output
-set(_win_sdk_dirs) # pre-output
-set(_win_sdk_versanddirs) # pre-output
-set(_win_sdk_buildsanddirs) # pre-output
-set(_winsdk_vistaonly) # search parameters
-set(_winsdk_kits) # search parameters
-
-
-set(_WINDOWSSDK_ANNOUNCE OFF)
-if(NOT WINDOWSSDK_FOUND AND (NOT WindowsSDK_FIND_QUIETLY))
-	set(_WINDOWSSDK_ANNOUNCE ON)
-endif()
-macro(_winsdk_announce)
-	if(_WINSDK_ANNOUNCE)
-		message(STATUS ${ARGN})
-	endif()
-endmacro()
-
-set(_winsdk_win10vers
-	10.0.18362.0 # 19H1 aka Win10 1809 "May 2019 Update"
-	10.0.17763.0 # Redstone 5 aka Win10 1809 "October 2018 Update"
-	10.0.17133.0 # Redstone 4 aka Win10 1803 "April 1018 Update"
-	10.0.16299.0 # Redstone 3 aka Win10 1709 "Fall Creators Update"
-	10.0.15063.0 # Redstone 2 aka Win10 1703 "Creators Update"
-	10.0.14393.0 # Redstone aka Win10 1607 "Anniversary Update"
-	10.0.10586.0 # TH2 aka Win10 1511
-	10.0.10240.0 # Win10 RTM
-	10.0.10150.0 # just ucrt
-	10.0.10056.0
-)
-
-if(WindowsSDK_FIND_COMPONENTS MATCHES "tools")
-	set(_WINDOWSSDK_IGNOREMSVC ON)
-	_winsdk_announce("Checking for tools from Windows/Platform SDKs...")
-else()
-	set(_WINDOWSSDK_IGNOREMSVC OFF)
-	_winsdk_announce("Checking for Windows/Platform SDKs...")
-endif()
-
-# Appends to the three main pre-output lists used only if the path exists
-# and is not already in the list.
-function(_winsdk_conditional_append _vername _build _path)
-	if(("${_path}" MATCHES "registry") OR (NOT EXISTS "${_path}"))
-		# Path invalid - do not add
-		return()
-	endif()
-	list(FIND _win_sdk_dirs "${_path}" _win_sdk_idx)
-	if(_win_sdk_idx GREATER -1)
-		# Path already in list - do not add
-		return()
-	endif()
-	_winsdk_announce( " - ${_vername}, Build ${_build} @ ${_path}")
-	# Not yet in the list, so we'll add it
-	list(APPEND _win_sdk_dirs "${_path}")
-	set(_win_sdk_dirs "${_win_sdk_dirs}" CACHE INTERNAL "" FORCE)
-	list(APPEND
-		_win_sdk_versanddirs
-		"${_vername}"
-		"${_path}")
-	set(_win_sdk_versanddirs "${_win_sdk_versanddirs}" CACHE INTERNAL "" FORCE)
-	list(APPEND
-		_win_sdk_buildsanddirs
-		"${_build}"
-		"${_path}")
-	set(_win_sdk_buildsanddirs "${_win_sdk_buildsanddirs}" CACHE INTERNAL "" FORCE)
-endfunction()
-
-# Appends to the "preferred SDK" lists only if the path exists
-function(_winsdk_conditional_append_preferred _info _path)
-	if(("${_path}" MATCHES "registry") OR (NOT EXISTS "${_path}"))
-		# Path invalid - do not add
-		return()
-	endif()
-
-	get_filename_component(_path "${_path}" ABSOLUTE)
-
-	list(FIND _win_sdk_preferred_sdk_dirs "${_path}" _win_sdk_idx)
-	if(_win_sdk_idx GREATER -1)
-		# Path already in list - do not add
-		return()
-	endif()
-	_winsdk_announce( " - Found \"preferred\" SDK ${_info} @ ${_path}")
-	# Not yet in the list, so we'll add it
-	list(APPEND _win_sdk_preferred_sdk_dirs "${_path}")
-	set(_win_sdk_preferred_sdk_dirs "${_win_sdk_dirs}" CACHE INTERNAL "" FORCE)
-
-	# Just in case we somehow missed it:
-	_winsdk_conditional_append("${_info}" "" "${_path}")
-endfunction()
-
-# Given a version like v7.0A, looks for an SDK in the registry under "Microsoft SDKs".
-# If the given version might be in both HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows
-# and HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows Kits\\Installed Roots aka "Windows Kits",
-# use this macro first, since these registry keys usually have more information.
-#
-# Pass a "default" build number as an extra argument in case we can't find it.
-function(_winsdk_check_microsoft_sdks_registry _winsdkver)
-	set(SDKKEY "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows\\${_winsdkver}")
-	get_filename_component(_sdkdir
-		"[${SDKKEY};InstallationFolder]"
-		ABSOLUTE)
-
-	set(_sdkname "Windows SDK ${_winsdkver}")
-
-	# Default build number passed as extra argument
-	set(_build ${ARGN})
-	# See if the registry holds a Microsoft-mutilated, err, designated, product name
-	# (just using get_filename_component to execute the registry lookup)
-	get_filename_component(_sdkproductname
-		"[${SDKKEY};ProductName]"
-		NAME)
-	if(NOT "${_sdkproductname}" MATCHES "registry")
-		# Got a product name
-		set(_sdkname "${_sdkname} (${_sdkproductname})")
-	endif()
-
-	# try for a version to augment our name
-	# (just using get_filename_component to execute the registry lookup)
-	get_filename_component(_sdkver
-		"[${SDKKEY};ProductVersion]"
-		NAME)
-	if(NOT "${_sdkver}" MATCHES "registry" AND NOT MATCHES)
-		# Got a version
-		if(NOT "${_sdkver}" MATCHES "\\.\\.")
-			# and it's not an invalid one with two dots in it:
-			# use to override the default build
-			set(_build ${_sdkver})
-			if(NOT "${_sdkname}" MATCHES "${_sdkver}")
-				# Got a version that's not already in the name, let's use it to improve our name.
-				set(_sdkname "${_sdkname} (${_sdkver})")
-			endif()
-		endif()
-	endif()
-	_winsdk_conditional_append("${_sdkname}" "${_build}" "${_sdkdir}")
-endfunction()
-
-# Given a name for identification purposes, the build number, and a key (technically a "value name")
-# corresponding to a Windows SDK packaged as a "Windows Kit", look for it
-# in HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows Kits\\Installed Roots
-# Note that the key or "value name" tends to be something weird like KitsRoot81 -
-# no easy way to predict, just have to observe them in the wild.
-# Doesn't hurt to also try _winsdk_check_microsoft_sdks_registry for these:
-# sometimes you get keys in both parts of the registry (in the wow64 portion especially),
-# and the non-"Windows Kits" location is often more descriptive.
-function(_winsdk_check_windows_kits_registry _winkit_name _winkit_build _winkit_key)
-	get_filename_component(_sdkdir
-		"[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows Kits\\Installed Roots;${_winkit_key}]"
-		ABSOLUTE)
-	_winsdk_conditional_append("${_winkit_name}" "${_winkit_build}" "${_sdkdir}")
-endfunction()
-
-# Given a name for identification purposes and the build number
-# corresponding to a Windows 10 SDK packaged as a "Windows Kit", look for it
-# in HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows Kits\\Installed Roots
-# Doesn't hurt to also try _winsdk_check_microsoft_sdks_registry for these:
-# sometimes you get keys in both parts of the registry (in the wow64 portion especially),
-# and the non-"Windows Kits" location is often more descriptive.
-function(_winsdk_check_win10_kits _winkit_build)
-	get_filename_component(_sdkdir
-		"[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows Kits\\Installed Roots;KitsRoot10]"
-		ABSOLUTE)
-	if(("${_sdkdir}" MATCHES "registry") OR (NOT EXISTS "${_sdkdir}"))
-		return() # not found
-	endif()
-	if(EXISTS "${_sdkdir}/Include/${_winkit_build}/um")
-		_winsdk_conditional_append("Windows Kits 10 (Build ${_winkit_build})" "${_winkit_build}" "${_sdkdir}")
-	endif()
-endfunction()
-
-# Given a name for indentification purposes, the build number, and the associated package GUID,
-# look in the registry under both HKLM and HKCU in \\SOFTWARE\\Microsoft\\MicrosoftSDK\\InstalledSDKs\\
-# for that guid and the SDK it points to.
-function(_winsdk_check_platformsdk_registry _platformsdkname _build _platformsdkguid)
-	foreach(_winsdk_hive HKEY_LOCAL_MACHINE HKEY_CURRENT_USER)
-		get_filename_component(_sdkdir
-			"[${_winsdk_hive}\\SOFTWARE\\Microsoft\\MicrosoftSDK\\InstalledSDKs\\${_platformsdkguid};Install Dir]"
-			ABSOLUTE)
-		_winsdk_conditional_append("${_platformsdkname} (${_build})" "${_build}" "${_sdkdir}")
-	endforeach()
-endfunction()
-
-###
-# Detect toolchain information: to know whether it's OK to use Vista+ only SDKs
-###
-set(_winsdk_vistaonly_ok OFF)
-if(MSVC AND NOT _WINDOWSSDK_IGNOREMSVC)
-	# VC 10 and older has broad target support
-	if(MSVC_VERSION LESS 1700)
-		# VC 11 by default targets Vista and later only, so we can add a few more SDKs that (might?) only work on vista+
-	elseif("${CMAKE_VS_PLATFORM_TOOLSET}" MATCHES "_xp")
-		# This is the XP-compatible v110+ toolset
-	elseif("${CMAKE_VS_PLATFORM_TOOLSET}" STREQUAL "v100" OR "${CMAKE_VS_PLATFORM_TOOLSET}" STREQUAL "v90")
-		# This is the VS2010/VS2008 toolset
-	else()
-		# OK, we're VC11 or newer and not using a backlevel or XP-compatible toolset.
-		# These versions have no XP (and possibly Vista pre-SP1) support
-		set(_winsdk_vistaonly_ok ON)
-		if(_WINDOWSSDK_ANNOUNCE AND NOT _WINDOWSSDK_VISTAONLY_PESTERED)
-			set(_WINDOWSSDK_VISTAONLY_PESTERED ON CACHE INTERNAL "" FORCE)
-			message(STATUS "FindWindowsSDK: Detected Visual Studio 2012 or newer, not using the _xp toolset variant: including SDK versions that drop XP support in search!")
-		endif()
-	endif()
-endif()
-if(_WINDOWSSDK_IGNOREMSVC)
-	set(_winsdk_vistaonly_ok ON)
-endif()
-
-###
-# MSVC version checks - keeps messy conditionals in one place
-# (messy because of _WINDOWSSDK_IGNOREMSVC)
-###
-set(_winsdk_msvc_greater_1200 OFF)
-if(_WINDOWSSDK_IGNOREMSVC OR (MSVC AND (MSVC_VERSION GREATER 1200)))
-	set(_winsdk_msvc_greater_1200 ON)
-endif()
-# Newer than VS .NET/VS Toolkit 2003
-set(_winsdk_msvc_greater_1310 OFF)
-if(_WINDOWSSDK_IGNOREMSVC OR (MSVC AND (MSVC_VERSION GREATER 1310)))
-	set(_winsdk_msvc_greater_1310 ON)
-endif()
-
-# VS2005/2008
-set(_winsdk_msvc_less_1600 OFF)
-if(_WINDOWSSDK_IGNOREMSVC OR (MSVC AND (MSVC_VERSION LESS 1600)))
-	set(_winsdk_msvc_less_1600 ON)
-endif()
-
-# VS2013+
-set(_winsdk_msvc_not_less_1800 OFF)
-if(_WINDOWSSDK_IGNOREMSVC OR (MSVC AND (NOT MSVC_VERSION LESS 1800)))
-	set(_winsdk_msvc_not_less_1800 ON)
-endif()
-
-###
-# START body of find module
-###
-if(_winsdk_msvc_greater_1310) # Newer than VS .NET/VS Toolkit 2003
-	###
-	# Look for "preferred" SDKs
-	###
-
-	# Environment variable for SDK dir
-	if(EXISTS "$ENV{WindowsSDKDir}" AND (NOT "$ENV{WindowsSDKDir}" STREQUAL ""))
-		_winsdk_conditional_append_preferred("WindowsSDKDir environment variable" "$ENV{WindowsSDKDir}")
-	endif()
-
-	if(_winsdk_msvc_less_1600)
-		# Per-user current Windows SDK for VS2005/2008
-		get_filename_component(_sdkdir
-			"[HKEY_CURRENT_USER\\Software\\Microsoft\\Microsoft SDKs\\Windows;CurrentInstallFolder]"
-			ABSOLUTE)
-		_winsdk_conditional_append_preferred("Per-user current Windows SDK" "${_sdkdir}")
-
-		# System-wide current Windows SDK for VS2005/2008
-		get_filename_component(_sdkdir
-			"[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows;CurrentInstallFolder]"
-			ABSOLUTE)
-		_winsdk_conditional_append_preferred("System-wide current Windows SDK" "${_sdkdir}")
-	endif()
-
-	###
-	# Begin the massive list of SDK searching!
-	###
-	if(_winsdk_vistaonly_ok AND _winsdk_msvc_not_less_1800)
-		# These require at least Visual Studio 2013 (VC12)
-
-		_winsdk_check_microsoft_sdks_registry(v10.0A)
-
-		# Windows Software Development Kit (SDK) for Windows 10
-		# Several different versions living in the same directory - if nothing else we can assume RTM (10240)
-		_winsdk_check_microsoft_sdks_registry(v10.0 10.0.10240.0)
-		foreach(_win10build ${_winsdk_win10vers})
-			_winsdk_check_win10_kits(${_win10build})
-		endforeach()
-	endif() # vista-only and 2013+
-
-	# Included in Visual Studio 2013
-	# Includes the v120_xp toolset
-	_winsdk_check_microsoft_sdks_registry(v8.1A 8.1.51636)
-
-	if(_winsdk_vistaonly_ok AND _winsdk_msvc_not_less_1800)
-		# Windows Software Development Kit (SDK) for Windows 8.1
-		# http://msdn.microsoft.com/en-gb/windows/desktop/bg162891
-		_winsdk_check_microsoft_sdks_registry(v8.1 8.1.25984.0)
-		_winsdk_check_windows_kits_registry("Windows Kits 8.1" 8.1.25984.0 KitsRoot81)
-	endif() # vista-only and 2013+
-
-	if(_winsdk_vistaonly_ok)
-		# Included in Visual Studio 2012
-		_winsdk_check_microsoft_sdks_registry(v8.0A 8.0.50727)
-
-		# Microsoft Windows SDK for Windows 8 and .NET Framework 4.5
-		# This is the first version to also include the DirectX SDK
-		# http://msdn.microsoft.com/en-US/windows/desktop/hh852363.aspx
-		_winsdk_check_microsoft_sdks_registry(v8.0 6.2.9200.16384)
-		_winsdk_check_windows_kits_registry("Windows Kits 8.0" 6.2.9200.16384 KitsRoot)
-	endif() # vista-only
-
-	# Included with VS 2012 Update 1 or later
-	# Introduces v110_xp toolset
-	_winsdk_check_microsoft_sdks_registry(v7.1A 7.1.51106)
-	if(_winsdk_vistaonly_ok)
-		# Microsoft Windows SDK for Windows 7 and .NET Framework 4
-		# http://www.microsoft.com/downloads/en/details.aspx?FamilyID=6b6c21d2-2006-4afa-9702-529fa782d63b
-		_winsdk_check_microsoft_sdks_registry(v7.1 7.1.7600.0.30514)
-	endif() # vista-only
-
-	# Included with VS 2010
-	_winsdk_check_microsoft_sdks_registry(v7.0A 6.1.7600.16385)
-
-	# Windows SDK for Windows 7 and .NET Framework 3.5 SP1
-	# Works with VC9
-	# http://www.microsoft.com/en-us/download/details.aspx?id=18950
-	_winsdk_check_microsoft_sdks_registry(v7.0 6.1.7600.16385)
-
-	# Two versions call themselves "v6.1":
-	# Older:
-	# Windows Vista Update & .NET 3.0 SDK
-	# http://www.microsoft.com/en-us/download/details.aspx?id=14477
-
-	# Newer:
-	# Windows Server 2008 & .NET 3.5 SDK
-	# may have broken VS9SP1? they recommend v7.0 instead, or a KB...
-	# http://www.microsoft.com/en-us/download/details.aspx?id=24826
-	_winsdk_check_microsoft_sdks_registry(v6.1 6.1.6000.16384.10)
-
-	# Included in VS 2008
-	_winsdk_check_microsoft_sdks_registry(v6.0A 6.1.6723.1)
-
-	# Microsoft Windows Software Development Kit for Windows Vista and .NET Framework 3.0 Runtime Components
-	# http://blogs.msdn.com/b/stanley/archive/2006/11/08/microsoft-windows-software-development-kit-for-windows-vista-and-net-framework-3-0-runtime-components.aspx
-	_winsdk_check_microsoft_sdks_registry(v6.0 6.0.6000.16384)
-endif()
-
-# Let's not forget the Platform SDKs, which sometimes are useful!
-if(_winsdk_msvc_greater_1200)
-	_winsdk_check_platformsdk_registry("Microsoft Platform SDK for Windows Server 2003 R2" "5.2.3790.2075.51" "D2FF9F89-8AA2-4373-8A31-C838BF4DBBE1")
-	_winsdk_check_platformsdk_registry("Microsoft Platform SDK for Windows Server 2003 SP1" "5.2.3790.1830.15" "8F9E5EF3-A9A5-491B-A889-C58EFFECE8B3")
-endif()
-###
-# Finally, look for "preferred" SDKs
-###
-if(_winsdk_msvc_greater_1310) # Newer than VS .NET/VS Toolkit 2003
-
-
-	# Environment variable for SDK dir
-	if(EXISTS "$ENV{WindowsSDKDir}" AND (NOT "$ENV{WindowsSDKDir}" STREQUAL ""))
-		_winsdk_conditional_append_preferred("WindowsSDKDir environment variable" "$ENV{WindowsSDKDir}")
-	endif()
-
-	if(_winsdk_msvc_less_1600)
-		# Per-user current Windows SDK for VS2005/2008
-		get_filename_component(_sdkdir
-			"[HKEY_CURRENT_USER\\Software\\Microsoft\\Microsoft SDKs\\Windows;CurrentInstallFolder]"
-			ABSOLUTE)
-		_winsdk_conditional_append_preferred("Per-user current Windows SDK" "${_sdkdir}")
-
-		# System-wide current Windows SDK for VS2005/2008
-		get_filename_component(_sdkdir
-			"[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows;CurrentInstallFolder]"
-			ABSOLUTE)
-		_winsdk_conditional_append_preferred("System-wide current Windows SDK" "${_sdkdir}")
-	endif()
-endif()
-
-
-function(windowssdk_name_lookup _dir _outvar)
-	list(FIND _win_sdk_versanddirs "${_dir}" _diridx)
-	math(EXPR _idx "${_diridx} - 1")
-	if(${_idx} GREATER -1)
-		list(GET _win_sdk_versanddirs ${_idx} _ret)
-	else()
-		set(_ret "NOTFOUND")
-	endif()
-	set(${_outvar} "${_ret}" PARENT_SCOPE)
-endfunction()
-
-function(windowssdk_build_lookup _dir _outvar)
-	list(FIND _win_sdk_buildsanddirs "${_dir}" _diridx)
-	math(EXPR _idx "${_diridx} - 1")
-	if(${_idx} GREATER -1)
-		list(GET _win_sdk_buildsanddirs ${_idx} _ret)
-	else()
-		set(_ret "NOTFOUND")
-	endif()
-	set(${_outvar} "${_ret}" PARENT_SCOPE)
-endfunction()
-
-# If we found something...
-if(_win_sdk_dirs)
-	list(GET _win_sdk_dirs 0 WINDOWSSDK_LATEST_DIR)
-	windowssdk_name_lookup("${WINDOWSSDK_LATEST_DIR}"
-		WINDOWSSDK_LATEST_NAME)
-	set(WINDOWSSDK_DIRS ${_win_sdk_dirs})
-
-	# Fallback, in case no preference found.
-	set(WINDOWSSDK_PREFERRED_DIR "${WINDOWSSDK_LATEST_DIR}")
-	set(WINDOWSSDK_PREFERRED_NAME "${WINDOWSSDK_LATEST_NAME}")
-	set(WINDOWSSDK_PREFERRED_FIRST_DIRS ${WINDOWSSDK_DIRS})
-	set(WINDOWSSDK_FOUND_PREFERENCE OFF)
-endif()
-
-# If we found indications of a user preference...
-if(_win_sdk_preferred_sdk_dirs)
-	list(GET _win_sdk_preferred_sdk_dirs 0 WINDOWSSDK_PREFERRED_DIR)
-	windowssdk_name_lookup("${WINDOWSSDK_PREFERRED_DIR}"
-		WINDOWSSDK_PREFERRED_NAME)
-	set(WINDOWSSDK_PREFERRED_FIRST_DIRS
-		${_win_sdk_preferred_sdk_dirs}
-		${_win_sdk_dirs})
-	list(REMOVE_DUPLICATES WINDOWSSDK_PREFERRED_FIRST_DIRS)
-	set(WINDOWSSDK_FOUND_PREFERENCE ON)
-endif()
-
-include(FindPackageHandleStandardArgs)
-find_package_handle_standard_args(WindowsSDK
-	"No compatible version of the Windows SDK or Platform SDK found."
-	WINDOWSSDK_DIRS)
-
-if(WINDOWSSDK_FOUND)
-	# Internal: Architecture-appropriate library directory names.
-	if("${CMAKE_VS_PLATFORM_NAME}" STREQUAL "ARM")
-		if(CMAKE_SIZEOF_VOID_P MATCHES "8")
-			# Only supported in Win10 SDK and up.
-			set(_winsdk_arch8 arm64) # what the WDK for Win8+ calls this architecture
-		else()
-			set(_winsdk_archbare /arm) # what the architecture used to be called in oldest SDKs
-			set(_winsdk_arch arm) # what the architecture used to be called
-			set(_winsdk_arch8 arm) # what the WDK for Win8+ calls this architecture
-		endif()
-	else()
-		if(CMAKE_SIZEOF_VOID_P MATCHES "8")
-			set(_winsdk_archbare /x64) # what the architecture used to be called in oldest SDKs
-			set(_winsdk_arch amd64) # what the architecture used to be called
-			set(_winsdk_arch8 x64) # what the WDK for Win8+ calls this architecture
-		else()
-			set(_winsdk_archbare ) # what the architecture used to be called in oldest SDKs
-			set(_winsdk_arch i386) # what the architecture used to be called
-			set(_winsdk_arch8 x86) # what the WDK for Win8+ calls this architecture
-		endif()
-	endif()
-
-	function(get_windowssdk_from_component _component _var)
-		get_filename_component(_component "${_component}" ABSOLUTE)
-		file(TO_CMAKE_PATH "${_component}" _component)
-		foreach(_sdkdir ${WINDOWSSDK_DIRS})
-			get_filename_component(_sdkdir "${_sdkdir}" ABSOLUTE)
-			string(LENGTH "${_sdkdir}" _sdklen)
-			file(RELATIVE_PATH _rel "${_sdkdir}" "${_component}")
-			# If we don't have any "parent directory" items...
-			if(NOT "${_rel}" MATCHES "[.][.]")
-				set(${_var} "${_sdkdir}" PARENT_SCOPE)
-				return()
-			endif()
-		endforeach()
-		# Fail.
-		set(${_var} "NOTFOUND" PARENT_SCOPE)
-	endfunction()
-	function(get_windowssdk_library_dirs _winsdk_dir _var)
-		set(_dirs)
-		set(_suffixes
-			"lib${_winsdk_archbare}" # SDKs like 7.1A
-			"lib/${_winsdk_arch}" # just because some SDKs have x86 dir and root dir
-			"lib/w2k/${_winsdk_arch}" # Win2k min requirement
-			"lib/wxp/${_winsdk_arch}" # WinXP min requirement
-			"lib/wnet/${_winsdk_arch}" # Win Server 2003 min requirement
-			"lib/wlh/${_winsdk_arch}"
-			"lib/wlh/um/${_winsdk_arch8}" # Win Vista ("Long Horn") min requirement
-			"lib/win7/${_winsdk_arch}"
-			"lib/win7/um/${_winsdk_arch8}" # Win 7 min requirement
-		)
-		foreach(_ver
-			wlh # Win Vista ("Long Horn") min requirement
-			win7 # Win 7 min requirement
-			win8 # Win 8 min requirement
-			winv6.3 # Win 8.1 min requirement
-		)
-
-			list(APPEND _suffixes
-				"lib/${_ver}/${_winsdk_arch}"
-				"lib/${_ver}/um/${_winsdk_arch8}"
-				"lib/${_ver}/km/${_winsdk_arch8}"
-			)
-		endforeach()
-
-		# Look for WDF libraries in Win10+ SDK
-		foreach(_mode umdf kmdf)
-			file(GLOB _wdfdirs RELATIVE "${_winsdk_dir}" "${_winsdk_dir}/lib/wdf/${_mode}/${_winsdk_arch8}/*")
-			if(_wdfdirs)
-				list(APPEND _suffixes ${_wdfdirs})
-			endif()
-		endforeach()
-
-		# Look in each Win10+ SDK version for the components
-		foreach(_win10ver ${_winsdk_win10vers})
-			foreach(_component um km ucrt mmos)
-				list(APPEND _suffixes "lib/${_win10ver}/${_component}/${_winsdk_arch8}")
-			endforeach()
-		endforeach()
-
-		foreach(_suffix ${_suffixes})
-			# Check to see if a library actually exists here.
-			file(GLOB _libs "${_winsdk_dir}/${_suffix}/*.lib")
-			if(_libs)
-				list(APPEND _dirs "${_winsdk_dir}/${_suffix}")
-			endif()
-		endforeach()
-		if("${_dirs}" STREQUAL "")
-			set(_dirs NOTFOUND)
-		else()
-			list(REMOVE_DUPLICATES _dirs)
-		endif()
-		set(${_var} ${_dirs} PARENT_SCOPE)
-	endfunction()
-	function(get_windowssdk_include_dirs _winsdk_dir _var)
-		set(_dirs)
-
-		set(_subdirs shared um winrt km wdf mmos ucrt)
-		set(_suffixes Include)
-
-		foreach(_dir ${_subdirs})
-			list(APPEND _suffixes "Include/${_dir}")
-		endforeach()
-
-		foreach(_ver ${_winsdk_win10vers})
-			foreach(_dir ${_subdirs})
-				list(APPEND _suffixes "Include/${_ver}/${_dir}")
-			endforeach()
-		endforeach()
-
-		foreach(_suffix ${_suffixes})
-			# Check to see if a header file actually exists here.
-			file(GLOB _headers "${_winsdk_dir}/${_suffix}/*.h")
-			if(_headers)
-				list(APPEND _dirs "${_winsdk_dir}/${_suffix}")
-			endif()
-		endforeach()
-		if("${_dirs}" STREQUAL "")
-			set(_dirs NOTFOUND)
-		else()
-			list(REMOVE_DUPLICATES _dirs)
-		endif()
-		set(${_var} ${_dirs} PARENT_SCOPE)
-	endfunction()
-	function(get_windowssdk_library_dirs_multiple _var)
-		set(_dirs)
-		foreach(_sdkdir ${ARGN})
-			get_windowssdk_library_dirs("${_sdkdir}" _current_sdk_libdirs)
-			if(_current_sdk_libdirs)
-				list(APPEND _dirs ${_current_sdk_libdirs})
-			endif()
-		endforeach()
-		if("${_dirs}" STREQUAL "")
-			set(_dirs NOTFOUND)
-		else()
-			list(REMOVE_DUPLICATES _dirs)
-		endif()
-		set(${_var} ${_dirs} PARENT_SCOPE)
-	endfunction()
-	function(get_windowssdk_include_dirs_multiple _var)
-		set(_dirs)
-		foreach(_sdkdir ${ARGN})
-			get_windowssdk_include_dirs("${_sdkdir}" _current_sdk_incdirs)
-			if(_current_sdk_libdirs)
-				list(APPEND _dirs ${_current_sdk_incdirs})
-			endif()
-		endforeach()
-		if("${_dirs}" STREQUAL "")
-			set(_dirs NOTFOUND)
-		else()
-			list(REMOVE_DUPLICATES _dirs)
-		endif()
-		set(${_var} ${_dirs} PARENT_SCOPE)
-	endfunction()
-endif()
\ No newline at end of file
diff --git a/indra/cmake/LLSharedLibs.cmake b/indra/cmake/LLSharedLibs.cmake
index f69b45cd926193e04ce625a7ae2ed0c1674d2d81..0773e7587a4c803b1f544a86036ee4a43f2e5213 100644
--- a/indra/cmake/LLSharedLibs.cmake
+++ b/indra/cmake/LLSharedLibs.cmake
@@ -18,6 +18,13 @@ macro(ll_deploy_sharedlibs_command target_exe)
   if(NOT DARWIN)
     if(WINDOWS)
       SET_TEST_PATH(SEARCH_DIRS)
+      if(ASAN)
+        if(ADDRESS_SIZE EQUAL 32)
+          LIST(APPEND SEARCH_DIRS "$ENV{VCToolsInstallDir}bin\\Hostx64\\x86")
+        else(ADDRESS_SIZE EQUAL 32)
+          LIST(APPEND SEARCH_DIRS "$ENV{VCToolsInstallDir}bin\\Hostx64\\x64")
+        endif(ADDRESS_SIZE EQUAL 32)
+      endif(ASAN)
       LIST(APPEND SEARCH_DIRS "$ENV{SystemRoot}/system32")
     elseif(LINUX)
       SET_TEST_PATH(SEARCH_DIRS)
diff --git a/indra/cmake/Linking.cmake b/indra/cmake/Linking.cmake
index 706cd33c21dd40e58060da1ad37560f417b2568d..f66cb35061d3e9f16bd5492a752db4d59e01b05b 100644
--- a/indra/cmake/Linking.cmake
+++ b/indra/cmake/Linking.cmake
@@ -73,6 +73,22 @@ if (WINDOWS)
       ole32
       dbghelp
       )
+
+  if(ASAN)
+    if(ADDRESS_SIZE EQUAL 32)
+      set(WINDOWS_LIBRARIES
+          ${WINDOWS_LIBRARIES}
+          clang_rt.asan_dynamic_runtime_thunk-i386
+          clang_rt.asan_dynamic-i386
+          )
+    else(ADDRESS_SIZE EQUAL 32)
+      set(WINDOWS_LIBRARIES
+          ${WINDOWS_LIBRARIES}
+          clang_rt.asan_dynamic_runtime_thunk-x86_64
+          clang_rt.asan_dynamic-x86_64
+          )
+    endif(ADDRESS_SIZE EQUAL 32)
+  endif(ASAN)
 else (WINDOWS)
   set(WINDOWS_LIBRARIES "")
 endif (WINDOWS)
diff --git a/indra/llappearance/llwearabletype.cpp b/indra/llappearance/llwearabletype.cpp
index 99a66611d6b414857b392449a9c28dc312e637a1..77b3bba56e8d75946a148a04e3f0f61a77f63d4d 100644
--- a/indra/llappearance/llwearabletype.cpp
+++ b/indra/llappearance/llwearabletype.cpp
@@ -91,7 +91,7 @@ LLWearableDictionary::LLWearableDictionary(LLWearableType& wtype)
 // [SL:KB] - Patch: Appearance-Misc | Checked: 2011-05-29 (Catznip-2.6)
 	addEntry(LLWearableType::WT_PHYSICS,      new WearableEntry(wtype, "physics",     "New Physics",		LLAssetType::AT_CLOTHING, 	LLInventoryType::ICONNAME_CLOTHING_PHYSICS, TRUE, FALSE));
 // [/SL:KB]
-//	addEntry(LLWearableType::WT_PHYSICS,      new WearableEntry("physics",     "New Physics",		LLAssetType::AT_CLOTHING, 	LLInventoryType::ICONNAME_CLOTHING_PHYSICS, TRUE, TRUE));
+//	addEntry(LLWearableType::WT_PHYSICS,      new WearableEntry(wtype, "physics",     "New Physics",		LLAssetType::AT_CLOTHING, 	LLInventoryType::ICONNAME_CLOTHING_PHYSICS, TRUE, TRUE));
 
 	addEntry(LLWearableType::WT_INVALID,      new WearableEntry(wtype, "invalid",     "Invalid Wearable", 	LLAssetType::AT_NONE, 		LLInventoryType::ICONNAME_UNKNOWN, FALSE, FALSE));
 	addEntry(LLWearableType::WT_NONE,      	  new WearableEntry(wtype, "none",        "Invalid Wearable", 	LLAssetType::AT_NONE, 		LLInventoryType::ICONNAME_NONE, FALSE, FALSE));
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index d209d9afdb4c367a035b906955821f4c0ad0437b..5f077e0471bfa87abac39d4d598d369fd1a4cbca 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -259,10 +259,21 @@
       <key>Value</key>
       <boolean>1</boolean>
     </map>
+    <key>RLVaShowRedirectChatTyping</key>
+    <map>
+      <key>Comment</key>
+      <string>Sends typing start messages (and optionally plays the typing animation) when @redirchat restricted</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>Boolean</string>
+      <key>Value</key>
+      <boolean>0</boolean>
+    </map>
     <key>RLVaSplitRedirectChat</key>
     <map>
       <key>Comment</key>
-      <string>Splits long nearby chat lines across multiple messages when @redir* restricted.</string>
+      <string>Splits long nearby chat lines across multiple messages when @redir* restricted</string>
       <key>Persist</key>
       <integer>1</integer>
       <key>Type</key>
diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp
index 3e2727de6b8c5e3f7dcebfe8d2dbe1a614d37e3a..ddd04d022037f2d42eb3f5b175f67ccaf0074a86 100644
--- a/indra/newview/llagent.cpp
+++ b/indra/newview/llagent.cpp
@@ -2022,6 +2022,13 @@ BOOL LLAgent::needsRenderHead()
 //-----------------------------------------------------------------------------
 void LLAgent::startTyping()
 {
+// [RLVa:KB] - @redirchat
+	if (!RlvActions::canSendTypingStart())
+	{
+		return;
+	}
+// [/RLVa:KB]
+
 	mTypingTimer.reset();
 
 	if (getRenderState() & AGENT_STATE_TYPING)
@@ -4155,7 +4162,7 @@ void LLAgent::teleportViaLandmark(const LLUUID& landmark_asset_id)
 		                                   : gRlvHandler.hasBehaviour(RLV_BHVR_TPLM) && gRlvHandler.hasBehaviour(RLV_BHVR_TPLOC) ) ||
 		   ((gRlvHandler.hasBehaviour(RLV_BHVR_UNSIT)) && (isAgentAvatarValid()) && (gAgentAvatarp->isSitting())) ))
 	{
-		RlvUtil::notifyBlocked(RLV_STRING_BLOCKED_TELEPORT);
+		RlvUtil::notifyBlocked(RlvStringKeys::Blocked::Teleport);
 		return;
 	}
 // [/RLVa:KB]
@@ -4257,7 +4264,7 @@ void LLAgent::teleportViaLocation(const LLVector3d& pos_global)
 	{
 		if ( (RlvActions::isLocalTp(pos_global)) ? !RlvActions::canTeleportToLocal(pos_global) : !RlvActions::canTeleportToLocation() )
 		{
-			RlvUtil::notifyBlocked(RLV_STRING_BLOCKED_TELEPORT);
+			RlvUtil::notifyBlocked(RlvStringKeys::Blocked::Teleport);
 			return;
 		}
 
@@ -4327,7 +4334,7 @@ void LLAgent::teleportViaLocationLookAt(const LLVector3d& pos_global, const LLVe
 	{
 		if ( (RlvActions::isLocalTp(pos_global)) ? !RlvActions::canTeleportToLocal(pos_global) : !RlvActions::canTeleportToLocation() )
 		{
-			RlvUtil::notifyBlocked(RLV_STRING_BLOCKED_TELEPORT);
+			RlvUtil::notifyBlocked(RlvStringKeys::Blocked::Teleport);
 			return;
 		}
 
diff --git a/indra/newview/llagentui.cpp b/indra/newview/llagentui.cpp
index 83b38db562fccc3fb2d0522651fdca227712130d..149f1a6d91deca0053c9947b6e88133afe66757b 100644
--- a/indra/newview/llagentui.cpp
+++ b/indra/newview/llagentui.cpp
@@ -102,11 +102,11 @@ BOOL LLAgentUI::buildLocationString(std::string& str, ELocationFormat fmt,const
 
 	// create a default name and description for the landmark
 	bool rlva_has_showloc = gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC);
-	const std::string& parcel_name = rlva_has_showloc  ? RlvStrings::getString(RLV_STRING_HIDDEN_PARCEL) : parcelMGr.getAgentParcelName();
-	const std::string& region_name = rlva_has_showloc ? RlvStrings::getString(RLV_STRING_HIDDEN_REGION) : region->getName();
+	const std::string& parcel_name = rlva_has_showloc  ? RlvStrings::getString(RlvStringKeys::Hidden::Parcel) : parcelMGr.getAgentParcelName();
+	const std::string& region_name = rlva_has_showloc ? RlvStrings::getString(RlvStringKeys::Hidden::Region) : region->getName();
 // [RLVa:KB] - Checked: 2010-04-04 (RLVa-1.2.0d) | Modified: RLVa-1.2.0d
 	// RELEASE-RLVa: [SL-2.0.0] Check ELocationFormat to make sure our switch still makes sense
-	if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC))
+	if (rlva_has_showloc)
 	{
 		if (LOCATION_FORMAT_NO_MATURITY == fmt)
 			fmt = LOCATION_FORMAT_LANDMARK;
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 03cc4af6b50edd0c3c90c90e22d87c84a8eacdb1..501b61179da8572542aa617495e8f1ba386deb9c 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -379,7 +379,10 @@ const std::string START_MARKER_FILE_NAME("Alchemy.start_marker");
 const std::string ERROR_MARKER_FILE_NAME("Alchemy.error_marker");
 const std::string LLERROR_MARKER_FILE_NAME("Alchemy.llerror_marker");
 const std::string LOGOUT_MARKER_FILE_NAME("Alchemy.logout_marker");
-static BOOL gDoDisconnect = FALSE;
+//static BOOL gDoDisconnect = FALSE;
+// [RLVa:KB] - Checked: RLVa-2.3
+BOOL gDoDisconnect = FALSE;
+// [/RLVa:KB]
 static std::string gLaunchFileOnQuit;
 
 // Used on Win32 for other apps to identify our window (eg, win_setup)
@@ -2890,7 +2893,7 @@ bool LLAppViewer::initConfiguration()
 	}
 
 // [RLVa:KB] - Patch: RLVa-2.1.0
-	if (LLControlVariable* pControl = gSavedSettings.getControl(RLV_SETTING_MAIN))
+    if (LLControlVariable* pControl = gSavedSettings.getControl(RlvSettingNames::Main))
 	{
 		if ( (pControl->getValue().asBoolean()) && (pControl->hasUnsavedValue()) )
 		{
@@ -3166,7 +3169,7 @@ LLSD LLAppViewer::getViewerInfo() const
 		}
 		else
 		{
-			info["REGION"] = RlvStrings::getString(RLV_STRING_HIDDEN_REGION);
+			info["REGION"] = RlvStrings::getString(RlvStringKeys::Hidden::Region);
 		}
 		info["SERVER_VERSION"] = gLastVersionChannel;
 // [/RLVa:KB]
diff --git a/indra/newview/llavataractions.cpp b/indra/newview/llavataractions.cpp
index e8ed61cbfbd0c33c71fb6bfd28d8c73a09e7684b..96028e3f8f4646bc87633d18c02004b01cbad02d 100644
--- a/indra/newview/llavataractions.cpp
+++ b/indra/newview/llavataractions.cpp
@@ -228,7 +228,7 @@ void LLAvatarActions::startIM(const LLUUID& id)
 	if (!RlvActions::canStartIM(id))
 	{
 		make_ui_sound("UISndInvalidOp");
-		RlvUtil::notifyBlocked(RLV_STRING_BLOCKED_STARTIM, LLSD().with("RECIPIENT", LLSLURL("agent", id, "completename").getSLURLString()));
+		RlvUtil::notifyBlocked(RlvStringKeys::Blocked::StartIm, LLSD().with("RECIPIENT", LLSLURL("agent", id, "completename").getSLURLString()));
 		return;
 	}
 // [/RLVa:KB]
@@ -273,7 +273,7 @@ void LLAvatarActions::startCall(const LLUUID& id)
 	if (!RlvActions::canStartIM(id))
 	{
 		make_ui_sound("UISndInvalidOp");
-		RlvUtil::notifyBlocked(RLV_STRING_BLOCKED_STARTIM, LLSD().with("RECIPIENT", LLSLURL("agent", id, "completename").getSLURLString()));
+		RlvUtil::notifyBlocked(RlvStringKeys::Blocked::StartIm, LLSD().with("RECIPIENT", LLSLURL("agent", id, "completename").getSLURLString()));
 		return;
 	}
 // [/RLVa:KB]
@@ -299,7 +299,7 @@ void LLAvatarActions::startAdhocCall(const uuid_vec_t& ids, const LLUUID& floate
 		if (!RlvActions::canStartIM(idAgent))
 		{
 			make_ui_sound("UISndInvalidOp");
-			RlvUtil::notifyBlocked(RLV_STRING_BLOCKED_STARTCONF);
+			RlvUtil::notifyBlocked(RlvStringKeys::Blocked::StartConference);
 			return;
 		}
 		id_array.push_back(idAgent);
@@ -356,7 +356,7 @@ void LLAvatarActions::startConference(const uuid_vec_t& ids, const LLUUID& float
 		if (!RlvActions::canStartIM(idAgent))
 		{
 			make_ui_sound("UISndInvalidOp");
-			RlvUtil::notifyBlocked(RLV_STRING_BLOCKED_STARTCONF);
+			RlvUtil::notifyBlocked(RlvStringKeys::Blocked::StartConference);
 			return;
 		}
 		id_array.push_back(idAgent);
@@ -533,7 +533,7 @@ void LLAvatarActions::teleport_request_callback(const LLSD& notification, const
 		// Filter the request message if the recipients is IM-blocked
 		if ( (RlvActions::isRlvEnabled()) && ((!RlvActions::canStartIM(idRecipient)) || (!RlvActions::canSendIM(idRecipient))) )
 		{
-			strMessage = RlvStrings::getString(RLV_STRING_HIDDEN);
+			strMessage = RlvStrings::getString(RlvStringKeys::Hidden::Generic);
 		}
 // [/RLVa:KB]
 
diff --git a/indra/newview/llchatbar.cpp b/indra/newview/llchatbar.cpp
index 764c2f1ead3b863ebaa540f56739085381e10154..631e983444ce6769dc3e4468091e2b3fcc519b14 100644
--- a/indra/newview/llchatbar.cpp
+++ b/indra/newview/llchatbar.cpp
@@ -480,11 +480,7 @@ void LLChatBar::onInputEditorKeystroke( LLLineEditor* caller, void* userdata )
 
 	S32 length = raw_text.length();
 
-//	if( (length > 0) && (raw_text[0] != '/') )  // forward slash is used for escape (eg. emote) sequences
-// [RLVa:KB] - Checked: 2010-03-26 (RLVa-1.2.0b) | Modified: RLVa-1.0.0d
-	// RELEASE-RLVa: [SL-2.0.0] This entire class appears to be dead/non-functional?
-	if ( (length > 0) && (raw_text[0] != '/') && (!RlvActions::hasBehaviour(RLV_BHVR_REDIRCHAT)) )
-// [/RLVa:KB]
+	if( (length > 0) && (raw_text[0] != '/') )  // forward slash is used for escape (eg. emote) sequences
 	{
 		gAgent.startTyping();
 	}
diff --git a/indra/newview/llchathistory.cpp b/indra/newview/llchathistory.cpp
index fa57d57689decc0b8b1bc92724a0e132bf5d97c5..27d69264b07da6f9e84b50004f69019743bea323 100644
--- a/indra/newview/llchathistory.cpp
+++ b/indra/newview/llchathistory.cpp
@@ -67,6 +67,7 @@
 #include "llviewercontrol.h"
 #include "llviewerobjectlist.h"
 // [RLVa:KB] - Checked: 2010-04-22 (RLVa-1.2.0f)
+#include "rlvactions.h"
 #include "rlvcommon.h"
 // [/RLVa:KB]
 
@@ -499,6 +500,12 @@ class LLChatHistoryHeader: public LLPanel
 		{
 			return canModerate(userdata);
 		}
+// [RLVa:KB] - @pay
+		else if (level == "can_pay")
+		{
+			return RlvActions::canPayAvatar(getAvatarId());
+		}
+// [/RLVa:KB]
 		else if (level == "can_ban_member")
 		{
 			return canBanGroupMember(getAvatarId());
diff --git a/indra/newview/llconversationloglist.cpp b/indra/newview/llconversationloglist.cpp
index 24d9d58fadf4c8400cb72b723e24c6ce49e9f7d5..485a48bc9f13b8dd06e934deb0f8a8eeabb15b7d 100644
--- a/indra/newview/llconversationloglist.cpp
+++ b/indra/newview/llconversationloglist.cpp
@@ -34,6 +34,9 @@
 #include "llconversationloglistitem.h"
 #include "llviewermenu.h"
 #include "lltrans.h"
+// [RLVa:KB] - @pay
+#include "rlvactions.h"
+// [/RLVa:KB]
 
 static LLDefaultChildRegistry::Register<LLConversationLogList> r("conversation_log_list");
 
@@ -388,6 +391,12 @@ bool LLConversationLogList::isActionEnabled(const LLSD& userdata)
 	{
 		return (is_p2p || is_group_member) && LLAvatarActions::canCall();
 	}
+// [RLVa:KB] - @pay
+	else if ("can_pay" == command_name)
+	{
+		return is_p2p && RlvActions::canPayAvatar(selected_id);
+	}
+// [/RLVa:KB]
 	else if ("add_rem_friend"		== command_name ||
 			 "can_invite_to_group"	== command_name ||
 			 "can_share"			== command_name ||
diff --git a/indra/newview/llexperiencelog.cpp b/indra/newview/llexperiencelog.cpp
index 09b61616f2fd0b44898f39a48aab7e9dddc3c77a..809b3385715e36e7aec62c2c76dd05adc42a8852 100644
--- a/indra/newview/llexperiencelog.cpp
+++ b/indra/newview/llexperiencelog.cpp
@@ -149,6 +149,13 @@ std::string LLExperienceLog::getPermissionString( const LLSD& message, const std
 		{
 			buf.str(entry);
 		}
+		else
+		{
+// [SL:KB] - Patch: Viewer-Build | Checked: Catznip-6.5
+			buf.str("");
+// [/SL:KB]
+//			buf.str();
+		}
 	}
 
 	if(buf.str().empty())
diff --git a/indra/newview/llfloaterimcontainer.cpp b/indra/newview/llfloaterimcontainer.cpp
index 45b419b947343bd7cc788898b39297c891be0d33..901db3e323e447b862dd357ccdda7caf724e64de 100644
--- a/indra/newview/llfloaterimcontainer.cpp
+++ b/indra/newview/llfloaterimcontainer.cpp
@@ -56,6 +56,9 @@
 #include "llworld.h"
 #include "llsdserialize.h"
 #include "llviewerobjectlist.h"
+// [RLVa:KB] - @pay
+#include "rlvactions.h"
+// [/RLVa:KB]
 
 //
 // LLFloaterIMContainer
@@ -1467,11 +1470,20 @@ bool LLFloaterIMContainer::enableContextMenuItem(const std::string& item, uuid_v
 	}
 
 	// Handle all other options
-	if (("can_invite" == item) || ("can_chat_history" == item) || ("can_share" == item) || ("can_pay" == item))
+//	if (("can_invite" == item) || ("can_chat_history" == item) || ("can_share" == item) || ("can_pay" == item))
+// [RLVa:KB] - @pay
+	if (("can_invite" == item) || ("can_chat_history" == item) || ("can_share" == item))
+// [/RLVa:KB]
 	{
 		// Those menu items are enable only if a single avatar is selected
 		return is_single_select;
 	}
+// [RLVa:KB] - @pay
+    else if ("can_pay" == item)
+    {
+		return is_single_select && RlvActions::canPayAvatar(single_id);
+    }
+// [/RLVa:KB]
     else if ("can_block" == item)
     {
         return (is_single_select ? LLAvatarActions::canBlock(single_id) : false);
diff --git a/indra/newview/llfloaterimnearbychat.cpp b/indra/newview/llfloaterimnearbychat.cpp
index c21679cc041224638f672f00bdf900d99167cd2f..af41c1c18ad83e28df09903a766da3b77ef94231 100644
--- a/indra/newview/llfloaterimnearbychat.cpp
+++ b/indra/newview/llfloaterimnearbychat.cpp
@@ -477,10 +477,7 @@ void LLFloaterIMNearbyChat::onChatBoxKeystroke()
 
 	S32 length = raw_text.length();
 
-//	if( (length > 0) && (raw_text[0] != '/') )  // forward slash is used for escape (eg. emote) sequences
-// [RLVa:KB] - Checked: 2010-03-26 (RLVa-1.2.0b) | Modified: RLVa-1.0.0d
-	if ( (length > 0) && (raw_text[0] != '/') && (!RlvActions::hasBehaviour(RLV_BHVR_REDIRCHAT)) )
-// [/RLVa:KB]
+	if( (length > 0) && (raw_text[0] != '/') )  // forward slash is used for escape (eg. emote) sequences
 	{
 		gAgent.startTyping();
 	}
diff --git a/indra/newview/llfloaterimsession.cpp b/indra/newview/llfloaterimsession.cpp
index 81afd5bf7583c8d703f8df80a1d69f2a1bf2f064..e2ae19bdf4e221e112fb0286a5d2015abcf0ae1f 100644
--- a/indra/newview/llfloaterimsession.cpp
+++ b/indra/newview/llfloaterimsession.cpp
@@ -321,7 +321,7 @@ void LLFloaterIMSession::sendMsg(const std::string& msg)
 
 		if (fRlvFilter)
 		{
-			utf8_text = RlvStrings::getString(RLV_STRING_BLOCKED_SENDIM);
+			utf8_text = RlvStrings::getString(RlvStringKeys::Blocked::SendIm);
 		}
 	}
 // [/RLVa:KB]
diff --git a/indra/newview/llfloaterworldmap.cpp b/indra/newview/llfloaterworldmap.cpp
index 1134410081852486e86d89afea48c32badc9a88b..61f2662bfa792f4a7e6e215a3ca98ffbec8fff7c 100644
--- a/indra/newview/llfloaterworldmap.cpp
+++ b/indra/newview/llfloaterworldmap.cpp
@@ -681,7 +681,7 @@ void LLFloaterWorldMap::trackLocation(const LLVector3d& pos_global)
 	mTrackedStatus = LLTracker::TRACKING_LOCATION;
 	LLWorldMap::getInstance()->cancelTracking();		// The floater is taking over the tracking
 // [RLVa:KB] - Checked: 2012-02-08 (RLVa-1.4.5) | Added: RLVa-1.4.5
-	LLTracker::trackLocation(pos_global, (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) ? full_name : RlvStrings::getString(RLV_STRING_HIDDEN).c_str(), tooltip);
+	LLTracker::trackLocation(pos_global, (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) ? full_name : RlvStrings::getString(RlvStringKeys::Hidden::Generic).c_str(), tooltip);
 // [/RLVa:KB]
 //	LLTracker::trackLocation(pos_global, full_name, tooltip);
 	
@@ -760,7 +760,7 @@ void LLFloaterWorldMap::updateLocation()
 				mSetToUserPosition = FALSE;
 
 				// Fill out the location field
-				getChild<LLUICtrl>("location")->setValue(RlvStrings::getString(RLV_STRING_HIDDEN_REGION));
+				getChild<LLUICtrl>("location")->setValue(RlvStrings::getString(RlvStringKeys::Hidden::Region));
 				
 				// update the coordinate display with location of avatar in region
 				updateTeleportCoordsDisplay( agentPos );
@@ -819,7 +819,7 @@ void LLFloaterWorldMap::updateLocation()
 		{
 			mSLURL = LLSLURL();
 
-			childSetValue("location", RlvStrings::getString(RLV_STRING_HIDDEN_REGION));
+			childSetValue("location", RlvStrings::getString(RlvStringKeys::Hidden::Region));
 		}
 		else if (gotSimName)
 // [/RLVa:KB]
diff --git a/indra/newview/llgroupactions.cpp b/indra/newview/llgroupactions.cpp
index 5409b00c2e425ad86a18d302188f8849413f72b9..c33ff3e709fb64b76847a3dc758b3601edd44987 100644
--- a/indra/newview/llgroupactions.cpp
+++ b/indra/newview/llgroupactions.cpp
@@ -215,7 +215,7 @@ void LLGroupActions::startCall(const LLUUID& group_id)
 	if (!RlvActions::canStartIM(group_id))
 	{
 		make_ui_sound("UISndInvalidOp");
-		RlvUtil::notifyBlocked(RLV_STRING_BLOCKED_STARTIM, LLSD().with("RECIPIENT", LLSLURL("group", group_id, "about").getSLURLString()));
+		RlvUtil::notifyBlocked(RlvStringKeys::Blocked::StartIm, LLSD().with("RECIPIENT", LLSLURL("group", group_id, "about").getSLURLString()));
 		return;
 	}
 // [/RLVa:KB]
@@ -455,7 +455,7 @@ LLUUID LLGroupActions::startIM(const LLUUID& group_id)
 	if (!RlvActions::canStartIM(group_id))
 	{
 		make_ui_sound("UISndInvalidOp");
-		RlvUtil::notifyBlocked(RLV_STRING_BLOCKED_STARTIM, LLSD().with("RECIPIENT", LLSLURL("group", group_id, "about").getSLURLString()));
+		RlvUtil::notifyBlocked(RlvStringKeys::Blocked::StartIm, LLSD().with("RECIPIENT", LLSLURL("group", group_id, "about").getSLURLString()));
 		return LLUUID::null;
 	}
 // [/RLVa:KB]
diff --git a/indra/newview/llimprocessing.cpp b/indra/newview/llimprocessing.cpp
index e5df39ae209b3b96a844847b232e3c9fd313df53..6c39e8b13c0ae8669082cad6523a3ba013788c88 100644
--- a/indra/newview/llimprocessing.cpp
+++ b/indra/newview/llimprocessing.cpp
@@ -643,8 +643,8 @@ void LLIMProcessing::processNewMessage(LLUUID from_id,
 				if ( (rlv_handler_t::isEnabled()) && (offline != IM_OFFLINE) && (!RlvActions::canReceiveIM(from_id)) && (!LLMuteList::getInstance()->isLinden(original_name) ))
 				{
 					if (!mute_im)
-						RlvUtil::sendBusyMessage(from_id, RlvStrings::getString(RLV_STRING_BLOCKED_RECVIM_REMOTE), session_id);
-					buffer = RlvStrings::getString(RLV_STRING_BLOCKED_RECVIM);
+						RlvUtil::sendBusyMessage(from_id, RlvStrings::getString(RlvStringKeys::Blocked::RecvImRemote), session_id);
+					buffer = RlvStrings::getString(RlvStringKeys::Blocked::RecvIm);
 				}
 // [/RLVa:KB]
 
@@ -1112,7 +1112,7 @@ void LLIMProcessing::processNewMessage(LLUUID from_id,
 				{
 					std::string::size_type idxPos = location.find('/');
 					if ( (std::string::npos != idxPos) && (RlvUtil::isNearbyRegion(location.substr(0, idxPos))) )
-						location = RlvStrings::getString(RLV_STRING_HIDDEN_REGION);
+						location = RlvStrings::getString(RlvStringKeys::Hidden::Region);
 				}
 			}
 // [/RLVa:KB]
@@ -1360,7 +1360,7 @@ void LLIMProcessing::processNewMessage(LLUUID from_id,
 					if ( ((IM_LURE_USER == dialog) && (!RlvActions::canAcceptTpOffer(from_id))) ||
 					     ((IM_TELEPORT_REQUEST == dialog) && (!RlvActions::canAcceptTpRequest(from_id))) )
 					{
-						RlvUtil::sendBusyMessage(from_id, RlvStrings::getString(RLV_STRING_BLOCKED_TPLUREREQ_REMOTE));
+						RlvUtil::sendBusyMessage(from_id, RlvStrings::getString(RlvStringKeys::Blocked::TpLureRequestRemote));
 						if (is_do_not_disturb)
 							send_do_not_disturb_message(gMessageSystem, from_id);
 						return;
@@ -1370,7 +1370,7 @@ void LLIMProcessing::processNewMessage(LLUUID from_id,
 					if ( (!RlvActions::canReceiveIM(from_id)) || 
 						 ((gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) && (IM_LURE_USER == dialog || IM_TELEPORT_REQUEST == dialog)) )
 					{
-						message = RlvStrings::getString(RLV_STRING_HIDDEN);
+						message = RlvStrings::getString(RlvStringKeys::Hidden::Generic);
 					}
 				}
 // [/RLVa:KB]
diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp
index 9d4c382d991b24bfd49681eb42392e07f8a8f587..572bb2db3cc3d86270c45c2ff8f3325005261d87 100644
--- a/indra/newview/llimview.cpp
+++ b/indra/newview/llimview.cpp
@@ -3656,7 +3656,7 @@ class LLViewerChatterBoxInvitation : public LLHTTPNode
 				}
 				else if (!RlvActions::canReceiveIM(from_id))			// Conference chat: don't block; censor if not an exception
 				{
-					message = RlvStrings::getString(RLV_STRING_BLOCKED_RECVIM);
+					message = RlvStrings::getString(RlvStringKeys::Blocked::RecvIm);
 				}
 			}
 // [/RLVa:KB]
diff --git a/indra/newview/llinspectremoteobject.cpp b/indra/newview/llinspectremoteobject.cpp
index 0cdafd75fc1805d503252b6016cd180ea41ddf11..da3ed9ebbfdb642b8d7a9ca02e842beaae2961ad 100644
--- a/indra/newview/llinspectremoteobject.cpp
+++ b/indra/newview/llinspectremoteobject.cpp
@@ -190,7 +190,7 @@ void LLInspectRemoteObject::update()
 	getChild<LLUICtrl>("block_btn")->setEnabled(!mObjectID.isNull() && !LLMuteList::getInstance()->isMuted(mObjectID));
 
 // [RLVa:KB] - Checked: 2010-04-22 (RLVa-1.2.0f) | Added: RLVa-1.2.0f
-	if ( (rlv_handler_t::isEnabled()) && (RlvStrings::getString(RLV_STRING_HIDDEN_REGION) == mSLurl) )
+	if ( (rlv_handler_t::isEnabled()) && (RlvStrings::getString(RlvStringKeys::Hidden::Region) == mSLurl) )
 	{
 		getChild<LLUICtrl>("object_slurl")->setValue(mSLurl);
 		getChild<LLUICtrl>("map_btn")->setEnabled(false);
diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp
index 2dc9461a0d722dbe8d85f84012ed84629a0ae1fb..0b6245a8d78cee47d24896e43a94f25ab5e2a1f0 100644
--- a/indra/newview/llinventorybridge.cpp
+++ b/indra/newview/llinventorybridge.cpp
@@ -3786,7 +3786,7 @@ void LLFolderBridge::perform_pasteFromClipboard()
 // [RLVa:KB] - Checked: RLVa-2.1.0
 				if ( ((item) && (!RlvActions::canPasteInventory(item, dest_folder))) || ((cat) && (!RlvActions::canPasteInventory(cat, dest_folder))) )
 				{
-					RlvActions::notifyBlocked(RLV_STRING_BLOCKED_INVFOLDER);
+					RlvActions::notifyBlocked(RlvStringKeys::Blocked::InvFolder);
 					return;
 				}
 // [/RLVa:KB]
@@ -5914,7 +5914,7 @@ void LLCallingCardBridge::performAction(LLInventoryModel* model, std::string act
 			if (!RlvActions::canStartIM(item->getCreatorUUID()))
 			{
 				make_ui_sound("UISndInvalidOp");
-				RlvUtil::notifyBlocked(RLV_STRING_BLOCKED_STARTIM, LLSD().with("RECIPIENT", LLSLURL("agent", item->getCreatorUUID(), "completename").getSLURLString()));
+				RlvUtil::notifyBlocked(RlvStringKeys::Blocked::StartIm, LLSD().with("RECIPIENT", LLSLURL("agent", item->getCreatorUUID(), "completename").getSLURLString()));
 				return;
 			}
 // [/RLVa:KB]
diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp
index 7a5c8148140d95982f0d1cd8515f8bcf8e2ae103..9a4160c690fc7e4199f2843f7a9b95186035874c 100644
--- a/indra/newview/llinventorymodel.cpp
+++ b/indra/newview/llinventorymodel.cpp
@@ -1686,7 +1686,10 @@ void LLInventoryModel::idleNotifyObservers()
 }
 
 // Call this method when it's time to update everyone on a new state.
-void LLInventoryModel::notifyObservers()
+//void LLInventoryModel::notifyObservers()
+// [SL:KB] - Patch: UI-Notifications | Checked: Catznip-6.5
+void LLInventoryModel::notifyObservers(const LLUUID& transaction_id)
+// [/SL:KB]
 {
 	if (mIsNotifyObservers)
 	{
@@ -1698,6 +1701,9 @@ void LLInventoryModel::notifyObservers()
 	}
 
 	mIsNotifyObservers = TRUE;
+// [SL:KB] - Patch: UI-Notifications | Checked: Catznip-6.5
+    mTransactionId = transaction_id;
+// [/SL:KB]
 	for (observer_list_t::iterator iter = mObservers.begin();
 		 iter != mObservers.end(); )
 	{
@@ -1711,6 +1717,9 @@ void LLInventoryModel::notifyObservers()
 	mModifyMask = LLInventoryObserver::NONE;
 	mChangedItemIDs.clear();
 	mAddedItemIDs.clear();
+// [SL:KB] - Patch: UI-Notifications | Checked: Catznip-6.5
+    mTransactionId.setNull();
+// [/SL:KB]
 	mIsNotifyObservers = FALSE;
 }
 
@@ -3372,7 +3381,10 @@ void LLInventoryModel::processBulkUpdateInventory(LLMessageSystem* msg, void**)
 	{
 		gInventory.updateItem(*iit);
 	}
-	gInventory.notifyObservers();
+// [SL:KB] - Patch: UI-Notifications | Checked: Catznip-6.5
+	gInventory.notifyObservers(tid);
+// [/SL:KB]
+//	gInventory.notifyObservers();
 
 	// The incoming inventory could span more than one BulkInventoryUpdate packet,
 	// so record the transaction ID for this purchase, then wear all clothing
diff --git a/indra/newview/llinventorymodel.h b/indra/newview/llinventorymodel.h
index cd2877d6f309a700ad666cdf8ec4f49a85fdcb5d..44c696c4ea5e73d1e6c63d5a6957d562e3090dae 100644
--- a/indra/newview/llinventorymodel.h
+++ b/indra/newview/llinventorymodel.h
@@ -534,7 +534,10 @@ class LLInventoryModel
 	void idleNotifyObservers();
 
 	// Call to explicitly update everyone on a new state.
-	void notifyObservers();
+// [SL:KB] - Patch: UI-Notifications | Checked: Catznip-6.5
+	void notifyObservers(const LLUUID& transaction_id = LLUUID::null);
+// [/SL:KB]
+//	void notifyObservers();
 
 	// Allows outsiders to tell the inventory if something has
 	// been changed 'under the hood', but outside the control of the
@@ -543,6 +546,9 @@ class LLInventoryModel
 	
 	const changed_items_t& getChangedIDs() const { return mChangedItemIDs; }
 	const changed_items_t& getAddedIDs() const { return mAddedItemIDs; }
+// [SL:KB] - Patch: UI-Notifications | Checked: Catznip-6.5
+    const LLUUID& getTransactionId() const { return mTransactionId; }
+// [/SL:KB]
 protected:
 	// Updates all linked items pointing to this id.
 	void addChangedMaskForLinks(const LLUUID& object_id, U32 mask);
@@ -554,6 +560,9 @@ class LLInventoryModel
 	U32 mModifyMask;
 	changed_items_t mChangedItemIDs;
 	changed_items_t mAddedItemIDs;
+// [SL:KB] - Patch: UI-Notifications | Checked: Catznip-6.5
+    LLUUID mTransactionId;
+// [/SL:KB]
 	
 	
 	//--------------------------------------------------------------------
diff --git a/indra/newview/llinventorypanel.cpp b/indra/newview/llinventorypanel.cpp
index e045c67887df9957c155cb278499117ae2ccbad6..42d70154f9c4e2661ce87a14b5d5aec179bdab12 100644
--- a/indra/newview/llinventorypanel.cpp
+++ b/indra/newview/llinventorypanel.cpp
@@ -1370,7 +1370,7 @@ bool LLInventoryPanel::beginIMSession()
 	if (!fRlvCanStartIM)
 	{
 		make_ui_sound("UISndInvalidOp");
-		RlvUtil::notifyBlocked(RLV_STRING_BLOCKED_STARTCONF);
+		RlvUtil::notifyBlocked(RlvStringKeys::Blocked::StartConference);
 		return true;
 	}
 // [/RLVa:KB]
diff --git a/indra/newview/llnetmap.cpp b/indra/newview/llnetmap.cpp
index c59970e7534fd2664597d1e8569d476fa6d1d266..702197bce8438379441ec4e7a64b8967d8f6ebe4 100644
--- a/indra/newview/llnetmap.cpp
+++ b/indra/newview/llnetmap.cpp
@@ -809,7 +809,7 @@ BOOL LLNetMap::handleToolTip( S32 x, S32 y, MASK mask )
 
 //		region_name = region->getName();
 // [RLVa:KB] - Checked: RLVa-1.2.2
-		region_name = (RlvActions::canShowLocation()) ? region->getName() : RlvStrings::getString(RLV_STRING_HIDDEN_REGION);
+		region_name = (RlvActions::canShowLocation()) ? region->getName() : RlvStrings::getString(RlvStringKeys::Hidden::Region);
 // [/RLVa:KB]
 		if (!region_name.empty())
 		{
diff --git a/indra/newview/llpanelpeoplemenus.cpp b/indra/newview/llpanelpeoplemenus.cpp
index 0cab855d14c9d81218c903f77c5715ec4171f036..e72bffa47d67ac75ce08aeafa6af20c909aa87f9 100644
--- a/indra/newview/llpanelpeoplemenus.cpp
+++ b/indra/newview/llpanelpeoplemenus.cpp
@@ -288,6 +288,12 @@ bool PeopleContextMenu::enableContextMenuItem(const LLSD& userdata)
 	{
 		return LLLogChat::isTranscriptExist(mUUIDs.front());
 	}
+// [RLVa:KB] - @pay
+	else if (item == std::string("can_pay"))
+	{
+		return RlvActions::canPayAvatar(mUUIDs.front());
+	}
+// [/RLVa:KB]
 	else if (item == std::string("can_im") || item == std::string("can_invite") ||
 	         item == std::string("can_share") || item == std::string("can_pay"))
 	{
diff --git a/indra/newview/llslurl.cpp b/indra/newview/llslurl.cpp
index c7caa8f0433e33c626cb1f16a7590e1239f92ddb..fbf9dab1ba46159ed4bdb58c4827e1aff3242a7e 100644
--- a/indra/newview/llslurl.cpp
+++ b/indra/newview/llslurl.cpp
@@ -397,7 +397,7 @@ std::string LLSLURL::getSLURLString() const
 // [RLVa:KB] - Checked: 2010-04-05 (RLVa-1.2.0d) | Added: RLVa-1.2.0d
 				return LLGridManager::getInstance()->getSLURLBase(mGrid) +
 					( ((!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) || (!RlvUtil::isNearbyRegion(mRegion)))
-						? (LLURI::escape(mRegion) + llformat("/%d/%d/%d",x,y,z)) : RlvStrings::getString(RLV_STRING_HIDDEN_REGION) );
+						? (LLURI::escape(mRegion) + llformat("/%d/%d/%d",x,y,z)) : RlvStrings::getString(RlvStringKeys::Hidden::Region) );
 // [/RLVa:KB]
 			}
 		case APP:
diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp
index 6ce1871a4af552f8b9e0e68009d4bb4ae3c0e983..13304a1c424fc835dfe2e9ee98d925757f9f9962 100644
--- a/indra/newview/llstartup.cpp
+++ b/indra/newview/llstartup.cpp
@@ -722,7 +722,7 @@ bool idle_startup()
 		}
 
 // [RLVa:KB] - Patch: RLVa-2.1.0
-		if (gSavedSettings.getBOOL(RLV_SETTING_MAIN))
+		if (gSavedSettings.get<bool>(RlvSettingNames::Main))
 		{
 			show_connect_box = TRUE;
 		}
@@ -877,7 +877,7 @@ bool idle_startup()
 		}
 
 // [RLVa:KB] - Checked: RLVa-0.2.1
-		if (gSavedSettings.getBOOL(RLV_SETTING_MAIN))
+		if (gSavedSettings.get<bool>(RlvSettingNames::Main))
 		{
 			RlvHandler::setEnabled(true);
 		}
diff --git a/indra/newview/llteleporthistory.cpp b/indra/newview/llteleporthistory.cpp
index ac7ee401bad3c9ad08b5c3d6d16ac4b3b6aec613..3fadae77173e1bdbb4fdfddd272dd95037087c72 100644
--- a/indra/newview/llteleporthistory.cpp
+++ b/indra/newview/llteleporthistory.cpp
@@ -187,7 +187,7 @@ void LLTeleportHistory::updateCurrentLocation(const LLVector3d& new_pos)
 		}
 		else
 		{
-			mItems[mCurrentItem] = LLTeleportHistoryItem(RlvStrings::getString(RLV_STRING_HIDDEN_PARCEL), LLVector3d::zero);
+			mItems[mCurrentItem] = LLTeleportHistoryItem(RlvStrings::getString(RlvStringKeys::Hidden::Parcel), LLVector3d::zero);
 		}
 // [/RLVa:KB]
 	}
diff --git a/indra/newview/lltoolpie.cpp b/indra/newview/lltoolpie.cpp
index 37813dab3310e4daafc0519bce8c748406d005bb..d5076019757a96d1cd615eaef7c8df9307a459d9 100644
--- a/indra/newview/lltoolpie.cpp
+++ b/indra/newview/lltoolpie.cpp
@@ -294,14 +294,39 @@ BOOL LLToolPie::handleLeftClickPick()
 		}
 // [/RLVa:KB]
 
+// [RLVa:KB] - @buy
+		const std::function<bool(const LLUUID&, U8)> fnRlvCheck = [](const LLUUID& idObj, U8 clickAction) {
+			switch (clickAction)
+			{
+				case CLICK_ACTION_BUY:
+					return RlvActions::canBuyObject(idObj);
+				case CLICK_ACTION_PAY:
+					return RlvActions::canPayObject(idObj);
+				default:
+					return true;
+			}
+		};
+// [/RLVa:KB]
 		mClickAction = 0;
 		if (object && object->getClickAction()) 
 		{
 			mClickAction = object->getClickAction();
+// [RLVa:KB] - @buy
+			if ( (RlvActions::isRlvEnabled()) && (!fnRlvCheck(object->getID(), mClickAction)) )
+			{
+				mClickAction = CLICK_ACTION_NONE;
+			}
+// [/RLVa:KB]
 		}
 		else if (parent && parent->getClickAction()) 
 		{
 			mClickAction = parent->getClickAction();
+// [RLVa:KB] - @buy
+			if ((RlvActions::isRlvEnabled()) && (!fnRlvCheck(parent->getID(), mClickAction)))
+			{
+				mClickAction = CLICK_ACTION_NONE;
+			}
+// [/RLVa:KB]
 		}
 
 		switch(mClickAction)
@@ -541,7 +566,12 @@ ECursorType LLToolPie::cursorFromObject(LLViewerObject* object)
 			LLSelectNode* node = LLSelectMgr::getInstance()->getHoverNode();
 			if (!node || node->mSaleInfo.isForSale())
 			{
-				cursor = UI_CURSOR_TOOLBUY;
+// [RLVa:KB] - @buy
+				cursor = (!object || RlvActions::canBuyObject(parent ? parent->getID() : object->getID()))
+					? UI_CURSOR_TOOLBUY
+					: ((object && object->flagHandleTouch()) || (parent && parent->flagHandleTouch())) ? UI_CURSOR_HAND : UI_CURSOR_ARROW;
+// [/RLVa:KB]
+//				cursor = UI_CURSOR_TOOLBUY;
 			}
 		}
 		break;
@@ -558,7 +588,12 @@ ECursorType LLToolPie::cursorFromObject(LLViewerObject* object)
 			if ((object && object->flagTakesMoney())
 				|| (parent && parent->flagTakesMoney()))
 			{
-				cursor = UI_CURSOR_TOOLBUY;
+// [RLVa:KB] - @buy
+				cursor = ((object && RlvActions::canPayObject(object->getID())) || (parent && RlvActions::canPayObject(parent->getID())))
+					? UI_CURSOR_TOOLBUY
+					: ((object && object->flagHandleTouch()) || (parent && parent->flagHandleTouch())) ? UI_CURSOR_HAND : UI_CURSOR_ARROW;
+// [/RLVa:KB]
+//				cursor = UI_CURSOR_TOOLBUY;
 			}
 		}
 		break;
@@ -809,7 +844,7 @@ BOOL LLToolPie::handleMouseUp(S32 x, S32 y, MASK mask)
 
 		if ( (fValidPick) && (RlvActions::isRlvEnabled()) && (!RlvActions::canTeleportToLocal(mPick.mPosGlobal)) )
 		{
-			RlvUtil::notifyBlocked(RLV_STRING_BLOCKED_AUTOPILOT);
+			RlvUtil::notifyBlocked(RlvStringKeys::Blocked::AutoPilot);
 			fValidPick = false;
 		}
 
@@ -920,7 +955,7 @@ BOOL LLToolPie::handleDoubleClick(S32 x, S32 y, MASK mask)
 
 		if ( (fValidPick) && (RlvActions::isRlvEnabled()) && (!RlvActions::canTeleportToLocal(mPick.mPosGlobal)) )
 		{
-			RlvUtil::notifyBlocked(RLV_STRING_BLOCKED_AUTOPILOT);
+			RlvUtil::notifyBlocked(RlvStringKeys::Blocked::AutoPilot);
 			fValidPick = false;
 		}
 
diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp
index 007fb0e33958d14f542a32bf0a78670194f0cd3a..6fc15c321d1830476da0b434b6308173230e6443 100644
--- a/indra/newview/llviewercontrol.cpp
+++ b/indra/newview/llviewercontrol.cpp
@@ -778,7 +778,7 @@ void settings_setup_listeners()
 	gSavedSettings.getControl("RenderAutoMuteByteLimit")->getSignal()->connect(boost::bind(&handleRenderAutoMuteByteLimitChanged, _2));
 	gSavedPerAccountSettings.getControl("AvatarHoverOffsetZ")->getCommitSignal()->connect(boost::bind(&handleAvatarHoverOffsetChanged, _2));
 // [RLVa:KB] - Checked: 2015-12-27 (RLVa-1.5.0)
-	gSavedSettings.getControl("RestrainedLove")->getSignal()->connect(boost::bind(&RlvSettings::onChangedSettingMain, _2));
+	gSavedSettings.getControl(RlvSettingNames::Main)->getSignal()->connect(boost::bind(&RlvSettings::onChangedSettingMain, _2));
 // [/RLVa:KB]
 }
 
diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp
index 4d192275b4adf0fb69ad08a86f4fc6b46eca9f9e..7c2f51e121103a452987943e2dcbd051079738bc 100644
--- a/indra/newview/llviewermenu.cpp
+++ b/indra/newview/llviewermenu.cpp
@@ -1241,7 +1241,7 @@ class LLAdvancedToggleWireframe : public view_listener_t
 // [RLVa:KB] - Checked: RLVa-2.0.0
 		bool fRlvBlockWireframe = gRlvAttachmentLocks.hasLockedHUD();
 		if ( (!gUseWireframe) && (fRlvBlockWireframe) )
-			RlvUtil::notifyBlocked(RLV_STRING_BLOCKED_WIREFRAME);
+			RlvUtil::notifyBlocked(RlvStringKeys::Blocked::Wireframe);
 		set_use_wireframe( (!gUseWireframe) && (!fRlvBlockWireframe) );
 		return true;
 	}
@@ -3585,6 +3585,11 @@ bool enable_buy_object()
 
 		if( for_sale_selection(node) )
 		{
+// [RLVa:KB] - @buy
+			if (!RlvActions::canBuyObject(obj->getID()))
+				return false;
+// [/RLVa:KB]
+
 			// *NOTE: Is this needed?  This checks to see if anyone owns the
 			// object, dating back to when we had "public" objects owned by
 			// no one.  JC
@@ -5067,6 +5072,11 @@ BOOL is_selection_buy_not_take()
 		LLViewerObject* obj = node->getObject();
 		if(obj && !(obj->permYouOwner()) && (node->mSaleInfo.isForSale()))
 		{
+// [RLVa:KB] - @buy
+			if (!RlvActions::canBuyObject(obj->getID()))
+				continue;
+// [/RLVa:KB]
+
 			// you do not own the object and it is for sale, thus,
 			// it's a buy
 			return TRUE;
@@ -6385,8 +6395,8 @@ bool enable_pay_avatar()
 	LLViewerObject* obj = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject();
 	LLVOAvatar* avatar = find_avatar_from_object(obj);
 //	return (avatar != NULL);
-// [RLVa:KB] - Checked: RLVa-1.2.1
-	return (avatar != NULL) && (RlvActions::canShowName(RlvActions::SNC_DEFAULT, avatar->getID()));
+// [RLVa:KB] - @shownames and @pay
+	return (avatar != NULL) && (RlvActions::canShowName(RlvActions::SNC_DEFAULT, avatar->getID())) && (RlvActions::canPayAvatar(avatar->getID()));
 // [/RLVa:KB]
 }
 
@@ -6398,7 +6408,10 @@ bool enable_pay_object()
 		LLViewerObject *parent = (LLViewerObject *)object->getParent();
 		if((object->flagTakesMoney()) || (parent && parent->flagTakesMoney()))
 		{
-			return true;
+// [RLVa:KB] - @buy
+			return RlvActions::canBuyObject(object->getID());
+// [/RLVa:KB]
+//			return true;
 		}
 	}
 	return false;
diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp
index 26757b3cf29c6473369d86d896a168fb324bc7d0..18d8b238b62159d4bed0748c22aac3d6e3de6802 100644
--- a/indra/newview/llviewermessage.cpp
+++ b/indra/newview/llviewermessage.cpp
@@ -2659,14 +2659,14 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data)
 					(((gRlvHandler.hasBehaviour(RLV_BHVR_RECVCHAT)) && (!gRlvHandler.isException(RLV_BHVR_RECVCHAT, from_id))) ||
 					 ((gRlvHandler.hasBehaviour(RLV_BHVR_RECVCHATFROM)) && (gRlvHandler.isException(RLV_BHVR_RECVCHATFROM, from_id))) ))
 				{
-					if ( (gRlvHandler.filterChat(mesg, false)) && (!gSavedSettings.getBOOL("RestrainedLoveShowEllipsis")) )
+					if ( (gRlvHandler.filterChat(mesg, false)) && (!gSavedSettings.get<bool>(RlvSettingNames::ShowEllipsis)) )
 						return;
 				}
 				else if ((fIsEmote) &&
 					     (((gRlvHandler.hasBehaviour(RLV_BHVR_RECVEMOTE)) && (!gRlvHandler.isException(RLV_BHVR_RECVEMOTE, from_id))) ||
 					      ((gRlvHandler.hasBehaviour(RLV_BHVR_RECVEMOTEFROM)) && (gRlvHandler.isException(RLV_BHVR_RECVEMOTEFROM, from_id))) ))
  				{
-					if (!gSavedSettings.getBOOL("RestrainedLoveShowEllipsis"))
+					if (!gSavedSettings.get<bool>(RlvSettingNames::ShowEllipsis))
 						return;
 					mesg = "/me ...";
 				}
@@ -5823,8 +5823,8 @@ void notify_cautioned_script_question(const LLSD& notification, const LLSD& resp
 // [RLVa:KB] - Checked: 2010-04-23 (RLVa-1.2.0g) | Modified: RLVa-1.0.0a
 		if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC))
 		{
-			notice.setArg("[REGIONNAME]", RlvStrings::getString(RLV_STRING_HIDDEN_REGION));
-			notice.setArg("[REGIONPOS]", RlvStrings::getString(RLV_STRING_HIDDEN));
+			notice.setArg("[REGIONNAME]", RlvStrings::getString(RlvStringKeys::Hidden::Region));
+			notice.setArg("[REGIONPOS]", RlvStrings::getString(RlvStringKeys::Hidden::Generic));
 		}
 		else if (!foundpos)
 // [/RLVa:KB]
@@ -6561,7 +6561,7 @@ void send_lures(const LLSD& notification, const LLSD& response)
 	if ( (gRlvHandler.isEnabled()) && 
 	     (std::any_of(sdRecipients.beginArray(), sdRecipients.endArray(), [](const LLSD& id) { return !RlvActions::canStartIM(id.asUUID()) || !RlvActions::canSendIM(id.asUUID()); })) )
 	{
-		text = RlvStrings::getString(RLV_STRING_HIDDEN);
+		text = RlvStrings::getString(RlvStringKeys::Hidden::Generic);
 	}
 // [/RLVa:KB]
 
@@ -6655,7 +6655,7 @@ void handle_lure(const uuid_vec_t& ids)
 
 	LLSD edit_args;
 // [RLVa:KB] - Checked: 2010-04-07 (RLVa-1.2.0d) | Modified: RLVa-1.0.0a
-	edit_args["REGION"] = (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) ? gAgent.getRegion()->getName() : RlvStrings::getString(RLV_STRING_HIDDEN);
+	edit_args["REGION"] = (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) ? gAgent.getRegion()->getName() : RlvStrings::getString(RlvStringKeys::Hidden::Generic);
 // [/RLVa:KB]
 //	edit_args["REGION"] = gAgent.getRegion()->getName();
 
@@ -6668,10 +6668,10 @@ void handle_lure(const uuid_vec_t& ids)
 		if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC))
 		{
 			const LLRelationship* pBuddyInfo = LLAvatarTracker::instance().getBuddyInfo(idAgent);
-			if ( (!gRlvHandler.isException(RLV_BHVR_TPLURE, idAgent, RLV_CHECK_PERMISSIVE)) &&
+			if ( (!gRlvHandler.isException(RLV_BHVR_TPLURE, idAgent, ERlvExceptionCheck::Permissive)) &&
 				 ((!pBuddyInfo) || (!pBuddyInfo->isOnline()) || (!pBuddyInfo->isRightGrantedTo(LLRelationship::GRANT_MAP_LOCATION))) )
 			{
-				RlvUtil::notifyBlocked(RLV_STRING_BLOCKED_TELEPORT_OFFER);
+				RlvUtil::notifyBlocked(RlvStringKeys::Blocked::TeleportOffer);
 				return;
 			}
 		}
diff --git a/indra/newview/llworldmapview.cpp b/indra/newview/llworldmapview.cpp
index 3149aa266dee9f43f68331f2cdc07bdb65c34eca..4c6a37a46d69ba493176f6ad8440ec5914df7304 100644
--- a/indra/newview/llworldmapview.cpp
+++ b/indra/newview/llworldmapview.cpp
@@ -1084,7 +1084,7 @@ BOOL LLWorldMapView::handleToolTip( S32 x, S32 y, MASK mask )
 
 // [RLVa:KB] - Checked: 2010-04-19 (RLVa-1.4.5) | Modified: RLVa-1.4.5
 		std::string message = llformat("%s (%s)", 
-			(RlvActions::canShowLocation()) ? info->getName().c_str() : RlvStrings::getString(RLV_STRING_HIDDEN_REGION).c_str(), 
+			(RlvActions::canShowLocation()) ? info->getName().c_str() : RlvStrings::getString(RlvStringKeys::Hidden::Region).c_str(),
 			info->getAccessString().c_str());
 // [/RLVa:KB]
 //		std::string message = llformat("%s (%s)", info->getName().c_str(), info->getAccessString().c_str());
diff --git a/indra/newview/rlvactions.cpp b/indra/newview/rlvactions.cpp
index 570b0b4c19306aa5ffff6bb229752e85ddbf1088..130dcc7d71fc4d1d711b5548af87a1ee83167cf1 100644
--- a/indra/newview/rlvactions.cpp
+++ b/indra/newview/rlvactions.cpp
@@ -1,6 +1,6 @@
 /**
  *
- * Copyright (c) 2009-2016, Kitty Barnett
+ * Copyright (c) 2009-2020, Kitty Barnett
  *
  * The source code in this file is provided to you under the terms of the
  * GNU Lesser General Public License, version 2.1, but WITHOUT ANY WARRANTY;
@@ -188,6 +188,15 @@ bool RlvActions::canSendIM(const LLUUID& idRecipient)
 		  ( (!gRlvHandler.hasBehaviour(RLV_BHVR_SENDIMTO)) || (!gRlvHandler.isException(RLV_BHVR_SENDIMTO, idRecipient)) ) );
 }
 
+// Handles: @redirchat
+bool RlvActions::canSendTypingStart()
+{
+	// The CHAT_TYPE_START indicator can be sent if:
+	//   - nearby chat isn't being redirected
+	//   - the user specifically indicated that they want to show typing under @redirchat
+	return !RlvHandler::instance().hasBehaviour(RLV_BHVR_REDIRCHAT) || gSavedSettings.get<bool>(RlvSettingNames::ShowRedirectChatTyping);
+}
+
 bool RlvActions::canStartIM(const LLUUID& idRecipient, bool fIgnoreOpen)
 {
 	// User can start an IM session with "recipient" (could be an agent or a group) if:
@@ -377,6 +386,14 @@ bool RlvActions::canBuild()
 		(!gRlvHandler.hasBehaviour(RLV_BHVR_REZ));
 }
 
+// Handles: @buy
+bool RlvActions::canBuyObject(const LLUUID& idObj)
+{
+	// User can buy an object set for sale if:
+	//    - not restricted from buying objects
+	return (!RlvHandler::instance().hasBehaviour(RLV_BHVR_BUY));
+}
+
 // Handles: @edit and @editobj
 bool RlvActions::canEdit(const LLViewerObject* pObj)
 {
@@ -407,6 +424,22 @@ bool RlvActions::canInteract(const LLViewerObject* pObj, const LLVector3& posOff
 		  ( (!rlvHandler.hasBehaviour(RLV_BHVR_FARTOUCH)) || (pObj->isHUDAttachment()) || (dist_vec_squared(gAgent.getPositionGlobal(), pObj->getPositionGlobal() + LLVector3d(posOffset)) <= s_nFartouchDist * s_nFartouchDist)) );
 }
 
+// Handles: @pay
+bool RlvActions::canPayAvatar(const LLUUID& idAvatar)
+{
+	// User can pay an avatar if:
+	//    - not restricted from paying avatars
+	return (!RlvHandler::instance().hasBehaviour(RLV_BHVR_PAY));
+}
+
+// Handles: @buy
+bool RlvActions::canPayObject(const LLUUID& idObj)
+{
+	// User can pay an object/vendor if:
+	//    - not restricted from buying objects
+	return (!RlvHandler::instance().hasBehaviour(RLV_BHVR_BUY));
+}
+
 bool RlvActions::canRez()
 {
 	return (!gRlvHandler.hasBehaviour(RLV_BHVR_REZ));
@@ -455,7 +488,7 @@ bool RlvActions::canShowHoverText(const LLViewerObject *pObj)
 		  !( (rlvHandler.hasBehaviour(RLV_BHVR_SHOWHOVERTEXTALL)) ||
 		     ( (rlvHandler.hasBehaviour(RLV_BHVR_SHOWHOVERTEXTWORLD)) && (!pObj->isHUDAttachment()) ) ||
 		     ( (rlvHandler.hasBehaviour(RLV_BHVR_SHOWHOVERTEXTHUD)) && (pObj->isHUDAttachment()) ) ||
-		     (rlvHandler.isException(RLV_BHVR_SHOWHOVERTEXT, pObj->getID(), RLV_CHECK_PERMISSIVE)) ) );
+		     (rlvHandler.isException(RLV_BHVR_SHOWHOVERTEXT, pObj->getID(), ERlvExceptionCheck::Permissive)) ) );
 }
 
 // Handles: @touchall, @touchthis, @touchworld, @touchattach, @touchattachself, @touchattachother, @touchhud, @touchme and @fartouch
@@ -502,28 +535,28 @@ bool RlvActions::canTouch(const LLViewerObject* pObj, const LLVector3& posOffset
 	bool fCanTouch =
 		(idRoot.notNull()) &&
 		( (pObj->isHUDAttachment()) || (!rlvHandler.hasBehaviour(RLV_BHVR_TOUCHALL)) ) &&
-		( (!rlvHandler.hasBehaviour(RLV_BHVR_TOUCHTHIS)) || (!rlvHandler.isException(RLV_BHVR_TOUCHTHIS, idRoot, RLV_CHECK_PERMISSIVE)) );
+		( (!rlvHandler.hasBehaviour(RLV_BHVR_TOUCHTHIS)) || (!rlvHandler.isException(RLV_BHVR_TOUCHTHIS, idRoot, ERlvExceptionCheck::Permissive)) );
 	if (fCanTouch)
 	{
 		if ( (!pObj->isAttachment()) || (!pObj->permYouOwner()) )
 		{
 			// Rezzed or attachment worn by other - test for (1.c), (2.d), (2.e) and (1/2.h)
 			fCanTouch =
-				( (!pObj->isAttachment()) ? (!rlvHandler.hasBehaviour(RLV_BHVR_TOUCHWORLD)) || (rlvHandler.isException(RLV_BHVR_TOUCHWORLD, idRoot, RLV_CHECK_PERMISSIVE))
-				                          : ((!rlvHandler.hasBehaviour(RLV_BHVR_TOUCHATTACH)) && (!rlvHandler.hasBehaviour(RLV_BHVR_TOUCHATTACHOTHER))) || (rlvHandler.isException(RLV_BHVR_TOUCHATTACH, idRoot, RLV_CHECK_PERMISSIVE)) ) &&
+				( (!pObj->isAttachment()) ? (!rlvHandler.hasBehaviour(RLV_BHVR_TOUCHWORLD)) || (rlvHandler.isException(RLV_BHVR_TOUCHWORLD, idRoot, ERlvExceptionCheck::Permissive))
+				                          : ((!rlvHandler.hasBehaviour(RLV_BHVR_TOUCHATTACH)) && (!rlvHandler.hasBehaviour(RLV_BHVR_TOUCHATTACHOTHER))) || (rlvHandler.isException(RLV_BHVR_TOUCHATTACH, idRoot, ERlvExceptionCheck::Permissive)) ) &&
 				( (!rlvHandler.hasBehaviour(RLV_BHVR_FARTOUCH)) || (dist_vec_squared(gAgent.getPositionGlobal(), pObj->getPositionGlobal() + LLVector3d(posOffset)) <= s_nFartouchDist * s_nFartouchDist) );
 		}
 		else if (!pObj->isHUDAttachment())
 		{
 			// Regular attachment worn by this avie - test for (3.d), (3.e) and (3.h)
 			fCanTouch =
-				((!rlvHandler.hasBehaviour(RLV_BHVR_TOUCHATTACH)) || (rlvHandler.isException(RLV_BHVR_TOUCHATTACH, idRoot, RLV_CHECK_PERMISSIVE))) &&
-				((!rlvHandler.hasBehaviour(RLV_BHVR_TOUCHATTACHSELF)) || (rlvHandler.isException(RLV_BHVR_TOUCHATTACH, idRoot, RLV_CHECK_PERMISSIVE)));
+				((!rlvHandler.hasBehaviour(RLV_BHVR_TOUCHATTACH)) || (rlvHandler.isException(RLV_BHVR_TOUCHATTACH, idRoot, ERlvExceptionCheck::Permissive))) &&
+				((!rlvHandler.hasBehaviour(RLV_BHVR_TOUCHATTACHSELF)) || (rlvHandler.isException(RLV_BHVR_TOUCHATTACH, idRoot, ERlvExceptionCheck::Permissive)));
 		}
 		else
 		{
 			// HUD attachment - test for (4.g)
-			fCanTouch = (!hasBehaviour(RLV_BHVR_TOUCHHUD)) || (rlvHandler.isException(RLV_BHVR_TOUCHHUD, idRoot, RLV_CHECK_PERMISSIVE));
+			fCanTouch = (!hasBehaviour(RLV_BHVR_TOUCHHUD)) || (rlvHandler.isException(RLV_BHVR_TOUCHHUD, idRoot, ERlvExceptionCheck::Permissive));
 		}
 	}
 	// Post-check for (1/2/3/4i)
@@ -585,7 +618,11 @@ bool RlvActions::isRlvEnabled()
 	return RlvHandler::isEnabled();
 }
 
+#ifdef CATZNIP_STRINGVIEW
+void RlvActions::notifyBlocked(const boost::string_view& strNotifcation, const LLSD& sdArgs)
+#else
 void RlvActions::notifyBlocked(const std::string& strNotifcation, const LLSD& sdArgs)
+#endif // CATZNIP_STRINGVIEW
 {
 	RlvUtil::notifyBlocked(strNotifcation, sdArgs);
 }
diff --git a/indra/newview/rlvactions.h b/indra/newview/rlvactions.h
index be22f4ce6ae20a1b2aa9eb41f0680527b480f608..fb2e14f7aafabff85044fae8f0e84831ff17055e 100644
--- a/indra/newview/rlvactions.h
+++ b/indra/newview/rlvactions.h
@@ -1,6 +1,6 @@
 /**
  *
- * Copyright (c) 2009-2016, Kitty Barnett
+ * Copyright (c) 2009-2020, Kitty Barnett
  *
  * The source code in this file is provided to you under the terms of the
  * GNU Lesser General Public License, version 2.1, but WITHOUT ANY WARRANTY;
@@ -108,6 +108,11 @@ class RlvActions
 	 */
 	static bool canSendIM(const LLUUID& idRecipient);
 
+	/*
+	 * Returns true if the viewer can inform the region about the user's (nearby chat) typing
+	 */
+	static bool canSendTypingStart();
+
 	/*
 	 * Returns true if the user is allowed to start a - P2P or group - conversation with the specified UUID (or if the session already exists, unless 'ignore open' is specified)
 	 */
@@ -233,6 +238,11 @@ class RlvActions
 	 */
 	static bool canBuild();
 
+	/*
+	 * Returns true if the user can buy an object set for sale
+	 */
+	static bool canBuyObject(const LLUUID& idObj);
+
 	/*
 	 * Returns true if the user can edit the specified object (with an optional relative offset)
 	 */
@@ -249,6 +259,16 @@ class RlvActions
 	 */
 	static bool canInteract(const LLViewerObject* pObj, const LLVector3& posOffset = LLVector3::zero);
 
+	/*
+	 * Returns true if the user can pay an avatar
+	 */
+	static bool canPayAvatar(const LLUUID& idAvatar);
+
+	/*
+	 * Returns true if the user can pay an object (i.e. vendor)
+	 */
+	static bool canPayObject(const LLUUID& idObj);
+
 	/*
 	 * Returns true if the user can rez new objects (from inventory or through the create tool)
 	 */
@@ -309,7 +329,11 @@ class RlvActions
 	/*
 	 * Shows one of the blocked toast notifications (see rlva_strings.xml)
 	 */
+#ifdef CATZNIP_STRINGVIEW
+	static void notifyBlocked(const boost::string_view& strNotifcation, const LLSD& sdArgs = LLSD());
+#else
 	static void notifyBlocked(const std::string& strNotifcation, const LLSD& sdArgs = LLSD());
+#endif // CATZNIP_STRINGVIEW
 };
 
 // ============================================================================
diff --git a/indra/newview/rlvcommon.cpp b/indra/newview/rlvcommon.cpp
index 4bd252b6443e52373cbff5d2822cb663770723b2..5d6c7e7ea70e528b8e6dd01c3cb7146a05dd085c 100644
--- a/indra/newview/rlvcommon.cpp
+++ b/indra/newview/rlvcommon.cpp
@@ -1,17 +1,17 @@
-/** 
+/**
  *
- * Copyright (c) 2009-2011, Kitty Barnett
- * 
- * The source code in this file is provided to you under the terms of the 
+ * Copyright (c) 2009-2020, Kitty Barnett
+ *
+ * The source code in this file is provided to you under the terms of the
  * GNU Lesser General Public License, version 2.1, but WITHOUT ANY WARRANTY;
- * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
- * PARTICULAR PURPOSE. Terms of the LGPL can be found in doc/LGPL-licence.txt 
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE. Terms of the LGPL can be found in doc/LGPL-licence.txt
  * in this distribution, or online at http://www.gnu.org/licenses/lgpl-2.1.txt
- * 
+ *
  * By copying, modifying or distributing this software, you acknowledge that
- * you have read and understood your obligations described above, and agree to 
+ * you have read and understood your obligations described above, and agree to
  * abide by those obligations.
- * 
+ *
  */
 
 #include "llviewerprecompiledheaders.h"
@@ -100,9 +100,9 @@ void RlvSettings::initClass()
 	{
 		initCompatibilityMode(LLStringUtil::null);
 
-		s_fTempAttach = rlvGetSetting<bool>(RLV_SETTING_ENABLETEMPATTACH, true);
-		if (gSavedSettings.controlExists(RLV_SETTING_ENABLETEMPATTACH))
-			gSavedSettings.getControl(RLV_SETTING_ENABLETEMPATTACH)->getSignal()->connect(boost::bind(&onChangedSettingBOOL, _2, &s_fTempAttach));
+		s_fTempAttach = rlvGetSetting<bool>(RlvSettingNames::EnableTempAttach, true);
+		if (gSavedSettings.controlExists(RlvSettingNames::EnableTempAttach))
+			gSavedSettings.getControl(RlvSettingNames::EnableTempAttach)->getSignal()->connect(boost::bind(&onChangedSettingBOOL, _2, &s_fTempAttach));
 
 		#ifdef RLV_EXPERIMENTAL_COMPOSITEFOLDERS
 		s_fCompositeFolders = rlvGetSetting<bool>(RLV_SETTING_ENABLECOMPOSITES, false);
@@ -110,19 +110,19 @@ void RlvSettings::initClass()
 			gSavedSettings.getControl(RLV_SETTING_ENABLECOMPOSITES)->getSignal()->connect(boost::bind(&onChangedSettingBOOL, _2, &s_fCompositeFolders));
 		#endif // RLV_EXPERIMENTAL_COMPOSITEFOLDERS
 
-		s_fLegacyNaming = rlvGetSetting<bool>(RLV_SETTING_ENABLELEGACYNAMING, true);
-		if (gSavedSettings.controlExists(RLV_SETTING_ENABLELEGACYNAMING))
-			gSavedSettings.getControl(RLV_SETTING_ENABLELEGACYNAMING)->getSignal()->connect(boost::bind(&onChangedSettingBOOL, _2, &s_fLegacyNaming));
+		s_fLegacyNaming = rlvGetSetting<bool>(RlvSettingNames::EnableLegacyNaming, true);
+		if (gSavedSettings.controlExists(RlvSettingNames::EnableLegacyNaming))
+			gSavedSettings.getControl(RlvSettingNames::EnableLegacyNaming)->getSignal()->connect(boost::bind(&onChangedSettingBOOL, _2, &s_fLegacyNaming));
 
-		s_fCanOOC = rlvGetSetting<bool>(RLV_SETTING_CANOOC, true);
-		s_fNoSetEnv = rlvGetSetting<bool>(RLV_SETTING_NOSETENV, false);
+		s_fCanOOC = rlvGetSetting<bool>(RlvSettingNames::CanOoc, true);
+		s_fNoSetEnv = rlvGetSetting<bool>(RlvSettingNames::NoSetEnv, false);
 
 		// Don't allow toggling RLVaLoginLastLocation from the debug settings floater
-		if (gSavedPerAccountSettings.controlExists(RLV_SETTING_LOGINLASTLOCATION))
-			gSavedPerAccountSettings.getControl(RLV_SETTING_LOGINLASTLOCATION)->setHiddenFromSettingsEditor(true);
+		if (gSavedPerAccountSettings.controlExists(RlvSettingNames::LoginLastLocation))
+			gSavedPerAccountSettings.getControl(RlvSettingNames::LoginLastLocation)->setHiddenFromSettingsEditor(true);
 
-		if (gSavedSettings.controlExists(RLV_SETTING_TOPLEVELMENU))
-			gSavedSettings.getControl(RLV_SETTING_TOPLEVELMENU)->getSignal()->connect(boost::bind(&onChangedMenuLevel));
+		if (gSavedSettings.controlExists(RlvSettingNames::TopLevelMenu))
+			gSavedSettings.getControl(RlvSettingNames::TopLevelMenu)->getSignal()->connect(boost::bind(&onChangedMenuLevel));
 
 		int nMinMaturity = gSavedSettings.getS32("RLVaExperienceMaturityThreshold");
 		s_nExperienceMinMaturity = (nMinMaturity == 0) ? 0 : ((nMinMaturity == 1) ? SIM_ACCESS_PG : ((nMinMaturity == 2) ? SIM_ACCESS_MATURE : SIM_ACCESS_ADULT));
@@ -136,12 +136,12 @@ void RlvSettings::initClass()
 // Checked: 2010-04-01 (RLVa-1.2.0c) | Modified: RLVa-0.2.1d
 void RlvSettings::updateLoginLastLocation()
 {
-	if ( (!LLApp::isQuitting()) && (gSavedPerAccountSettings.controlExists(RLV_SETTING_LOGINLASTLOCATION)) )
+	if ( (!LLApp::isExiting()) && (gSavedPerAccountSettings.controlExists(RlvSettingNames::LoginLastLocation)) )
 	{
-		BOOL fValue = (gRlvHandler.hasBehaviour(RLV_BHVR_TPLOC)) || (!RlvActions::canStand());
-		if (gSavedPerAccountSettings.getBOOL(RLV_SETTING_LOGINLASTLOCATION) != fValue)
+		bool fValue = (gRlvHandler.hasBehaviour(RLV_BHVR_TPLOC)) || (!RlvActions::canStand());
+		if (gSavedPerAccountSettings.get<bool>(RlvSettingNames::LoginLastLocation) != fValue)
 		{
-			gSavedPerAccountSettings.setBOOL(RLV_SETTING_LOGINLASTLOCATION, fValue);
+			gSavedPerAccountSettings.set<bool>(RlvSettingNames::LoginLastLocation, fValue);
 			gSavedPerAccountSettings.saveToFile(gSavedSettings.getString("PerAccountSettingsFile"), TRUE);
 		}
 	}
@@ -360,7 +360,11 @@ const std::string& RlvStrings::getAnonym(const std::string& strName)
 }
 
 // Checked: 2011-11-08 (RLVa-1.5.0)
+#ifdef CATZNIP_STRINGVIEW
+const std::string& RlvStrings::getString(const boost::string_view& strStringName)
+#else
 const std::string& RlvStrings::getString(const std::string& strStringName)
+#endif // CATZNIP_STRINGVIEW
 {
 	static const std::string strMissing = "(Missing RLVa string)";
 	string_map_t::const_iterator itString = m_StringMap.find(strStringName);
@@ -428,7 +432,8 @@ std::string RlvStrings::getVersion(const LLUUID& idRlvObject, bool fLegacy)
 
 std::string RlvStrings::getVersionAbout()
 {
-	return llformat("RLV v%d.%d.%d / RLVa v%d.%d.%d.%d", RLV_VERSION_MAJOR, RLV_VERSION_MINOR, RLV_VERSION_PATCH, RLVa_VERSION_MAJOR, RLVa_VERSION_MINOR, RLVa_VERSION_PATCH, LLVersionInfo::instance().getBuild());
+	return llformat("RLV v%d.%d.%d / RLVa v%d.%d.%d.%d",
+	                RLV_VERSION_MAJOR, RLV_VERSION_MINOR, RLV_VERSION_PATCH, RLVa_VERSION_MAJOR, RLVa_VERSION_MINOR, RLVa_VERSION_PATCH, LLVersionInfo::instance().getBuild());
 }
 
 std::string RlvStrings::getVersionNum(const LLUUID& idRlvObject)
@@ -474,7 +479,7 @@ bool RlvUtil::m_fForceTp = false;
 void RlvUtil::filterLocation(std::string& strUTF8Text)
 {
 	// Filter any mention of the surrounding region names
-	const std::string& strHiddenRegion = RlvStrings::getString(RLV_STRING_HIDDEN_REGION);
+	const std::string& strHiddenRegion = RlvStrings::getString(RlvStringKeys::Hidden::Region);
 	for (LLViewerRegion* pRegion : LLWorld::getInstance()->getRegionList())
 	{
 		boost::ireplace_all(strUTF8Text, pRegion->getName(), strHiddenRegion);
@@ -483,7 +488,7 @@ void RlvUtil::filterLocation(std::string& strUTF8Text)
 	// Filter any mention of the parcel name
 	LLViewerParcelMgr* pParcelMgr = LLViewerParcelMgr::getInstance();
 	if (pParcelMgr)
-		boost::ireplace_all(strUTF8Text, pParcelMgr->getAgentParcelName(), RlvStrings::getString(RLV_STRING_HIDDEN_PARCEL));
+		boost::ireplace_all(strUTF8Text, pParcelMgr->getAgentParcelName(), RlvStrings::getString(RlvStringKeys::Hidden::Parcel));
 }
 
 // Checked: 2010-12-08 (RLVa-1.2.2c) | Modified: RLVa-1.2.2c
@@ -529,7 +534,7 @@ void RlvUtil::filterScriptQuestions(S32& nQuestions, LLSD& sdPayload)
 	if ((!gRlvAttachmentLocks.canAttach()) && (SCRIPT_PERMISSIONS[SCRIPT_PERMISSION_ATTACH].permbit & nQuestions))
 	{
 		// Notify the user that we blocked it since they're not allowed to wear any new attachments
-		sdPayload["rlv_blocked"] = RLV_STRING_BLOCKED_PERMATTACH;
+		sdPayload["rlv_blocked"] = RlvStringKeys::Blocked::PermissionAttach;
 		nQuestions &= ~SCRIPT_PERMISSIONS[SCRIPT_PERMISSION_ATTACH].permbit;
 	}
 
@@ -537,7 +542,7 @@ void RlvUtil::filterScriptQuestions(S32& nQuestions, LLSD& sdPayload)
 	if ((gRlvHandler.hasBehaviour(RLV_BHVR_TPLOC)) && (SCRIPT_PERMISSIONS[SCRIPT_PERMISSION_TELEPORT].permbit & nQuestions))
 	{
 		// Notify the user that we blocked it since they're not allowed to teleport
-		sdPayload["rlv_blocked"] = RLV_STRING_BLOCKED_PERMTELEPORT;
+		sdPayload["rlv_blocked"] = RlvStringKeys::Blocked::PermissionTeleport;
 		nQuestions &= ~SCRIPT_PERMISSIONS[SCRIPT_PERMISSION_TELEPORT].permbit;
 	}
 
@@ -579,7 +584,11 @@ bool RlvUtil::isNearbyRegion(const std::string& strRegion)
 }
 
 // Checked: 2011-04-11 (RLVa-1.3.0h) | Modified: RLVa-1.3.0h
+#ifdef CATZNIP_STRINGVIEW
+void RlvUtil::notifyBlocked(const boost::string_view& strNotifcation, const LLSD& sdArgs, bool fLogToChat)
+#else
 void RlvUtil::notifyBlocked(const std::string& strNotifcation, const LLSD& sdArgs, bool fLogToChat)
+#endif // CATZNIP_STRINGVIEW
 {
 	std::string strMsg = RlvStrings::getString(strNotifcation);
 	LLStringUtil::format(strMsg, sdArgs);
@@ -598,7 +607,7 @@ void RlvUtil::notifyFailedAssertion(const std::string& strAssert, const std::str
 	// Don't show the same assertion over and over, or if the user opted out
 	static std::string strAssertPrev, strFilePrev; static int nLinePrev;
 	if ( ((strAssertPrev == strAssert) && (strFile == strFilePrev) && (nLine == nLinePrev)) ||
-		 (!rlvGetSetting<bool>(RLV_SETTING_SHOWASSERTIONFAIL, true)) )
+		 (!rlvGetSetting<bool>(RlvSettingNames::ShowAssertionFail, true)) )
 	{
 		return;
 	}
@@ -696,7 +705,7 @@ bool rlvMenuMainToggleVisible(LLUICtrl* pMenuCtrl)
 	if (pMenuItem)
 	{
 		static std::string strLabel = pMenuItem->getLabel();
-		if ((bool)gSavedSettings.getBOOL(RLV_SETTING_MAIN) == rlv_handler_t::isEnabled())
+		if ((bool)gSavedSettings.get<bool>(RlvSettingNames::Main) == rlv_handler_t::isEnabled())
 			pMenuItem->setLabel(strLabel);
 		else
 			pMenuItem->setLabel(strLabel + " " + LLTrans::getString("RLVaPendingRestart"));
@@ -707,7 +716,7 @@ bool rlvMenuMainToggleVisible(LLUICtrl* pMenuCtrl)
 // Checked: 2011-08-16 (RLVa-1.4.0b) | Added: RLVa-1.4.0b
 void rlvMenuToggleVisible()
 {
-	bool fTopLevel = rlvGetSetting(RLV_SETTING_TOPLEVELMENU, true);
+	bool fTopLevel = rlvGetSetting(RlvSettingNames::TopLevelMenu, true);
 	bool fRlvEnabled = rlv_handler_t::isEnabled();
 
 	LLMenuGL* pRLVaMenuMain = gMenuBarView->findChildMenuByName("RLVa Main", FALSE);
diff --git a/indra/newview/rlvcommon.h b/indra/newview/rlvcommon.h
index 82fca44f91b6772692f6708f4ee3a20e9d3a831d..216b5320d37c57a8534ab061536fc129c9a8931b 100644
--- a/indra/newview/rlvcommon.h
+++ b/indra/newview/rlvcommon.h
@@ -1,21 +1,20 @@
-/** 
+/**
  *
- * Copyright (c) 2009-2011, Kitty Barnett
- * 
- * The source code in this file is provided to you under the terms of the 
+ * Copyright (c) 2009-2020, Kitty Barnett
+ *
+ * The source code in this file is provided to you under the terms of the
  * GNU Lesser General Public License, version 2.1, but WITHOUT ANY WARRANTY;
- * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
- * PARTICULAR PURPOSE. Terms of the LGPL can be found in doc/LGPL-licence.txt 
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE. Terms of the LGPL can be found in doc/LGPL-licence.txt
  * in this distribution, or online at http://www.gnu.org/licenses/lgpl-2.1.txt
- * 
+ *
  * By copying, modifying or distributing this software, you acknowledge that
- * you have read and understood your obligations described above, and agree to 
+ * you have read and understood your obligations described above, and agree to
  * abide by those obligations.
- * 
+ *
  */
 
-#ifndef RLV_COMMON_H
-#define RLV_COMMON_H
+#pragma once
 
 #include "llavatarname.h"
 #include "llselectmgr.h"
@@ -64,13 +63,21 @@ class RlvGCTimer;
 // RlvSettings
 //
 
+#ifdef CATZNIP_STRINGVIEW
+template<typename T> inline T rlvGetSetting(const boost::string_view& strSetting, const T& defaultValue)
+#else
 template<typename T> inline T rlvGetSetting(const std::string& strSetting, const T& defaultValue)
+#endif // CATZNIP_STRINGVIEW
 {
 	RLV_ASSERT_DBG(gSavedSettings.controlExists(strSetting));
 	return (gSavedSettings.controlExists(strSetting)) ? gSavedSettings.get<T>(strSetting) : defaultValue;
 }
 
+#ifdef CATZNIP_STRINGVIEW
+template<typename T> inline T rlvGetPerUserSetting(const boost::string_view& strSetting, const T& defaultValue)
+#else
 template<typename T> inline T rlvGetPerUserSetting(const std::string& strSetting, const T& defaultValue)
+#endif // CATZNIP_STRINGVIEW
 {
 	RLV_ASSERT_DBG(gSavedPerAccountSettings.controlExists(strSetting));
 	return (gSavedPerAccountSettings.controlExists(strSetting)) ? gSavedPerAccountSettings.get<T>(strSetting) : defaultValue;
@@ -79,29 +86,29 @@ template<typename T> inline T rlvGetPerUserSetting(const std::string& strSetting
 class RlvSettings
 {
 public:
-	static bool getDebug()						{ return rlvGetSetting<bool>(RLV_SETTING_DEBUG, false); }
+	static bool getDebug()						{ return rlvGetSetting<bool>(RlvSettingNames::Debug, false); }
 	static bool getCanOOC()						{ return s_fCanOOC; }
-	static bool getForbidGiveToRLV()			{ return rlvGetSetting<bool>(RLV_SETTING_FORBIDGIVETORLV, true); }
+	static bool getForbidGiveToRLV()			{ return rlvGetSetting<bool>(RlvSettingNames::ForbidGiveToRlv, true); }
 	static bool getNoSetEnv()					{ return s_fNoSetEnv; }
 
-	static std::string getWearAddPrefix()		{ return rlvGetSetting<std::string>(RLV_SETTING_WEARADDPREFIX, LLStringUtil::null); }
-	static std::string getWearReplacePrefix()	{ return rlvGetSetting<std::string>(RLV_SETTING_WEARREPLACEPREFIX, LLStringUtil::null); }
+	static std::string getWearAddPrefix()		{ return rlvGetSetting<std::string>(RlvSettingNames::WearAddPrefix, LLStringUtil::null); }
+	static std::string getWearReplacePrefix()	{ return rlvGetSetting<std::string>(RlvSettingNames::WearReplacePrefix, LLStringUtil::null); }
 
-	static bool getDebugHideUnsetDup()			{ return rlvGetSetting<bool>(RLV_SETTING_DEBUGHIDEUNSETDUP, false); }
+	static bool getDebugHideUnsetDup()			{ return rlvGetSetting<bool>(RlvSettingNames::DebugHideUnsetDup, false); }
 	#ifdef RLV_EXPERIMENTAL_COMPOSITEFOLDERS
 	static BOOL getEnableComposites()			{ return s_fCompositeFolders; }
 	#endif // RLV_EXPERIMENTAL_COMPOSITEFOLDERS
-	static bool getEnableIMQuery()              { return rlvGetSetting<bool>("RLVaEnableIMQuery", true); }
+	static bool getEnableIMQuery()              { return rlvGetSetting<bool>(RlvSettingNames::EnableIMQuery, true); }
 	static bool getEnableLegacyNaming()			{ return s_fLegacyNaming; }
-	static bool getEnableSharedWear()			{ return rlvGetSetting<bool>(RLV_SETTING_ENABLESHAREDWEAR, false); }
+	static bool getEnableSharedWear()			{ return rlvGetSetting<bool>(RlvSettingNames::EnableSharedWear, false); }
 	static bool getEnableTemporaryAttachments() { return s_fTempAttach; }
-	static bool getHideLockedLayers()			{ return rlvGetSetting<bool>(RLV_SETTING_HIDELOCKEDLAYER, false); }
-	static bool getHideLockedAttach()			{ return rlvGetSetting<bool>(RLV_SETTING_HIDELOCKEDATTACH, false); }
-	static bool getHideLockedInventory()		{ return rlvGetSetting<bool>(RLV_SETTING_HIDELOCKEDINVENTORY, false); }
-	static bool getSharedInvAutoRename()		{ return rlvGetSetting<bool>(RLV_SETTING_SHAREDINVAUTORENAME, true); }
-	static bool getSplitRedirectChat()          { return rlvGetSetting<bool>(RLV_SETTING_SPLITREDIRECTCHAT, false); }
+	static bool getHideLockedLayers()			{ return rlvGetSetting<bool>(RlvSettingNames::HideLockedLayer, false); }
+	static bool getHideLockedAttach()			{ return rlvGetSetting<bool>(RlvSettingNames::HideLockedAttach, false); }
+	static bool getHideLockedInventory()		{ return rlvGetSetting<bool>(RlvSettingNames::HideLockedInventory, false); }
+	static bool getSharedInvAutoRename()		{ return rlvGetSetting<bool>(RlvSettingNames::SharedInvAutoRename, true); }
+	static bool getSplitRedirectChat()          { return rlvGetSetting<bool>(RlvSettingNames::SplitRedirectChat, false); }
 
-	static bool getLoginLastLocation()			{ return rlvGetPerUserSetting<bool>(RLV_SETTING_LOGINLASTLOCATION, true); }
+	static bool getLoginLastLocation()			{ return rlvGetPerUserSetting<bool>(RlvSettingNames::LoginLastLocation, true); }
 	static void updateLoginLastLocation();
 
 	static void initCompatibilityMode(std::string strCompatList);
@@ -146,7 +153,11 @@ class RlvStrings
 
 	static const std::string& getAnonym(const LLAvatarName& avName);		// @shownames
 	static const std::string& getAnonym(const std::string& strName);		// @shownames
+#ifdef CATZNIP_STRINGVIEW
+	static const std::string& getString(const boost::string_view& strStringName);
+#else
 	static const std::string& getString(const std::string& strStringName);
+#endif // CATZNIP_STRINGVIEW
 	static const char*        getStringFromReturnCode(ERlvCmdRet eRet);
 	static const std::string& getStringMapPath() { return m_StringMapPath; }
 	static std::string        getVersion(const LLUUID& idRlvObject, bool fLegacy = false);
@@ -158,7 +169,7 @@ class RlvStrings
 
 protected:
 	static std::vector<std::string> m_Anonyms;
-	typedef std::map<std::string, std::list<std::string> > string_map_t;
+	typedef std::map<std::string, std::list<std::string>, std::less<>> string_map_t;
 	static string_map_t m_StringMap;
 	static std::string  m_StringMapPath;
 };
@@ -181,9 +192,14 @@ class RlvUtil
 	static bool isForceTp()	{ return m_fForceTp; }
 	static void forceTp(const LLVector3d& posDest);									// Ignores restrictions that might otherwise prevent tp'ing
 
+#ifdef CATZNIP_STRINGVIEW
+	static void notifyBlocked(const std::string& strNotifcation, const LLSD& sdArgs = LLSD(), bool fLogToChat = false) { notifyBlocked(boost::string_view(strNotifcation), sdArgs, fLogToChat); }
+	static void notifyBlocked(const boost::string_view& strNotifcation, const LLSD& sdArgs = LLSD(), bool fLogToChat = false);
+#else
 	static void notifyBlocked(const std::string& strNotifcation, const LLSD& sdArgs = LLSD(), bool fLogToChat = false);
-	static void notifyBlockedGeneric()	{ notifyBlocked(RLV_STRING_BLOCKED_GENERIC); }
-	static void notifyBlockedViewXXX(LLAssetType::EType assetType) { notifyBlocked(RLV_STRING_BLOCKED_VIEWXXX, LLSD().with("[TYPE]", LLAssetType::lookup(assetType))); }
+#endif // CATZNIP_STRINGVIEW
+	static void notifyBlockedGeneric() { notifyBlocked(RlvStringKeys::Blocked::Generic); }
+	static void notifyBlockedViewXXX(LLAssetType::EType assetType) { notifyBlocked(RlvStringKeys::Blocked::ViewXxx, LLSD().with("[TYPE]", LLAssetType::lookup(assetType))); }
 	static void notifyFailedAssertion(const std::string& strAssert, const std::string& strFile, int nLine);
 
 	static void sendBusyMessage(const LLUUID& idTo, const std::string& strMsg, const LLUUID& idSession = LLUUID::null);
@@ -332,5 +348,3 @@ inline bool RlvUtil::sendChatReply(const std::string& strChannel, const std::str
 }
 
 // ============================================================================
-
-#endif // RLV_COMMON_H
diff --git a/indra/newview/rlvdefines.h b/indra/newview/rlvdefines.h
index a3938876a00319e428565109050ea56bbe13322c..ca3180d5c18ccad603422bcf7ac4e4016a44a27e 100644
--- a/indra/newview/rlvdefines.h
+++ b/indra/newview/rlvdefines.h
@@ -1,6 +1,6 @@
 /**
  *
- * Copyright (c) 2009-2016, Kitty Barnett
+ * Copyright (c) 2009-2020, Kitty Barnett
  *
  * The source code in this file is provided to you under the terms of the
  * GNU Lesser General Public License, version 2.1, but WITHOUT ANY WARRANTY;
@@ -14,8 +14,11 @@
  *
  */
 
-#ifndef RLV_DEFINES_H
-#define RLV_DEFINES_H
+#pragma once
+
+#ifdef CATZNIP_STRINGVIEW
+#include "llstringview.h"
+#endif // CATZNIP_STRINGVIE
 
 // ============================================================================
 // Defines
@@ -151,8 +154,10 @@ enum ERlvBehaviour {
 	RLV_BHVR_ACCEPTTP,				// "accepttp"
 	RLV_BHVR_ACCEPTTPREQUEST,		// "accepttprequest"
 	RLV_BHVR_ALLOWIDLE,				// "allowidle"
+	RLV_BHVR_BUY,					// "buy"
 	RLV_BHVR_EDIT,					// "edit"
 	RLV_BHVR_EDITOBJ,				// "editobj"
+	RLV_BHVR_PAY,					// "pay"
 	RLV_BHVR_REZ,					// "rez"
 	RLV_BHVR_FARTOUCH,				// "fartouch"
 	RLV_BHVR_INTERACT,				// "interact"
@@ -324,11 +329,11 @@ enum ERlvCmdRet {
 };
 #define RLV_RET_SUCCEEDED(eCmdRet)  (((eCmdRet) & RLV_RET_SUCCESS) == RLV_RET_SUCCESS)
 
-enum ERlvExceptionCheck
+enum class ERlvExceptionCheck
 {
-	RLV_CHECK_PERMISSIVE,			// Exception can be set by any object
-	RLV_CHECK_STRICT,				// Exception must be set by all objects holding the restriction
-	RLV_CHECK_DEFAULT				// Permissive or strict will be determined by currently enforced restrictions
+	Permissive,						// Exception can be set by any object
+	Strict,							// Exception must be set by all objects holding the restriction
+	Default,						// Permissive or strict will be determined by currently enforced restrictions
 };
 
 enum ERlvLockMask
@@ -362,61 +367,131 @@ enum ERlvAttachGroupType
 // Settings
 //
 
-#define RLV_SETTING_MAIN				"RestrainedLove"
-#define RLV_SETTING_DEBUG				"RestrainedLoveDebug"
-#define RLV_SETTING_CANOOC				"RestrainedLoveCanOOC"
-#define RLV_SETTING_FORBIDGIVETORLV		"RestrainedLoveForbidGiveToRLV"
-#define RLV_SETTING_NOSETENV			"RestrainedLoveNoSetEnv"
-#define RLV_SETTING_SHOWELLIPSIS		"RestrainedLoveShowEllipsis"
-#define RLV_SETTING_WEARADDPREFIX       "RestrainedLoveStackWhenFolderBeginsWith"
-#define RLV_SETTING_WEARREPLACEPREFIX   "RestrainedLoveReplaceWhenFolderBeginsWith"
-
-#define RLV_SETTING_DEBUGHIDEUNSETDUP   "RLVaDebugHideUnsetDuplicate"
-#define RLV_SETTING_ENABLECOMPOSITES	"RLVaEnableCompositeFolders"
-#define RLV_SETTING_ENABLELEGACYNAMING	"RLVaEnableLegacyNaming"
-#define RLV_SETTING_ENABLESHAREDWEAR	"RLVaEnableSharedWear"
-#define RLV_SETTING_ENABLETEMPATTACH    "RLVaEnableTemporaryAttachments"
-#define RLV_SETTING_HIDELOCKEDLAYER		"RLVaHideLockedLayers"
-#define RLV_SETTING_HIDELOCKEDATTACH	"RLVaHideLockedAttachments"
-#define RLV_SETTING_HIDELOCKEDINVENTORY	"RLVaHideLockedInventory"
-#define RLV_SETTING_LOGINLASTLOCATION	"RLVaLoginLastLocation"
-#define RLV_SETTING_SHAREDINVAUTORENAME	"RLVaSharedInvAutoRename"
-#define RLV_SETTING_SHOWASSERTIONFAIL	"RLVaShowAssertionFailures"
-#define RLV_SETTING_SPLITREDIRECTCHAT   "RLVaSplitRedirectChat"
-#define RLV_SETTING_TOPLEVELMENU		"RLVaTopLevelMenu"
-#define RLV_SETTING_WEARREPLACEUNLOCKED	"RLVaWearReplaceUnlocked"
-
-#define RLV_SETTING_FIRSTUSE_PREFIX		"FirstRLV"
-#define RLV_SETTING_FIRSTUSE_GIVETORLV	RLV_SETTING_FIRSTUSE_PREFIX"GiveToRLV"
+namespace RlvSettingNames
+{
+#ifdef CATZNIP_STRINGVIEW
+	/*inline*/ constexpr boost::string_view Main = make_string_view("RestrainedLove");
+	/*inline*/ constexpr boost::string_view Debug = make_string_view("RestrainedLoveDebug");
+	/*inline*/ constexpr boost::string_view CanOoc = make_string_view("RestrainedLoveCanOOC");
+	/*inline*/ constexpr boost::string_view ForbidGiveToRlv = make_string_view("RestrainedLoveForbidGiveToRLV");
+	/*inline*/ constexpr boost::string_view NoSetEnv = make_string_view("RestrainedLoveNoSetEnv");
+	/*inline*/ constexpr boost::string_view ShowEllipsis = make_string_view("RestrainedLoveShowEllipsis");
+	/*inline*/ constexpr boost::string_view WearAddPrefix = make_string_view("RestrainedLoveStackWhenFolderBeginsWith");
+	/*inline*/ constexpr boost::string_view WearReplacePrefix = make_string_view("RestrainedLoveReplaceWhenFolderBeginsWith");
+
+	/*inline*/ constexpr boost::string_view DebugHideUnsetDup = make_string_view("RLVaDebugHideUnsetDuplicate");
+	/*inline*/ constexpr boost::string_view EnableIMQuery = make_string_view("RLVaEnableIMQuery");
+	/*inline*/ constexpr boost::string_view EnableLegacyNaming = make_string_view("RLVaEnableLegacyNaming");
+	/*inline*/ constexpr boost::string_view EnableSharedWear = make_string_view("RLVaEnableSharedWear");
+	/*inline*/ constexpr boost::string_view EnableTempAttach = make_string_view("RLVaEnableTemporaryAttachments");
+	/*inline*/ constexpr boost::string_view HideLockedLayer = make_string_view("RLVaHideLockedLayers");
+	/*inline*/ constexpr boost::string_view HideLockedAttach = make_string_view("RLVaHideLockedAttachments");
+	/*inline*/ constexpr boost::string_view HideLockedInventory = make_string_view("RLVaHideLockedInventory");
+	/*inline*/ constexpr boost::string_view LoginLastLocation = make_string_view("RLVaLoginLastLocation");
+	/*inline*/ constexpr boost::string_view SharedInvAutoRename = make_string_view("RLVaSharedInvAutoRename");
+	/*inline*/ constexpr boost::string_view ShowAssertionFail = make_string_view("RLVaShowAssertionFailures");
+	/*inline*/ constexpr boost::string_view ShowRedirectChatTyping = make_string_view("RLVaShowRedirectChatTyping");
+	/*inline*/ constexpr boost::string_view SplitRedirectChat = make_string_view("RLVaSplitRedirectChat");
+	/*inline*/ constexpr boost::string_view TopLevelMenu = make_string_view("RLVaTopLevelMenu");
+	/*inline*/ constexpr boost::string_view WearReplaceUnlocked = make_string_view("RLVaWearReplaceUnlocked");
+#else
+	constexpr const char Main[] = "RestrainedLove";
+	constexpr const char Debug[] = "RestrainedLoveDebug";
+	constexpr const char CanOoc[] = "RestrainedLoveCanOOC";
+	constexpr const char ForbidGiveToRlv[] = "RestrainedLoveForbidGiveToRLV";
+	constexpr const char NoSetEnv[] = "RestrainedLoveNoSetEnv";
+	constexpr const char ShowEllipsis[] = "RestrainedLoveShowEllipsis";
+	constexpr const char WearAddPrefix[] = "RestrainedLoveStackWhenFolderBeginsWith";
+	constexpr const char WearReplacePrefix[] = "RestrainedLoveReplaceWhenFolderBeginsWith";
+
+	constexpr const char DebugHideUnsetDup[] = "RLVaDebugHideUnsetDuplicate";
+	constexpr const char EnableIMQuery[] = "RLVaEnableIMQuery";
+	constexpr const char EnableLegacyNaming[] = "RLVaEnableLegacyNaming";
+	constexpr const char EnableSharedWear[] = "RLVaEnableSharedWear";
+	constexpr const char EnableTempAttach[] = "RLVaEnableTemporaryAttachments";
+	constexpr const char HideLockedLayer[] = "RLVaHideLockedLayers";
+	constexpr const char HideLockedAttach[] = "RLVaHideLockedAttachments";
+	constexpr const char HideLockedInventory[] = "RLVaHideLockedInventory";
+	constexpr const char LoginLastLocation[] = "RLVaLoginLastLocation";
+	constexpr const char SharedInvAutoRename[] = "RLVaSharedInvAutoRename";
+	constexpr const char ShowAssertionFail[] = "RLVaShowAssertionFailures";
+	constexpr const char ShowRedirectChatTyping[] = "RLVaShowRedirectChatTyping";
+	constexpr const char SplitRedirectChat[] = "RLVaSplitRedirectChat";
+	constexpr const char TopLevelMenu[] = "RLVaTopLevelMenu";
+	constexpr const char WearReplaceUnlocked[] = "RLVaWearReplaceUnlocked";
+#endif // CATZNIP_STRINGVIEW
+}
 
 // ============================================================================
 // Strings (see rlva_strings.xml)
 //
 
-#define RLV_STRING_HIDDEN					"hidden_generic"
-#define RLV_STRING_HIDDEN_PARCEL			"hidden_parcel"
-#define RLV_STRING_HIDDEN_REGION			"hidden_region"
-
-#define RLV_STRING_BLOCKED_AUTOPILOT		"blocked_autopilot"
-#define RLV_STRING_BLOCKED_GENERIC			"blocked_generic"
-#define RLV_STRING_BLOCKED_GROUPCHANGE		"blocked_groupchange"
-#define RLV_STRING_BLOCKED_INVFOLDER		"blocked_invfolder"
-#define RLV_STRING_BLOCKED_PERMATTACH		"blocked_permattach"
-#define RLV_STRING_BLOCKED_PERMTELEPORT		"blocked_permteleport"
-#define RLV_STRING_BLOCKED_RECVIM			"blocked_recvim"
-#define RLV_STRING_BLOCKED_RECVIM_REMOTE	"blocked_recvim_remote"
-#define RLV_STRING_BLOCKED_SENDIM			"blocked_sendim"
-#define RLV_STRING_BLOCKED_STARTCONF		"blocked_startconf"
-#define RLV_STRING_BLOCKED_STARTIM			"blocked_startim"
-#define RLV_STRING_BLOCKED_TELEPORT			"blocked_teleport"
-#define RLV_STRING_BLOCKED_TELEPORT_OFFER   "blocked_teleport_offer"
-#define RLV_STRING_BLOCKED_TPLUREREQ_REMOTE	"blocked_tplurerequest_remote"
-#define RLV_STRING_BLOCKED_VIEWXXX			"blocked_viewxxx"
-#define RLV_STRING_BLOCKED_WIREFRAME		"blocked_wireframe"
-#define RLV_STRING_STOPIM_NOSESSION         "stopim_nosession"
-#define RLV_STRING_STOPIM_ENDSESSION_REMOTE "stopim_endsession_remote"
-#define RLV_STRING_STOPIM_ENDSESSION_LOCAL  "stopim_endsession_local"
+namespace RlvStringKeys
+{
+	namespace Blocked
+	{
+#ifdef CATZNIP_STRINGVIEW
+		/*inline*/ constexpr boost::string_view AutoPilot = make_string_view("blocked_autopilot");
+		/*inline*/ constexpr boost::string_view Generic = make_string_view("blocked_generic");
+		/*inline*/ constexpr boost::string_view GroupChange = make_string_view("blocked_groupchange");
+		/*inline*/ constexpr boost::string_view InvFolder = make_string_view("blocked_invfolder");
+		/*inline*/ constexpr boost::string_view PermissionAttach = make_string_view("blocked_permattach");
+		/*inline*/ constexpr boost::string_view PermissionTeleport = make_string_view("blocked_permteleport");
+		/*inline*/ constexpr boost::string_view RecvIm = make_string_view("blocked_recvim");
+		/*inline*/ constexpr boost::string_view RecvImRemote = make_string_view("blocked_recvim_remote");
+		/*inline*/ constexpr boost::string_view SendIm = make_string_view("blocked_sendim");
+		/*inline*/ constexpr boost::string_view StartConference = make_string_view("blocked_startconf");
+		/*inline*/ constexpr boost::string_view StartIm = make_string_view("blocked_startim");
+		/*inline*/ constexpr boost::string_view Teleport = make_string_view("blocked_teleport");
+		/*inline*/ constexpr boost::string_view TeleportOffer = make_string_view("blocked_teleport_offer");
+		/*inline*/ constexpr boost::string_view TpLureRequestRemote = make_string_view("blocked_tplurerequest_remote");
+		/*inline*/ constexpr boost::string_view ViewXxx = make_string_view("blocked_viewxxx");
+		/*inline*/ constexpr boost::string_view Wireframe = make_string_view("blocked_wireframe");
+#else
+		constexpr const char AutoPilot[] = "blocked_autopilot";
+		constexpr const char Generic[] = "blocked_generic";
+		constexpr const char GroupChange[] = "blocked_groupchange";
+		constexpr const char InvFolder[] = "blocked_invfolder";
+		constexpr const char PermissionAttach[] = "blocked_permattach";
+		constexpr const char PermissionTeleport[] = "blocked_permteleport";
+		constexpr const char RecvIm[] = "blocked_recvim";
+		constexpr const char RecvImRemote[] = "blocked_recvim_remote";
+		constexpr const char SendIm[] = "blocked_sendim";
+		constexpr const char StartConference[] = "blocked_startconf";
+		constexpr const char StartIm[] = "blocked_startim";
+		constexpr const char Teleport[] = "blocked_teleport";
+		constexpr const char TeleportOffer[] = "blocked_teleport_offer";
+		constexpr const char TpLureRequestRemote[] = "blocked_tplurerequest_remote";
+		constexpr const char ViewXxx[] = "blocked_viewxxx";
+		constexpr const char Wireframe[] = "blocked_wireframe";
+#endif // CATZNIP_STRINGVIEW
+	}
+
+	namespace Hidden
+	{
+#ifdef CATZNIP_STRINGVIEW
+		/*inline*/ constexpr boost::string_view Generic = make_string_view("hidden_generic");
+		/*inline*/ constexpr boost::string_view Parcel = make_string_view("hidden_parcel");
+		/*inline*/ constexpr boost::string_view Region = make_string_view("hidden_region");
+#else
+		constexpr const char Generic[] = "hidden_generic";
+		constexpr const char Parcel[] = "hidden_parcel";
+		constexpr const char Region[] = "hidden_region";
+#endif // CATZNIP_STRINGVIEW
+	}
+
+	namespace StopIm
+	{
+#ifdef CATZNIP_STRINGVIEW
+		/*inline*/ constexpr boost::string_view NoSession = make_string_view("stopim_nosession");
+		/*inline*/ constexpr boost::string_view EndSessionRemote = make_string_view("stopim_endsession_remote");
+		/*inline*/ constexpr boost::string_view EndSessionLocal = make_string_view("stopim_endsession_local");
+#else
+		constexpr const char NoSession[] = "stopim_nosession";
+		constexpr const char EndSessionRemote[] = "stopim_endsession_remote";
+		constexpr const char EndSessionLocal[] = "stopim_endsession_local";
+#endif // CATZNIP_STRINGVIEW
+	}
+}
 
 // ============================================================================
-
-#endif // RLV_DEFINES_H
diff --git a/indra/newview/rlvenvironment.cpp b/indra/newview/rlvenvironment.cpp
index 970514ee46c1040036ac7f137bd4c9c234841937..91e043da231ac574c241afe5f7a9cfe4bcb989da 100644
--- a/indra/newview/rlvenvironment.cpp
+++ b/indra/newview/rlvenvironment.cpp
@@ -558,15 +558,15 @@ ERlvCmdRet RlvEnvironment::handleSetFn(const std::string& strRlvOption, const st
 }
 
 template<>
-std::string RlvEnvironment::handleLegacyGetFn<LLVector2>(const std::function<LLVector2(LLSettingsSkyPtr_t)>& getFn, U32 idxComponent)
+std::string RlvEnvironment::handleLegacyGetFn<LLVector2>(const std::function<const LLVector2 (LLSettingsSkyPtr_t)>& getFn, U32 idxComponent)
 {
-	if (idxComponent > 2)
+	if (idxComponent >= 2)
 		return LLStringUtil::null;
 	return std::to_string(getFn(LLEnvironment::instance().getCurrentSky()).mV[idxComponent]);
 }
 
 template<>
-std::string RlvEnvironment::handleLegacyGetFn<LLColor3>(const std::function<LLColor3(LLSettingsSkyPtr_t)>& getFn, U32 idxComponent)
+std::string RlvEnvironment::handleLegacyGetFn<LLColor3>(const std::function<const LLColor3 (LLSettingsSkyPtr_t)>& getFn, U32 idxComponent)
 {
 	if ( (idxComponent >= VRED) && (idxComponent <= VBLUE) )
 	{
@@ -583,7 +583,7 @@ std::string RlvEnvironment::handleLegacyGetFn<LLColor3>(const std::function<LLCo
 template<>
 ERlvCmdRet RlvEnvironment::handleLegacySetFn<LLVector2>(float optionValue, LLVector2 curValue, const std::function<void(LLSettingsSkyPtr_t, const LLVector2&)>& setFn, U32 idxComponent)
 {
-	if (idxComponent > 2)
+	if (idxComponent >= 2)
 		return RLV_RET_FAILED_UNKNOWN;
 
 	LLSettingsSky::ptr_t pSky = LLEnvironment::instance().getCurrentSky();
@@ -672,7 +672,7 @@ void RlvEnvironment::registerSetEnvFn(const std::string& strFnName, const std::f
 }
 
 template<typename T>
-void RlvEnvironment::registerLegacySkyFn(const std::string& strFnName, const std::function<T(LLSettingsSkyPtr_t)>& getFn, const std::function<void(LLSettingsSkyPtr_t, const T&)>& setFn)
+void RlvEnvironment::registerLegacySkyFn(const std::string& strFnName, const std::function<const T (LLSettingsSkyPtr_t)>& getFn, const std::function<void(LLSettingsSkyPtr_t, const T&)>& setFn)
 {
 	RLV_ASSERT(m_LegacyGetFnLookup.end() == m_LegacyGetFnLookup.find(strFnName));
 	m_LegacyGetFnLookup.insert(std::make_pair(strFnName, [this, getFn](const std::string& strRlvParam, U32 idxComponent)
diff --git a/indra/newview/rlvenvironment.h b/indra/newview/rlvenvironment.h
index 1f6d577335e2b6dbacb2c49172baf2778707ed76..2d19ab2341f60750285879fd390b924e984ef3f3 100644
--- a/indra/newview/rlvenvironment.h
+++ b/indra/newview/rlvenvironment.h
@@ -45,12 +45,12 @@ class RlvEnvironment : public RlvExtCommandHandler
 	                     void registerGetEnvFn(const std::string& strFnName, const std::function<std::string(LLEnvironment::EnvSelection_t env)>& getFn);
 	template<typename T> void registerSetEnvFn(const std::string& strFnName, const std::function<ERlvCmdRet(LLEnvironment::EnvSelection_t env, const T& strRlvOption)>& setFn);
 	template<typename T> void registerSkyFn(const std::string& strFnName, const std::function<T(LLSettingsSky::ptr_t)>& getFn, const std::function<void(LLSettingsSky::ptr_t, const T&)>& setFn);
-	template<typename T> void registerLegacySkyFn(const std::string& strFnName, const std::function<T(LLSettingsSky::ptr_t)>& getFn, const std::function<void(LLSettingsSky::ptr_t, const T&)>& setFn);
+	template<typename T> void registerLegacySkyFn(const std::string& strFnName, const std::function<const T (LLSettingsSky::ptr_t)>& getFn, const std::function<void(LLSettingsSky::ptr_t, const T&)>& setFn);
 
 	// Command handling helpers
 	template<typename T> std::string handleGetFn(const std::function<T(LLSettingsSky::ptr_t)>& fn);
 	template<typename T> ERlvCmdRet  handleSetFn(const std::string& strRlvOption, const std::function<void(LLSettingsSky::ptr_t, const T&)>& fn);
-	template<typename T> std::string handleLegacyGetFn(const std::function<T(LLSettingsSky::ptr_t)>& getFn, U32 idxComponent);
+	template<typename T> std::string handleLegacyGetFn(const std::function<const T (LLSettingsSky::ptr_t)>& getFn, U32 idxComponent);
 	template<typename T> ERlvCmdRet  handleLegacySetFn(float optionValue, T value, const std::function<void(LLSettingsSky::ptr_t, const T&)>& setFn, U32 idxComponent);
 
 	/*
diff --git a/indra/newview/rlvextensions.cpp b/indra/newview/rlvextensions.cpp
index 4612331c96f5200b3914c613f96fb5efa2601f24..9a44df67785f313ed40fba53f2d822839e086a01 100644
--- a/indra/newview/rlvextensions.cpp
+++ b/indra/newview/rlvextensions.cpp
@@ -35,8 +35,8 @@ RlvExtGetSet::RlvExtGetSet()
 	{
 		m_DbgAllowed.insert(std::pair<std::string, S16>("AvatarSex", DBG_READ | DBG_WRITE | DBG_PSEUDO));
 		m_DbgAllowed.insert(std::pair<std::string, S16>("RenderResolutionDivisor", DBG_READ | DBG_WRITE));
-		m_DbgAllowed.insert(std::pair<std::string, S16>(RLV_SETTING_FORBIDGIVETORLV, DBG_READ));
-		m_DbgAllowed.insert(std::pair<std::string, S16>(RLV_SETTING_NOSETENV, DBG_READ));
+		m_DbgAllowed.insert(std::pair<std::string, S16>(RlvSettingNames::ForbidGiveToRlv, DBG_READ));
+		m_DbgAllowed.insert(std::pair<std::string, S16>(RlvSettingNames::NoSetEnv, DBG_READ));
 		m_DbgAllowed.insert(std::pair<std::string, S16>("WindLightUseAtmosShaders", DBG_READ));
 
 		// Cache persistance of every setting
diff --git a/indra/newview/rlvhandler.cpp b/indra/newview/rlvhandler.cpp
index 6ba6117e32ad3c0ebff276b7aab662629ea514e5..256904cb4c24df7b2f46e8d67604cc4012226941 100644
--- a/indra/newview/rlvhandler.cpp
+++ b/indra/newview/rlvhandler.cpp
@@ -70,6 +70,9 @@
 // Boost includes
 #include <boost/algorithm/string.hpp>
 
+// llappviewer.cpp
+extern BOOL gDoDisconnect;
+
 // ============================================================================
 // Static variable initialization
 //
@@ -158,7 +161,7 @@ void RlvHandler::cleanup()
 	//
 	// Clean up any restrictions that are still active
 	//
-	RLV_ASSERT(LLApp::isQuitting());	// Several commands toggle debug settings but won't if they know the viewer is quitting
+	RLV_ASSERT(LLApp::isExiting() || gDoDisconnect);	// Several commands toggle debug settings but won't if they know the viewer is quitting
 
 	// Assume we have no way to predict how m_Objects will change so make a copy ahead of time
 	uuid_vec_t idRlvObjects;
@@ -257,35 +260,34 @@ bool RlvHandler::ownsBehaviour(const LLUUID& idObj, ERlvBehaviour eBhvr) const
 // Behaviour exception handling
 //
 
-// Checked: 2009-10-04 (RLVa-1.0.4a) | Modified: RLVa-1.0.4a
 void RlvHandler::addException(const LLUUID& idObj, ERlvBehaviour eBhvr, const RlvExceptionOption& varOption)
 {
-	m_Exceptions.insert(std::pair<ERlvBehaviour, RlvException>(eBhvr, RlvException(idObj, eBhvr, varOption)));
+	m_Exceptions.insert(std::make_pair(eBhvr, RlvException(idObj, eBhvr, varOption)));
 }
 
-// Checked: 2009-10-04 (RLVa-1.0.4c) | Modified: RLVa-1.0.4c
-bool RlvHandler::isException(ERlvBehaviour eBhvr, const RlvExceptionOption& varOption, ERlvExceptionCheck typeCheck) const
+bool RlvHandler::isException(ERlvBehaviour eBhvr, const RlvExceptionOption& varOption, ERlvExceptionCheck eCheckType) const
 {
 	// We need to "strict check" exceptions only if: the restriction is actually in place *and* (isPermissive(eBhvr) == FALSE)
-	if (RLV_CHECK_DEFAULT == typeCheck)
-		typeCheck = ( (hasBehaviour(eBhvr)) && (!isPermissive(eBhvr)) ) ? RLV_CHECK_STRICT : RLV_CHECK_PERMISSIVE;
+	if (ERlvExceptionCheck::Default == eCheckType)
+		eCheckType = ( (hasBehaviour(eBhvr)) && (!isPermissive(eBhvr)) ) ? ERlvExceptionCheck::Strict : ERlvExceptionCheck::Permissive;
 
 	uuid_vec_t objList;
-	if (RLV_CHECK_STRICT == typeCheck)
+	if (ERlvExceptionCheck::Strict == eCheckType)
 	{
 		// If we're "strict checking" then we need the UUID of every object that currently has 'eBhvr' restricted
-		for (rlv_object_map_t::const_iterator itObj = m_Objects.begin(); itObj != m_Objects.end(); ++itObj)
-			if (itObj->second.hasBehaviour(eBhvr, !hasBehaviour(RLV_BHVR_PERMISSIVE)))
-				objList.push_back(itObj->first);
+		for (const auto& objEntry : m_Objects)
+		{
+			if (objEntry.second.hasBehaviour(eBhvr, !hasBehaviour(RLV_BHVR_PERMISSIVE)))
+				objList.push_back(objEntry.first);
+		}
 	}
 
-	for (rlv_exception_map_t::const_iterator itException = m_Exceptions.lower_bound(eBhvr), 
-			endException = m_Exceptions.upper_bound(eBhvr); itException != endException; ++itException)
+	for (rlv_exception_map_t::const_iterator itException = m_Exceptions.lower_bound(eBhvr), endException = m_Exceptions.upper_bound(eBhvr); itException != endException; ++itException)
 	{
 		if (itException->second.varOption == varOption)
 		{
 			// For permissive checks we just return on the very first match
-			if (RLV_CHECK_PERMISSIVE == typeCheck)
+			if (ERlvExceptionCheck::Permissive == eCheckType)
 				return true;
 
 			// For strict checks we don't return until the list is empty (every object with 'eBhvr' restricted also contains the exception)
@@ -299,19 +301,16 @@ bool RlvHandler::isException(ERlvBehaviour eBhvr, const RlvExceptionOption& varO
 	return false;
 }
 
-// Checked: 2009-10-04 (RLVa-1.0.4a) | Modified: RLVa-1.0.4a
 bool RlvHandler::isPermissive(ERlvBehaviour eBhvr) const
 {
-	return (RlvBehaviourDictionary::instance().getHasStrict(eBhvr)) 
-		? !((hasBehaviour(RLV_BHVR_PERMISSIVE)) || (isException(RLV_BHVR_PERMISSIVE, eBhvr, RLV_CHECK_PERMISSIVE)))
+	return (RlvBehaviourDictionary::instance().getHasStrict(eBhvr))
+		? !((hasBehaviour(RLV_BHVR_PERMISSIVE)) || (isException(RLV_BHVR_PERMISSIVE, eBhvr, ERlvExceptionCheck::Permissive)))
 		: true;
 }
 
-// Checked: 2009-10-04 (RLVa-1.0.4a) | Modified: RLVa-1.0.4a
 void RlvHandler::removeException(const LLUUID& idObj, ERlvBehaviour eBhvr, const RlvExceptionOption& varOption)
 {
-	for (rlv_exception_map_t::iterator itException = m_Exceptions.lower_bound(eBhvr), 
-			endException = m_Exceptions.upper_bound(eBhvr); itException != endException; ++itException)
+	for (rlv_exception_map_t::iterator itException = m_Exceptions.lower_bound(eBhvr), endException = m_Exceptions.upper_bound(eBhvr); itException != endException; ++itException)
 	{
 		if ( (itException->second.idObject == idObj) && (itException->second.varOption == varOption) )
 		{
@@ -506,6 +505,11 @@ ERlvCmdRet RlvHandler::processCommand(std::reference_wrapper<const RlvCommand> r
 					{
 						RlvCommand rlvCmdRem(rlvCmd, RLV_TYPE_REMOVE);
 						itObj->second.removeCommand(rlvCmdRem);
+						if (itObj->second.m_Commands.empty())
+						{
+							RLV_DEBUGS << "\t- command list empty => removing " << idCurObj << RLV_ENDL;
+							m_Objects.erase(itObj);
+						}
 					}
 //					notifyBehaviourObservers(rlvCmd, !fFromObj);
 				}
@@ -631,11 +635,11 @@ bool RlvHandler::processIMQuery(const LLUUID& idSender, const std::string& strMe
 		// If the user can't start an IM session terminate it (if one is open) - always notify the sender in this case
 		if (!RlvActions::canStartIM(idSender, true))
 		{
-			RlvUtil::sendBusyMessage(idSender, RlvStrings::getString(RLV_STRING_STOPIM_ENDSESSION_REMOTE));
+			RlvUtil::sendBusyMessage(idSender, RlvStrings::getString(RlvStringKeys::StopIm::EndSessionRemote));
 			if (RlvActions::hasOpenP2PSession(idSender))
 			{
 				LLAvatarActions::endIM(idSender);
-				RlvUtil::notifyBlocked(RLV_STRING_STOPIM_ENDSESSION_LOCAL, LLSD().with("NAME", LLSLURL("agent", idSender, "about").getSLURLString()), true);
+				RlvUtil::notifyBlocked(RlvStringKeys::StopIm::EndSessionLocal, LLSD().with("NAME", LLSLURL("agent", idSender, "about").getSLURLString()), true);
 			}
 			return true;
 		}
@@ -643,7 +647,7 @@ bool RlvHandler::processIMQuery(const LLUUID& idSender, const std::string& strMe
 		// User can start an IM session so we do nothing - notify and hide it from the user only if IM queries are enabled
 		if (!RlvSettings::getEnableIMQuery())
 			return false;
-		RlvUtil::sendBusyMessage(idSender, RlvStrings::getString(RLV_STRING_STOPIM_NOSESSION));
+		RlvUtil::sendBusyMessage(idSender, RlvStrings::getString(RlvStringKeys::StopIm::NoSession));
 		return true;
 	}
 	else if (RlvSettings::getEnableIMQuery())
@@ -766,7 +770,7 @@ void RlvHandler::onActiveGroupChanged()
 
 		// Notify them about the change
 		const LLSD sdArgs = LLSD().with("GROUP_SLURL", (m_idAgentGroup.notNull()) ? llformat("secondlife:///app/group/%s/about", m_idAgentGroup.asString().c_str()) : "(none)");
-		RlvUtil::notifyBlocked(RLV_STRING_BLOCKED_GROUPCHANGE, sdArgs);
+		RlvUtil::notifyBlocked(RlvStringKeys::Blocked::GroupChange, sdArgs);
 
 		setActiveGroup(m_idAgentGroup);
 	}
@@ -1241,7 +1245,7 @@ bool RlvHandler::filterChat(std::string& strUTF8Text, bool fFilterEmote) const
 	}
 
 	if (fFilter)
-		strUTF8Text = (gSavedSettings.getBOOL("RestrainedLoveShowEllipsis")) ? "..." : "";
+		strUTF8Text = (gSavedSettings.get<bool>(RlvSettingNames::ShowEllipsis)) ? "..." : "";
 	return fFilter;
 }
 
@@ -1521,7 +1525,7 @@ bool RlvHandler::setEnabled(bool fEnable)
 
 		// Reset to show assertions if the viewer version changed
 		if (gSavedSettings.getString("LastRunVersion") != gLastRunVersion)
-			gSavedSettings.setBOOL("RLVaShowAssertionFailures", TRUE);
+			gSavedSettings.set<bool>(RlvSettingNames::ShowAssertionFail, TRUE);
 	}
 
 	return m_fEnabled;
@@ -1747,9 +1751,9 @@ ERlvCmdRet RlvBehaviourGenericHandler<RLV_OPTION_EXCEPTION>::onCommand(const Rlv
 		return RLV_RET_FAILED_OPTION;
 
 	if (RLV_TYPE_ADD == rlvCmd.getParamType())
-		gRlvHandler.addException(rlvCmd.getObjectID(), rlvCmd.getBehaviourType(), idException);
+		RlvHandler::instance().addException(rlvCmd.getObjectID(), rlvCmd.getBehaviourType(), idException);
 	else
-		gRlvHandler.removeException(rlvCmd.getObjectID(), rlvCmd.getBehaviourType(), idException);
+		RlvHandler::instance().removeException(rlvCmd.getObjectID(), rlvCmd.getBehaviourType(), idException);
 
 	fRefCount = true;
 	return RLV_RET_SUCCESS;
@@ -1861,6 +1865,25 @@ ERlvCmdRet RlvBehaviourAddRemAttachHandler::onCommand(const RlvCommand& rlvCmd,
 	return RLV_RET_SUCCESS;
 }
 
+// Handles: @buy=n|y toggles
+template<> template<>
+void RlvBehaviourToggleHandler<RLV_BHVR_BUY>::onCommandToggle(ERlvBehaviour eBhvr, bool fHasBhvr)
+{
+	// Start or stop filtering opening the buy, buy contents and pay object floaters
+	if (fHasBhvr)
+	{
+		RLV_VERIFY(RlvUIEnabler::instance().addGenericFloaterFilter("buy_object", RlvStringKeys::Blocked::Generic));
+		RLV_VERIFY(RlvUIEnabler::instance().addGenericFloaterFilter("buy_object_contents", RlvStringKeys::Blocked::Generic));
+		RLV_VERIFY(RlvUIEnabler::instance().addGenericFloaterFilter("pay_object", RlvStringKeys::Blocked::Generic));
+	}
+	else
+	{
+		RLV_VERIFY(RlvUIEnabler::instance().removeGenericFloaterFilter("buy_object"));
+		RLV_VERIFY(RlvUIEnabler::instance().removeGenericFloaterFilter("buy_object_contents"));
+		RLV_VERIFY(RlvUIEnabler::instance().removeGenericFloaterFilter("pay_object"));
+	}
+}
+
 // Handles: @detach[:<attachpt>]=n|y
 template<> template<>
 ERlvCmdRet RlvBehaviourHandler<RLV_BHVR_DETACH>::onCommand(const RlvCommand& rlvCmd, bool& fRefCount)
@@ -1994,9 +2017,28 @@ void RlvBehaviourToggleHandler<RLV_BHVR_EDIT>::onCommandToggle(ERlvBehaviour eBh
 
 	// Start or stop filtering opening the beacons floater
 	if (fHasBhvr)
-		RlvUIEnabler::instance().addGenericFloaterFilter("beacons");
+	{
+		RLV_VERIFY(RlvUIEnabler::instance().addGenericFloaterFilter("beacons"));
+	}
 	else
-		RlvUIEnabler::instance().removeGenericFloaterFilter("beacons");
+	{
+		RLV_VERIFY(RlvUIEnabler::instance().removeGenericFloaterFilter("beacons"));
+	}
+}
+
+// Handles: @pay=n|y toggles
+template<> template<>
+void RlvBehaviourToggleHandler<RLV_BHVR_PAY>::onCommandToggle(ERlvBehaviour eBhvr, bool fHasBhvr)
+{
+	// Start or stop filtering opening the pay avatar floater
+	if (fHasBhvr)
+	{
+		RLV_VERIFY(RlvUIEnabler::instance().addGenericFloaterFilter("pay_resident", RlvStringKeys::Blocked::Generic));
+	}
+	else
+	{
+		RLV_VERIFY(RlvUIEnabler::instance().removeGenericFloaterFilter("pay_resident"));
+	}
 }
 
 // Handles: @setoverlay=n|y toggles
@@ -2338,11 +2380,11 @@ void RlvBehaviourToggleHandler<RLV_BHVR_SETENV>::onCommandToggle(ERlvBehaviour e
 			LLFloaterReg::const_instance_list_t envFloaters = LLFloaterReg::getFloaterList(strEnvFloaters[idxFloater]);
 			for (LLFloater* pFloater : envFloaters)
 				pFloater->closeFloater();
-			RlvUIEnabler::instance().addGenericFloaterFilter(strEnvFloaters[idxFloater]);
+			RLV_VERIFY(RlvUIEnabler::instance().addGenericFloaterFilter(strEnvFloaters[idxFloater]));
 		}
 		else
 		{
-			RlvUIEnabler::instance().removeGenericFloaterFilter(strEnvFloaters[idxFloater]);
+			RLV_VERIFY(RlvUIEnabler::instance().removeGenericFloaterFilter(strEnvFloaters[idxFloater]));
 		}
 	}
 
@@ -2395,7 +2437,7 @@ ERlvCmdRet RlvBehaviourHandler<RLV_BHVR_SHOWHOVERTEXT>::onCommand(const RlvComma
 template<> template<>
 void RlvBehaviourToggleHandler<RLV_BHVR_SHOWINV>::onCommandToggle(ERlvBehaviour eBhvr, bool fHasBhvr)
 {
-	if (LLApp::isQuitting())
+	if (LLApp::isExiting())
 		return;	// Nothing to do if the viewer is shutting down
 
 	//
@@ -2441,16 +2483,20 @@ void RlvBehaviourToggleHandler<RLV_BHVR_SHOWINV>::onCommandToggle(ERlvBehaviour
 	// Filter (or stop filtering) opening new inventory floaters
 	//
 	if (fHasBhvr)
-		RlvUIEnabler::instance().addGenericFloaterFilter("inventory");
+	{
+		RLV_VERIFY(RlvUIEnabler::instance().addGenericFloaterFilter("inventory"));
+	}
 	else
-		RlvUIEnabler::instance().removeGenericFloaterFilter("inventory");
+	{
+		RLV_VERIFY(RlvUIEnabler::instance().removeGenericFloaterFilter("inventory"));
+	}
 }
 
 // Handles: @shownames[:<uuid>]=n|y toggles
 template<> template<>
 void RlvBehaviourToggleHandler<RLV_BHVR_SHOWNAMES>::onCommandToggle(ERlvBehaviour eBhvr, bool fHasBhvr)
 {
-	if (LLApp::isQuitting())
+	if (LLApp::isExiting())
 		return;	// Nothing to do if the viewer is shutting down
 
 	// Update the shownames context
@@ -2487,7 +2533,7 @@ template<> template<>
 ERlvCmdRet RlvBehaviourHandler<RLV_BHVR_SHOWNAMES>::onCommand(const RlvCommand& rlvCmd, bool& fRefCount)
 {
 	ERlvCmdRet eRet = RlvBehaviourGenericHandler<RLV_OPTION_NONE_OR_EXCEPTION>::onCommand(rlvCmd, fRefCount);
-	if ( (RLV_RET_SUCCESS == eRet) && (rlvCmd.hasOption()) && (!LLApp::isQuitting()) )
+	if ( (RLV_RET_SUCCESS == eRet) && (rlvCmd.hasOption()) && (!LLApp::isExiting()) )
 	{
 		const LLUUID idAgent = RlvCommandOptionHelper::parseOption<LLUUID>(rlvCmd.getOption());
 
@@ -2512,7 +2558,7 @@ ERlvCmdRet RlvBehaviourHandler<RLV_BHVR_SHOWNAMES>::onCommand(const RlvCommand&
 template<> template<>
 void RlvBehaviourToggleHandler<RLV_BHVR_SHOWNAMETAGS>::onCommandToggle(ERlvBehaviour eBhvr, bool fHasBhvr)
 {
-	if (LLApp::isQuitting())
+	if (LLApp::isExiting())
 		return;	// Nothing to do if the viewer is shutting down
 
 	// Update the shownames context
@@ -2536,7 +2582,7 @@ ERlvCmdRet RlvBehaviourHandler<RLV_BHVR_SHOWNAMETAGS>::onCommand(const RlvComman
 template<> template<>
 void RlvBehaviourToggleHandler<RLV_BHVR_SHOWNEARBY>::onCommandToggle(ERlvBehaviour eBhvr, bool fHasBhvr)
 {
-	if (LLApp::isQuitting())
+	if (LLApp::isExiting())
 		return;	// Nothing to do if the viewer is shutting down
 
 	// Refresh the nearby people list
diff --git a/indra/newview/rlvhandler.h b/indra/newview/rlvhandler.h
index 70d50df020798ab9c7ced7a0c7590661a046631c..adacbbe0f3d2d28573435e7a3fbf16053477f6f6 100644
--- a/indra/newview/rlvhandler.h
+++ b/indra/newview/rlvhandler.h
@@ -78,7 +78,7 @@ class RlvHandler : public LLOldEvents::LLSimpleListener, public LLParticularGrou
 	// Returns TRUE if the specified behaviour has an added exception
 	bool hasException(ERlvBehaviour eBhvr) const;
 	// Returns TRUE if the specified option was added as an exception for the specified behaviour
-	bool isException(ERlvBehaviour eBhvr, const RlvExceptionOption& varOption, ERlvExceptionCheck typeCheck = RLV_CHECK_DEFAULT) const;
+	bool isException(ERlvBehaviour eBhvr, const RlvExceptionOption& varOption, ERlvExceptionCheck eCheckType = ERlvExceptionCheck::Default) const;
 	// Returns TRUE if the specified behaviour should behave "permissive" (rather than "strict"/"secure")
 	bool isPermissive(ERlvBehaviour eBhvr) const;
 
@@ -236,6 +236,18 @@ class RlvHandler : public LLOldEvents::LLSimpleListener, public LLParticularGrou
 	typedef std::map<LLUUID, RlvObject> rlv_object_map_t;
 	typedef std::tuple<LLUUID, std::string, double> rlv_blocked_object_t;
 	typedef std::list<rlv_blocked_object_t> rlv_blocked_object_list_t;
+
+	struct RlvException
+	{
+	public:
+		LLUUID				idObject;    // UUID of the object that added the exception
+		ERlvBehaviour		eBehaviour;  // Behaviour the exception applies to
+		RlvExceptionOption	varOption;   // Exception data (type is dependent on eBehaviour)
+
+		RlvException(const LLUUID& idObj, ERlvBehaviour eBhvr, const RlvExceptionOption& option) : idObject(idObj), eBehaviour(eBhvr), varOption(option) {}
+	private:
+		RlvException();
+	};
 	typedef std::multimap<ERlvBehaviour, RlvException> rlv_exception_map_t;
 protected:
 	rlv_object_map_t      m_Objects;				// Map of objects that have active restrictions (idObj -> RlvObject)
diff --git a/indra/newview/rlvhelper.cpp b/indra/newview/rlvhelper.cpp
index a4fd04acac3a4bd8d24e8f47b5bc7457042f104c..8316b0d114183c69521c9f247de54351b43940da 100644
--- a/indra/newview/rlvhelper.cpp
+++ b/indra/newview/rlvhelper.cpp
@@ -1,6 +1,6 @@
 /**
  *
- * Copyright (c) 2009-2016, Kitty Barnett
+ * Copyright (c) 2009-2020, Kitty Barnett
  *
  * The source code in this file is provided to you under the terms of the
  * GNU Lesser General Public License, version 2.1, but WITHOUT ANY WARRANTY;
@@ -89,6 +89,7 @@ RlvBehaviourDictionary::RlvBehaviourDictionary()
 	addEntry(new RlvBehaviourInfo("attachallthis",			RLV_BHVR_ATTACHTHIS,			RLV_TYPE_ADDREM, RlvBehaviourInfo::FORCEWEAR_SUBTREE));
 	addEntry(new RlvBehaviourInfo("attachthis_except",		RLV_BHVR_ATTACHTHISEXCEPT,		RLV_TYPE_ADDREM, RlvBehaviourInfo::FORCEWEAR_NODE));
 	addEntry(new RlvBehaviourInfo("attachallthis_except",	RLV_BHVR_ATTACHTHISEXCEPT,		RLV_TYPE_ADDREM, RlvBehaviourInfo::FORCEWEAR_SUBTREE));
+	addEntry(new RlvBehaviourGenericToggleProcessor<RLV_BHVR_BUY, RLV_OPTION_NONE>("buy"));
 	addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE>("chatwhisper", RLV_BHVR_CHATWHISPER));
 	addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE>("chatnormal", RLV_BHVR_CHATNORMAL));
 	addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE>("chatshout", RLV_BHVR_CHATSHOUT));
@@ -106,6 +107,7 @@ RlvBehaviourDictionary::RlvBehaviourDictionary()
 	addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE>("interact", RLV_BHVR_INTERACT, RlvBehaviourInfo::BHVR_EXTENDED));
 	addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE>("jump", RLV_BHVR_JUMP));
 	addEntry(new RlvBehaviourInfo("notify",					RLV_BHVR_NOTIFY,				RLV_TYPE_ADDREM));
+	addEntry(new RlvBehaviourGenericToggleProcessor<RLV_BHVR_PAY, RLV_OPTION_NONE>("pay"));
 	addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE>("permissive", RLV_BHVR_PERMISSIVE));
 	addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE_OR_EXCEPTION>("recvchat", RLV_BHVR_RECVCHAT, RlvBehaviourInfo::BHVR_STRICT));
 	addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_EXCEPTION>("recvchatfrom", RLV_BHVR_RECVCHATFROM, RlvBehaviourInfo::BHVR_STRICT));
diff --git a/indra/newview/rlvhelper.h b/indra/newview/rlvhelper.h
index abd0b78d76562084861ef019f0bba2e92dd27082..2ddeb1a4eaee9478b29a0f3efb56d46916bb1efc 100644
--- a/indra/newview/rlvhelper.h
+++ b/indra/newview/rlvhelper.h
@@ -622,21 +622,6 @@ class RlvBehaviourNotifyHandler final : public LLSingleton<RlvBehaviourNotifyHan
 	boost::signals2::connection m_ConnCommand;
 };
 
-// ============================================================================
-// RlvException
-//
-
-struct RlvException
-{
-public:
-	LLUUID				idObject;    // UUID of the object that added the exception
-	ERlvBehaviour		eBehaviour;  // Behaviour the exception applies to
-	RlvExceptionOption	varOption;   // Exception data (type is dependent on eBehaviour)
-
-	RlvException(const LLUUID& idObj, ERlvBehaviour eBhvr, const RlvExceptionOption& option) : idObject(idObj), eBehaviour(eBhvr), varOption(option) {}
-private:
-	RlvException();
-};
 
 // ============================================================================
 // Various helper classes/timers/functors
diff --git a/indra/newview/rlvinventory.cpp b/indra/newview/rlvinventory.cpp
index c0259af3d4b3d8e95fec2062ff1ea947abd9f8ab..c29a7f38636a2ff6e1a7568ddf5f886305fcb682 100644
--- a/indra/newview/rlvinventory.cpp
+++ b/indra/newview/rlvinventory.cpp
@@ -1,17 +1,17 @@
-/** 
+/**
  *
- * Copyright (c) 2009-2014, Kitty Barnett
- * 
- * The source code in this file is provided to you under the terms of the 
+ * Copyright (c) 2009-2020, Kitty Barnett
+ *
+ * The source code in this file is provided to you under the terms of the
  * GNU Lesser General Public License, version 2.1, but WITHOUT ANY WARRANTY;
- * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
- * PARTICULAR PURPOSE. Terms of the LGPL can be found in doc/LGPL-licence.txt 
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE. Terms of the LGPL can be found in doc/LGPL-licence.txt
  * in this distribution, or online at http://www.gnu.org/licenses/lgpl-2.1.txt
- * 
+ *
  * By copying, modifying or distributing this software, you acknowledge that
- * you have read and understood your obligations described above, and agree to 
+ * you have read and understood your obligations described above, and agree to
  * abide by those obligations.
- * 
+ *
  */
 
 #include "llviewerprecompiledheaders.h"
@@ -630,26 +630,18 @@ void RlvGiveToRLVOffer::moveAndRename(const LLUUID& idFolder, const LLUUID& idDe
 
 void RlvGiveToRLVTaskOffer::changed(U32 mask)
 {
-	if (mask & LLInventoryObserver::ADD)
-	{
-		LLMessageSystem* pMsg = gMessageSystem;
-		if ( (pMsg->getMessageName()) && (0 == strcmp(pMsg->getMessageName(), "BulkUpdateInventory")) )
-		{
-			LLUUID idTransaction;
-			pMsg->getUUIDFast(_PREHASH_AgentData, _PREHASH_TransactionID, idTransaction);
-			if (m_idTransaction == idTransaction)
+	if ( (mask & LLInventoryObserver::ADD) && (gInventory.getTransactionId().notNull()) && (m_idTransaction == gInventory.getTransactionId()) )
+	{    // BulkUpdateInventory
+	    const auto& idItems = gInventory.getAddedIDs();
+	    for (const LLUUID& idItem : idItems)
+	    {
+	        if (LLInventoryCategory* pCategory = gInventory.getCategory(idItem))
 			{
-				LLUUID idInvObject;
-				for (S32 idxBlock = 0, cntBlock = pMsg->getNumberOfBlocksFast(_PREHASH_FolderData); idxBlock < cntBlock; idxBlock++)
-				{
-					pMsg->getUUIDFast(_PREHASH_FolderData, _PREHASH_FolderID, idInvObject, idxBlock);
-					if ( (idInvObject.notNull()) && (std::find(m_Folders.begin(), m_Folders.end(), idInvObject) == m_Folders.end()) )
-						m_Folders.push_back(idInvObject);
-				}
-
-				done();
+				if (std::find(m_Folders.begin(), m_Folders.end(), pCategory->getUUID()) == m_Folders.end())
+					m_Folders.push_back(pCategory->getUUID());
 			}
 		}
+		done();
 	}
 }
 
diff --git a/indra/newview/rlvinventory.h b/indra/newview/rlvinventory.h
index a1f0c7d00d1b2c306d6ef8a066455664f5eaf951..97573ba380d907b1c90f198297c4946f135de153 100644
--- a/indra/newview/rlvinventory.h
+++ b/indra/newview/rlvinventory.h
@@ -1,17 +1,17 @@
-/** 
+/**
  *
- * Copyright (c) 2009-2014, Kitty Barnett
- * 
- * The source code in this file is provided to you under the terms of the 
+ * Copyright (c) 2009-2020, Kitty Barnett
+ *
+ * The source code in this file is provided to you under the terms of the
  * GNU Lesser General Public License, version 2.1, but WITHOUT ANY WARRANTY;
- * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
- * PARTICULAR PURPOSE. Terms of the LGPL can be found in doc/LGPL-licence.txt 
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE. Terms of the LGPL can be found in doc/LGPL-licence.txt
  * in this distribution, or online at http://www.gnu.org/licenses/lgpl-2.1.txt
- * 
+ *
  * By copying, modifying or distributing this software, you acknowledge that
- * you have read and understood your obligations described above, and agree to 
+ * you have read and understood your obligations described above, and agree to
  * abide by those obligations.
- * 
+ *
  */
 
 #ifndef RLV_INVENTORY_H
diff --git a/indra/newview/rlvlocks.cpp b/indra/newview/rlvlocks.cpp
index 746338685385f4b0b6f776992734ca0da03c1b7a..4b94e34fdf55b2dd4d89d76bb9969583fa7fa642 100644
--- a/indra/newview/rlvlocks.cpp
+++ b/indra/newview/rlvlocks.cpp
@@ -631,7 +631,7 @@ void RlvAttachmentLockWatchdog::onAttach(const LLViewerObject* pAttachObj, const
 				if ( (pAttachObj != *itAttachObj) && (gRlvAttachmentLocks.isLockedAttachment(*itAttachObj)) )
 				{
 					// Fail if we encounter a non-detachable attachment (unless we're only replacing detachable attachments)
-					if (gSavedSettings.getBOOL("RLVaWearReplaceUnlocked"))
+					if (gSavedSettings.get<bool>(RlvSettingNames::WearReplaceUnlocked))
 						idsAttachObjExcept.push_back((*itAttachObj)->getID());
 					else
 						fAttachAllowed = false;
diff --git a/indra/newview/rlvui.cpp b/indra/newview/rlvui.cpp
index cd6e5831ce72e71df7c6032578164c4ccd579ba7..ae6a4e358af11c55fe61be91d39c184ffb1c9cdc 100644
--- a/indra/newview/rlvui.cpp
+++ b/indra/newview/rlvui.cpp
@@ -77,7 +77,7 @@ RlvUIEnabler::RlvUIEnabler()
 // Checked: 2010-02-28 (RLVa-1.4.0a) | Added: RLVa-1.2.0a
 void RlvUIEnabler::onBehaviourToggle(ERlvBehaviour eBhvr, ERlvParamType eType)
 {
-	bool fQuitting = LLApp::isQuitting();
+	bool fQuitting = LLApp::isExiting();
 	for (behaviour_handler_map_t::const_iterator itHandler = m_Handlers.lower_bound(eBhvr), endHandler = m_Handlers.upper_bound(eBhvr);
 			itHandler != endHandler; ++itHandler)
 	{
@@ -182,9 +182,13 @@ void RlvUIEnabler::onToggleShowMinimap()
 
 	// Start or stop filtering showing the mini-map floater
 	if (!fEnable)
-		addGenericFloaterFilter("mini_map");
+	{
+		RLV_VERIFY(addGenericFloaterFilter("mini_map"));
+	}
 	else
-		removeGenericFloaterFilter("mini_map");
+	{
+		RLV_VERIFY(removeGenericFloaterFilter("mini_map"));
+	}
 
 	// Hide the mini-map floater if it's currently visible (or restore it if it was previously visible)
 	static bool fPrevVisibile = false;
@@ -217,9 +221,13 @@ void RlvUIEnabler::onToggleShowWorldMap()
 
 	// Start or stop filtering opening the world map
 	if (!fEnable)
-		addGenericFloaterFilter("world_map");
+	{
+		RLV_VERIFY(addGenericFloaterFilter("world_map"));
+	}
 	else
-		removeGenericFloaterFilter("world_map");
+	{
+		RLV_VERIFY(removeGenericFloaterFilter("world_map"));
+	}
 }
 
 // Checked: 2010-08-22 (RLVa-1.2.1a) | Added: RLVa-1.2.1a
@@ -271,31 +279,57 @@ void RlvUIEnabler::onUpdateLoginLastLocation(bool fQuitting)
 
 // ============================================================================
 
-// Checked: 2010-02-28 (RLVa-1.4.0a) | Added: RLVa-1.2.0a
-void RlvUIEnabler::addGenericFloaterFilter(const std::string& strFloaterName)
+#ifdef CATZNIP_STRINGVIEW
+bool RlvUIEnabler::addGenericFloaterFilter(const std::string& strFloaterName, const boost::string_view& strRlvNotification)
+#else
+bool RlvUIEnabler::addGenericFloaterFilter(const std::string& strFloaterName, const std::string& strRlvNotification)
+#endif // CATZNIP_STRINGVIEW
 {
-	m_FilteredFloaters.insert(strFloaterName);
+	return addGenericFloaterFilter(strFloaterName, [strRlvNotification]() { RlvUtil::notifyBlocked(strRlvNotification); });
+}
+
+bool RlvUIEnabler::addGenericFloaterFilter(const std::string& strFloaterName, const std::function<void()>& fn)
+{
+	// NOTE: we don't currently support multiple filters for the same floater (due to the need to remove the correct one at the end of it all)
+	if (m_FilteredFloaterMap.end() != m_FilteredFloaterMap.find(strFloaterName))
+		return false;
+
+	m_FilteredFloaterMap.insert(std::make_pair(strFloaterName, fn));
 
 	if (!m_ConnFloaterGeneric.connected())
+	{
 		m_ConnFloaterGeneric = LLFloaterReg::setValidateCallback(boost::bind(&RlvUIEnabler::filterFloaterGeneric, this, _1, _2));
+	}
+
+	return true;
 }
 
-// Checked: 2010-02-28 (RLVa-1.4.0a) | Added: RLVa-1.2.0a
-void RlvUIEnabler::removeGenericFloaterFilter(const std::string& strFloaterName)
+bool RlvUIEnabler::removeGenericFloaterFilter(const std::string& strFloaterName)
 {
-	std::multiset<std::string>::iterator itFloater = m_FilteredFloaters.find(strFloaterName);
-	RLV_ASSERT_DBG(itFloater != m_FilteredFloaters.end());
-	m_FilteredFloaters.erase(itFloater);
+	auto itFloater = m_FilteredFloaterMap.find(strFloaterName);
+	if (m_FilteredFloaterMap.end() == itFloater)
+		return false;
+
+	m_FilteredFloaterMap.erase(itFloater);
 
 	RLV_ASSERT_DBG(m_ConnFloaterGeneric.connected());
-	if (m_FilteredFloaters.empty())
+	if (m_FilteredFloaterMap.empty())
 		m_ConnFloaterGeneric.disconnect();
+
+	return true;
 }
 
-// Checked: 2010-02-28 (RLVa-1.4.0a) | Added: RLVa-1.2.0a
-bool RlvUIEnabler::filterFloaterGeneric(const std::string& strName, const LLSD&)
+bool RlvUIEnabler::filterFloaterGeneric(const std::string& strFloaterName, const LLSD&)
 {
-	return m_FilteredFloaters.end() == m_FilteredFloaters.find(strName);
+	auto itFloater = m_FilteredFloaterMap.find(strFloaterName);
+	if (m_FilteredFloaterMap.end() != itFloater)
+	{
+		if (itFloater->second)
+			itFloater->second();
+		return false;
+	}
+	return true;
+
 }
 
 // Checked: 2010-04-22 (RLVa-1.4.5) | Added: RLVa-1.2.0
diff --git a/indra/newview/rlvui.h b/indra/newview/rlvui.h
index 1a5f68e9acf37395a7365bbccf7ac7e5b413a2fa..36478d6442d594cdad0ed7f5404c08c75bf5eb46 100644
--- a/indra/newview/rlvui.h
+++ b/indra/newview/rlvui.h
@@ -55,8 +55,13 @@ class RlvUIEnabler final : public LLSingleton<RlvUIEnabler>
 	 * Floater and sidebar validation callbacks
 	 */
 public:
-	void addGenericFloaterFilter(const std::string& strFloaterName);
-	void removeGenericFloaterFilter(const std::string& strFloaterName);
+#ifdef CATZNIP_STRINGVIEW
+	bool addGenericFloaterFilter(const std::string& strFloaterName, const boost::string_view& strRlvNotification);
+#else
+	bool addGenericFloaterFilter(const std::string& strFloaterName, const std::string& strRlvNotification);
+#endif // CATZNIP_STRINGVIEW
+	bool addGenericFloaterFilter(const std::string& strFloaterName, const std::function<void()>& fn = nullptr);
+	bool removeGenericFloaterFilter(const std::string& strFloaterName);
 
 protected:
 	bool filterFloaterGeneric(const std::string&, const LLSD&);
@@ -86,7 +91,7 @@ class RlvUIEnabler final : public LLSingleton<RlvUIEnabler>
 	typedef std::multimap<ERlvBehaviour, behaviour_handler_t> behaviour_handler_map_t;
 	behaviour_handler_map_t m_Handlers;
 
-	std::multiset<std::string> m_FilteredFloaters;
+	std::map<std::string, std::function<void()>> m_FilteredFloaterMap;
 };
 
 // ============================================================================
diff --git a/indra/newview/skins/default/xui/en/menu_avatar_icon.xml b/indra/newview/skins/default/xui/en/menu_avatar_icon.xml
index aaf8c6c55fc3aab7d593e9d1263edd3bafea46e7..70bf4ea77c56226b8c19f526f94b9421cd2c12cd 100644
--- a/indra/newview/skins/default/xui/en/menu_avatar_icon.xml
+++ b/indra/newview/skins/default/xui/en/menu_avatar_icon.xml
@@ -95,6 +95,7 @@
      layout="topleft"
      name="Pay">
        <on_click function="AvatarIcon.Action" parameter="pay" />
+       <on_enable function="AvatarIcon.Enable" parameter="can_pay" />
     </menu_item_call>
     <menu_item_check
      label="Block Voice"
diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml
index 11b8b3017be7a65596d44c9decd59d03de57f544..60e693be4d9393c89b26c2020ead8bab400d4c0c 100644
--- a/indra/newview/skins/default/xui/en/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/en/menu_viewer.xml
@@ -1688,6 +1688,16 @@ function="World.EnvPreset"
       	 function="ToggleControl"
       	 parameter="RestrainedLoveShowEllipsis" />
       </menu_item_check>
+      <menu_item_check
+       label="Show Redirected Chat Typing"
+       name="Show Redirected Chat Typing">
+        <menu_item_check.on_check
+      	 function="CheckControl"
+      	 parameter="RLVaShowRedirectChatTyping" />
+        <menu_item_check.on_click
+      	 function="ToggleControl"
+      	 parameter="RLVaShowRedirectChatTyping" />
+      </menu_item_check>
       <menu_item_check
        label="Split Long Redirected Chat"
        name="Split Long Redirected Chat">