diff --git a/indra/viewer_components/manager/InstallerError.py b/indra/viewer_components/manager/InstallerError.py
deleted file mode 100644
index 3b199ea231217b7727ed880e9a233028a150664a..0000000000000000000000000000000000000000
--- a/indra/viewer_components/manager/InstallerError.py
+++ /dev/null
@@ -1,49 +0,0 @@
-#!/usr/bin/env python
-
-"""\
-@file InstallerError.py
-@author coyot
-@date 2016-05-16
-@brief custom exception class for VMP
-
-$LicenseInfo:firstyear=2016&license=viewerlgpl$
-Second Life Viewer Source Code
-Copyright (C) 2016, Linden Research, Inc.
-
-This library is free software; you can redistribute it and/or
-modify it under the terms of the GNU Lesser General Public
-License as published by the Free Software Foundation;
-version 2.1 of the License only.
-
-This library is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-Lesser General Public License for more details.
-
-You should have received a copy of the GNU Lesser General Public
-License along with this library; if not, write to the Free Software
-Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
-
-Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
-$/LicenseInfo$
-"""
-
-"""
-usage:
-
->>> import InstallerError
->>> import os
->>> try:
-...    os.mkdir('/tmp')
-... except OSError, oe:
-...    ie = InstallerError.InstallerError(oe, "foo")
-...    raise ie
-
-Traceback (most recent call last):
-  File "<stdin>", line 5, in <module>
-InstallerError.InstallerError: [Errno [Errno 17] File exists: '/tmp'] foo
-"""
-
-class InstallerError(OSError):
-    def __init___(self, message):
-        Exception.__init__(self, message)
diff --git a/indra/viewer_components/manager/InstallerUserMessage.py b/indra/viewer_components/manager/InstallerUserMessage.py
deleted file mode 100644
index 8002399659d081c429066285679e90762bf0a104..0000000000000000000000000000000000000000
--- a/indra/viewer_components/manager/InstallerUserMessage.py
+++ /dev/null
@@ -1,316 +0,0 @@
-#!/usr/bin/env python
-
-# $LicenseInfo:firstyear=2016&license=internal$
-# 
-# Copyright (c) 2016, Linden Research, Inc.
-# 
-# The following source code is PROPRIETARY AND CONFIDENTIAL. Use of
-# this source code is governed by the Linden Lab Source Code Disclosure
-# Agreement ("Agreement") previously entered between you and Linden
-# Lab. By accessing, using, copying, modifying or distributing this
-# software, you acknowledge that you have been informed of your
-# obligations under the Agreement and agree to abide by those obligations.
-# 
-# ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
-# WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
-# COMPLETENESS OR PERFORMANCE.
-# $LicenseInfo:firstyear=2013&license=viewerlgpl$
-# Copyright (c) 2013, Linden Research, Inc.
-# $/LicenseInfo$
-
-"""
-@file   InstallerUserMessage.py
-@author coyot
-@date   2016-05-16
-"""
-
-"""
-This does everything the old updater/scripts/darwin/messageframe.py script did and some more bits.  
-Pushed up the manager directory to be multiplatform.
-"""
-
-import os
-import Queue
-import threading
-import time
-import Tkinter as tk
-import ttk
-
-
-class InstallerUserMessage(tk.Tk):
-    #Goals for this class:
-    #  Provide a uniform look and feel
-    #  Provide an easy to use convenience class for other scripts
-    #  Provide windows that automatically disappear when done (for differing notions of done)
-    #  Provide a progress bar that isn't a glorified spinner, but based on download progress
-    #Non-goals:
-    #  No claim to threadsafety is made or warranted.  Your mileage may vary. 
-    #     Please consult a doctor if you experience thread pain.
-
-    #Linden standard green color, from Marketing
-    linden_green = "#487A7B"
-
-    def __init__(self, text="", title="", width=500, height=200, wraplength = 400, icon_name = None, icon_path = None):
-        tk.Tk.__init__(self)
-        self.grid()
-        self.title(title)
-        self.choice = tk.BooleanVar()
-        self.config(background = 'black')
-        # background="..." doesn't work on MacOS for radiobuttons or progress bars
-        # http://tinyurl.com/tkmacbuttons
-        ttk.Style().configure('Linden.TLabel', foreground=InstallerUserMessage.linden_green, background='black')
-        ttk.Style().configure('Linden.TButton', foreground=InstallerUserMessage.linden_green, background='black')
-        ttk.Style().configure("black.Horizontal.TProgressbar", foreground=InstallerUserMessage.linden_green, background='black')
-
-        #This bit of configuration centers the window on the screen
-        # The constants below are to adjust for typical overhead from the
-        # frame borders.
-        self.xp = (self.winfo_screenwidth()  / 2) - (width  / 2) - 8
-        self.yp = (self.winfo_screenheight() / 2) - (height / 2) - 20
-        self.geometry('{0}x{1}+{2}+{3}'.format(width, height, self.xp, self.yp))
-
-        #find a few things
-        self.script_dir = os.path.dirname(os.path.realpath(__file__))
-        self.contents_dir = os.path.dirname(self.script_dir)
-        self.icon_dir = os.path.abspath(os.path.join(self.contents_dir, 'Resources/vmp_icons'))
-
-        #finds the icon and creates the widget
-        self.find_icon(icon_path, icon_name)
-
-        #defines what to do when window is closed
-        self.protocol("WM_DELETE_WINDOW", self._delete_window)
-        
-        #callback id
-        self.id = -1
-
-    def _delete_window(self):
-        #capture and discard all destroy events before the choice is set
-        if not ((self.choice == None) or (self.choice == "")):
-            try:
-                #initialized value.  If we have an outstanding callback, kill it before killing ourselves
-                if self.id != -1:
-                    self.after_cancel(self.id)
-                self.destroy()
-            except:
-                #tk may try to destroy the same object twice
-                pass
-
-    def set_colors(self, widget):
-        # #487A7B is "Linden Green"
-        widget.config(foreground = InstallerUserMessage.linden_green)
-        widget.config(background='black') 
-
-    def find_icon(self, icon_path = None, icon_name = None):
-        #we do this in each message, let's do it just once instead.
-        if not icon_path:
-            icon_path = self.icon_dir
-        icon_path = os.path.join(icon_path, icon_name)
-        print icon_path
-        if os.path.exists(icon_path):
-            icon = tk.PhotoImage(file=icon_path)
-            self.image_label = tk.Label(image = icon)
-            self.image_label.image = icon
-        else:
-            #default to text if image not available
-            self.image_label = tk.Label(text = "Second Life")
-
-    def auto_resize(self, row_count = 0, column_count = 0, heavy_row = None, heavy_column = None):
-        #auto resize window to fit all rows and columns
-        #"heavy" gets extra weight
-        for x in range(column_count):
-            if x == heavy_column:
-                self.columnconfigure(x, weight = 2)
-            else:
-                self.columnconfigure(x, weight=1)
-
-        for y in range(row_count):
-            if y == heavy_row:
-                self.rowconfigure(y, weight = 2)
-            else:
-                self.rowconfigure(x, weight=1)
-
-    def basic_message(self, message):
-        #message: text to be displayed
-        #icon_path: directory holding the icon, defaults to icons subdir of script dir
-        #icon_name: filename of icon to be displayed
-        self.choice.set(True)
-        self.text_label = tk.Label(text = message)
-        self.set_colors(self.text_label)
-        self.set_colors(self.image_label)
-        #pad, direction and weight are all experimentally derived by retrying various values
-        self.image_label.grid(row = 1, column = 1, sticky = 'W')
-        self.text_label.grid(row = 1, column = 2, sticky = 'W', padx =100)
-        self.auto_resize(row_count = 1, column_count = 2)
-        self.mainloop()
-
-    def binary_choice_message(self, message, true = 'Yes', false = 'No'):
-        #true: first option, returns True
-        #false: second option, returns False
-        #usage is kind of opaque and relies on this object persisting after the window destruction to pass back choice
-        #usage:
-        #   frame = InstallerUserMessage.InstallerUserMessage( ... )
-        #   frame = frame.binary_choice_message( ... )
-        #   (wait for user to click)
-        #   value = frame.choice.get()
-
-        self.text_label = tk.Label(text = message)
-        #command registers the callback to the method named.  We want the frame to go away once clicked.
-        #button 1 returns True/1, button 2 returns False/0
-        self.button_one = ttk.Radiobutton(text = true, variable = self.choice, value = True, 
-            command = self._delete_window, style = 'Linden.TButton')
-        self.button_two = ttk.Radiobutton(text = false, variable = self.choice, value = False, 
-            command = self._delete_window, style = 'Linden.TButton')
-        self.set_colors(self.text_label)
-        self.set_colors(self.image_label)
-        #pad, direction and weight are all experimentally derived by retrying various values
-        self.image_label.grid(row = 1, column = 1, rowspan = 3, sticky = 'W')
-        self.text_label.grid(row = 1, column = 2, rowspan = 3)
-        self.button_one.grid(row = 1, column = 3, sticky = 'W', pady = 40)
-        self.button_two.grid(row = 2, column = 3, sticky = 'W', pady = 0)
-        self.auto_resize(row_count = 2, column_count = 3, heavy_column = 3)
-        #self.button_two.deselect()
-        self.update()
-        self.mainloop()
-
-    def trinary_choice_message(self, message, one = 1, two = 2, three = 3):
-        #one: first option, returns 1
-        #two: second option, returns 2
-        #three: third option, returns 3
-        #usage is kind of opaque and relies on this object persisting after the window destruction to pass back choice
-        #usage:
-        #   frame = InstallerUserMessage.InstallerUserMessage( ... )
-        #   frame = frame.binary_choice_message( ... )
-        #   (wait for user to click)
-        #   value = frame.choice.get()
-
-        self.text_label = tk.Label(text = message)
-        #command registers the callback to the method named.  We want the frame to go away once clicked.
-        self.button_one = ttk.Radiobutton(text = one, variable = self.choice, value = 1, 
-            command = self._delete_window, style = 'Linden.TButton')
-        self.button_two = ttk.Radiobutton(text = two, variable = self.choice, value = 2, 
-            command = self._delete_window, style = 'Linden.TButton')
-        self.button_three = ttk.Radiobutton(text = three, variable = self.choice, value = 3, 
-            command = self._delete_window, style = 'Linden.TButton')
-        self.set_colors(self.text_label)
-        self.set_colors(self.image_label)
-        #pad, direction and weight are all experimentally derived by retrying various values
-        self.image_label.grid(row = 1, column = 1, rowspan = 4, sticky = 'W')
-        self.text_label.grid(row = 1, column = 2, rowspan = 4, padx = 5)
-        self.button_one.grid(row = 1, column = 3, sticky = 'W', pady = 5)
-        self.button_two.grid(row = 2, column = 3, sticky = 'W', pady = 5)
-        self.button_three.grid(row = 3, column = 3, sticky = 'W', pady = 5)
-        self.auto_resize(row_count = 3, column_count = 3, heavy_column = 3)
-        #self.button_two.deselect()
-        self.update()
-        self.mainloop()
-
-    def progress_bar(self, message = None, size = 0, interval = 100, pb_queue = None):
-        #Best effort attempt at a real progress bar
-        #  This is what Tk calls "determinate mode" rather than "indeterminate mode"
-        #size: denominator of percent complete
-        #interval: frequency, in ms, of how often to poll the file for progress
-        #pb_queue: queue object used to send updates to the bar
-        self.text_label = tk.Label(text = message)
-        self.set_colors(self.text_label)
-        self.set_colors(self.image_label)
-        self.image_label.grid(row = 1, column = 1, sticky = 'NSEW')
-        self.text_label.grid(row = 2, column = 1, sticky = 'NSEW')
-        self.progress = ttk.Progressbar(self, style = 'black.Horizontal.TProgressbar', orient="horizontal", length=100, mode="determinate")
-        self.progress.grid(row = 3, column = 1, sticky = 'NSEW')
-        self.value = 0
-        self.progress["maximum"] = size
-        self.auto_resize(row_count = 1, column_count = 3)
-        self.queue = pb_queue
-        self.check_scheduler()
-
-    def check_scheduler(self):
-        try:
-            if self.value < self.progress["maximum"]:
-                self.check_queue()            
-                self.id = self.after(100, self.check_scheduler)
-            else:
-                #prevent a race condition between polling and the widget destruction
-                self.after_cancel(self.id)
-        except tk.TclError:
-            #we're already dead, just die quietly
-            pass
-
-    def check_queue(self):
-        while self.queue.qsize():
-            try:
-                msg = float(self.queue.get(0))
-                #custom signal, time to tear down
-                if msg == -1:
-                    self.choice.set(True)
-                    self.destroy()
-                else:
-                    self.progress.step(msg)
-                    self.value = msg
-            except Queue.Empty:
-                #nothing to do
-                return
-
-class ThreadedClient(threading.Thread):
-    #for test only, not part of the functional code
-    def __init__(self, queue):
-        threading.Thread.__init__(self)
-        self.queue = queue
-
-    def run(self):
-        for x in range(1, 90, 10):
-            time.sleep(1)
-            print "run " + str(x)
-            self.queue.put(10)
-        #tkk progress bars wrap at exactly 100 percent, look full at 99%
-        print "leftovers"
-        self.queue.put(9)
-        time.sleep(5)
-        # -1 is a custom signal to the progress_bar to quit
-        self.queue.put(-1)
-
-if __name__ == "__main__":
-    #When run as a script, just test the InstallUserMessage.  
-    #To proceed with the test, close the first window, select on the second and fourth.  The third will close by itself.
-    import sys
-    import tempfile
-
-    def set_and_check(frame, value):
-        print "value: " + str(value)
-        frame.progress.step(value)
-        if frame.progress["value"] < frame.progress["maximum"]:
-            print "In Progress"
-        else:
-            print "Over now"
-
-    #basic message window test
-    frame2 = InstallerUserMessage(text = "Something in the way she moves....", title = "Beatles Quotes for 100", icon_name="head-sl-logo.gif")
-    print frame2.contents_dir
-    print frame2.icon_dir
-    frame2.basic_message(message = "...attracts me like no other.")
-    print "Destroyed!"
-    sys.stdout.flush()
-
-    #binary choice test.  User destroys window when they select.
-    frame3 = InstallerUserMessage(text = "Something in the way she knows....", title = "Beatles Quotes for 200", icon_name="head-sl-logo.gif")
-    frame3.binary_choice_message(message = "And all I have to do is think of her.", 
-        true = "Don't want to leave her now", false = 'You know I believe and how')
-    print frame3.choice.get()
-    sys.stdout.flush()
-
-    #progress bar
-    queue = Queue.Queue()
-    thread = ThreadedClient(queue)
-    thread.start()
-    print "thread started"
-
-    frame4 = InstallerUserMessage(text = "Something in the way she knows....", title = "Beatles Quotes for 300", icon_name="head-sl-logo.gif")
-    frame4.progress_bar(message = "You're asking me will my love grow", size = 100, pb_queue = queue)
-    print "frame defined"
-    frame4.mainloop()
-
-    #trinary choice test.  User destroys window when they select.
-    frame3a = InstallerUserMessage(text = "Something in the way she knows....", title = "Beatles Quotes for 200", icon_name="head-sl-logo.gif")
-    frame3a.trinary_choice_message(message = "And all I have to do is think of her.", 
-        one = "Don't want to leave her now", two = 'You know I believe and how', three = 'John is Dead')
-    print frame3a.choice.get()
-    sys.stdout.flush()
diff --git a/indra/viewer_components/manager/SL_Launcher b/indra/viewer_components/manager/SL_Launcher
deleted file mode 100755
index 257543187cbd293cf7a8eea6f1b9617d0e361140..0000000000000000000000000000000000000000
--- a/indra/viewer_components/manager/SL_Launcher
+++ /dev/null
@@ -1,199 +0,0 @@
-#!/usr/bin/env python
-
-# $LicenseInfo:firstyear=2016&license=internal$
-# 
-# Copyright (c) 2016, Linden Research, Inc.
-# 
-# The following source code is PROPRIETARY AND CONFIDENTIAL. Use of
-# this source code is governed by the Linden Lab Source Code Disclosure
-# Agreement ("Agreement") previously entered between you and Linden
-# Lab. By accessing, using, copying, modifying or distributing this
-# software, you acknowledge that you have been informed of your
-# obligations under the Agreement and agree to abide by those obligations.
-# 
-# ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
-# WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
-# COMPLETENESS OR PERFORMANCE.
-# $/LicenseInfo$
-# Copyright (c) 2013, Linden Research, Inc.
-
-import os
-import sys
-
-#module globals
-log_file_handle = None
-cwd = os.path.dirname(os.path.realpath(__file__))
-sys.path.insert(0, os.path.join(cwd, 'llbase'))
-
-import argparse
-import collections
-import InstallerUserMessage
-#NOTA BENE: 
-#   For POSIX platforms, llsd.py will be imported from the same directory.  
-#   For Windows, llsd.py will be compiled into the executable by pyinstaller
-try:
-   from llbase import llsd
-except:
-   #if Windows, this is expected, if not, we're dead
-   if os.name == 'nt':
-      pass
-import platform
-import subprocess
-import update_manager
-
-
-def silent_write(log_file_handle, text):
-   #if we have a log file, write.  If not, do nothing.
-   #this is so we don't have to keep trapping for an exception with a None handle
-   #oh and because it is best effort, it is also a holey_write ;)
-   if (log_file_handle):
-      #prepend text for easy grepping
-      timestamp = datetime.utcnow().strftime("%Y-%m-%D %H:%M:%S")
-      log_file_handle.write(timestamp + " LAUNCHER: " + text + "\n")
-  
-def get_cmd_line():
-   platform_name = platform.system()
-   #find the parent of the logs and user_settings directories
-   if (platform_name == 'Darwin'):
-      settings_file = os.path.join(os.path.dirname(os.path.dirname(os.path.realpath(__file__))), 'Resources/app_settings/cmd_line.xml')
-   elif (platform_name == 'Linux'): 
-      settings_file = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'app_settings/cmd_line.xml')
-   #using list format of join is important here because the Windows pathsep in a string escapes the next char
-   elif (platform_name == 'Windows'):
-      settings_file = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'app_settings/cmd_line.xml')
-   else:
-      settings_file = None
-      
-   try:
-      cmd_line = llsd.parse((open(settings_file)).read())
-   except:
-      silent_write(log_file_handle, "Could not parse settings file %s" % settings_file)
-      cmd_line = None
-   
-   return cmd_line
-
-def get_settings():
-   #return the settings file parsed into a dict
-   try:
-      settings_file = os.path.abspath(os.path.join(parent_dir,'user_settings','settings.xml'))
-      settings = llsd.parse((open(settings_file)).read())
-   except llsd.LLSDParseError as lpe:
-      silent_write(log_file_handle, "Could not parse settings file %s" % lpe)
-      return None
-   return settings
-
-def capture_vmp_args(arg_list = None, cmd_line = None):
-   #expected input format: arg_list = ['--set', 'foo', 'bar', '-X', '-Y', 'qux']
-   #take a copy of the viewer parameters that are of interest to VMP.
-   #the regex for a parameter is --<param> {opt1} {opt2}
-   cli_overrides = {}   
-   cmd_line = get_cmd_line()
-   
-   vmp_params = {'--channel':'channel', '--settings':'settings', '--update-service':'update-service', '--set':'set'}
-   #the settings set with --set.  All such settings have only one argument.
-   vmp_setters = ('UpdaterMaximumBandwidth', 'UpdaterServiceCheckPeriod', 'UpdaterServicePath', 'UpdaterServiceSetting', 'UpdaterServiceURL', 'UpdaterWillingToTest')   
-   
-   #Here turn the list into a queue, popping off the left as we go. Note that deque() makes a copy by value, not by reference
-   #Because of the complexity introduced by the uncertainty of how many options a parameter can take, this is far less complicated code than the more
-   #pythonic (x,y) = <some generator> since we will sometimes have (x), sometimes (x,y) and sometimes (x,y,z)
-   #also, because the pop is destructive, we prevent ourselves from iterating back over list elements that iterator methods would peek ahead at
-   vmp_queue = collections.deque(arg_list)
-   while (len(vmp_queue)):
-      param = vmp_queue.popleft()
-      #if it is not one of ours, pop through args until we get to the next parameter
-      if param in vmp_params.keys():
-         if param == '--set':
-            setting_name = vmp_queue.popleft()
-            setting_value = vmp_queue.popleft()
-            if setting_name in vmp_setters:
-               cli_overrides[vmp_params[param]] = (setting_name, setting_value)
-         else:
-            #find out how many args this parameter has
-            no_dashes = vmp_params[param]
-            count = cmd_line[no_dashes]['count']
-            param_args = []
-            if count > 0:
-               for argh in range(0,count):
-                  param_args.append(vmp_queue.popleft())
-            #the parameter name is the key, the (possibly empty) list of args is the value
-            cli_overrides[vmp_params[param]] = param_args
-            
-   #to prevent KeyErrors on missing keys, set the remainder to None
-   for key in vmp_params:
-      if key != '--set':
-         try:
-            cli_overrides[key]
-         except KeyError:
-            cli_overrides[key] = None
-      else:
-         cli_overrides["--set"] = {}
-         for arg in vmp_setters:
-            try:
-               cli_overrides[key][arg]
-            except KeyError:
-               cli_overrides[key][arg] = None
-   return cli_overrides
-   
-#main entry point   
-#this and a few other update manager methods really should be refactored into a util lib
-parent_dir = update_manager.get_parent_path(update_manager.get_platform_key())
-log_file_handle = update_manager.get_log_file_handle(parent_dir, 'launcher.log')
-
-executable_name = ""
-if sys.platform.startswith('darwin'):
-   executable_name = "Second Life"
-elif sys.platform.startswith("win") or sys.platform.startswith("cyg"):
-   if os.path.isfile(os.path.join(cwd,"SecondLifeViewer.exe")):
-      executable_name = "SecondLifeViewer.exe"
-   elif os.path.isfile(os.path.join(cwd,"SecondLifeTest.exe")):
-      executable_name = "SecondLifeTest.exe"
-   else:
-      sys.exit("Can't find Windows viewer binary")
-elif sys.platform.startswith("linux"):
-   executable_name = "secondlife"
-else:
-   #SL doesn't run on VMS or punch cards
-   sys.exit("Unsupported platform")
-   
-#find the viewer to be lauched
-viewer_binary = os.path.join(os.path.dirname(os.path.abspath(sys.argv[0])),executable_name) 
-
-parser = argparse.ArgumentParser()
-args = parser.parse_known_args(sys.argv)
-#args[1] looks like ['./SL_Launcher', '--set', 'foo', 'bar', '-X', '-Y', 'qux'], dump the progname
-args_list_to_pass = args[1][1:]
-vmp_args = capture_vmp_args(args_list_to_pass)
-#make a copy by value, not by reference
-command = list(args_list_to_pass)
-
-(success, state, condition) = update_manager.update_manager(vmp_args)
-# From update_manager:
-#  (False, 'setup', None): error occurred before we knew what the update was (e.g., in setup or parsing)
-#  (False, 'download', version): we failed to download the new version
-#  (False, 'apply', version): we failed to apply the new version
-#  (True, None, None): No update found
-#  (True, 'in place', True): update applied in place
-#  (True, 'in place', path_to_new_launcher): Update applied by a new install to a new location
-#  (True, 'background', True): background download initiated
-#These boil down three cases:
-#  Success is False, then pop up a message and launch the current viewer
-#  No update, update succeeded in place in foreground, or background update started: silently launch the current viewer channel
-#  Updated succeed to a different channel, launch that viewer and exit
-if not success:
-   msg = 'Update failed in the %s process.  Please check logs.  Viewer will launch starting momentarily.' % state
-   update_manager.after_frame(msg)
-   command.insert(0,viewer_binary)
-   viewer_process = subprocess.Popen(command)
-   #at the moment, we just exit here.  Later, the crash monitor will be launched at this point
-elif (success == True and 
-      (state == None 
-       or (state ==  'background' and condition == True)
-       or (state == 'in_place' and condition == True))):
-   command.insert(0,viewer_binary)
-   viewer_process = subprocess.Popen(command)
-   #at the moment, we just exit here.  Later, the crash monitor will be launched at this point
-else:
-   #'condition' is the path to the new launcher.
-   command.insert(0,condition)
-   viewer_process = subprocess.Popen(command)
-   sys.exit(0)
diff --git a/indra/viewer_components/manager/apply_update.py b/indra/viewer_components/manager/apply_update.py
deleted file mode 100755
index 643e4ad2bc4d732c61086029b414bd45d568e50e..0000000000000000000000000000000000000000
--- a/indra/viewer_components/manager/apply_update.py
+++ /dev/null
@@ -1,277 +0,0 @@
-#!/usr/bin/env python
-
-# Copyright (c) 2016, Linden Research, Inc.
-# 
-# The following source code is PROPRIETARY AND CONFIDENTIAL. Use of
-# this source code is governed by the Linden Lab Source Code Disclosure
-# Agreement ("Agreement") previously entered between you and Linden
-# Lab. By accessing, using, copying, modifying or distributing this
-# software, you acknowledge that you have been informed of your
-# obligations under the Agreement and agree to abide by those obligations.
-# 
-# ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
-# WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
-# COMPLETENESS OR PERFORMANCE.
-# $LicenseInfo:firstyear=2016&license=viewerlgpl$
-# Copyright (c) 2016, Linden Research, Inc.
-# $/LicenseInfo$
-
-"""
-@file   apply_update.py
-@author coyot
-@date   2016-06-28
-"""
-
-"""
-Applies an already downloaded update.
-"""
-
-import argparse
-import errno
-import fnmatch
-import InstallerUserMessage as IUM
-import os
-import os.path
-import plistlib
-import re
-import shutil
-import subprocess
-import sys
-import tarfile
-import tempfile
-
-#Module level variables
-
-#fnmatch expressions
-LNX_REGEX = '*' + '.bz2'
-MAC_REGEX = '*' + '.dmg'
-MAC_APP_REGEX = '*' + '.app'
-WIN_REGEX = '*' + '.exe'
-
-#which install the updater is run from
-INSTALL_DIR = os.path.abspath(os.path.dirname(os.path.realpath(__file__)))
-
-#whether the update is to the INSTALL_DIR or not.  Most of the time this is the case.
-IN_PLACE = True
-
-BUNDLE_IDENTIFIER = "com.secondlife.indra.viewer"
-# Magic OS directory name that causes Cocoa viewer to crash on OS X 10.7.5
-# (see MAINT-3331)
-STATE_DIR = os.path.join(os.environ["HOME"], "Library", "Saved Application State",
-    BUNDLE_IDENTIFIER + ".savedState")
-
-def silent_write(log_file_handle, text):
-    #if we have a log file, write.  If not, do nothing.
-    if (log_file_handle):
-        #prepend text for easy grepping
-        log_file_handle.write("APPLY UPDATE: " + text + "\n")
-
-def get_filename(download_dir = None):
-    #given a directory that supposedly has the download, find the installable
-    #if you are on platform X and you give the updater a directory with an installable  
-    #for platform Y, you are either trying something fancy or get what you deserve
-    #or both
-    for filename in os.listdir(download_dir):
-        if (fnmatch.fnmatch(filename, LNX_REGEX) 
-          or fnmatch.fnmatch(filename, MAC_REGEX) 
-          or fnmatch.fnmatch(filename, WIN_REGEX)):            
-            return os.path.join(download_dir, filename)
-    #someone gave us a bad directory
-    return None  
-          
-def try_dismount(log_file_handle = None, installable = None, tmpdir = None):
-    #best effort cleanup try to dismount the dmg file if we have mounted one
-    #the French judge gave it a 5.8
-    try:
-        #use the df command to find the device name
-        #Filesystem   512-blocks   Used Available Capacity iused  ifree %iused  Mounted on
-        #/dev/disk1s2    2047936 643280   1404656    32%   80408 175582   31%   /private/tmp/mnt/Second Life Installer
-        command = ["df", os.path.join(tmpdir, "Second Life Installer")]
-        output = subprocess.check_output(command)
-        #first word of second line of df output is the device name
-        mnt_dev = output.split('\n')[1].split()[0]
-        #do the dismount
-        command = ["hdiutil", "detach", "-force", mnt_dev]
-        output = subprocess.check_output(command)
-        silent_write(log_file_handle, "hdiutil detach succeeded")
-        silent_write(log_file_handle, output)
-    except Exception, e:
-        silent_write(log_file_handle, "Could not detach dmg file %s.  Error messages: %s" % (installable, e.message))    
-
-def apply_update(download_dir = None, platform_key = None, log_file_handle = None, in_place = True):
-    #for lnx and mac, returns path to newly installed viewer
-    #for win, return the name of the executable
-    #returns None on failure for all three
-    #throws an exception if it can't find an installable at all
-    
-    IN_PLACE = in_place
-    
-    installable = get_filename(download_dir)
-    if not installable:
-        #could not find the download
-        raise ValueError("Could not find installable in " + download_dir)
-    
-    #apply update using the platform specific tools
-    if platform_key == 'lnx':
-        installed = apply_linux_update(installable, log_file_handle)
-    elif platform_key == 'mac':
-        installed = apply_mac_update(installable, log_file_handle)
-    elif platform_key == 'win':
-        installed = apply_windows_update(installable, log_file_handle)
-    else:
-        #wtf?
-        raise ValueError("Unknown Platform: " + platform_key)
-    
-    if not installed:
-        #only mark the download as done when everything is done
-        done_filename = os.path.join(os.path.dirname(installable), ".done")
-        open(done_filename, 'w+').close()
-        
-    return installed
-    
-def apply_linux_update(installable = None, log_file_handle = None):
-    try:
-        #untar to tmpdir
-        tmpdir = tempfile.mkdtemp()
-        tar = tarfile.open(name = installable, mode="r:bz2")
-        tar.extractall(path = tmpdir)
-        if IN_PLACE:
-            #rename current install dir
-            shutil.move(INSTALL_DIR,install_dir + ".bak")
-        #mv new to current
-        shutil.move(tmpdir, INSTALL_DIR)
-        #delete tarball on success
-        os.remove(installable)
-    except Exception, e:
-        silent_write(log_file_handle, "Update failed due to " + repr(e))
-        return None
-    return INSTALL_DIR
-
-def apply_mac_update(installable = None, log_file_handle = None):
-    #INSTALL_DIR is something like /Applications/Second Life Viewer.app/Contents/MacOS, need to jump up two levels for the install base
-    install_base = os.path.dirname(INSTALL_DIR)
-    install_base = os.path.dirname(install_base)
-    
-    #verify dmg file
-    try:
-        output = subprocess.check_output(["hdiutil", "verify", installable], stderr=subprocess.STDOUT)
-        silent_write(log_file_handle, "dmg verification succeeded")
-        silent_write(log_file_handle, output)
-    except Exception, e:
-        silent_write(log_file_handle, "Could not verify dmg file %s.  Error messages: %s" % (installable, e.message))
-        return None
-    #make temp dir and mount & attach dmg
-    tmpdir = tempfile.mkdtemp()
-    try:
-        output = subprocess.check_output(["hdiutil", "attach", installable, "-mountroot", tmpdir])
-        silent_write(log_file_handle, "hdiutil attach succeeded")
-        silent_write(log_file_handle, output)
-    except Exception, e:
-        silent_write(log_file_handle, "Could not attach dmg file %s.  Error messages: %s" % (installable, e.message))
-        return None
-    #verify plist
-    mounted_appdir = None
-    for top_dir in os.listdir(tmpdir):
-        for appdir in os.listdir(os.path.join(tmpdir, top_dir)):
-            appdir = os.path.join(os.path.join(tmpdir, top_dir), appdir)
-            if fnmatch.fnmatch(appdir, MAC_APP_REGEX):
-                try:
-                    plist = os.path.join(appdir, "Contents", "Info.plist")
-                    CFBundleIdentifier = plistlib.readPlist(plist)["CFBundleIdentifier"]
-                    mounted_appdir = appdir
-                except:
-                    #there is no except for this try because there are multiple directories that legimately don't have what we are looking for
-                    pass
-    if not mounted_appdir:
-        silent_write(log_file_handle, "Could not find app bundle in dmg %s." % (installable,))
-        return None        
-    if CFBundleIdentifier != BUNDLE_IDENTIFIER:
-        silent_write(log_file_handle, "Wrong or null bundle identifier for dmg %s.  Bundle identifier: %s" % (installable, CFBundleIdentifier))
-        try_dismount(log_file_handle, installable, tmpdir)                   
-        return None
-    #do the install, finally
-    if IN_PLACE:
-        #  swap out old install directory
-        bundlename = os.path.basename(mounted_appdir)
-        silent_write(log_file_handle, "Updating %s" % bundlename)
-        swapped_out = os.path.join(tmpdir, INSTALL_DIR.lstrip('/'))
-        shutil.move(install_base, swapped_out)               
-    else:
-        silent_write(log_file_handle, "Installing %s" % install_base)
-        
-    #   copy over the new bits    
-    try:
-        shutil.copytree(mounted_appdir, install_base, symlinks=True)
-        retcode = 0
-    except Exception, e:
-        # try to restore previous viewer
-        if os.path.exists(swapped_out):
-            silent_write(log_file_handle, "Install of %s failed, rolling back to previous viewer." % installable)
-            shutil.move(swapped_out, installed_test)
-            retcode = 1
-    finally:
-        try_dismount(log_file_handle, installable, tmpdir)
-        if retcode:
-            return None
-    
-    #see MAINT-3331        
-    try:
-        shutil.rmtree(STATE_DIR)  
-    except Exception, e:
-        #if we fail to delete something that isn't there, that's okay
-        if e[0] == errno.ENOENT:
-            pass
-        else:
-            raise e
-    
-    os.remove(installable)
-    return install_base
-    
-def apply_windows_update(installable = None, log_file_handle = None):
-    #the windows install is just running the NSIS installer executable
-    #from VMP's perspective, it is a black box
-    try:
-        output = subprocess.check_output(installable, stderr=subprocess.STDOUT)
-        silent_write(log_file_handle, "Install of %s succeeded." % installable)
-        silent_write(log_file_handle, output)
-    except subprocess.CalledProcessError, cpe:
-        silent_write(log_file_handle, "%s failed with return code %s. Error messages: %s." % 
-                     (cpe.cmd, cpe.returncode, cpe.message))
-        return None
-    #Due to the black box nature of the install, we have to derive the application path from the
-    #name of the installable.  This is essentially reverse-engineering app_name()/app_name_oneword()
-    #in viewer_manifest.py
-    #the format of the filename is:  Second_Life_{Project Name}_A-B-C-XXXXXX_i686_Setup.exe
-    #which deploys to C:\Program Files (x86)\SecondLifeProjectName\
-    #so we want all but the last four phrases and tack on Viewer if there is no project
-    if re.search('Project', installable):
-        winstall = os.path.join("C:\\Program Files (x86)\\", "".join(installable.split("_")[:-3]))
-    else:
-        winstall = os.path.join("C:\\Program Files (x86)\\", "".join(installable.split("_")[:-3])+"Viewer")
-    return winstall
-
-def main():
-    parser = argparse.ArgumentParser("Apply Downloaded Update")
-    parser.add_argument('--dir', dest = 'download_dir', help = 'directory to find installable', required = True)
-    parser.add_argument('--pkey', dest = 'platform_key', help =' OS: lnx|mac|win', required = True)
-    parser.add_argument('--in_place', action = 'store_false', help = 'This upgrade is for a different channel', default = True)
-    parser.add_argument('--log_file', dest = 'log_file', default = None, help = 'file to write messages to')
-    args = parser.parse_args()
-    
-    if args.log_file:
-        try:
-            f = open(args.log_file,'w+') 
-        except:
-            print "%s could not be found or opened" % args.log_file
-            sys.exit(1)
-    
-    IN_PLACE = args.in_place
-    result = apply_update(download_dir = args.download_dir, platform_key = args.platform_key, log_file_handle = f)
-    if not result:
-        sys.exit("Update failed")
-    else:
-        sys.exit(0)
-
-
-if __name__ == "__main__":
-    main()
diff --git a/indra/viewer_components/manager/download_update.py b/indra/viewer_components/manager/download_update.py
deleted file mode 100755
index a5e365fa37b41663be28621b43b8dae9e01ac901..0000000000000000000000000000000000000000
--- a/indra/viewer_components/manager/download_update.py
+++ /dev/null
@@ -1,105 +0,0 @@
-#!/usr/bin/env python
-
-# Copyright (c) 2016, Linden Research, Inc.
-# 
-# The following source code is PROPRIETARY AND CONFIDENTIAL. Use of
-# this source code is governed by the Linden Lab Source Code Disclosure
-# Agreement ("Agreement") previously entered between you and Linden
-# Lab. By accessing, using, copying, modifying or distributing this
-# software, you acknowledge that you have been informed of your
-# obligations under the Agreement and agree to abide by those obligations.
-# 
-# ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
-# WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
-# COMPLETENESS OR PERFORMANCE.
-# $LicenseInfo:firstyear=2016&license=viewerlgpl$
-# Copyright (c) 2016, Linden Research, Inc.
-# $/LicenseInfo$
-
-"""
-@file   download_update.py
-@author coyot
-@date   2016-06-23
-"""
-
-"""
-Performs a download of an update.  In a separate script from update_manager so that we can
-call it with subprocess.
-"""
-
-import argparse
-import InstallerUserMessage as IUM
-import os
-import Queue
-import requests
-import threading
-
-#module default
-CHUNK_SIZE = 1024
-
-def download_update(url = None, download_dir = None, size = None, progressbar = False, chunk_size = CHUNK_SIZE):
-    #url to download from
-    #download_dir to download to
-    #total size (for progressbar) of download
-    #progressbar: whether to display one (not used for background downloads)
-    #chunk_size is in bytes, amount to download at once
-    
-    queue = Queue.Queue()
-    if not os.path.exists(download_dir):
-        os.makedirs(download_dir)
-    #the url split provides the basename of the filename
-    filename = os.path.join(download_dir, url.split('/')[-1])
-    req = requests.get(url, stream=True)
-    down_thread = ThreadedDownload(req, filename, chunk_size, progressbar, queue)
-    down_thread.start()
-    
-    if progressbar:
-        frame = IUM.InstallerUserMessage(title = "Second Life Downloader", icon_name="head-sl-logo.gif")
-        frame.progress_bar(message = "Download Progress", size = size, pb_queue = queue)
-        frame.mainloop()
-    else:
-        #nothing for the main thread to do
-        down_thread.join()
-
-class ThreadedDownload(threading.Thread):
-    def __init__(self, req, filename, chunk_size, progressbar, in_queue):
-        #req is a python request object
-        #target filename to download to
-        #chunk_size is in bytes, amount to download at once
-        #progressbar: whether to display one (not used for background downloads)
-        #in_queue mediates communication between this thread and the progressbar
-        threading.Thread.__init__(self)
-        self.req = req
-        self.filename = filename
-        self.chunk_size = int(chunk_size)
-        self.progressbar = progressbar
-        self.in_queue = in_queue
-        
-    def run(self):
-        with open(self.filename, 'wb') as fd:
-            #keep downloading until we run out of chunks, then download the last bit
-            for chunk in self.req.iter_content(self.chunk_size):
-                fd.write(chunk)
-                if self.progressbar:
-                    #this will increment the progress bar by len(chunk)/size units
-                    self.in_queue.put(len(chunk))  
-            #signal value saying to the progress bar that it is done and can destroy itself
-            #if len(chunk) is ever -1, we get to file a bug against Python
-            self.in_queue.put(-1)
-
-def main():
-    #main method is for standalone use such as support and QA
-    #VMP will import this module and run download_update directly
-    parser = argparse.ArgumentParser("Download URI to directory")
-    parser.add_argument('--url', dest='url', help='URL of file to be downloaded', required=True)
-    parser.add_argument('--dir', dest='download_dir', help='directory to be downloaded to', required=True)
-    parser.add_argument('--pb', dest='progressbar', help='whether or not to show a progressbar', action="store_true", default = False)
-    parser.add_argument('--size', dest='size', help='size of download for progressbar')
-    parser.add_argument('--chunk_size', dest='chunk_size', default=CHUNK_SIZE, help='max portion size of download to be loaded in memory in bytes.')
-    args = parser.parse_args()
-
-    download_update(url = args.url, download_dir = args.download_dir, size = args.size, progressbar = args.progressbar, chunk_size = args.chunk_size)
-
-
-if __name__ == "__main__":
-    main()
diff --git a/indra/viewer_components/manager/tests/data/settings.xml b/indra/viewer_components/manager/tests/data/settings.xml
deleted file mode 100644
index 07e420dcb31e26eeea25b4c955c5fd69f325e4ef..0000000000000000000000000000000000000000
--- a/indra/viewer_components/manager/tests/data/settings.xml
+++ /dev/null
@@ -1,1184 +0,0 @@
-<llsd>
-    <map>
-    <key>AllowMultipleViewers</key>
-        <map>
-        <key>Comment</key>
-            <string>Allow multiple viewers.</string>
-        <key>Type</key>
-            <string>Boolean</string>
-        <key>Value</key>
-            <integer>1</integer>
-        </map>
-    <key>AllowTapTapHoldRun</key>
-        <map>
-        <key>Comment</key>
-            <string>Tapping a direction key twice and holding it down makes avatar run</string>
-        <key>Type</key>
-            <string>Boolean</string>
-        <key>Value</key>
-            <integer>0</integer>
-        </map>
-    <key>AppearanceCameraMovement</key>
-        <map>
-        <key>Comment</key>
-            <string>When entering appearance editing mode, camera zooms in on currently selected portion of avatar</string>
-        <key>Type</key>
-            <string>Boolean</string>
-        <key>Value</key>
-            <integer>0</integer>
-        </map>
-    <key>AudioLevelMedia</key>
-        <map>
-        <key>Comment</key>
-            <string>Audio level of Quicktime movies</string>
-        <key>Type</key>
-            <string>F32</string>
-        <key>Value</key>
-            <real>0.699999988079071044921875</real>
-        </map>
-    <key>AudioLevelMic</key>
-        <map>
-        <key>Comment</key>
-            <string>Audio level of microphone input</string>
-        <key>Type</key>
-            <string>F32</string>
-        <key>Value</key>
-            <real>0.1749999970197677612304688</real>
-        </map>
-    <key>AudioLevelMusic</key>
-        <map>
-        <key>Comment</key>
-            <string>Audio level of streaming music</string>
-        <key>Type</key>
-            <string>F32</string>
-        <key>Value</key>
-            <real>0</real>
-        </map>
-    <key>AudioLevelSFX</key>
-        <map>
-        <key>Comment</key>
-            <string>Audio level of in-world sound effects</string>
-        <key>Type</key>
-            <string>F32</string>
-        <key>Value</key>
-            <real>0.699999988079071044921875</real>
-        </map>
-    <key>AudioLevelVoice</key>
-        <map>
-        <key>Comment</key>
-            <string>Audio level of voice chat</string>
-        <key>Type</key>
-            <string>F32</string>
-        <key>Value</key>
-            <real>1</real>
-        </map>
-    <key>AudioStreamingMedia</key>
-        <map>
-        <key>Comment</key>
-            <string>Enable streaming</string>
-        <key>Type</key>
-            <string>Boolean</string>
-        <key>Value</key>
-            <integer>0</integer>
-        </map>
-    <key>AvatarAxisDeadZone0</key>
-        <map>
-        <key>Comment</key>
-            <string>Avatar axis 0 dead zone.</string>
-        <key>Type</key>
-            <string>F32</string>
-        <key>Value</key>
-            <real>0.1000000014901161193847656</real>
-        </map>
-    <key>AvatarAxisDeadZone1</key>
-        <map>
-        <key>Comment</key>
-            <string>Avatar axis 1 dead zone.</string>
-        <key>Type</key>
-            <string>F32</string>
-        <key>Value</key>
-            <real>0.1000000014901161193847656</real>
-        </map>
-    <key>AvatarAxisDeadZone2</key>
-        <map>
-        <key>Comment</key>
-            <string>Avatar axis 2 dead zone.</string>
-        <key>Type</key>
-            <string>F32</string>
-        <key>Value</key>
-            <real>0.1000000014901161193847656</real>
-        </map>
-    <key>AvatarAxisDeadZone3</key>
-        <map>
-        <key>Comment</key>
-            <string>Avatar axis 3 dead zone.</string>
-        <key>Type</key>
-            <string>F32</string>
-        <key>Value</key>
-            <real>1</real>
-        </map>
-    <key>AvatarAxisDeadZone4</key>
-        <map>
-        <key>Comment</key>
-            <string>Avatar axis 4 dead zone.</string>
-        <key>Type</key>
-            <string>F32</string>
-        <key>Value</key>
-            <real>0.01999999955296516418457031</real>
-        </map>
-    <key>AvatarAxisDeadZone5</key>
-        <map>
-        <key>Comment</key>
-            <string>Avatar axis 5 dead zone.</string>
-        <key>Type</key>
-            <string>F32</string>
-        <key>Value</key>
-            <real>0.009999999776482582092285156</real>
-        </map>
-    <key>AvatarAxisScale3</key>
-        <map>
-        <key>Comment</key>
-            <string>Avatar axis 3 scaler.</string>
-        <key>Type</key>
-            <string>F32</string>
-        <key>Value</key>
-            <real>0</real>
-        </map>
-    <key>AvatarAxisScale4</key>
-        <map>
-        <key>Comment</key>
-            <string>Avatar axis 4 scaler.</string>
-        <key>Type</key>
-            <string>F32</string>
-        <key>Value</key>
-            <real>2</real>
-        </map>
-    <key>AvatarAxisScale5</key>
-        <map>
-        <key>Comment</key>
-            <string>Avatar axis 5 scaler.</string>
-        <key>Type</key>
-            <string>F32</string>
-        <key>Value</key>
-            <real>2</real>
-        </map>
-    <key>AvatarFeathering</key>
-        <map>
-        <key>Comment</key>
-            <string>Avatar feathering (less is softer)</string>
-        <key>Type</key>
-            <string>F32</string>
-        <key>Value</key>
-            <real>6</real>
-        </map>
-    <key>AvatarFileName</key>
-        <map>
-        <key>Comment</key>
-            <string>Alternative avatar file name</string>
-        <key>Type</key>
-            <string>String</string>
-        <key>Value</key>
-            <string>avatar_lad_tentacles.xml</string>
-        </map>
-    <key>BuildAxisDeadZone0</key>
-        <map>
-        <key>Comment</key>
-            <string>Build axis 0 dead zone.</string>
-        <key>Type</key>
-            <string>F32</string>
-        <key>Value</key>
-            <real>0.009999999776482582092285156</real>
-        </map>
-    <key>BuildAxisDeadZone1</key>
-        <map>
-        <key>Comment</key>
-            <string>Build axis 1 dead zone.</string>
-        <key>Type</key>
-            <string>F32</string>
-        <key>Value</key>
-            <real>0.009999999776482582092285156</real>
-        </map>
-    <key>BuildAxisDeadZone2</key>
-        <map>
-        <key>Comment</key>
-            <string>Build axis 2 dead zone.</string>
-        <key>Type</key>
-            <string>F32</string>
-        <key>Value</key>
-            <real>0.009999999776482582092285156</real>
-        </map>
-    <key>BuildAxisDeadZone3</key>
-        <map>
-        <key>Comment</key>
-            <string>Build axis 3 dead zone.</string>
-        <key>Type</key>
-            <string>F32</string>
-        <key>Value</key>
-            <real>0.009999999776482582092285156</real>
-        </map>
-    <key>BuildAxisDeadZone4</key>
-        <map>
-        <key>Comment</key>
-            <string>Build axis 4 dead zone.</string>
-        <key>Type</key>
-            <string>F32</string>
-        <key>Value</key>
-            <real>0.009999999776482582092285156</real>
-        </map>
-    <key>BuildAxisDeadZone5</key>
-        <map>
-        <key>Comment</key>
-            <string>Build axis 5 dead zone.</string>
-        <key>Type</key>
-            <string>F32</string>
-        <key>Value</key>
-            <real>0.009999999776482582092285156</real>
-        </map>
-    <key>BuildAxisScale0</key>
-        <map>
-        <key>Comment</key>
-            <string>Build axis 0 scaler.</string>
-        <key>Type</key>
-            <string>F32</string>
-        <key>Value</key>
-            <real>6</real>
-        </map>
-    <key>BuildAxisScale1</key>
-        <map>
-        <key>Comment</key>
-            <string>Build axis 1 scaler.</string>
-        <key>Type</key>
-            <string>F32</string>
-        <key>Value</key>
-            <real>6</real>
-        </map>
-    <key>BuildAxisScale2</key>
-        <map>
-        <key>Comment</key>
-            <string>Build axis 2 scaler.</string>
-        <key>Type</key>
-            <string>F32</string>
-        <key>Value</key>
-            <real>6</real>
-        </map>
-    <key>BuildAxisScale3</key>
-        <map>
-        <key>Comment</key>
-            <string>Build axis 3 scaler.</string>
-        <key>Type</key>
-            <string>F32</string>
-        <key>Value</key>
-            <real>6</real>
-        </map>
-    <key>BuildAxisScale4</key>
-        <map>
-        <key>Comment</key>
-            <string>Build axis 4 scaler.</string>
-        <key>Type</key>
-            <string>F32</string>
-        <key>Value</key>
-            <real>6</real>
-        </map>
-    <key>BuildAxisScale5</key>
-        <map>
-        <key>Comment</key>
-            <string>Build axis 5 scaler.</string>
-        <key>Type</key>
-            <string>F32</string>
-        <key>Value</key>
-            <real>6</real>
-        </map>
-    <key>BuildFeathering</key>
-        <map>
-        <key>Comment</key>
-            <string>Build feathering (less is softer)</string>
-        <key>Type</key>
-            <string>F32</string>
-        <key>Value</key>
-            <real>12</real>
-        </map>
-    <key>BulkChangeEveryoneCopy</key>
-        <map>
-        <key>Comment</key>
-            <string>Bulk changed objects can be copied by everyone</string>
-        <key>Type</key>
-            <string>Boolean</string>
-        <key>Value</key>
-            <boolean>1</boolean>
-        </map>
-    <key>BulkChangeNextOwnerCopy</key>
-        <map>
-        <key>Comment</key>
-            <string>Bulk changed objects can be copied by next owner</string>
-        <key>Type</key>
-            <string>Boolean</string>
-        <key>Value</key>
-            <boolean>1</boolean>
-        </map>
-    <key>BulkChangeNextOwnerModify</key>
-        <map>
-        <key>Comment</key>
-            <string>Bulk changed objects can be modified by next owner</string>
-        <key>Type</key>
-            <string>Boolean</string>
-        <key>Value</key>
-            <boolean>1</boolean>
-        </map>
-    <key>BulkChangeShareWithGroup</key>
-        <map>
-        <key>Comment</key>
-            <string>Bulk changed objects are shared with the currently active group</string>
-        <key>Type</key>
-            <string>Boolean</string>
-        <key>Value</key>
-            <boolean>1</boolean>
-        </map>
-    <key>CacheValidateCounter</key>
-        <map>
-        <key>Comment</key>
-            <string>Used to distribute cache validation</string>
-        <key>Type</key>
-            <string>U32</string>
-        <key>Value</key>
-            <integer>122</integer>
-        </map>
-    <key>CameraPosOnLogout</key>
-        <map>
-        <key>Comment</key>
-            <string>Camera position when last logged out (global coordinates)</string>
-        <key>Type</key>
-            <string>Vector3D</string>
-        <key>Value</key>
-            <array>
-                <real>288290.4477181434631347656</real>
-                <real>275988.5277819633483886719</real>
-                <real>49.10921102762222290039062</real>
-            </array>
-        </map>
-    <key>ClickToWalk</key>
-        <map>
-        <key>Comment</key>
-            <string>Click in world to walk to location</string>
-        <key>Type</key>
-            <string>Boolean</string>
-        <key>Value</key>
-            <boolean>0</boolean>
-        </map>
-    <key>ConversationSortOrder</key>
-        <map>
-        <key>Comment</key>
-            <string>Specifies sort key for conversations</string>
-        <key>Type</key>
-            <string>U32</string>
-        <key>Value</key>
-            <integer>0</integer>
-        </map>
-    <key>CurrentGrid</key>
-        <map>
-        <key>Comment</key>
-            <string>Currently Selected Grid</string>
-        <key>Type</key>
-            <string>String</string>
-        <key>Value</key>
-            <string>util.agni.lindenlab.com</string>
-        </map>
-    <key>Cursor3D</key>
-        <map>
-        <key>Comment</key>
-            <string>Treat Joystick values as absolute positions (not deltas).</string>
-        <key>Type</key>
-            <string>Boolean</string>
-        <key>Value</key>
-            <boolean>0</boolean>
-        </map>
-    <key>FirstLoginThisInstall</key>
-        <map>
-        <key>Comment</key>
-            <string>Specifies that you have not logged in with the viewer since you performed a clean install</string>
-        <key>Type</key>
-            <string>Boolean</string>
-        <key>Value</key>
-            <boolean>0</boolean>
-        </map>
-    <key>FirstRunThisInstall</key>
-        <map>
-        <key>Comment</key>
-            <string>Specifies that you have not run the viewer since you performed a clean install</string>
-        <key>Type</key>
-            <string>Boolean</string>
-        <key>Value</key>
-            <boolean>0</boolean>
-        </map>
-    <key>FlycamAxisDeadZone0</key>
-        <map>
-        <key>Comment</key>
-            <string>Flycam axis 0 dead zone.</string>
-        <key>Type</key>
-            <string>F32</string>
-        <key>Value</key>
-            <real>0.009999999776482582092285156</real>
-        </map>
-    <key>FlycamAxisDeadZone1</key>
-        <map>
-        <key>Comment</key>
-            <string>Flycam axis 1 dead zone.</string>
-        <key>Type</key>
-            <string>F32</string>
-        <key>Value</key>
-            <real>0.009999999776482582092285156</real>
-        </map>
-    <key>FlycamAxisDeadZone2</key>
-        <map>
-        <key>Comment</key>
-            <string>Flycam axis 2 dead zone.</string>
-        <key>Type</key>
-            <string>F32</string>
-        <key>Value</key>
-            <real>0.009999999776482582092285156</real>
-        </map>
-    <key>FlycamAxisDeadZone3</key>
-        <map>
-        <key>Comment</key>
-            <string>Flycam axis 3 dead zone.</string>
-        <key>Type</key>
-            <string>F32</string>
-        <key>Value</key>
-            <real>0.009999999776482582092285156</real>
-        </map>
-    <key>FlycamAxisDeadZone4</key>
-        <map>
-        <key>Comment</key>
-            <string>Flycam axis 4 dead zone.</string>
-        <key>Type</key>
-            <string>F32</string>
-        <key>Value</key>
-            <real>0.009999999776482582092285156</real>
-        </map>
-    <key>FlycamAxisDeadZone5</key>
-        <map>
-        <key>Comment</key>
-            <string>Flycam axis 5 dead zone.</string>
-        <key>Type</key>
-            <string>F32</string>
-        <key>Value</key>
-            <real>0.009999999776482582092285156</real>
-        </map>
-    <key>FlycamAxisDeadZone6</key>
-        <map>
-        <key>Comment</key>
-            <string>Flycam axis 6 dead zone.</string>
-        <key>Type</key>
-            <string>F32</string>
-        <key>Value</key>
-            <real>1</real>
-        </map>
-    <key>FlycamAxisScale0</key>
-        <map>
-        <key>Comment</key>
-            <string>Flycam axis 0 scaler.</string>
-        <key>Type</key>
-            <string>F32</string>
-        <key>Value</key>
-            <real>42</real>
-        </map>
-    <key>FlycamAxisScale1</key>
-        <map>
-        <key>Comment</key>
-            <string>Flycam axis 1 scaler.</string>
-        <key>Type</key>
-            <string>F32</string>
-        <key>Value</key>
-            <real>40</real>
-        </map>
-    <key>FlycamAxisScale2</key>
-        <map>
-        <key>Comment</key>
-            <string>Flycam axis 2 scaler.</string>
-        <key>Type</key>
-            <string>F32</string>
-        <key>Value</key>
-            <real>40</real>
-        </map>
-    <key>FlycamAxisScale3</key>
-        <map>
-        <key>Comment</key>
-            <string>Flycam axis 3 scaler.</string>
-        <key>Type</key>
-            <string>F32</string>
-        <key>Value</key>
-            <real>0</real>
-        </map>
-    <key>FlycamAxisScale4</key>
-        <map>
-        <key>Comment</key>
-            <string>Flycam axis 4 scaler.</string>
-        <key>Type</key>
-            <string>F32</string>
-        <key>Value</key>
-            <real>2</real>
-        </map>
-    <key>FlycamAxisScale5</key>
-        <map>
-        <key>Comment</key>
-            <string>Flycam axis 5 scaler.</string>
-        <key>Type</key>
-            <string>F32</string>
-        <key>Value</key>
-            <real>3</real>
-        </map>
-    <key>FlycamAxisScale6</key>
-        <map>
-        <key>Comment</key>
-            <string>Flycam axis 6 scaler.</string>
-        <key>Type</key>
-            <string>F32</string>
-        <key>Value</key>
-            <real>0</real>
-        </map>
-    <key>FlycamFeathering</key>
-        <map>
-        <key>Comment</key>
-            <string>Flycam feathering (less is softer)</string>
-        <key>Type</key>
-            <string>F32</string>
-        <key>Value</key>
-            <real>5</real>
-        </map>
-    <key>FocusPosOnLogout</key>
-        <map>
-        <key>Comment</key>
-            <string>Camera focus point when last logged out (global coordinates)</string>
-        <key>Type</key>
-            <string>Vector3D</string>
-        <key>Value</key>
-            <array>
-                <real>288287.8830481640761718154</real>
-                <real>275991.5973855691263452172</real>
-                <real>47.96361158013021963597566</real>
-            </array>
-        </map>
-    <key>ForceShowGrid</key>
-        <map>
-        <key>Comment</key>
-            <string>Always show grid dropdown on login screen</string>
-        <key>Type</key>
-            <string>Boolean</string>
-        <key>Value</key>
-            <integer>1</integer>
-        </map>
-    <key>HttpProxyType</key>
-        <map>
-        <key>Comment</key>
-            <string>Proxy type to use for HTTP operations</string>
-        <key>Type</key>
-            <string>String</string>
-        <key>Value</key>
-            <string>None</string>
-        </map>
-    <key>JoystickInitialized</key>
-        <map>
-        <key>Comment</key>
-            <string>Whether or not a joystick has been detected and initiailized.</string>
-        <key>Type</key>
-            <string>String</string>
-        <key>Value</key>
-            <string>UnknownDevice</string>
-        </map>
-    <key>LSLFindCaseInsensitivity</key>
-        <map>
-        <key>Comment</key>
-            <string>Use case insensitivity when searching in LSL editor</string>
-        <key>Type</key>
-            <string>Boolean</string>
-        <key>Value</key>
-            <integer>1</integer>
-        </map>
-    <key>LastFeatureVersion</key>
-        <map>
-        <key>Comment</key>
-            <string>[DO NOT MODIFY] Feature Table Version number for tracking rendering system changes</string>
-        <key>Type</key>
-            <string>S32</string>
-        <key>Value</key>
-            <integer>37</integer>
-        </map>
-    <key>LastGPUString</key>
-        <map>
-        <key>Comment</key>
-            <string>[DO NOT MODIFY] previous GPU id string for tracking hardware changes</string>
-        <key>Type</key>
-            <string>String</string>
-        <key>Value</key>
-            <string>NVIDIA Corporation NVIDIA GeForce GT 750M OpenGL Engine</string>
-        </map>
-    <key>LastPrefTab</key>
-        <map>
-        <key>Comment</key>
-            <string>Last selected tab in preferences window</string>
-        <key>Type</key>
-            <string>S32</string>
-        <key>Value</key>
-            <integer>1</integer>
-        </map>
-    <key>LastRunVersion</key>
-        <map>
-        <key>Comment</key>
-            <string>Version number of last instance of the viewer that you ran</string>
-        <key>Type</key>
-            <string>String</string>
-        <key>Value</key>
-            <string>Second Life Project Bento 5.0.0.315657</string>
-        </map>
-    <key>LocalCacheVersion</key>
-        <map>
-        <key>Comment</key>
-            <string>Version number of cache</string>
-        <key>Type</key>
-            <string>S32</string>
-        <key>Value</key>
-            <integer>7</integer>
-        </map>
-    <key>LoginLocation</key>
-        <map>
-        <key>Comment</key>
-            <string>Default Login location (&apos;last&apos;, &apos;home&apos;) preference</string>
-        <key>Type</key>
-            <string>String</string>
-        <key>Value</key>
-            <string>home</string>
-        </map>
-    <key>MapScale</key>
-        <map>
-        <key>Comment</key>
-            <string>World map zoom level (pixels per region)</string>
-        <key>Type</key>
-            <string>F32</string>
-        <key>Value</key>
-            <real>256</real>
-        </map>
-    <key>MaxJointsPerMeshObject</key>
-        <map>
-        <key>Comment</key>
-            <string>Maximum joints per rigged mesh object</string>
-        <key>Type</key>
-            <string>U32</string>
-        <key>Value</key>
-            <real>51</real>
-        </map>
-    <key>MediaEnablePopups</key>
-        <map>
-        <key>Comment</key>
-            <string>If true, enable targeted links and javascript in media to open new media browser windows without a prompt.</string>
-        <key>Type</key>
-            <string>Boolean</string>
-        <key>Value</key>
-            <boolean>1</boolean>
-        </map>
-    <key>MediaShowOnOthers</key>
-        <map>
-        <key>Comment</key>
-            <string>Whether or not to show media on other avatars</string>
-        <key>Type</key>
-            <string>Boolean</string>
-        <key>Value</key>
-            <integer>1</integer>
-        </map>
-    <key>MigrateCacheDirectory</key>
-        <map>
-        <key>Comment</key>
-            <string>Check for old version of disk cache to migrate to current location</string>
-        <key>Type</key>
-            <string>Boolean</string>
-        <key>Value</key>
-            <boolean>0</boolean>
-        </map>
-    <key>NavBarShowParcelProperties</key>
-        <map>
-        <key>Comment</key>
-            <string>Show parcel property icons in navigation bar</string>
-        <key>Type</key>
-            <string>Boolean</string>
-        <key>Value</key>
-            <boolean>0</boolean>
-        </map>
-    <key>NextLoginLocation</key>
-        <map>
-        <key>Comment</key>
-            <string>Location to log into for this session - set from command line or the login panel, cleared following a successfull login.</string>
-        <key>Type</key>
-            <string>String</string>
-        <key>Value</key>
-            <string>home</string>
-        </map>
-    <key>NotificationConferenceIMOptions</key>
-        <map>
-        <key>Comment</key>
-            <string>
-        Specifies how the UI responds to Conference IM Notifications.
-        Allowed values: [openconversations,toast,flash,noaction]
-      </string>
-        <key>Type</key>
-            <string>String</string>
-        <key>Value</key>
-            <string>none</string>
-        </map>
-    <key>NotificationFriendIMOptions</key>
-        <map>
-        <key>Comment</key>
-            <string>
-        Specifies how the UI responds to Friend IM Notifications.
-        Allowed values: [openconversations,toast,flash,noaction]
-      </string>
-        <key>Type</key>
-            <string>String</string>
-        <key>Value</key>
-            <string>openconversations</string>
-        </map>
-    <key>NotificationGroupChatOptions</key>
-        <map>
-        <key>Comment</key>
-            <string>
-        Specifies how the UI responds to Group Chat Notifications.
-        Allowed values: [openconversations,toast,flash,noaction]
-      </string>
-        <key>Type</key>
-            <string>String</string>
-        <key>Value</key>
-            <string>none</string>
-        </map>
-    <key>NotificationNearbyChatOptions</key>
-        <map>
-        <key>Comment</key>
-            <string>
-        Specifies how the UI responds to Nearby Chat Notifications.
-        Allowed values: [openconversations,toast,flash,noaction]
-      </string>
-        <key>Type</key>
-            <string>String</string>
-        <key>Value</key>
-            <string>none</string>
-        </map>
-    <key>NotificationNonFriendIMOptions</key>
-        <map>
-        <key>Comment</key>
-            <string>
-        Specifies how the UI responds to Non Friend IM Notifications.
-        Allowed values: [openconversations,toast,flash,noaction]
-      </string>
-        <key>Type</key>
-            <string>String</string>
-        <key>Value</key>
-            <string>openconversations</string>
-        </map>
-    <key>NumSessions</key>
-        <map>
-        <key>Comment</key>
-            <string>Number of successful logins to Second Life</string>
-        <key>Type</key>
-            <string>S32</string>
-        <key>Value</key>
-            <integer>1674</integer>
-        </map>
-    <key>PlayTypingAnim</key>
-        <map>
-        <key>Comment</key>
-            <string>Your avatar plays the typing animation whenever you type in the chat bar</string>
-        <key>Type</key>
-            <string>Boolean</string>
-        <key>Value</key>
-            <integer>0</integer>
-        </map>
-    <key>PoolSizeExpCache</key>
-        <map>
-        <key>Comment</key>
-            <string>Coroutine Pool size for ExpCache</string>
-        <key>Type</key>
-            <string>U32</string>
-        <key>Value</key>
-            <integer>5</integer>
-        </map>
-    <key>PreferredBrowserBehavior</key>
-        <map>
-        <key>Comment</key>
-            <string>Use system browser for any links (0), use builtin browser for SL links and system one for others (1) or use builtin browser only (2).</string>
-        <key>Type</key>
-            <string>U32</string>
-        <key>Value</key>
-            <string>0</string>
-        </map>
-    <key>PreferredMaturity</key>
-        <map>
-        <key>Comment</key>
-            <string>Setting for the user&apos;s preferred maturity level (consts in indra_constants.h)</string>
-        <key>Type</key>
-            <string>U32</string>
-        <key>Value</key>
-            <integer>42</integer>
-        </map>
-    <key>PresetGraphicActive</key>
-        <map>
-        <key>Comment</key>
-            <string>Name of currently selected preference</string>
-        <key>Type</key>
-            <string>String</string>
-        <key>Value</key>
-            <string>Default</string>
-        </map>
-    <key>ProbeHardwareOnStartup</key>
-        <map>
-        <key>Comment</key>
-            <string>Query current hardware configuration on application startup</string>
-        <key>Type</key>
-            <string>Boolean</string>
-        <key>Value</key>
-            <boolean>0</boolean>
-        </map>
-    <key>QAMode</key>
-        <map>
-        <key>Comment</key>
-            <string>Enable Testing Features.</string>
-        <key>Type</key>
-            <string>Boolean</string>
-        <key>Value</key>
-            <boolean>1</boolean>
-        </map>
-    <key>RenderAnisotropic</key>
-        <map>
-        <key>Comment</key>
-            <string>Render textures using anisotropic filtering</string>
-        <key>Type</key>
-            <string>Boolean</string>
-        <key>Value</key>
-            <boolean>1</boolean>
-        </map>
-    <key>RenderAvatarCloth</key>
-        <map>
-        <key>Comment</key>
-            <string>Controls if avatars use wavy cloth</string>
-        <key>Type</key>
-            <string>Boolean</string>
-        <key>Value</key>
-            <boolean>0</boolean>
-        </map>
-    <key>RenderAvatarLODFactor</key>
-        <map>
-        <key>Comment</key>
-            <string>Controls level of detail of avatars (multiplier for current screen area when calculated level of detail)</string>
-        <key>Type</key>
-            <string>F32</string>
-        <key>Value</key>
-            <real>1</real>
-        </map>
-    <key>RenderFSAASamples</key>
-        <map>
-        <key>Comment</key>
-            <string>Number of samples to use for FSAA (0 = no AA).</string>
-        <key>Type</key>
-            <string>U32</string>
-        <key>Value</key>
-            <integer>2</integer>
-        </map>
-    <key>RenderFarClip</key>
-        <map>
-        <key>Comment</key>
-            <string>Distance of far clip plane from camera (meters)</string>
-        <key>Type</key>
-            <string>F32</string>
-        <key>Value</key>
-            <real>128</real>
-        </map>
-    <key>RenderMaxPartCount</key>
-        <map>
-        <key>Comment</key>
-            <string>Maximum number of particles to display on screen</string>
-        <key>Type</key>
-            <string>S32</string>
-        <key>Value</key>
-            <real>2048</real>
-        </map>
-    <key>RenderQualityPerformance</key>
-        <map>
-        <key>Comment</key>
-            <string>Which graphics settings you&apos;ve chosen</string>
-        <key>Type</key>
-            <string>U32</string>
-        <key>Value</key>
-            <real>4</real>
-        </map>
-    <key>RenderReflectionDetail</key>
-        <map>
-        <key>Comment</key>
-            <string>Detail of reflection render pass.</string>
-        <key>Type</key>
-            <string>S32</string>
-        <key>Value</key>
-            <integer>0</integer>
-        </map>
-    <key>RenderTerrainLODFactor</key>
-        <map>
-        <key>Comment</key>
-            <string>Controls level of detail of terrain (multiplier for current screen area when calculated level of detail)</string>
-        <key>Type</key>
-            <string>F32</string>
-        <key>Value</key>
-            <real>2</real>
-        </map>
-    <key>RenderVBOEnable</key>
-        <map>
-        <key>Comment</key>
-            <string>Use GL Vertex Buffer Objects</string>
-        <key>Type</key>
-            <string>Boolean</string>
-        <key>Value</key>
-            <boolean>0</boolean>
-        </map>
-    <key>RenderVolumeLODFactor</key>
-        <map>
-        <key>Comment</key>
-            <string>Controls level of detail of primitives (multiplier for current screen area when calculated level of detail)</string>
-        <key>Type</key>
-            <string>F32</string>
-        <key>Value</key>
-            <real>1.125</real>
-        </map>
-    <key>ShowAdvancedGraphicsSettings</key>
-        <map>
-        <key>Comment</key>
-            <string>Show advanced graphics settings</string>
-        <key>Type</key>
-            <string>Boolean</string>
-        <key>Value</key>
-            <integer>1</integer>
-        </map>
-    <key>ShowBanLines</key>
-        <map>
-        <key>Comment</key>
-            <string>Show in-world ban/access borders</string>
-        <key>Type</key>
-            <string>Boolean</string>
-        <key>Value</key>
-            <boolean>0</boolean>
-        </map>
-    <key>ShowStartLocation</key>
-        <map>
-        <key>Comment</key>
-            <string>Display starting location menu on login screen</string>
-        <key>Type</key>
-            <string>Boolean</string>
-        <key>Value</key>
-            <boolean>1</boolean>
-        </map>
-    <key>SkeletonFileName</key>
-        <map>
-        <key>Comment</key>
-            <string>Alternative skeleton file name</string>
-        <key>Type</key>
-            <string>String</string>
-        <key>Value</key>
-            <string>avatar_skeleton_tentacles.xml</string>
-        </map>
-    <key>SkyPresetName</key>
-        <map>
-        <key>Comment</key>
-            <string>Sky preset to use. May be superseded by region settings or by a day cycle (see DayCycleName).</string>
-        <key>Type</key>
-            <string>String</string>
-        <key>Value</key>
-            <string>Sunset</string>
-        </map>
-    <key>SnapshotConfigURL</key>
-        <map>
-        <key>Comment</key>
-            <string>URL to fetch Snapshot Sharing configuration data from.</string>
-        <key>Type</key>
-            <string>String</string>
-        <key>Value</key>
-            <string>http://photos.apps.avatarsunited.com/viewer_config</string>
-        </map>
-    <key>SnapshotFormat</key>
-        <map>
-        <key>Comment</key>
-            <string>Save snapshots in this format (0 = PNG, 1 = JPEG, 2 = BMP)</string>
-        <key>Type</key>
-            <string>S32</string>
-        <key>Value</key>
-            <integer>1</integer>
-        </map>
-    <key>SnapshotQuality</key>
-        <map>
-        <key>Comment</key>
-            <string>Quality setting of postcard JPEGs (0 = worst, 100 = best)</string>
-        <key>Type</key>
-            <string>S32</string>
-        <key>Value</key>
-            <integer>100</integer>
-        </map>
-    <key>SpellCheck</key>
-        <map>
-        <key>Comment</key>
-            <string>Enable spellchecking on line and text editors</string>
-        <key>Type</key>
-            <string>Boolean</string>
-        <key>Value</key>
-            <integer>0</integer>
-        </map>
-    <key>SpellCheckDictionary</key>
-        <map>
-        <key>Comment</key>
-            <string>Current primary and secondary dictionaries used for spell checking</string>
-        <key>Type</key>
-            <string>String</string>
-        <key>Value</key>
-            <string>English (United States)</string>
-        </map>
-    <key>TextureMemory</key>
-        <map>
-        <key>Comment</key>
-            <string>Amount of memory to use for textures in MB (0 = autodetect)</string>
-        <key>Type</key>
-            <string>S32</string>
-        <key>Value</key>
-            <integer>256</integer>
-        </map>
-    <key>UseDayCycle</key>
-        <map>
-        <key>Comment</key>
-            <string>Whether to use use a day cycle or a fixed sky.</string>
-        <key>Type</key>
-            <string>Boolean</string>
-        <key>Value</key>
-            <boolean>0</boolean>
-        </map>
-    <key>UseDebugMenus</key>
-        <map>
-        <key>Comment</key>
-            <string>Turns on &quot;Debug&quot; menu</string>
-        <key>Type</key>
-            <string>Boolean</string>
-        <key>Value</key>
-            <boolean>1</boolean>
-        </map>
-    <key>UseEnvironmentFromRegion</key>
-        <map>
-        <key>Comment</key>
-            <string>Choose whether to use the region&apos;s environment settings, or override them with the local settings.</string>
-        <key>Type</key>
-            <string>Boolean</string>
-        <key>Value</key>
-            <boolean>0</boolean>
-        </map>
-    <key>VFSOldSize</key>
-        <map>
-        <key>Comment</key>
-            <string>[DO NOT MODIFY] Controls resizing of local file cache</string>
-        <key>Type</key>
-            <string>U32</string>
-        <key>Value</key>
-            <integer>102</integer>
-        </map>
-    <key>VFSSalt</key>
-        <map>
-        <key>Comment</key>
-            <string>[DO NOT MODIFY] Controls local file caching behavior</string>
-        <key>Type</key>
-            <string>U32</string>
-        <key>Value</key>
-            <integer>260093998</integer>
-        </map>
-    <key>VersionChannelName</key>
-        <map>
-        <key>Comment</key>
-            <string>Version information generated by running the viewer</string>
-        <key>Type</key>
-            <string>String</string>
-        <key>Value</key>
-            <string>Second Life Release</string>
-        </map>
-    <key>VertexShaderEnable</key>
-        <map>
-        <key>Comment</key>
-            <string>Enable/disable all GLSL shaders (debug)</string>
-        <key>Type</key>
-            <string>Boolean</string>
-        <key>Value</key>
-            <boolean>1</boolean>
-        </map>
-    <key>VoiceInputAudioDevice</key>
-        <map>
-        <key>Comment</key>
-            <string>Audio input device to use for voice</string>
-        <key>Type</key>
-            <string>String</string>
-        <key>Value</key>
-            <string>C-Media USB Audio Device</string>
-        </map>
-    <key>VoiceOutputAudioDevice</key>
-        <map>
-        <key>Comment</key>
-            <string>Audio output device to use for voice</string>
-        <key>Type</key>
-            <string>String</string>
-        <key>Value</key>
-            <string>C-Media USB Audio Device</string>
-        </map>
-    <key>WLSkyDetail</key>
-        <map>
-        <key>Comment</key>
-            <string>Controls vertex detail on the WindLight sky.  Lower numbers will give better performance and uglier skies.</string>
-        <key>Type</key>
-            <string>U32</string>
-        <key>Value</key>
-            <integer>48</integer>
-        </map>
-    <key>WebProfileFloaterRect</key>
-        <map>
-        <key>Comment</key>
-            <string>Web profile floater dimensions</string>
-        <key>Type</key>
-            <string>Rect</string>
-        <key>Value</key>
-            <array>
-                <integer>1189</integer>
-                <integer>957</integer>
-                <integer>1674</integer>
-                <integer>277</integer>
-            </array>
-        </map>
-    <key>WindowHeight</key>
-        <map>
-        <key>Comment</key>
-            <string>SL viewer window height</string>
-        <key>Type</key>
-            <string>U32</string>
-        <key>Value</key>
-            <integer>1000</integer>
-        </map>
-    <key>WindowWidth</key>
-        <map>
-        <key>Comment</key>
-            <string>SL viewer window width</string>
-        <key>Type</key>
-            <string>U32</string>
-        <key>Value</key>
-            <integer>1626</integer>
-        </map>
-    <key>WindowX</key>
-        <map>
-        <key>Comment</key>
-            <string>X coordinate of upper left corner of SL viewer window, relative to upper left corner of primary display (pixels)</string>
-        <key>Type</key>
-            <string>S32</string>
-        <key>Value</key>
-            <integer>50</integer>
-        </map>
-    <key>WindowY</key>
-        <map>
-        <key>Comment</key>
-            <string>Y coordinate of upper left corner of SL viewer window, relative to upper left corner of primary display (pixels)</string>
-        <key>Type</key>
-            <string>S32</string>
-        <key>Value</key>
-            <integer>50</integer>
-        </map>
-    </map>
-</llsd>
diff --git a/indra/viewer_components/manager/tests/summary.json b/indra/viewer_components/manager/tests/summary.json
deleted file mode 100644
index b78859d427758d56322f9c1c67b5e7d8be411bdb..0000000000000000000000000000000000000000
--- a/indra/viewer_components/manager/tests/summary.json
+++ /dev/null
@@ -1 +0,0 @@
-{"Type":"viewer","Version":"4.0.5.315117","Channel":"Second Life Release"}
diff --git a/indra/viewer_components/manager/tests/test_InstallerError.py b/indra/viewer_components/manager/tests/test_InstallerError.py
deleted file mode 100644
index 9139447932130547e7425cba1bef10728a841ea2..0000000000000000000000000000000000000000
--- a/indra/viewer_components/manager/tests/test_InstallerError.py
+++ /dev/null
@@ -1,45 +0,0 @@
-#!/usr/bin/env python
-
-"""\
-@file   test_InstallerError.py
-@author coyot
-@date   2016-06-01
-
-$LicenseInfo:firstyear=2016&license=viewerlgpl$
-Second Life Viewer Source Code
-Copyright (C) 2016, Linden Research, Inc.
-
-This library is free software; you can redistribute it and/or
-modify it under the terms of the GNU Lesser General Public
-License as published by the Free Software Foundation;
-version 2.1 of the License only.
-
-This library is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-Lesser General Public License for more details.
-
-You should have received a copy of the GNU Lesser General Public
-License along with this library; if not, write to the Free Software
-Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
-
-Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
-$/LicenseInfo$
-"""
-
-
-from nose.tools import assert_equal
-
-import InstallerError
-import os
-
-def test_InstallerError():
-    try:
-        #try to make our own homedir, this will fail on all three platforms
-        homedir = os.path.abspath(os.path.expanduser('~'))
-        os.mkdir(homedir)
-    except OSError, oe:
-        ie = InstallerError.InstallerError(oe, "Installer failed to create a homedir that already exists.")
-
-    assert_equal( str(ie), 
-        "[Errno [Errno 17] File exists: '%s'] Installer failed to create a homedir that already exists." % homedir)
diff --git a/indra/viewer_components/manager/tests/test_check_for_completed_download.py b/indra/viewer_components/manager/tests/test_check_for_completed_download.py
deleted file mode 100644
index bcaaef4c3f0f12bbf351cfd4ac647499451fe09e..0000000000000000000000000000000000000000
--- a/indra/viewer_components/manager/tests/test_check_for_completed_download.py
+++ /dev/null
@@ -1,59 +0,0 @@
-#!/usr/bin/env python
-
-
-"""
-@file   test_check_for_completed_download.py
-@author coyot
-@date   2016-06-03
-
-$LicenseInfo:firstyear=2016&license=viewerlgpl$
-Second Life Viewer Source Code
-Copyright (C) 2016, Linden Research, Inc.
-
-This library is free software; you can redistribute it and/or
-modify it under the terms of the GNU Lesser General Public
-License as published by the Free Software Foundation;
-version 2.1 of the License only.
-
-This library is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-Lesser General Public License for more details.
-
-You should have received a copy of the GNU Lesser General Public
-License along with this library; if not, write to the Free Software
-Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
-
-Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
-$/LicenseInfo$
-"""
-
-from nose.tools import *
-from nose import with_setup
-
-import os
-import shutil
-import tempfile
-import update_manager
-import with_setup_args
-
-def check_for_completed_download_setup():
-    tmpdir1 = tempfile.mkdtemp(prefix = 'test1')
-    tmpdir2 = tempfile.mkdtemp(prefix = 'test2')
-    tempfile.mkstemp(suffix = '.done', dir = tmpdir1)
-
-    return [tmpdir1,tmpdir2], {}
-
-def check_for_completed_download_teardown(tmpdir1,tmpdir2):
-    shutil.rmtree(tmpdir1, ignore_errors = True)
-    shutil.rmtree(tmpdir2, ignore_errors = True)
-
-@with_setup_args.with_setup_args(check_for_completed_download_setup, check_for_completed_download_teardown)
-def test_completed_check_for_completed_download(tmpdir1,tmpdir2):
-    assert_equal(update_manager.check_for_completed_download(tmpdir1), 'done'), "Failed to find completion marker"
-
-@with_setup_args.with_setup_args(check_for_completed_download_setup, check_for_completed_download_teardown)
-def test_incomplete_check_for_completed_download(tmpdir1,tmpdir2):
-    #should return False
-    incomplete = not update_manager.check_for_completed_download(tmpdir2)
-    assert incomplete, "False positive, should not mark complete without a marker"
diff --git a/indra/viewer_components/manager/tests/test_convert_version_file_style.py b/indra/viewer_components/manager/tests/test_convert_version_file_style.py
deleted file mode 100644
index 244c22c458f90407b0b6e00da3a16647f6aea850..0000000000000000000000000000000000000000
--- a/indra/viewer_components/manager/tests/test_convert_version_file_style.py
+++ /dev/null
@@ -1,61 +0,0 @@
-#!/usr/bin/env python
-
-"""\
-@file   test_convert_version_file_style.py
-@author coyot
-@date   2016-06-01
-
-$LicenseInfo:firstyear=2016&license=viewerlgpl$
-Second Life Viewer Source Code
-Copyright (C) 2016, Linden Research, Inc.
-
-This library is free software; you can redistribute it and/or
-modify it under the terms of the GNU Lesser General Public
-License as published by the Free Software Foundation;
-version 2.1 of the License only.
-
-This library is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-Lesser General Public License for more details.
-
-You should have received a copy of the GNU Lesser General Public
-License along with this library; if not, write to the Free Software
-Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
-
-Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
-$/LicenseInfo$
-"""
-
-
-from nose.tools import assert_equal
-
-import update_manager
-
-def test_normal_form():
-    version = '1.2.3.456789'
-    golden = '1_2_3_456789'
-    converted = update_manager.convert_version_file_style(version)
-    
-    assert_equal(golden, converted)
-
-def test_short_form():
-    version = '1.23'
-    golden = '1_23'
-    converted = update_manager.convert_version_file_style(version)
-    
-    assert_equal(golden, converted)
-
-def test_idempotent():
-    version = '123'
-    golden = '123'
-    converted = update_manager.convert_version_file_style(version)
-    
-    assert_equal(golden, converted)
-
-def test_none():
-    version = None
-    golden = None
-    converted = update_manager.convert_version_file_style(version)
-    
-    assert_equal(golden, converted)
diff --git a/indra/viewer_components/manager/tests/test_get_filename.py b/indra/viewer_components/manager/tests/test_get_filename.py
deleted file mode 100644
index efb634937414cd1b63b5f4bb4140967f0b5e6e3e..0000000000000000000000000000000000000000
--- a/indra/viewer_components/manager/tests/test_get_filename.py
+++ /dev/null
@@ -1,66 +0,0 @@
-#!/usr/bin/env python
-
-
-"""
-@file   test_get_filename.py
-@author coyot
-@date   2016-06-30
-
-$LicenseInfo:firstyear=2016&license=viewerlgpl$
-Second Life Viewer Source Code
-Copyright (C) 2016, Linden Research, Inc.
-
-This library is free software; you can redistribute it and/or
-modify it under the terms of the GNU Lesser General Public
-License as published by the Free Software Foundation;
-version 2.1 of the License only.
-
-This library is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-Lesser General Public License for more details.
-
-You should have received a copy of the GNU Lesser General Public
-License along with this library; if not, write to the Free Software
-Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
-
-Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
-$/LicenseInfo$
-"""
-
-from nose.tools import *
-from nose import with_setup
-
-import os
-import shutil
-import tempfile
-import apply_update
-import with_setup_args
-
-def get_filename_setup():
-    tmpdir1 = tempfile.mkdtemp(prefix = 'lnx')
-    tmpdir2 = tempfile.mkdtemp(prefix = 'mac')
-    tmpdir3 = tempfile.mkdtemp(prefix = 'win')
-    tmpdir4 = tempfile.mkdtemp(prefix = 'bad')
-    tempfile.mkstemp(suffix = '.bz2', dir = tmpdir1)
-    tempfile.mkstemp(suffix = '.dmg', dir = tmpdir2)
-    tempfile.mkstemp(suffix = '.exe', dir = tmpdir3)
-
-    return [tmpdir1,tmpdir2, tmpdir3, tmpdir4], {}
-
-def get_filename_teardown(tmpdir1,tmpdir2, tmpdir3, tmpdir4):
-    shutil.rmtree(tmpdir1, ignore_errors = True)
-    shutil.rmtree(tmpdir2, ignore_errors = True)
-    shutil.rmtree(tmpdir3, ignore_errors = True)
-    shutil.rmtree(tmpdir4, ignore_errors = True)
-
-@with_setup_args.with_setup_args(get_filename_setup, get_filename_teardown)
-def test_get_filename(tmpdir1, tmpdir2, tmpdir3, tmpdir4):
-    assert_is_not_none(apply_update.get_filename(tmpdir1)), "Failed to find installable"
-    assert_is_not_none(apply_update.get_filename(tmpdir2)), "Failed to find installable"
-    assert_is_not_none(apply_update.get_filename(tmpdir3)), "Failed to find installable"
-
-@with_setup_args.with_setup_args(get_filename_setup, get_filename_teardown)
-def test_missing_get_filename(tmpdir1, tmpdir2, tmpdir3, tmpdir4):
-    not_found = not apply_update.get_filename(tmpdir4)
-    assert not_found, "False positive, should not find an installable in an empty dir"
diff --git a/indra/viewer_components/manager/tests/test_get_log_file_handle.py b/indra/viewer_components/manager/tests/test_get_log_file_handle.py
deleted file mode 100644
index 5ea821acf7ccb2f9862390d96f23da854c0a169d..0000000000000000000000000000000000000000
--- a/indra/viewer_components/manager/tests/test_get_log_file_handle.py
+++ /dev/null
@@ -1,68 +0,0 @@
-#!/usr/bin/env python
-
-"""
-@file   test_get_log_file_handle.py
-@author coyot
-@date   2016-06-08
-
-$LicenseInfo:firstyear=2016&license=viewerlgpl$
-Second Life Viewer Source Code
-Copyright (C) 2016, Linden Research, Inc.
-
-This library is free software; you can redistribute it and/or
-modify it under the terms of the GNU Lesser General Public
-License as published by the Free Software Foundation;
-version 2.1 of the License only.
-
-This library is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-Lesser General Public License for more details.
-
-You should have received a copy of the GNU Lesser General Public
-License along with this library; if not, write to the Free Software
-Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
-
-Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
-$/LicenseInfo$
-"""
-
-from nose.tools import *
-
-import os
-import shutil
-import tempfile
-import update_manager
-import with_setup_args
-
-def get_log_file_handle_setup():
-    tmpdir1 = tempfile.mkdtemp(prefix = 'test1')
-    tmpdir2 = tempfile.mkdtemp(prefix = 'test2')
-    log_file_path = os.path.abspath(os.path.join(tmpdir1,"update_manager.log"))
-    #not using tempfile because we want a particular filename
-    open(log_file_path, 'w+').close
-
-    return [tmpdir1,tmpdir2,log_file_path], {}
-
-def get_log_file_handle_teardown(tmpdir1,tmpdir2,log_file_path):
-    shutil.rmtree(tmpdir1, ignore_errors = True)
-    shutil.rmtree(tmpdir2, ignore_errors = True)
-    
-@with_setup_args.with_setup_args(get_log_file_handle_setup, get_log_file_handle_teardown)
-def test_existing_get_log_file_handle(tmpdir1,tmpdir2,log_file_path):
-    handle = update_manager.get_log_file_handle(tmpdir1)
-    if not handle:
-        print "Failed to find existing log file"
-        assert False
-    elif not os.path.exists(os.path.abspath(log_file_path+".old")):
-        print "Failed to rotate update manager log"
-        assert False
-    assert True
-    
-@with_setup_args.with_setup_args(get_log_file_handle_setup, get_log_file_handle_teardown)
-def test_missing_get_log_file_handle(tmpdir1,tmpdir2,log_file_path):
-    handle = update_manager.get_log_file_handle(tmpdir2)
-    if not os.path.exists(log_file_path):
-        print "Failed to touch new log file"
-        assert False
-    assert True
diff --git a/indra/viewer_components/manager/tests/test_get_parent_path.py b/indra/viewer_components/manager/tests/test_get_parent_path.py
deleted file mode 100644
index 6e4b9dfaff0fe67ed113c802e9831360e73889cb..0000000000000000000000000000000000000000
--- a/indra/viewer_components/manager/tests/test_get_parent_path.py
+++ /dev/null
@@ -1,83 +0,0 @@
-#!/usr/bin/env python
-
-
-"""
-@file   test_get_parent_path.py
-@author coyot
-@date   2016-06-02
-
-$LicenseInfo:firstyear=2016&license=viewerlgpl$
-Second Life Viewer Source Code
-Copyright (C) 2016, Linden Research, Inc.
-
-This library is free software; you can redistribute it and/or
-modify it under the terms of the GNU Lesser General Public
-License as published by the Free Software Foundation;
-version 2.1 of the License only.
-
-This library is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-Lesser General Public License for more details.
-
-You should have received a copy of the GNU Lesser General Public
-License along with this library; if not, write to the Free Software
-Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
-
-Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
-$/LicenseInfo$
-"""
-
-from nose.tools import *
-from nose import with_setup
-
-import os
-import shutil
-import update_manager
-import with_setup_args
-
-def get_parent_path_setup():
-    key = update_manager.get_platform_key()
-    try:
-        if key == 'mac':
-            settings_dir = os.path.join(os.path.expanduser('~'),'Library','Application Support','SecondLife')
-        elif key == 'lnx':
-            settings_dir = os.path.join(os.path.expanduser('~'),'.secondlife')
-        elif key == 'win':
-            settings_dir = os.path.join(os.path.expanduser('~'),'AppData','Roaming','SecondLife')
-        else:
-            raise Exception("Invalid Platform Key")
-
-        #preserve existing settings dir if any
-        if os.path.exists(settings_dir):
-            old_dir = settings_dir + ".tmp" 
-            if os.path.exists(old_dir):
-                shutil.rmtree(old_dir, ignore_errors = True)
-            os.rename(settings_dir, old_dir)
-        os.makedirs(settings_dir)
-    except Exception, e:
-        print "get_parent_path_setup failed due to: %s" % str(e)
-        assert False
-
-    #this is we don't have to rediscover settings_dir for test and teardown
-    return [settings_dir], {}
- 
-def get_parent_path_teardown(settings_dir):
-    try:
-        shutil.rmtree(settings_dir, ignore_errors = True)
-        #restore previous settings dir if any
-        old_dir = settings_dir + ".tmp"
-        if os.path.exists(old_dir):
-            os.rename(old_dir, settings_dir)
-    except:
-        #cleanup is best effort
-        pass
-
-@with_setup_args.with_setup_args(get_parent_path_setup, get_parent_path_teardown)
-def test_get_parent_path(settings_dir):
-    key = update_manager.get_platform_key()
-    got_settings_dir = update_manager.get_parent_path(key)
-    
-    assert settings_dir, "test_get_parent_path failed to obtain parent path"
-
-    assert_equal(settings_dir, got_settings_dir)
diff --git a/indra/viewer_components/manager/tests/test_get_platform_key.py b/indra/viewer_components/manager/tests/test_get_platform_key.py
deleted file mode 100644
index eeaca1dff7d515101b96b6c3ef467fff83d761bf..0000000000000000000000000000000000000000
--- a/indra/viewer_components/manager/tests/test_get_platform_key.py
+++ /dev/null
@@ -1,44 +0,0 @@
-#!/usr/bin/env python
-
-"""
-@file   test_get_platform_key.py
-@author coyot
-@date   2016-06-01
-
-$LicenseInfo:firstyear=2016&license=viewerlgpl$
-Second Life Viewer Source Code
-Copyright (C) 2016, Linden Research, Inc.
-
-This library is free software; you can redistribute it and/or
-modify it under the terms of the GNU Lesser General Public
-License as published by the Free Software Foundation;
-version 2.1 of the License only.
-
-This library is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-Lesser General Public License for more details.
-
-You should have received a copy of the GNU Lesser General Public
-License along with this library; if not, write to the Free Software
-Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
-
-Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
-$/LicenseInfo$
-"""
-
-from nose.tools import assert_equal
-
-import platform
-import update_manager
-
-def test_get_platform_key():
-    key = update_manager.get_platform_key()
-    if key == 'mac':
-        assert_equal(platform.system(),'Darwin')
-    elif key == 'lnx':
-        assert_equal(platform.system(),'Linux')
-    elif key == 'win':
-        assert_equal(platform.system(),'Windows')
-    else:
-        assert_equal(key, None)
diff --git a/indra/viewer_components/manager/tests/test_get_settings.py b/indra/viewer_components/manager/tests/test_get_settings.py
deleted file mode 100644
index 7efcf626730cc7f6f13298f6a4671e04a52ff19d..0000000000000000000000000000000000000000
--- a/indra/viewer_components/manager/tests/test_get_settings.py
+++ /dev/null
@@ -1,87 +0,0 @@
-#!/usr/bin/env python
-
-
-"""
-@file   test_get_settings.py
-@author coyot
-@date   2016-06-03
-
-$LicenseInfo:firstyear=2016&license=viewerlgpl$
-Second Life Viewer Source Code
-Copyright (C) 2016, Linden Research, Inc.
-
-This library is free software; you can redistribute it and/or
-modify it under the terms of the GNU Lesser General Public
-License as published by the Free Software Foundation;
-version 2.1 of the License only.
-
-This library is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-Lesser General Public License for more details.
-
-You should have received a copy of the GNU Lesser General Public
-License along with this library; if not, write to the Free Software
-Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
-
-Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
-$/LicenseInfo$
-"""
-
-from nose.tools import *
-from nose import with_setup
-
-import os
-import shutil
-import update_manager
-import with_setup_args
-
-def get_settings_setup():
-    try:
-        key = update_manager.get_platform_key()
-        settings_dir = os.path.join(update_manager.get_parent_path(key), "user_settings")
-        print settings_dir
-
-        #preserve existing settings dir if any
-        if os.path.exists(settings_dir):
-            old_dir = settings_dir + ".tmp"
-            if os.path.exists(old_dir):
-                shutil.rmtree(old_dir, ignore_errors = True)
-            os.rename(settings_dir, old_dir)  
-        os.makedirs(settings_dir)
-
-        #the data subdir of the tests dir that this script is in
-        data_dir = os.path.join(os.path.dirname(os.path.realpath(__file__)), "data")
-        #the test settings file
-        settings_file = os.path.join(data_dir, "settings.xml")
-        shutil.copyfile(settings_file, os.path.join(settings_dir, "settings.xml"))
-
-    except Exception, e:
-        print "get_settings_setup failed due to: %s" % str(e)
-        assert False
-
-    #this is we don't have to rediscover settings_dir for test and teardown
-    return [settings_dir], {}
- 
-def get_settings_teardown(settings_dir):
-    try:
-        shutil.rmtree(settings_dir, ignore_errors = True)
-        #restore previous settings dir if any
-        old_dir = settings_dir + ".tmp"
-        if os.path.exists(old_dir):
-            os.rename(old_dir, settings_dir)
-    except:
-        #cleanup is best effort
-        pass
-
-@with_setup_args.with_setup_args(get_settings_setup, get_settings_teardown)
-def test_get_settings(settings_dir):
-    key = update_manager.get_platform_key()
-    parent = update_manager.get_parent_path(key)
-    log_file = update_manager.get_log_file_handle(parent)
-    got_settings = update_manager.get_settings(log_file, parent)
-
-    assert got_settings, "test_get_settings failed to find a settings.xml file"
-
-    #test one key just to make sure it parsed
-    assert_equal(got_settings['CurrentGrid']['Value'], 'util.agni.lindenlab.com')
diff --git a/indra/viewer_components/manager/tests/test_make_VVM_UUID_hash.py b/indra/viewer_components/manager/tests/test_make_VVM_UUID_hash.py
deleted file mode 100644
index 5939e5806a3b94082973e5c17f5980c4b5de96de..0000000000000000000000000000000000000000
--- a/indra/viewer_components/manager/tests/test_make_VVM_UUID_hash.py
+++ /dev/null
@@ -1,47 +0,0 @@
-#!/usr/bin/env python
-
-
-"""
-@file   test_make_VVM_UUID_hash.py
-@author coyot
-@date   2016-06-03
-
-$LicenseInfo:firstyear=2016&license=viewerlgpl$
-Second Life Viewer Source Code
-Copyright (C) 2016, Linden Research, Inc.
-
-This library is free software; you can redistribute it and/or
-modify it under the terms of the GNU Lesser General Public
-License as published by the Free Software Foundation;
-version 2.1 of the License only.
-
-This library is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-Lesser General Public License for more details.
-
-You should have received a copy of the GNU Lesser General Public
-License along with this library; if not, write to the Free Software
-Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
-
-Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
-$/LicenseInfo$
-"""
-
-from nose.tools import *
-
-import update_manager
-
-def test_make_VVM_UUID_hash():
-    #because the method returns different results on different hosts
-    #it is not easy to unit test it reliably.  
-    #About the best we can do is check for the exception from subprocess
-    key = update_manager.get_platform_key()
-    try:
-        UUID_hash = update_manager.make_VVM_UUID_hash(key)
-    except Exception, e:
-        print "Test failed due to: %s" % str(e)
-        assert False
-
-    #make_UUID_hash returned None
-    assert UUID_hash, "make_UUID_hash failed to make a hash."
diff --git a/indra/viewer_components/manager/tests/test_make_download_dir.py b/indra/viewer_components/manager/tests/test_make_download_dir.py
deleted file mode 100644
index e3f9cb83fe84faf75400d3a08f974f78ea89471b..0000000000000000000000000000000000000000
--- a/indra/viewer_components/manager/tests/test_make_download_dir.py
+++ /dev/null
@@ -1,47 +0,0 @@
-#!/usr/bin/env python
-
-"""
-@file   test_make_download_dir.py
-@author coyot
-@date   2016-06-03
-
-$LicenseInfo:firstyear=2016&license=viewerlgpl$
-Second Life Viewer Source Code
-Copyright (C) 2016, Linden Research, Inc.
-
-This library is free software; you can redistribute it and/or
-modify it under the terms of the GNU Lesser General Public
-License as published by the Free Software Foundation;
-version 2.1 of the License only.
-
-This library is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-Lesser General Public License for more details.
-
-You should have received a copy of the GNU Lesser General Public
-License along with this library; if not, write to the Free Software
-Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
-
-Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
-$/LicenseInfo$
-"""
-
-from nose.tools import *
-
-import update_manager
-
-def test_make_download_dir():
-    key = update_manager.get_platform_key()
-    path = update_manager.get_parent_path(key)
-    version = '1.2.3.456789'
-    try:
-        download_dir = update_manager.make_download_dir(path, version)
-    except OSError, e:
-        print "make_download_dir failed to eat OSError %s" % str(e)
-        assert False
-    except Exception, e:
-        print "make_download_dir raised an unexpected exception %s" % str(e)
-        assert False
-
-    assert download_dir, "make_download_dir returned None for path %s and version %s" % (path, version)
diff --git a/indra/viewer_components/manager/tests/test_query_vvm.py b/indra/viewer_components/manager/tests/test_query_vvm.py
deleted file mode 100644
index 79c8ede48067d6469d395b228d012eb81ff61d92..0000000000000000000000000000000000000000
--- a/indra/viewer_components/manager/tests/test_query_vvm.py
+++ /dev/null
@@ -1,73 +0,0 @@
-#!/usr/bin/env python
-
-
-"""
-@file   test_query_vvm.py
-@author coyot
-@date   2016-06-08
-
-$LicenseInfo:firstyear=2016&license=viewerlgpl$
-Second Life Viewer Source Code
-Copyright (C) 2016, Linden Research, Inc.
-
-This library is free software; you can redistribute it and/or
-modify it under the terms of the GNU Lesser General Public
-License as published by the Free Software Foundation;
-version 2.1 of the License only.
-
-This library is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-Lesser General Public License for more details.
-
-You should have received a copy of the GNU Lesser General Public
-License along with this library; if not, write to the Free Software
-Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
-
-Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
-$/LicenseInfo$
-"""
-
-from nose.tools import *
-
-import os
-import re
-import shutil
-import tempfile
-import update_manager
-import with_setup_args
-
-def query_vvm_setup():
-    tmpdir1 = tempfile.mkdtemp(prefix = 'test1')
-    handle = update_manager.get_log_file_handle(tmpdir1)
-
-    return [tmpdir1,handle], {}
-
-def query_vvm_teardown(tmpdir1, handle):
-    shutil.rmtree(tmpdir1, ignore_errors = True)
-
-@with_setup_args.with_setup_args(query_vvm_setup, query_vvm_teardown)
-def test_query_vvm(tmpdir1, handle):
-    key = update_manager.get_platform_key()
-    parent = update_manager.get_parent_path(key)
-    settings = update_manager.get_settings(handle, parent)
-    launcher_path = os.path.dirname(os.path.dirname(os.path.abspath(os.path.realpath(__file__))))
-    summary = update_manager.get_summary(key, launcher_path)
-
-    #for unit testing purposes, just testing a value from results.  If no update, then None and it falls through
-    #for formal QA see:
-    #   https://docs.google.com/document/d/1WNjOPdKlq0j_7s7gdNe_3QlyGnQDa3bFNvtyVM6Hx8M/edit
-    #   https://wiki.lindenlab.com/wiki/Login_Test#Test_Viewer_Updater
-    #for test plans on all cases, as it requires setting up a fake VVM service
-
-    try:
-        results = update_manager.query_vvm(handle, key, settings, summary)
-    except Exception, e:
-        print "query_vvm threw unexpected exception %s" % str(e)
-        assert False
-
-    if results:
-        pattern = re.compile('Second Life')
-        assert pattern.search(results['channel']), "Bad results returned %s" % str(results)
-        
-    assert True
diff --git a/indra/viewer_components/manager/tests/test_silent_write.py b/indra/viewer_components/manager/tests/test_silent_write.py
deleted file mode 100644
index ad286787e239bf0a45dfaa4369f57a107adf5187..0000000000000000000000000000000000000000
--- a/indra/viewer_components/manager/tests/test_silent_write.py
+++ /dev/null
@@ -1,49 +0,0 @@
-#!/usr/bin/env python
-
-
-"""
-@file   test_silent_write.py
-@author coyot
-@date   2016-06-02
-
-$LicenseInfo:firstyear=2016&license=viewerlgpl$
-Second Life Viewer Source Code
-Copyright (C) 2016, Linden Research, Inc.
-
-This library is free software; you can redistribute it and/or
-modify it under the terms of the GNU Lesser General Public
-License as published by the Free Software Foundation;
-version 2.1 of the License only.
-
-This library is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-Lesser General Public License for more details.
-
-You should have received a copy of the GNU Lesser General Public
-License along with this library; if not, write to the Free Software
-Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
-
-Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
-$/LicenseInfo$
-"""
-
-from nose.tools import *
-
-import tempfile
-import update_manager
-
-def test_silent_write_to_file(): 
-    test_log = tempfile.TemporaryFile()
-    try:
-        update_manager.silent_write(test_log, "This is a test.")
-    except Exception, e:
-        print "Test failed due to: %s" % str(e)
-        assert False
-
-def test_silent_write_to_null(): 
-    try:
-        update_manager.silent_write(None, "This is a test.")
-    except Exception, e:
-        print "Test failed due to: %s" % str(e)
-        assert False
diff --git a/indra/viewer_components/manager/tests/test_summary.py b/indra/viewer_components/manager/tests/test_summary.py
deleted file mode 100644
index f2f2af7347f4537d6b8d110409d2d0502561df1a..0000000000000000000000000000000000000000
--- a/indra/viewer_components/manager/tests/test_summary.py
+++ /dev/null
@@ -1,45 +0,0 @@
-#!/usr/bin/env python
-
-
-"""
-@file   test_summary.py
-@author coyot
-@date   2016-06-02
-
-$LicenseInfo:firstyear=2016&license=viewerlgpl$
-Second Life Viewer Source Code
-Copyright (C) 2016, Linden Research, Inc.
-
-This library is free software; you can redistribute it and/or
-modify it under the terms of the GNU Lesser General Public
-License as published by the Free Software Foundation;
-version 2.1 of the License only.
-
-This library is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-Lesser General Public License for more details.
-
-You should have received a copy of the GNU Lesser General Public
-License along with this library; if not, write to the Free Software
-Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
-
-Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
-$/LicenseInfo$
-"""
-
-from nose.tools import *
-
-import os.path
-import tempfile
-import update_manager
-
-def test_get_summary():
-    key = update_manager.get_platform_key()
-    #launcher is one dir above tests
-    launcher_path = os.path.dirname(os.path.dirname(os.path.abspath(os.path.realpath(__file__))))
-    summary_json = update_manager.get_summary(key, launcher_path)
-
-    #we aren't testing the JSON library, one key pair is enough
-    #so we will use the one pair that is actually a constant
-    assert_equal(summary_json['Type'],'viewer')
diff --git a/indra/viewer_components/manager/tests/with_setup_args.py b/indra/viewer_components/manager/tests/with_setup_args.py
deleted file mode 100644
index 94d33aa5fe9766011d46bd88fafcf75cde275591..0000000000000000000000000000000000000000
--- a/indra/viewer_components/manager/tests/with_setup_args.py
+++ /dev/null
@@ -1,68 +0,0 @@
-#!/usr/bin/env python
-
-"""
-@file   with_setup_args.py
-@author garyvdm
-@date   2016-06-02
-
-$LicenseInfo:firstyear=2016&license=viewerlgpl$
-Second Life Viewer Source Code
-Copyright (C) 2016, Linden Research, Inc.
-
-This library is free software; you can redistribute it and/or
-modify it under the terms of the GNU Lesser General Public
-License as published by the Free Software Foundation;
-version 2.1 of the License only.
-
-This library is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-Lesser General Public License for more details.
-
-You should have received a copy of the GNU Lesser General Public
-License along with this library; if not, write to the Free Software
-Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
-
-Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
-$/LicenseInfo$
-"""
-
-def with_setup_args(setup, teardown=None):
-    """Decorator to add setup and/or teardown methods to a test function::
-      @with_setup_args(setup, teardown)
-      def test_something():
-          " ... "
-    The setup function should return (args, kwargs) which will be passed to
-    test function, and teardown function.
-    Note that `with_setup_args` is useful *only* for test functions, not for test
-    methods or inside of TestCase subclasses.
-    """
-    def decorate(func):
-        args = []
-        kwargs = {}
-
-        def test_wrapped():
-            func(*args, **kwargs)
-
-        test_wrapped.__name__ = func.__name__
-
-        def setup_wrapped():
-            a, k = setup()
-            args.extend(a)
-            kwargs.update(k)
-            if hasattr(func, 'setup'):
-                func.setup()
-        test_wrapped.setup = setup_wrapped
-
-        if teardown:
-            def teardown_wrapped():
-                if hasattr(func, 'teardown'):
-                    func.teardown()
-                teardown(*args, **kwargs)
-
-            test_wrapped.teardown = teardown_wrapped
-        else:
-            if hasattr(func, 'teardown'):
-                test_wrapped.teardown = func.teardown()
-        return test_wrapped
-    return decorate
diff --git a/indra/viewer_components/manager/update_manager.py b/indra/viewer_components/manager/update_manager.py
deleted file mode 100755
index 796256811930fb46ea1059fb3870fad858fb6b6c..0000000000000000000000000000000000000000
--- a/indra/viewer_components/manager/update_manager.py
+++ /dev/null
@@ -1,547 +0,0 @@
-#!/usr/bin/env python
-
-"""\
-@file update_manager.py
-@author coyot
-@date 2016-05-16
-@brief executes viewer update checking and manages downloading and applying of updates
-
-$LicenseInfo:firstyear=2016&license=viewerlgpl$
-Second Life Viewer Source Code
-Copyright (C) 2016, Linden Research, Inc.
-
-This library is free software; you can redistribute it and/or
-modify it under the terms of the GNU Lesser General Public
-License as published by the Free Software Foundation;
-version 2.1 of the License only.
-
-This library is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-Lesser General Public License for more details.
-
-You should have received a copy of the GNU Lesser General Public
-License along with this library; if not, write to the Free Software
-Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
-
-Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
-$/LicenseInfo$
-"""
-
-import os
-
-#NOTA BENE: 
-#   For POSIX platforms, llbase will be imported from the same directory.  
-#   For Windows, llbase will be compiled into the executable by pyinstaller
-try:
-    from llbase import llrest
-    from llbase.llrest import RESTError
-    from llbase import llsd    
-except:
-    #if Windows, this is expected, if not, we're dead
-    if os.name == 'nt':
-        pass
-
-from copy import deepcopy
-from datetime import datetime
-from urlparse import urljoin
-
-import apply_update
-import download_update
-import errno
-import fnmatch
-import hashlib
-import InstallerUserMessage
-import json
-import platform
-import re
-import shutil
-import subprocess
-import sys
-import tempfile
-import thread
-import urllib
-
-def silent_write(log_file_handle, text):
-    #if we have a log file, write.  If not, do nothing.
-    #this is so we don't have to keep trapping for an exception with a None handle
-    #oh and because it is best effort, it is also a holey_write ;)
-    if (log_file_handle):
-        #prepend text for easy grepping
-        timestamp = datetime.utcnow().strftime("%Y-%m-%D %H:%M:%S")
-        log_file_handle.write(timestamp + " UPDATE MANAGER: " + text + "\n")
-
-def after_frame(message, timeout = 10000):
-    #pop up a InstallerUserMessage.basic_message that kills itself after timeout milliseconds
-    #note that this blocks the caller for the duration of timeout
-    frame = InstallerUserMessage.InstallerUserMessage(title = "Second Life Installer", icon_name="head-sl-logo.gif")
-    #this is done before basic_message so that we aren't blocked by mainloop()
-    #frame.after(timeout, lambda: frame._delete_window)
-    frame.after(timeout, lambda: frame.destroy())
-    frame.basic_message(message = message)
-
-def convert_version_file_style(version):
-    #converts a version string a.b.c.d to a_b_c_d as used in downloaded filenames
-    #re will throw a TypeError if it gets None, just return that.
-    try:
-        pattern = re.compile('\.')
-        return pattern.sub('_', version)
-    except TypeError, te:
-        return None
-
-def get_platform_key():
-    #this is the name that is inserted into the VVM URI
-    #and carried forward through the rest of the updater to determine
-    #platform specific actions as appropriate
-    platform_dict = {'Darwin':'mac', 'Linux':'lnx', 'Windows':'win'}
-    platform_uname = platform.system()
-    try:
-        return platform_dict[platform_uname]
-    except KeyError:
-        return None
-
-def get_summary(platform_name, launcher_path):
-    #get the contents of the summary.json file.
-    #for linux and windows, this file is in the same directory as the script
-    #for mac, the script is in ../Contents/MacOS/ and the file is in ../Contents/Resources/
-    script_dir = os.path.abspath(os.path.dirname(os.path.realpath(__file__)))
-    if (platform_name == 'mac'):
-        summary_dir = os.path.abspath(os.path.join(script_dir, "../Resources"))
-    else:
-        summary_dir = script_dir
-    summary_file = os.path.join(summary_dir,"summary.json")
-    with open(summary_file) as summary_handle:
-        return json.load(summary_handle)
-
-def get_parent_path(platform_name):
-    #find the parent of the logs and user_settings directories
-    if (platform_name == 'mac'):
-        settings_dir = os.path.join(os.path.expanduser('~'),'Library','Application Support','SecondLife')
-    elif (platform_name == 'lnx'): 
-        settings_dir = os.path.join(os.path.expanduser('~'),'.secondlife')
-    #using list format of join is important here because the Windows pathsep in a string escapes the next char
-    elif (platform_name == 'win'):
-        settings_dir = os.path.join(os.path.expanduser('~'),'AppData','Roaming','SecondLife')
-    else:
-        settings_dir = None
-    return settings_dir
-
-def make_download_dir(parent_dir, new_version):
-    #make a canonical download dir if it does not already exist
-    #format: ../user_settings/downloads/1.2.3.456789
-    #we do this so that multiple viewers on the same host can update separately
-    #this also functions as a getter
-    try:
-        download_dir = os.path.join(parent_dir, "downloads", new_version)
-        os.makedirs(download_dir)
-    except OSError, hell:
-        #Directory already exists, that's okay.  Other OSErrors are not okay.
-        if hell[0] == errno.EEXIST:  
-            pass
-        else:
-            raise hell
-    return download_dir
-
-def check_for_completed_download(download_dir):
-    #there will be two files on completion, the download and a marker file called "".done""
-    #for optional upgrades, there may also be a .skip file to skip this particular upgrade 
-    #or .next to install on next run
-    completed = None
-    marker_regex = '*' + '.done'
-    skip_regex = '*' + '.skip'
-    next_regex = '*' + '.next'
-    for filename in os.listdir(download_dir):
-        if fnmatch.fnmatch(filename, marker_regex):
-            completed = 'done'
-        elif fnmatch.fnmatch(filename, skip_regex):
-            completed = 'skip'
-        elif fnmatch.fnmatch(filename, next_regex):
-            #so we don't skip infinitely
-            os.remove(filename)
-            completed = 'next'
-    if not completed:
-        #cleanup
-        shutil.rmtree(download_dir)
-    return completed  
-
-def get_settings(log_file_handle, parent_dir):
-    #return the settings file parsed into a dict
-    try:
-        settings_file = os.path.abspath(os.path.join(parent_dir,'user_settings','settings.xml'))
-        #this happens when the path to settings file happens on the command line
-        #we get a full path and don't need to munge it
-        if not os.path.exists(settings_file):
-            settings_file = parent_dir
-        settings = llsd.parse((open(settings_file)).read())
-    except llsd.LLSDParseError as lpe:
-        silent_write(log_file_handle, "Could not parse settings file %s" % lpe)
-        return None
-    return settings
-
-def get_log_file_handle(parent_dir, filename = None):
-    #return a write handle on the log file
-    #plus log rotation and not dying on failure
-    if not filename:
-        return None
-    log_file = os.path.join(parent_dir, filename)
-    old_file = log_file + '.old'
-    #if someone's log files are present but not writable, they've screwed up their install.
-    if os.access(log_file, os.W_OK):
-        if os.access(old_file, os.W_OK):
-            os.unlink(old_file)
-        os.rename(log_file, old_file)
-    elif not os.path.exists(log_file):
-        #reimplement TOUCH(1) in Python
-        #perms default to 644 which is fine
-        open(log_file, 'w+').close()
-    try:
-        f = open(log_file,'w+')
-    except Exception as e:
-        #we don't have a log file to write to, make a best effort and sally onward
-        print "Could not open update manager log file %s" % log_file
-        f = None
-    return f
-
-def make_VVM_UUID_hash(platform_key):
-    #NOTE: There is no python library support for a persistent machine specific UUID
-    #      AND all three platforms do this a different way, so exec'ing out is really the best we can do
-    #Lastly, this is a best effort service.  If we fail, we should still carry on with the update 
-    uuid = None
-    if (platform_key == 'lnx'):
-        uuid = subprocess.check_output(['/usr/bin/hostid']).rstrip()
-    elif (platform_key == 'mac'):
-        #this is absurdly baroque
-        #/usr/sbin/system_profiler SPHardwareDataType | fgrep 'Serial' | awk '{print $NF}'
-        uuid = subprocess.check_output(["/usr/sbin/system_profiler", "SPHardwareDataType"])
-        #findall[0] does the grep for the value we are looking for: "Serial Number (system): XXXXXXXX"
-        #split(:)[1] gets us the XXXXXXX part
-        #lstrip shaves off the leading space that was after the colon
-        uuid = re.split(":", re.findall('Serial Number \(system\): \S*', uuid)[0])[1].lstrip()
-    elif (platform_key == 'win'):
-        # wmic csproduct get UUID | grep -v UUID
-        uuid = subprocess.check_output(['wmic','csproduct','get','UUID'])
-        #outputs in two rows:
-        #UUID
-        #XXXXXXX-XXXX...
-        uuid = re.split('\n',uuid)[1].rstrip()
-    if uuid is not None:
-        return hashlib.md5(uuid).hexdigest()
-    else:
-        #fake it
-        return hashlib.md5(str(uuid.uuid1())).hexdigest()
-
-def query_vvm(log_file_handle = None, platform_key = None, settings = None, summary_dict = None, UpdaterServiceURL = None, UpdaterWillingToTest = None):
-    result_data = None
-    baseURI = None
-    #URI template /update/v1.1/channelname/version/platformkey/platformversion/willing-to-test/uniqueid
-    #https://wiki.lindenlab.com/wiki/Viewer_Version_Manager_REST_API#Viewer_Update_Query
-    #note that the only two valid options are:
-    # # version-phx0.damballah.lindenlab.com
-    # # version-qa.secondlife-staging.com
-    print "updater service host: " + repr(UpdaterServiceURL)
-    if UpdaterServiceURL:
-        #we can't really expect the users to put the protocol or base dir on, they will give us a host
-        base_URI = urljoin('https://' + UpdaterServiceURL[0], '/update/')
-    else:
-        base_URI = 'https://update.secondlife.com/update/'
-    channelname = summary_dict['Channel']
-    #this is kind of a mess because the settings value is a) in a map and b) is both the cohort and the version in one string
-    version = summary_dict['Version']
-    #we need to use the dotted versions of the platform versions in order to be compatible with VVM rules and arithmetic
-    if platform_key == 'win':
-        platform_version = platform.win32_ver()[1]
-    elif platform_key == 'mac':
-        platform_version = platform.mac_ver()[0]
-    else:
-        platform_version = platform.release()
-    #this will always return something usable, error handling in method
-    UUID = str(make_VVM_UUID_hash(platform_key))
-    #note that this will not normally be in a settings.xml file and is only here for test builds.
-    #for test builds, add this key to the ../user_settings/settings.xml
-    """
-        <key>test</key>
-        <map>
-        <key>Comment</key>
-            <string>Tell update manager you aren't willing to test.</string>
-        <key>Type</key>
-            <string>String</string>
-        <key>Value</key>
-            <integer>testno</integer>
-        </map>
-    </map>
-    """
-    if UpdaterWillingToTest is not None:
-        if UpdaterWillingToTest:
-            test_ok = 'testok'
-        else:
-            test_ok = 'testno'
-    else:   
-        try:
-            test_ok = settings['test']['Value']
-        except KeyError:
-            #normal case, no testing key
-            test_ok = 'testok'
-    #because urljoin can't be arsed to take multiple elements
-    #channelname is a list because although it is only one string, it is a kind of argument and viewer args can take multiple keywords.
-    query_string =  urllib.quote('v1.0/' + channelname[0] + '/' + version + '/' + platform_key + '/' + platform_version + '/' + test_ok + '/' + UUID)
-    silent_write(log_file_handle, "About to query VVM: %s" % base_URI + query_string)
-    VVMService = llrest.SimpleRESTService(name='VVM', baseurl=base_URI)
-    try:
-        result_data = VVMService.get(query_string)
-    except RESTError as re:
-        silent_write(log_file_handle, "Failed to query VVM using %s failed as %s" % (urljoin(base_URI,query_string), re))
-        return None
-    return result_data
-
-def download(url = None, version = None, download_dir = None, size = 0, background = False, chunk_size = None, log_file_handle = None):
-    download_tries = 0
-    download_success = False
-    if not chunk_size:
-        chunk_size = 1024
-    #for background execution
-    path_to_downloader = os.path.join(os.path.dirname(os.path.realpath(__file__)), "download_update.py")
-    #three strikes and you're out
-    while download_tries < 3 and not download_success:
-        #323: Check for a partial update of the required update; in either event, display an alert that a download is required, initiate the download, and then install and launch
-        if download_tries == 0:
-            after_frame(message = "Downloading new version " + version + " Please wait.", timeout = 5000)
-        else:
-            after_frame(message = "Trying again to download new version " + version + " Please wait.", timeout = 5000)
-        if not background:
-            try:
-                download_update.download_update(url = url, download_dir = download_dir, size = size, progressbar = True, chunk_size = chunk_size)
-                download_success = True
-            except Exception, e:
-                download_tries += 1    
-                silent_write(log_file_handle, "Failed to download new version " + version + ". Trying again.")
-                silent_write(log_file_handle, "Logging download exception: %s" % e.message)
-        else:
-            try:
-                #Python does not have a facility to multithread a method, so we make the method a standalone
-                #and subprocess that
-                subprocess.call(path_to_downloader, "--url = %s --dir = %s --pb --size = %s --chunk_size = %s" % (url, download_dir, size, chunk_size))
-                download_success = True
-            except:
-                download_tries += 1
-                silent_write(log_file_handle, "Failed to download new version " + version + ". Trying again.")
-    if not download_success:
-        silent_write(log_file_handle, "Failed to download new version " + version)
-        after_frame(message = "Failed to download new version " + version + " Please check connectivity.")
-        return False
-    return True
-
-def install(platform_key = None, download_dir = None, log_file_handle = None, in_place = None, downloaded = None):
-    #user said no to this one
-    if downloaded != 'skip':
-        after_frame(message = "New version downloaded.  Installing now, please wait.")
-        success = apply_update.apply_update(download_dir, platform_key, log_file_handle, in_place)
-        version = download_dir.split('/')[-1]
-        if success:
-            silent_write(log_file_handle, "successfully updated to " + version)
-            shutil.rmtree(download_dir)
-            #this is either True for in place or the path to the new install for not in place
-            return success
-        else:
-            after_frame(message = "Failed to apply " + version)
-            silent_write(log_file_handle, "Failed to update viewer to " + version)
-            return False
-        
-def download_and_install(downloaded = None, url = None, version = None, download_dir = None, size = None, 
-                         platform_key = None, log_file_handle = None, in_place = None, chunk_size = 1024):
-    #extracted to a method because we do it twice in update_manager() and this makes the logic clearer
-    if not downloaded:
-        #do the download, exit if we fail
-        if not download(url = url, version = version, download_dir = download_dir, size = size, chunk_size = chunk_size, log_file_handle = log_file_handle): 
-            return (False, 'download', version)  
-    #do the install
-    path_to_new_launcher = install(platform_key = platform_key, download_dir = download_dir, 
-                                   log_file_handle = log_file_handle, in_place = in_place, downloaded = downloaded)
-    if path_to_new_launcher:
-        #if we succeed, propagate the success type upwards
-        if in_place:
-            return (True, 'in place', True)
-        else:
-            return (True, 'in place', path_to_new_launcher)
-    else:
-        #propagate failure
-        return (False, 'apply', version)    
-            
-def update_manager(cli_overrides = None):
-    #cli_overrides is a dict where the keys are specific parameters of interest and the values are the arguments to 
-    #comments that begin with '323:' are steps taken from the algorithm in the description of SL-323. 
-    #  Note that in the interest of efficiency, such as determining download success once at the top
-    #  The code does follow precisely the same order as the algorithm.
-    #return values rather than exit codes.  All of them are to communicate with launcher
-    #we print just before we return so that __main__ outputs something - returns are swallowed
-    #  (False, 'setup', None): error occurred before we knew what the update was (e.g., in setup or parsing)
-    #  (False, 'download', version): we failed to download the new version
-    #  (False, 'apply', version): we failed to apply the new version
-    #  (True, None, None): No update found
-    #  (True, 'in place, True): update applied in place
-    #  (True, 'in place', path_to_new_launcher): Update applied by a new install to a new location
-    #  (True, 'background', True): background download initiated
-
-    #setup and getting initial parameters
-    platform_key = get_platform_key()
-    parent_dir = get_parent_path(platform_key)
-    log_file_handle = get_log_file_handle(parent_dir, 'update_manager.log')
-    settings = None
-
-    #check to see if user has install rights
-    #get the owner of the install and the current user
-    script_owner_id = os.stat(os.path.realpath(__file__)).st_uid
-    user_id = os.geteuid()
-    #if we are on lnx or mac, we can pretty print the IDs as names using the pwd module
-    #win does not provide this support and Python will throw an ImportError there, so just use raw IDs
-    if script_owner_id != user_id:
-        if platform_key != 'win':
-            import pwd
-            script_owner_name = pwd.getpwuid(script_owner_id)[0]
-            username = pwd.getpwuid(user_id)[0]
-        else:
-            username = user_id
-            script_owner_name = script_owner_id
-        silent_write(log_file_handle, "Upgrade notification attempted by userid " + username)    
-        frame = InstallerUserMessage(title = "Second Life Installer", icon_name="head-sl-logo.gif")
-        frame.binary_choice_message(message = "Second Life was installed by userid " + script_owner_name 
-            + ".  Do you have privileges to install?", true = "Yes", false = 'No')
-        if not frame.choice.get():
-            silent_write(log_file_handle, "Upgrade attempt declined by userid " + username)
-            after_frame(message = "Please find a system admin to upgrade Second Life")
-            print "Update manager exited with (%s, %s, %s)" % (False, 'setup', None)
-            return (False, 'setup', None)
-
-    if cli_overrides is not None: 
-        if 'settings' in cli_overrides.keys():
-            if cli_overrides['settings'] is not None:
-                settings = get_settings(log_file_handle, cli_overrides['settings'][0])
-        else:
-            settings = get_settings(log_file_handle, parent_dir)   
-        
-    if settings is None:
-        silent_write(log_file_handle, "Failed to load viewer settings")
-        print "Update manager exited with (%s, %s, %s)" % (False, 'setup', None)
-        return (False, 'setup', None)
-
-    #323: If a complete download of that update is found, check the update preference:
-    #settings['UpdaterServiceSetting'] = 0 is manual install
-    """
-    <key>UpdaterServiceSetting</key>
-        <map>
-        <key>Comment</key>
-            <string>Configure updater service.</string>
-        <key>Type</key>
-            <string>U32</string>
-        <key>Value</key>
-            <string>0</string>
-        </map>
-    """
-    if cli_overrides is not None: 
-        if 'set' in cli_overrides.keys():
-            if 'UpdaterServiceSetting' in cli_overrides['set'].keys():
-                install_automatically = cli_overrides['set']['UpdaterServiceSetting']
-    else:
-        try:
-            install_automatically = settings['UpdaterServiceSetting']['Value']
-        #because, for some godforsaken reason, we delete the setting rather than changing the value
-        except KeyError:
-            install_automatically = 1
-    
-    #use default chunk size if none is given     
-    if cli_overrides is not None: 
-        if 'set' in cli_overrides.keys():
-            if 'UpdaterMaximumBandwidth' in cli_overrides['set'].keys():    
-                chunk_size = cli_overrides['set']['UpdaterMaximumBandwidth']
-        else:
-            chunk_size = 1024
-    else:
-        chunk_size = 1024
-
-    #get channel and version
-    try:
-        summary_dict = get_summary(platform_key, os.path.abspath(os.path.realpath(__file__)))
-        #we send the override to the VVM, but retain the summary.json version for in_place computations
-        channel_override_summary = deepcopy(summary_dict)        
-        if cli_overrides is not None:
-            if 'channel' in cli_overrides.keys():
-                channel_override_summary['Channel'] = cli_overrides['channel']
-    except Exception, e:
-        silent_write(log_file_handle, "Could not obtain channel and version, exiting.")
-        silent_write(log_file_handle, e.message)
-        print "Update manager exited with (%s, %s, %s)" % (False, 'setup', None)
-        return (False, 'setup', None)        
-
-    #323: On launch, the Viewer Manager should query the Viewer Version Manager update api.
-    if cli_overrides is not None:
-        if 'update-service' in cli_overrides.keys():
-            UpdaterServiceURL = cli_overrides['update-service']
-        else:
-            #tells query_vvm to use the default
-            UpdaterServiceURL = None
-    else:
-        UpdaterServiceURL = None
-    result_data = query_vvm(log_file_handle, platform_key, settings, channel_override_summary, UpdaterServiceURL)
-    
-    #nothing to do or error
-    if not result_data:
-        silent_write(log_file_handle, "No update found.")
-        print "Update manager exited with (%s, %s, %s)" % (True, None, None)
-        return (True, None, None)
-
-    #get download directory, if there are perm issues or similar problems, give up
-    try:
-        download_dir = make_download_dir(parent_dir, result_data['version'])
-    except Exception, e:
-        print "Update manager exited with (%s, %s, %s)" % (False, 'setup', None)
-        return (False, 'setup', None)
-    
-    #if the channel name of the response is the same as the channel we are launched from, the update is "in place"
-    #and launcher will launch the viewer in this install location.  Otherwise, it will launch the Launcher from 
-    #the new location and kill itself.
-    in_place = (summary_dict['Channel'] == result_data['channel'])
-    print "summary %s, result %s, in_place %s" % (summary_dict['Channel'], result_data['channel'], in_place)
-    
-    #determine if we've tried this download before
-    downloaded = check_for_completed_download(download_dir)
-
-    #323: If the response indicates that there is a required update: 
-    if result_data['required'] or (not result_data['required'] and install_automatically):
-        #323: Check for a completed download of the required update; if found, display an alert, install the required update, and launch the newly installed viewer.
-        #323: If [optional download and] Install Automatically: display an alert, install the update and launch updated viewer.
-        return download_and_install(downloaded = downloaded, url = result_data['url'], version = result_data['version'], download_dir = download_dir, 
-                                    size = result_data['size'], platform_key = platform_key, log_file_handle = log_file_handle, in_place = in_place, chunk_size = chunk_size)
-    else:
-        #323: If the update response indicates that there is an optional update: 
-        #323: Check to see if the optional update has already been downloaded.
-        #323: If a complete download of that update is found, check the update preference: 
-        #note: automatic install handled above as the steps are the same as required upgrades
-        #323: If Install Manually: display a message with the update information and ask the user whether or not to install the update with three choices:
-        #323: Skip this update: create a marker that subsequent launches should not prompt for this update as long as it is optional, 
-        #     but leave the download in place so that if it becomes required it will be there.
-        #323: Install next time: create a marker that skips the prompt and installs on the next launch
-        #323: Install and launch now: do it.
-        if downloaded is not None and downloaded != 'skip':
-            frame = InstallerUserMessage(title = "Second Life Installer", icon_name="head-sl-logo.gif")
-            #The choices are reordered slightly to encourage immediate install and slightly discourage skipping
-            frame.trinary_message(message = "Please make a selection", 
-                one = "Install new version now.", two = 'Install the next time the viewer is launched.', three = 'Skip this update.')
-            choice = frame.choice.get()
-            if choice == 1:
-                return download_and_install(downloaded = downloaded, url = result_data['url'], version = result_data['version'], download_dir = download_dir, 
-                                    size = result_data['size'], platform_key = platform_key, log_file_handle = log_file_handle, in_place = in_place, chunk_size = chunk_size)
-            elif choice == 2:
-                tempfile.mkstmp(suffix = ".next", dir = download_dir)
-                return (True, None, None)
-            else:
-                tempfile.mkstmp(suffix = ".skip", dir = download_dir)
-                return (True, None, None)
-        else:
-            #multithread a download
-            download(url = result_data['url'], version = result_data['version'], download_dir = download_dir, size = result_data['size'], background = True, log_file_handle = log_file_handle)
-            print "Update manager exited with (%s, %s, %s)" % (True, 'background', True)
-            return (True, 'background', True)                  
-
-
-if __name__ == '__main__':
-    #there is no argument parsing or other main() work to be done
-    update_manager()