Push for 0.9.4.

Khaibit [08-26-14 - 17:45]
Push for 0.9.4.

  Offline sales report (optional report in chat of what you sold while offline)
  Reset button now has a confirmation dialog associated with it
  Reset and Refresh buttons will now be disabled (dimmed out) and a 'wait' animation will play when a scan is in progress
  Fixed bugs related to me making a typo in the sorting functions
  Fixed bugs related to the search box, updating the slider range, and correctly carrying over your search between full and mini windows
  Further refined the store searching - login search will be faster again now, and better handle the upcoming changes in Update 4
  Increased maximum history size to 15000 - if you use several other memory intensive addons this may cause issues!
  Optimized searching and sorting routines to be a little more efficient with large sales histories
  French localization updates (thanks jupi!)
Filename
Shopkeeper.txt
Shopkeeper.xml
Shopkeeper_Namespace_Init.lua
Shopkeeper_UI.lua
Shopkeeper_Util.lua
i18n/DE.lua
i18n/EN.lua
i18n/FR.lua
readme
diff --git a/Shopkeeper.txt b/Shopkeeper.txt
index fd455cc..28192e3 100644
--- a/Shopkeeper.txt
+++ b/Shopkeeper.txt
@@ -2,9 +2,9 @@
 ## APIVersion: 100008
 ## Description: Notifies you when you've sold something in a guild store and presents guild sales info in a convenient table.
 ## Author: Dan Stone (@khaibit) - dankitymao@gmail.com
-## Version: 0.9.3
+## Version: 0.9.4
 ## License: See license - distribution without license is prohibited!
-## LastUpdated: August 19, 2014
+## LastUpdated: August 26, 2014
 ## SavedVariables: ShopkeeperSavedVars
 ## OptionalDependsOn: LibAddonMenu-2.0 LibMediaProvider-1.0 LibStub

diff --git a/Shopkeeper.xml b/Shopkeeper.xml
index 9b29b6d..79d759f 100644
--- a/Shopkeeper.xml
+++ b/Shopkeeper.xml
@@ -1,6 +1,6 @@
 <!--
       Shopkeeper UI Layout File
-      Last Updated August 18, 2014
+      Last Updated August 26, 2014
       Written July 2014 by Dan Stone (@khaibit) - dankitymao@gmail.com
       Released under terms in license accompanying this file.
       Distribution without license is prohibited!
@@ -9,9 +9,9 @@
   <Controls>
     <!-- Stats Window -->
     <TopLevelControl movable="true" mouseEnabled="true" name="ShopkeeperStatsWindow" hidden="true">
-      <Dimensions x="540" y="225" />
+      <Dimensions x="550" y="225" />
       <OnMoveStop>
-        Shopkeeper.OnStatsWindowMoveStop()
+        Shopkeeper:OnWindowMoveStop(self)
       </OnMoveStop>
       <Controls>
         <Backdrop name="$(parent)BG" inherits="ZO_DefaultBackdrop" />
@@ -42,12 +42,12 @@
           <Anchor point="TOP" relativeTo="$(parent)" relativePoint="TOP" offsetX="0" offsetY="165" />
         </Label>
         <Label name="$(parent)SliderLabel" height="25" width="50" inheritAlpha="true" color="FFFFFF" verticalAlignment="CENTER" horizontalAlignment="LEFT" text="Days: ">
-          <Anchor point="BOTTOMLEFT" relativeTo="$(parent)" relativePoint="BOTTOMLEFT" offsetX="10" offsetY="-14" />
+          <Anchor point="BOTTOMLEFT" relativeTo="$(parent)" relativePoint="BOTTOMLEFT" offsetX="20" offsetY="-14" />
         </Label>
         <Slider name="$(parent)Slider" mouseEnabled="true" step="1" orientation="horizontal">
           <Anchor point="BOTTOM" relativeTo="$(parent)" relativePoint="BOTTOM" offsetX="25" offsetY="-15" />
           <ThumbTexture textureFile="/esoui/art/miscellaneous/scrollbox_elevator.dds" disabledTextureFile="/esoui/art/miscellaneous/scrollbox_elevator.dds" highlightedTextureFile="/esoui/art/miscellaneous/scrollbox_elevator.dds" thumbWidth="8" thumbHeight="16" left="0" top="0" bottom="1" right="1" />
-          <Dimensions x="375" y="14" />
+          <Dimensions x="400" y="14" />
           <Limits min="0" max="30" />
           <OnValueChanged>
             Shopkeeper.OnStatsSliderMoved()
@@ -65,15 +65,15 @@

     <!-- Full-size Main Window -->
     <TopLevelControl movable="true" mouseEnabled="true" name="ShopkeeperWindow" hidden="true">
-      <Dimensions x="950" y="685" />
+      <Dimensions x="930" y="685" />
       <OnMoveStop>
-        Shopkeeper.OnWindowMoveStop()
+        Shopkeeper:OnWindowMoveStop(self)
       </OnMoveStop>
       <Controls>
         <Backdrop name="$(parent)BG" inherits="ZO_DefaultBackdrop" />
         <Texture name="$(parent)SearchIcon" textureFile="/esoui/art/tradinghouse/tradinghouse_browse_tabicon_up.dds" alpha="1">
           <Dimensions x="40" y="40" />
-          <Anchor point="TOPLEFT" relativeTo="$(parent)" relativePoint="TOPLEFT" offsetX="15" offsetY="3" />
+          <Anchor point="TOPLEFT" relativeTo="$(parent)" relativePoint="TOPLEFT" offsetX="0" offsetY="3" />
           <TextureCoords left="0" right="1" top="0" bottom="1" />
         </Texture>
         <EditBox name="$(parent)SearchBox" mouseEnabled="true" editEnabled="true" textType="TEXT_TYPE_ALL" multiLine="false" newLineEnabled="false">
@@ -122,14 +122,14 @@
           <Dimensions x="48" y="48" />
           <Textures normal="/esoui/art/inventory/inventory_tabicon_quest_up.dds" mouseOver="/esoui/art/inventory/inventory_tabicon_quest_over.dds" />
           <OnClicked>
-            Shopkeeper.ToggleViewMode()
+            Shopkeeper:ToggleViewMode()
           </OnClicked>
           <OnMouseExit>
             ZO_Tooltips_HideTextTooltip()
           </OnMouseExit>
         </Button>
         <Button name="$(parent)Buyer" inheritAlpha="true" verticalAlignment="TOP" horizontalAlignment="LEFT" text="Buyer">
-          <Anchor point="TOPLEFT" relativeTo="$(parent)" relativePoint="TOPLEFT" offsetX="30" offsetY="44" />
+          <Anchor point="TOPLEFT" relativeTo="$(parent)" relativePoint="TOPLEFT" offsetX="10" offsetY="44" />
           <Dimensions x="78" y="25" />
           <FontColors normalColor="3689EF" mouseOverColor="3689EF" pressedColor="3689EF"/>
           <OnMouseExit>
@@ -137,20 +137,20 @@
           </OnMouseExit>
         </Button>
         <Label name="$(parent)Guild" width="140" height="25" inheritAlpha="true" color="FFFFFF" verticalAlignment="TOP" horizontalAlignment="LEFT" text="Guild">
-          <Anchor point="TOPLEFT" relativeTo="$(parent)" relativePoint="TOPLEFT" offsetX="161" offsetY="44" />
+          <Anchor point="TOPLEFT" relativeTo="$(parent)" relativePoint="TOPLEFT" offsetX="141" offsetY="44" />
         </Label>
         <Button name="$(parent)ItemName" inheritAlpha="true" color="FFFFFF" verticalAlignment="TOP" horizontalAlignment="LEFT" text="Item">
           <Dimensions x="200" y="25" />
-          <Anchor point="TOPLEFT" relativeTo="$(parent)" relativePoint="TOPLEFT" offsetX="370" offsetY="44" />
+          <Anchor point="TOPLEFT" relativeTo="$(parent)" relativePoint="TOPLEFT" offsetX="350" offsetY="44" />
           <OnMouseExit>
             ZO_Tooltips_HideTextTooltip()
           </OnMouseExit>
         </Button>
         <Button name="$(parent)SellTime" inheritAlpha="true" color="FFFFFF" verticalAlignment="TOP" horizontalAlignment="LEFT" text="Sale Time">
-          <Anchor point="TOPLEFT" relativeTo="$(parent)" relativePoint="TOPLEFT" offsetX="667" offsetY="44" />
+          <Anchor point="TOPLEFT" relativeTo="$(parent)" relativePoint="TOPLEFT" offsetX="647" offsetY="44" />
           <Dimensions x="120" y="25" />
           <OnMouseUp>
-            Shopkeeper.TimeSort()
+            Shopkeeper:TimeSort()
           </OnMouseUp>
           <OnMouseExit>
             ZO_Tooltips_HideTextTooltip()
@@ -158,15 +158,15 @@
         </Button>
         <Texture name="$(parent)SortTime" textureFile="/esoui/art/miscellaneous/list_sortheader_icon_sortdown.dds" alpha="1">
           <Dimensions x="40" y="40" />
-          <Anchor point="LEFT" relativeTo="$(parent)" relativePoint="TOPLEFT" offsetX="777" offsetY="54" />
+          <Anchor point="LEFT" relativeTo="$(parent)" relativePoint="TOPLEFT" offsetX="759" offsetY="54" />
           <TextureCoords left="0" right="1" top="0" bottom="1" />
         </Texture>
         <Button name="$(parent)Price" inheritAlpha="true" verticalAlignment="TOP" horizontalAlignment="LEFT" text="Price">
-          <Anchor point="TOPLEFT" relativeTo="$(parent)" relativePoint="TOPLEFT" offsetX="818" offsetY="44" />
+          <Anchor point="TOPLEFT" relativeTo="$(parent)" relativePoint="TOPLEFT" offsetX="798" offsetY="44" />
           <Dimensions x="85" y="25" />
           <FontColors normalColor="D5B526" mouseOverColor="D5B526" pressedColor="D5B526" />
           <OnMouseUp>
-            Shopkeeper.PriceSort()
+            Shopkeeper:PriceSort()
           </OnMouseUp>
           <OnMouseExit>
             ZO_Tooltips_HideTextTooltip()
@@ -174,35 +174,39 @@
         </Button>
         <Texture name="$(parent)SortPrice" textureFile="/esoui/art/miscellaneous/list_sortheader_icon_neutral.dds" alpha="1">
           <Dimensions x="40" y="40" />
-          <Anchor point="LEFT" relativeTo="$(parent)" relativePoint="TOPLEFT" offsetX="893" offsetY="54" />
+          <Anchor point="LEFT" relativeTo="$(parent)" relativePoint="TOPLEFT" offsetX="873" offsetY="54" />
           <TextureCoords left="0" right="1" top="0" bottom="1" />
         </Texture>
         <Button name="ShopkeeperSwitchViewButton" inherits="ZO_DefaultButton">
-          <Anchor point="BOTTOMLEFT" relativeTo="$(parent)" relativePoint="BOTTOMLEFT" offsetX="20" offsetY="-5" />
+          <Anchor point="BOTTOMLEFT" relativeTo="$(parent)" relativePoint="BOTTOMLEFT" offsetX="0" offsetY="-5" />
           <Dimensions x="180" />
           <OnClicked>
-            Shopkeeper.SwitchViewMode()
+            Shopkeeper:SwitchViewMode()
           </OnClicked>
         </Button>
         <Button name="ShopkeeperPriceSwitchButton" inherits="ZO_DefaultButton">
           <Anchor point="LEFT" relativeTo="ShopkeeperSwitchViewButton" relativePoint="RIGHT" offsetX="0" offsetY="0" />
           <Dimensions x="180" />
           <OnClicked>
-            Shopkeeper.SwitchPriceMode()
+            Shopkeeper:SwitchPriceMode()
           </OnClicked>
         </Button>
+        <Texture name="$(parent)LoadingIcon" textureFile="EsoUI/Art/Miscellaneous/wait_icon.dds" hidden="true">
+				  <Anchor point="BOTTOM" relativeTo="$(parent)" relativePoint="BOTTOM" offsetX="0" offsetY="-3" />
+					<Dimensions x="32" y="32" />
+				</Texture>
         <Button name="ShopkeeperRefreshButton" inherits="ZO_DefaultButton">
           <Anchor point="BOTTOMRIGHT" relativeTo="$(parent)" relativePoint="BOTTOMRIGHT" offsetX="-20" offsetY="-5" />
           <Dimensions x="160" />
           <OnClicked>
-            Shopkeeper.DoRefresh()
+            Shopkeeper:DoRefresh()
           </OnClicked>
         </Button>
         <Button name="ShopkeeperResetButton" inherits="ZO_DefaultButton">
           <Anchor point="RIGHT" relativeTo="ShopkeeperRefreshButton" relativePoint="LEFT" offsetX="0" offsetY="0" />
           <Dimensions x="160" />
           <OnClicked>
-            Shopkeeper.DoReset()
+            ZO_Dialogs_ShowDialog("ShopkeeperResetConfirmation", nil, nil)
           </OnClicked>
         </Button>
         <Slider name="$(parent)Slider" mouseEnabled="true" step="1">
@@ -228,7 +232,7 @@
     <TopLevelControl movable="true" mouseEnabled="true" name="ShopkeeperMiniWindow" hidden="true">
       <Dimensions x="670" y="416" />
       <OnMoveStop>
-        Shopkeeper.OnWindowMoveStop()
+        Shopkeeper:OnWindowMoveStop(self)
       </OnMoveStop>
       <Controls>
         <Backdrop name="$(parent)BG" inherits="ZO_DefaultBackdrop" />
@@ -239,7 +243,7 @@
         </Texture>
         <EditBox name="$(parent)SearchBox" mouseEnabled="true" editEnabled="true" textType="TEXT_TYPE_ALL" multiLine="false" newLineEnabled="false">
           <Anchor point="LEFT" relativeTo="$(parent)SearchIcon" relativePoint="RIGHT" offsetX="2" offsetY="-2" />
-          <Dimensions x="155" y="25" />
+          <Dimensions x="150" y="25" />
           <Controls>
             <Backdrop name="$(parent)TextBG" centerColor="000000" edgeColor="AAAAAA">
               <AnchorFill />
@@ -265,7 +269,7 @@
           </OnClicked>
         </Button>
         <Label name="$(parent)Title" height="25" inheritAlpha="true" color="D5B526" verticalAlignment="TOP" horizontalAlignment="CENTER" text="Shopkeeper - Your Sales">
-	        <Anchor point="TOP" relativeTo="$(parent)" relativePoint="TOP" offsetX="40" offsetY="5" />
+	        <Anchor point="TOP" relativeTo="$(parent)" relativePoint="TOP" offsetX="0" offsetY="5" />
         </Label>
         <Button name="$(parent)StatsButton" inheritAlpha="true" verticalAlignment="CENTER" horizontalAlignment="CENTER">
           <Anchor point="LEFT" relativeTo="$(parent)Title" relativePoint="RIGHT" offsetX="15" offsetY="0" />
@@ -283,7 +287,7 @@
           <Dimensions x="48" y="48" />
           <Textures normal="/esoui/art/inventory/inventory_tabicon_quest_up.dds" mouseOver="/esoui/art/inventory/inventory_tabicon_quest_over.dds" />
           <OnClicked>
-            Shopkeeper.ToggleViewMode()
+            Shopkeeper:ToggleViewMode()
           </OnClicked>
           <OnMouseExit>
             ZO_Tooltips_HideTextTooltip()
@@ -303,7 +307,7 @@
           <Anchor point="TOPLEFT" relativeTo="$(parent)" relativePoint="TOPLEFT" offsetX="420" offsetY="44" />
           <Dimensions x="95" y="25" />
           <OnMouseUp>
-            Shopkeeper.TimeSort()
+            Shopkeeper:TimeSort()
           </OnMouseUp>
           <OnMouseExit>
             ZO_Tooltips_HideTextTooltip()
@@ -319,7 +323,7 @@
           <Dimensions x="85" y="25" />
           <FontColors normalColor="D5B526" mouseOverColor="D5B526" pressedColor="D5B526" />
           <OnMouseUp>
-            Shopkeeper.PriceSort()
+            Shopkeeper:PriceSort()
           </OnMouseUp>
           <OnMouseExit>
             ZO_Tooltips_HideTextTooltip()
@@ -334,28 +338,32 @@
           <Anchor point="BOTTOMLEFT" relativeTo="$(parent)" relativePoint="BOTTOMLEFT" offsetX="2" offsetY="-5" />
           <Dimensions x="160" />
           <OnClicked>
-            Shopkeeper.SwitchViewMode()
+            Shopkeeper:SwitchViewMode()
           </OnClicked>
         </Button>
         <Button name="ShopkeeperMiniPriceSwitchButton" inherits="ZO_DefaultButton">
           <Anchor point="LEFT" relativeTo="ShopkeeperMiniSwitchViewButton" relativePoint="RIGHT" offsetX="0" offsetY="0" />
           <Dimensions x="160" />
           <OnClicked>
-            Shopkeeper.SwitchPriceMode()
+            Shopkeeper:SwitchPriceMode()
           </OnClicked>
         </Button>
+        <Texture name="$(parent)LoadingIcon" textureFile="EsoUI/Art/Miscellaneous/wait_icon.dds" hidden="true">
+				  <Anchor point="BOTTOM" relativeTo="$(parent)" relativePoint="BOTTOM" offsetX="0" offsetY="-3" />
+					<Dimensions x="32" y="32" />
+				</Texture>
         <Button name="ShopkeeperMiniRefreshButton" inherits="ZO_DefaultButton">
           <Anchor point="BOTTOMRIGHT" relativeTo="$(parent)" relativePoint="BOTTOMRIGHT" offsetX="-2" offsetY="-5" />
           <Dimensions x="160" />
           <OnClicked>
-            Shopkeeper.DoRefresh()
+            Shopkeeper:DoRefresh()
           </OnClicked>
         </Button>
         <Button name="ShopkeeperMiniResetButton" inherits="ZO_DefaultButton">
           <Anchor point="RIGHT" relativeTo="ShopkeeperMiniRefreshButton" relativePoint="LEFT" offsetX="0" offsetY="0" />
           <Dimensions x="160" />
           <OnClicked>
-            Shopkeeper.DoReset()
+            ZO_Dialogs_ShowDialog("ShopkeeperResetConfirmation", nil, nil)
           </OnClicked>
         </Button>
         <Slider name="$(parent)Slider" mouseEnabled="true" step="1">
@@ -448,11 +456,21 @@
       </Controls>
     </Control>

-    <!-- Guild filter for stats window -->
+    <!-- Guild filter for stats window (virtual) -->
     <Control name="ShopkeeperStatsGuildDropdown" inherits="ZO_ComboBox" virtual="true">
 			<OnInitialized>
 			  ZO_ComboBox:New(self)
       </OnInitialized>
     </Control>
+
+    <!-- Spinning loading icon for during scans (virtual) -->
+    <Control name="ShopkeeperLoading" hidden="true" virtual="true">
+		  <Controls>
+			  <Texture name="$(parent)LoadingIcon" textureFile="EsoUI/Art/Miscellaneous/wait_icon.dds" layer="OVERLAY">
+				  <Anchor point="BOTTOM" relativeTo="$(parent)" relativePoint="BOTTOM" offsetX="0" offsetY="-5" />
+					<Dimensions x="32" y="32" />
+				</Texture>
+			</Controls>
+		</Control>
   </Controls>
 </GuiXml>
\ No newline at end of file
diff --git a/Shopkeeper_Namespace_Init.lua b/Shopkeeper_Namespace_Init.lua
index 6710de7..ee316ae 100644
--- a/Shopkeeper_Namespace_Init.lua
+++ b/Shopkeeper_Namespace_Init.lua
@@ -1,16 +1,15 @@
 -- Shopkeeper Namespace Setup
--- Last Updated August 18, 2014
+-- Last Updated August 26, 2014
 -- Written July 2014 by Dan Stone (@khaibit) - dankitymao@gmail.com
 -- Released under terms in license accompanying this file.
 -- Distribution without license is prohibited!

 Shopkeeper = {}
 Shopkeeper.name = "Shopkeeper"
-Shopkeeper.version = "0.9.3"
+Shopkeeper.version = "0.9.4"
 Shopkeeper.locale = "en"
 Shopkeeper.viewMode = "self"
 Shopkeeper.isScanning = false
-Shopkeeper.i18n = {}
 Shopkeeper.DataRows = {}
 Shopkeeper.MiniDataRows = {}
   -- ScanResults, SelfSales and SearchTable have the following fields:
diff --git a/Shopkeeper_UI.lua b/Shopkeeper_UI.lua
index fa73950..cd22f06 100644
--- a/Shopkeeper_UI.lua
+++ b/Shopkeeper_UI.lua
@@ -1,122 +1,120 @@
 -- Shopkeeper UI Functions File
--- Last Updated August 19, 2014
+-- Last Updated August 26, 2014
 -- Written August 2014 by Dan Stone (@khaibit) - dankitymao@gmail.com
 -- Released under terms in license accompanying this file.
 -- Distribution without license is prohibited!

 -- Handle the OnMoveStop event for the windows
-function Shopkeeper.OnWindowMoveStop()
-  local settingsToUse = Shopkeeper.savedVariables
-  if Shopkeeper.acctSavedVariables.allSettingsAccount then settingsToUse = Shopkeeper.acctSavedVariables end
-  settingsToUse.winLeft = ShopkeeperWindow:GetLeft()
-  settingsToUse.winTop = ShopkeeperWindow:GetTop()
-  settingsToUse.miniWinLeft = ShopkeeperMiniWindow:GetLeft()
-  settingsToUse.miniWinTop = ShopkeeperMiniWindow:GetTop()
-end
+function Shopkeeper:OnWindowMoveStop(windowMoved)
+  local settingsToUse = Shopkeeper:ActiveSettings()

-function Shopkeeper.OnStatsWindowMoveStop()
-  local settingsToUse = Shopkeeper.savedVariables
-  if Shopkeeper.acctSavedVariables.allSettingsAccount then settingsToUse = Shopkeeper.acctSavedVariables end
-  settingsToUse.statsWinLeft = ShopkeeperStatsWindow:GetLeft()
-  settingsToUse.statsWinTop = ShopkeeperStatsWindow:GetTop()
+  if windowMoved == ShopkeeperWindow then
+    settingsToUse.winLeft = ShopkeeperWindow:GetLeft()
+    settingsToUse.winTop = ShopkeeperWindow:GetTop()
+  elseif windowMoved == ShopkeeperMiniWindow then
+    settingsToUse.miniWinLeft = ShopkeeperMiniWindow:GetLeft()
+    settingsToUse.miniWinTop = ShopkeeperMiniWindow:GetTop()
+  else
+    settingsToUse.statsWinLeft = ShopkeeperStatsWindow:GetLeft()
+    settingsToUse.statsWinTop = ShopkeeperStatsWindow:GetTop()
+  end
 end

 -- Restore the window positions from saved vars
 function Shopkeeper:RestoreWindowPosition()
-  local settingsToUse = Shopkeeper.savedVariables
-  if Shopkeeper.acctSavedVariables.allSettingsAccount then settingsToUse = Shopkeeper.acctSavedVariables end
-  local left = settingsToUse.winLeft
-  local top = settingsToUse.winTop
-  local statsLeft = settingsToUse.statsWinLeft
-  local statsTop = settingsToUse.statsWinTop
-  local miniLeft = settingsToUse.miniWinLeft
-  local miniTop = settingsToUse.miniWinTop
+  local settingsToUse = Shopkeeper:ActiveSettings()

   ShopkeeperWindow:ClearAnchors()
   ShopkeeperStatsWindow:ClearAnchors()
   ShopkeeperMiniWindow:ClearAnchors()
-  ShopkeeperWindow:SetAnchor(TOPLEFT, GuiRoot, TOPLEFT, left, top)
-  ShopkeeperStatsWindow:SetAnchor(TOPLEFT, GuiRoot, TOPLEFT, statsLeft, statsTop)
-  ShopkeeperMiniWindow:SetAnchor(TOPLEFT, GuiRoot, TOPLEFT, miniLeft, miniTop)
+
+  ShopkeeperWindow:SetAnchor(TOPLEFT, GuiRoot, TOPLEFT, settingsToUse.winLeft, settingsToUse.winTop)
+  ShopkeeperStatsWindow:SetAnchor(TOPLEFT, GuiRoot, TOPLEFT, settingsToUse.statsWinLeft, settingsToUse.statsWinTop)
+  ShopkeeperMiniWindow:SetAnchor(TOPLEFT, GuiRoot, TOPLEFT, settingsToUse.miniWinLeft, settingsToUse.miniWinTop)
 end

 -- Handle the changing of window font settings
 function Shopkeeper:UpdateFonts()
   local LMP = LibStub("LibMediaProvider-1.0")
   if LMP then
-    local font = LMP:Fetch('font', Shopkeeper.savedVariables.windowFont)
-    if Shopkeeper.acctSavedVariables.allSettingsAccount then font = LMP:Fetch('font', Shopkeeper.acctSavedVariables.windowFont) end
+    local font = LMP:Fetch('font', Shopkeeper:ActiveSettings().windowFont)
     local fontString = font .. "|%d"
+    local mainButtonLabel = 16
+    local mainTitle = 26
+    local mainHeader = 18
+    local miniButtonLabel = 12
+    local miniTitle = 20
+    local miniHeader = 14

     -- Main Window
-    ShopkeeperWindowSearchBox:SetFont(string.format(fontString, 16))
-    ShopkeeperWindowTitle:SetFont(string.format(fontString, 26))
-    ShopkeeperWindowBuyer:SetFont(string.format(fontString, 18))
-    ShopkeeperWindowGuild:SetFont(string.format(fontString, 18))
-    ShopkeeperWindowItemName:SetFont(string.format(fontString, 18))
-    ShopkeeperWindowSellTime:SetFont(string.format(fontString, 18))
-    ShopkeeperWindowPrice:SetFont(string.format(fontString, 18))
-    ShopkeeperSwitchViewButton:SetFont(string.format(fontString, 16))
-    ShopkeeperPriceSwitchButton:SetFont(string.format(fontString, 16))
-    ShopkeeperResetButton:SetFont(string.format(fontString, 16))
-    ShopkeeperRefreshButton:SetFont(string.format(fontString, 16))
+    ShopkeeperWindowSearchBox:SetFont(string.format(fontString, mainButtonLabel))
+    ShopkeeperWindowTitle:SetFont(string.format(fontString, mainTitle))
+    ShopkeeperWindowBuyer:SetFont(string.format(fontString, mainHeader))
+    ShopkeeperWindowGuild:SetFont(string.format(fontString, mainHeader))
+    ShopkeeperWindowItemName:SetFont(string.format(fontString, mainHeader))
+    ShopkeeperWindowSellTime:SetFont(string.format(fontString, mainHeader))
+    ShopkeeperWindowPrice:SetFont(string.format(fontString, mainHeader))
+    ShopkeeperSwitchViewButton:SetFont(string.format(fontString, mainButtonLabel))
+    ShopkeeperPriceSwitchButton:SetFont(string.format(fontString, mainButtonLabel))
+    ShopkeeperResetButton:SetFont(string.format(fontString, mainButtonLabel))
+    ShopkeeperRefreshButton:SetFont(string.format(fontString, mainButtonLabel))

     -- Mini Window
-    ShopkeeperMiniWindowSearchBox:SetFont(string.format(fontString, 12))
-    ShopkeeperMiniWindowTitle:SetFont(string.format(fontString, 20))
-    ShopkeeperMiniWindowGuild:SetFont(string.format(fontString, 14))
-    ShopkeeperMiniWindowItemName:SetFont(string.format(fontString, 14))
-    ShopkeeperMiniWindowSellTime:SetFont(string.format(fontString, 14))
-    ShopkeeperMiniWindowPrice:SetFont(string.format(fontString, 14))
-    ShopkeeperMiniSwitchViewButton:SetFont(string.format(fontString, 12))
-    ShopkeeperMiniPriceSwitchButton:SetFont(string.format(fontString, 12))
-    ShopkeeperMiniResetButton:SetFont(string.format(fontString, 12))
-    ShopkeeperMiniRefreshButton:SetFont(string.format(fontString, 12))
+    ShopkeeperMiniWindowSearchBox:SetFont(string.format(fontString, miniButtonLabel))
+    ShopkeeperMiniWindowTitle:SetFont(string.format(fontString, miniTitle))
+    ShopkeeperMiniWindowGuild:SetFont(string.format(fontString, miniHeader))
+    ShopkeeperMiniWindowItemName:SetFont(string.format(fontString, miniHeader))
+    ShopkeeperMiniWindowSellTime:SetFont(string.format(fontString, miniHeader))
+    ShopkeeperMiniWindowPrice:SetFont(string.format(fontString, miniHeader))
+    ShopkeeperMiniSwitchViewButton:SetFont(string.format(fontString, miniButtonLabel))
+    ShopkeeperMiniPriceSwitchButton:SetFont(string.format(fontString, miniButtonLabel))
+    ShopkeeperMiniResetButton:SetFont(string.format(fontString, miniButtonLabel))
+    ShopkeeperMiniRefreshButton:SetFont(string.format(fontString, miniButtonLabel))

     -- Stats Window
-    ShopkeeperStatsWindowTitle:SetFont(string.format(fontString, 26))
-    ShopkeeperStatsWindowGuildChooserLabel:SetFont(string.format(fontString, 18))
-    ShopkeeperStatsGuildChooser.m_comboBox:SetFont(string.format(fontString, 18))
-    ShopkeeperStatsWindowItemsSoldLabel:SetFont(string.format(fontString, 18))
-    ShopkeeperStatsWindowTotalGoldLabel:SetFont(string.format(fontString, 18))
-    ShopkeeperStatsWindowBiggestSaleLabel:SetFont(string.format(fontString, 18))
-    ShopkeeperStatsWindowSliderSettingLabel:SetFont(string.format(fontString, 18))
-    ShopkeeperStatsWindowSliderLabel:SetFont(string.format(fontString, 16))
+    ShopkeeperStatsWindowTitle:SetFont(string.format(fontString, mainTitle))
+    ShopkeeperStatsWindowGuildChooserLabel:SetFont(string.format(fontString, mainHeader))
+    ShopkeeperStatsGuildChooser.m_comboBox:SetFont(string.format(fontString, mainHeader))
+    ShopkeeperStatsWindowItemsSoldLabel:SetFont(string.format(fontString, mainHeader))
+    ShopkeeperStatsWindowTotalGoldLabel:SetFont(string.format(fontString, mainHeader))
+    ShopkeeperStatsWindowBiggestSaleLabel:SetFont(string.format(fontString, mainHeader))
+    ShopkeeperStatsWindowSliderSettingLabel:SetFont(string.format(fontString, mainHeader))
+    ShopkeeperStatsWindowSliderLabel:SetFont(string.format(fontString, mainButtonLabel))

     -- Rows for inside main/mini windows
-    for i = 1, #Shopkeeper.DataRows do
-      local dataRow = Shopkeeper.DataRows[i]
-      dataRow:GetNamedChild("Buyer"):SetFont(string.format(fontString, 16))
-      dataRow:GetNamedChild("Guild"):SetFont(string.format(fontString, 16))
-      dataRow:GetNamedChild("ItemName"):SetFont(string.format(fontString, 16))
-      dataRow:GetNamedChild("Quantity"):SetFont(string.format(fontString, 16))
-      dataRow:GetNamedChild("SellTime"):SetFont(string.format(fontString, 16))
-      dataRow:GetNamedChild("Price"):SetFont(string.format(fontString, 16))
-      if i <= #Shopkeeper.MiniDataRows then
-        local miniDataRow = Shopkeeper.MiniDataRows[i]
-        miniDataRow:GetNamedChild("Guild"):SetFont(string.format(fontString, 12))
-        miniDataRow:GetNamedChild("ItemName"):SetFont(string.format(fontString, 12))
-        miniDataRow:GetNamedChild("Quantity"):SetFont(string.format(fontString, 12))
-        miniDataRow:GetNamedChild("SellTime"):SetFont(string.format(fontString, 12))
-        miniDataRow:GetNamedChild("Price"):SetFont(string.format(fontString, 12))
+    for i = 1, #self.DataRows do
+      local dataRow = self.DataRows[i]
+      dataRow:GetNamedChild("Buyer"):SetFont(string.format(fontString, mainButtonLabel))
+      dataRow:GetNamedChild("Guild"):SetFont(string.format(fontString, mainButtonLabel))
+      dataRow:GetNamedChild("ItemName"):SetFont(string.format(fontString, mainButtonLabel))
+      dataRow:GetNamedChild("Quantity"):SetFont(string.format(fontString, mainButtonLabel))
+      dataRow:GetNamedChild("SellTime"):SetFont(string.format(fontString, mainButtonLabel))
+      dataRow:GetNamedChild("Price"):SetFont(string.format(fontString, mainButtonLabel))
+      if i <= #self.MiniDataRows then
+        local miniDataRow = self.MiniDataRows[i]
+        miniDataRow:GetNamedChild("Guild"):SetFont(string.format(fontString, miniButtonLabel))
+        miniDataRow:GetNamedChild("ItemName"):SetFont(string.format(fontString, miniButtonLabel))
+        miniDataRow:GetNamedChild("Quantity"):SetFont(string.format(fontString, miniButtonLabel))
+        miniDataRow:GetNamedChild("SellTime"):SetFont(string.format(fontString, miniButtonLabel))
+        miniDataRow:GetNamedChild("Price"):SetFont(string.format(fontString, miniButtonLabel))
       end
     end
   end
 end

 -- Display item tooltips
-function Shopkeeper:ShowToolTip(itemName, itemButton)
+function Shopkeeper.ShowToolTip(itemName, itemButton)
   InitializeTooltip(ItemTooltip, itemButton)
   ItemTooltip:SetLink(itemName)
 end

 -- Clear a given row (1-indexed)'s data
-function Shopkeeper.ClearDataRow(index)
+function Shopkeeper:ClearDataRow(index)
   if index < 1 or index > 15 then
     return
   end

-  local dataRow = Shopkeeper.DataRows[index]
+  local dataRow = self.DataRows[index]
   dataRow:GetNamedChild("Buyer"):SetText("")
   dataRow:GetNamedChild("Buyer"):SetHandler("OnMouseDoubleClick", nil)
   dataRow:GetNamedChild("Guild"):SetText("")
@@ -132,12 +130,12 @@ function Shopkeeper.ClearDataRow(index)
 end

 -- Clear a given mini row (1-indexed)'s data
-function Shopkeeper.ClearMiniDataRow(index)
+function Shopkeeper:ClearMiniDataRow(index)
   if index < 1 or index > 8 then
     return
   end

-  local dataRow = Shopkeeper.MiniDataRows[index]
+  local dataRow = self.MiniDataRows[index]
   dataRow:GetNamedChild("Guild"):SetText("")
   dataRow:GetNamedChild("ItemIcon"):SetTexture(nil)
   dataRow:GetNamedChild("ItemIcon"):SetHidden(true)
@@ -151,16 +149,16 @@ function Shopkeeper.ClearMiniDataRow(index)
 end

 -- Fill out a row with the given data
-function Shopkeeper.SetDataRow(index, buyer, guild, itemName, icon, quantity, sellTime, price, seller, kioskSale)
+function Shopkeeper:SetDataRow(index, buyer, guild, itemName, icon, quantity, sellTime, price, seller, kioskSale)
   if index < 1 or index > 15 then return end

-  local dataRow = Shopkeeper.DataRows[index]
+  local dataRow = self.DataRows[index]

   -- Some extra stuff for the Buyer cell to handle double-click and color changes
   -- Plus add a marker if buyer is not in-guild (kiosk sale)
   local buyerCell = dataRow:GetNamedChild("Buyer")
   local buyerString = buyer
-  if kioskSale ~= nil and kioskSale == true then
+  if kioskSale then
     buyerString = "|t16:16:/EsoUI/Art/icons/item_generic_coinbag.dds|t" .. buyerString
   end
   buyerCell:SetText(buyerString)
@@ -202,7 +200,7 @@ function Shopkeeper.SetDataRow(index, buyer, guild, itemName, icon, quantity, se
   itemCell:SetHandler("OnMouseDoubleClick", function()
     ZO_ChatWindowTextEntryEditBox:SetText(ZO_ChatWindowTextEntryEditBox:GetText() .. string.gsub(itemName, "|H0", "|H1"))
   end)
-  itemCell:SetHandler("OnMouseEnter", function() Shopkeeper:ShowToolTip(itemName, itemCell) end)
+  itemCell:SetHandler("OnMouseEnter", function() self.ShowToolTip(itemName, itemCell) end)
   itemCell:SetHandler("OnMouseExit", function() ClearTooltip(ItemTooltip) end)
   local itemCellLabel = itemCell:GetLabelControl()
   itemCellLabel:SetWrapMode(TEXT_WRAP_MODE_ELLIPSIS)
@@ -217,8 +215,7 @@ function Shopkeeper.SetDataRow(index, buyer, guild, itemName, icon, quantity, se
   -- math.floor(number + 0.5) is a quick shorthand way to round for
   -- positive values.
   local dispPrice = price
-  local settingsToUse = Shopkeeper.savedVariables
-  if Shopkeeper.acctSavedVariables.allSettingsAccount then settingsToUse = Shopkeeper.acctSavedVariables end
+  local settingsToUse = Shopkeeper:ActiveSettings()
   if settingsToUse.showFullPrice then
     if settingsToUse.showUnitPrice and quantity > 0 then
       dispPrice = math.floor((dispPrice / quantity) + 0.5)
@@ -232,17 +229,17 @@ function Shopkeeper.SetDataRow(index, buyer, guild, itemName, icon, quantity, se
   end

   -- Insert thousands separators for the price
-  local stringPrice = Shopkeeper.localizedNumber(dispPrice)
+  local stringPrice = self.LocalizedNumber(dispPrice)

   -- Finally, set the price
   dataRow:GetNamedChild("Price"):SetText(stringPrice .. " |t16:16:EsoUI/Art/currency/currency_gold.dds|t")
 end

 -- Fill out a row with the given data
-function Shopkeeper.SetMiniDataRow(index, guild, itemName, icon, quantity, sellTime, price, seller)
+function Shopkeeper:SetMiniDataRow(index, guild, itemName, icon, quantity, sellTime, price, seller)
   if index < 1 or index > 8 then return end

-  local dataRow = Shopkeeper.MiniDataRows[index]
+  local dataRow = self.MiniDataRows[index]

   -- Guild cell
   dataRow:GetNamedChild("Guild"):SetText(guild)
@@ -260,7 +257,7 @@ function Shopkeeper.SetMiniDataRow(index, guild, itemName, icon, quantity, sellT
   itemCell:SetHandler("OnMouseDoubleClick", function()
     ZO_ChatWindowTextEntryEditBox:SetText(ZO_ChatWindowTextEntryEditBox:GetText() .. string.gsub(itemName, "|H0", "|H1"))
   end)
-  itemCell:SetHandler("OnMouseEnter", function() Shopkeeper:ShowToolTip(itemName, itemCell) end)
+  itemCell:SetHandler("OnMouseEnter", function() self.ShowToolTip(itemName, itemCell) end)
   itemCell:SetHandler("OnMouseExit", function() ClearTooltip(ItemTooltip) end)
   local itemCellLabel = itemCell:GetLabelControl()
   itemCellLabel:SetWrapMode(TEXT_WRAP_MODE_ELLIPSIS)
@@ -275,8 +272,7 @@ function Shopkeeper.SetMiniDataRow(index, guild, itemName, icon, quantity, sellT
   -- math.floor(number + 0.5) is a quick shorthand way to round for
   -- positive values.
   local dispPrice = price
-  local settingsToUse = Shopkeeper.savedVariables
-  if Shopkeeper.acctSavedVariables.allSettingsAccount then settingsToUse = Shopkeeper.acctSavedVariables end
+  local settingsToUse = Shopkeeper:ActiveSettings()
   if settingsToUse.showFullPrice then
     if settingsToUse.showUnitPrice and quantity > 0 then
       dispPrice = math.floor((dispPrice / quantity) + 0.5)
@@ -290,78 +286,75 @@ function Shopkeeper.SetMiniDataRow(index, guild, itemName, icon, quantity, sellT
   end

   -- Insert thousands separators for the price
-  local stringPrice = Shopkeeper.localizedNumber(dispPrice)
+  local stringPrice = self.LocalizedNumber(dispPrice)

   -- Finally, set the price
   dataRow:GetNamedChild("Price"):SetText(stringPrice .. " |t16:16:EsoUI/Art/currency/currency_gold.dds|t")
 end

 -- Build the data rows based on the position of the slider
-function Shopkeeper.DisplayRows()
-  if (Shopkeeper.acctSavedVariables.allSettingsAccount and Shopkeeper.acctSavedVariables.viewSize == "full") or
-     (not Shopkeeper.acctSavedVariables.allSettingsAccount and Shopkeeper.savedVariables.viewSize == "full") then
+function Shopkeeper:DisplayRows()
+  if Shopkeeper:ActiveSettings().viewSize == "full" then
     local startIndex = ShopkeeperWindowSlider:GetValue()
-    if startIndex + #Shopkeeper.DataRows > #Shopkeeper.SearchTable then
-      startIndex = #Shopkeeper.SearchTable - #Shopkeeper.DataRows
+    if startIndex + #self.DataRows > #self.SearchTable then
+      startIndex = #self.SearchTable - #self.DataRows
     end

     if startIndex < 1 then startIndex = 0 end

     -- Hide the slider if there's less than a full page of results
-    ShopkeeperWindowSlider:SetHidden(#Shopkeeper.SearchTable < 16)
+    ShopkeeperWindowSlider:SetHidden(#self.SearchTable < 16)

     -- Now that we know where to start in the table, fill out rows with the next
     -- (currently) 15 items in the scan results table.
-    for i = 1, #Shopkeeper.DataRows do
+    for i = 1, #self.DataRows do
       local rowIndex = i + startIndex
-      if rowIndex > #Shopkeeper.SearchTable then
-        Shopkeeper.ClearDataRow(i)
+      if rowIndex > #self.SearchTable then
+        self:ClearDataRow(i)
         ShopkeeperWindowSlider:SetHidden(true)
       else
-        local scanResult = Shopkeeper.SearchTable[rowIndex]
+        local scanResult = self.SearchTable[rowIndex]
         -- Older data won't have kiosk info
         local kioskSale = nil
         if #scanResult > 8 then kioskSale = scanResult[9] end
-        Shopkeeper.SetDataRow(i, scanResult[1], scanResult[2], scanResult[3], scanResult[4], scanResult[5], Shopkeeper.textTimeSince(scanResult[6], false), scanResult[7], scanResult[8], kioskSale)
+        self:SetDataRow(i, scanResult[1], scanResult[2], scanResult[3], scanResult[4], scanResult[5], self.TextTimeSince(scanResult[6], false), scanResult[7], scanResult[8], kioskSale)
       end
     end

     -- Scale the slider's range to the number of items we have minus the number of rows
     local sliderMax = 0
-    local tableToUse = Shopkeeper.ScanResults
-    if Shopkeeper.viewMode == "self" then tableToUse = Shopkeeper.SelfSales end
+    local tableToUse = self.SearchTable
     if #tableToUse > 15 then sliderMax = (#tableToUse - 15) end
     ShopkeeperWindowSlider:SetMinMax(0, sliderMax)
+
   -- Mini size
   else
     local startIndex = ShopkeeperMiniWindowSlider:GetValue()
-    if startIndex + #Shopkeeper.MiniDataRows > #Shopkeeper.SearchTable then
-      startIndex = #Shopkeeper.SearchTable - #Shopkeeper.MiniDataRows
+    if startIndex + #self.MiniDataRows > #self.SearchTable then
+      startIndex = #self.SearchTable - #self.MiniDataRows
     end

     if startIndex < 1 then startIndex = 0 end

     -- Hide the slider if there's less than a full page of results
-    ShopkeeperMiniWindowSlider:SetHidden(#Shopkeeper.SearchTable < 9)
+    ShopkeeperMiniWindowSlider:SetHidden(#self.SearchTable < 9)

     -- Now that we know where to start in the table, fill out rows with the next
     -- (currently) 8 items in the scan results table.
-    for i = 1, #Shopkeeper.MiniDataRows do
+    for i = 1, #self.MiniDataRows do
       local rowIndex = i + startIndex
-      if rowIndex > #Shopkeeper.SearchTable then
-        Shopkeeper.ClearMiniDataRow(i)
+      if rowIndex > #self.SearchTable then
+        self:ClearMiniDataRow(i)
         ShopkeeperMiniWindowSlider:SetHidden(true)
       else
-        local scanResult = Shopkeeper.SearchTable[rowIndex]
-        Shopkeeper.SetMiniDataRow(i, scanResult[2], scanResult[3], scanResult[4], scanResult[5], Shopkeeper.textTimeSince(scanResult[6], false), scanResult[7], scanResult[8])
+        local scanResult = self.SearchTable[rowIndex]
+        self:SetMiniDataRow(i, scanResult[2], scanResult[3], scanResult[4], scanResult[5], self.TextTimeSince(scanResult[6], false), scanResult[7], scanResult[8])
       end
     end

     -- Scale the slider's range to the number of items we have minus the number of rows
     local sliderMax = 0
-    local tableToUse = Shopkeeper.ScanResults
-    if Shopkeeper.viewMode == "self" then tableToUse = Shopkeeper.SelfSales end
-    if #tableToUse > 8 then sliderMax = (#tableToUse - 8) end
+    if #self.SearchTable > 8 then sliderMax = (#self.SearchTable - 8) end
     ShopkeeperMiniWindowSlider:SetMinMax(0, sliderMax)
   end

@@ -370,60 +363,98 @@ function Shopkeeper.DisplayRows()
     local guildDropdown = ZO_ComboBox_ObjectFromContainer(ShopkeeperStatsGuildChooser)
     local selectedGuild = guildDropdown:GetSelectedItem()
     if selectedGuild == GetString(SK_STATS_ALL_GUILDS) then selectedGuild = "SK_STATS_TOTAL" end
-    Shopkeeper.UpdateStatsWindow(selectedGuild)
+    self:UpdateStatsWindow(selectedGuild)
+  end
+end
+
+-- Update all the fields of the stats window based on the response from SalesStats()
+function Shopkeeper:UpdateStatsWindow(guildName)
+  local sliderLevel = ShopkeeperStatsWindowSlider:GetValue()
+  self.newStats = self:SalesStats(sliderLevel)
+
+  -- Hide the slider if there's less than a day of data
+  -- and set the slider's range for the new day range returned
+  ShopkeeperStatsWindowSliderLabel:SetHidden(false)
+  ShopkeeperStatsWindowSlider:SetHidden(false)
+  if self.newStats['totalDays'] == nil or self.newStats['totalDays'] < 2 then
+    ShopkeeperStatsWindowSlider:SetHidden(true)
+    ShopkeeperStatsWindowSliderLabel:SetHidden(true)
+    sliderLevel = 0
+  elseif sliderLevel > (self.newStats['totalDays'] - 1) then
+    sliderLevel = 0
   end
+  ShopkeeperStatsWindowSlider:SetMinMax(0, (self.newStats['totalDays'] - 1))
+
+  -- Set the time range label appropriately
+  if sliderLevel == 0 then
+    ShopkeeperStatsWindowSliderSettingLabel:SetText(GetString(SK_STATS_TIME_ALL))
+  else
+    ShopkeeperStatsWindowSliderSettingLabel:SetText(zo_strformat(GetString(SK_STATS_TIME_SOME), sliderLevel))
+  end
+
+  -- Grab which guild is selected
+  local guildSelected = GetString(SK_STATS_ALL_GUILDS)
+  if guildName ~= "SK_STATS_TOTAL" then guildSelected = guildName end
+  local guildDropdown = ZO_ComboBox_ObjectFromContainer(ShopkeeperStatsGuildChooser)
+  guildDropdown:SetSelectedItem(guildSelected)
+
+  -- And set the rest of the stats window up with data from the appropriate
+  -- guild (or overall data)
+  ShopkeeperStatsWindowItemsSoldLabel:SetText(string.format(GetString(SK_STATS_ITEMS_SOLD), self.LocalizedNumber(self.newStats['numSold'][guildName]), self.newStats['kioskPercent'][guildName]))
+  ShopkeeperStatsWindowTotalGoldLabel:SetText(string.format(GetString(SK_STATS_TOTAL_GOLD), self.LocalizedNumber(self.newStats['totalGold'][guildName]), self.LocalizedNumber(self.newStats['avgGold'][guildName])))
+  ShopkeeperStatsWindowBiggestSaleLabel:SetText(string.format(GetString(SK_STATS_BIGGEST), zo_strformat("<<t:1>>", self.newStats['biggestSale'][guildName][2]), self.LocalizedNumber(self.newStats['biggestSale'][guildName][1])))
 end

 -- Switches the main window between full and half size.  Really this is hiding one
 -- and showing the other, but close enough ;)  Also makes the scene adjustments
 -- necessary to maintain the desired mail/trading house behaviors.
-function Shopkeeper.ToggleViewMode()
-  local settingsToUse = Shopkeeper.savedVariables
-  if Shopkeeper.acctSavedVariables.allSettingsAccount then settingsToUse = Shopkeeper.acctSavedVariables end
+function Shopkeeper:ToggleViewMode()
+  local settingsToUse = Shopkeeper:ActiveSettings()
   if settingsToUse.viewSize == "full" then
     settingsToUse.viewSize = "half"
+    ShopkeeperMiniWindowSearchBox:SetText(ShopkeeperWindowSearchBox:GetText())
     ShopkeeperWindow:SetHidden(true)
-    Shopkeeper.DisplayRows()
+    self:DisplayRows()
     ShopkeeperMiniWindow:SetHidden(false)

     if settingsToUse.openWithMail then
-      MAIL_INBOX_SCENE:RemoveFragment(Shopkeeper.uiFragment)
-      MAIL_SEND_SCENE:RemoveFragment(Shopkeeper.uiFragment)
-      MAIL_INBOX_SCENE:AddFragment(Shopkeeper.miniUiFragment)
-      MAIL_SEND_SCENE:AddFragment(Shopkeeper.miniUiFragment)
+      MAIL_INBOX_SCENE:RemoveFragment(self.uiFragment)
+      MAIL_SEND_SCENE:RemoveFragment(self.uiFragment)
+      MAIL_INBOX_SCENE:AddFragment(self.miniUiFragment)
+      MAIL_SEND_SCENE:AddFragment(self.miniUiFragment)
     end

     if settingsToUse.openWithStore then
-      TRADING_HOUSE_SCENE:RemoveFragment(Shopkeeper.uiFragment)
-      TRADING_HOUSE_SCENE:AddFragment(Shopkeeper.miniUiFragment)
+      TRADING_HOUSE_SCENE:RemoveFragment(self.uiFragment)
+      TRADING_HOUSE_SCENE:AddFragment(self.miniUiFragment)
     end
   else
     settingsToUse.viewSize = "full"
+    ShopkeeperWindowSearchBox:SetText(ShopkeeperMiniWindowSearchBox:GetText())
     ShopkeeperMiniWindow:SetHidden(true)
-    Shopkeeper.DisplayRows()
+    self:DisplayRows()
     ShopkeeperWindow:SetHidden(false)

     if settingsToUse.openWithMail then
-      MAIL_INBOX_SCENE:RemoveFragment(Shopkeeper.miniUiFragment)
-      MAIL_SEND_SCENE:RemoveFragment(Shopkeeper.miniUiFragment)
-      MAIL_INBOX_SCENE:AddFragment(Shopkeeper.uiFragment)
-      MAIL_SEND_SCENE:AddFragment(Shopkeeper.uiFragment)
+      MAIL_INBOX_SCENE:RemoveFragment(self.miniUiFragment)
+      MAIL_SEND_SCENE:RemoveFragment(self.miniUiFragment)
+      MAIL_INBOX_SCENE:AddFragment(self.uiFragment)
+      MAIL_SEND_SCENE:AddFragment(self.uiFragment)
     end

     if settingsToUse.openWithStore then
-      TRADING_HOUSE_SCENE:RemoveFragment(Shopkeeper.miniUiFragment)
-      TRADING_HOUSE_SCENE:AddFragment(Shopkeeper.uiFragment)
+      TRADING_HOUSE_SCENE:RemoveFragment(self.miniUiFragment)
+      TRADING_HOUSE_SCENE:AddFragment(self.uiFragment)
     end
   end
 end

 -- Set the visibility status of the main window to the opposite of its current status
 function Shopkeeper.ToggleShopkeeperWindow()
-  if (Shopkeeper.acctSavedVariables.allSettingsAccount and Shopkeeper.acctSavedVariables.viewSize == "full") or
-     (not Shopkeeper.acctSavedVariables.allSettingsAccount and Shopkeeper.savedVariables.viewSize == "full") then
+  if Shopkeeper:ActiveSettings().viewSize == "full" then
     ShopkeeperMiniWindow:SetHidden(true)
     if ShopkeeperWindow:IsHidden() then
-      Shopkeeper.DisplayRows()
+      Shopkeeper:DisplayRows()
       SetGameCameraUIMode(true)
     end

@@ -431,7 +462,7 @@ function Shopkeeper.ToggleShopkeeperWindow()
   else
     ShopkeeperWindow:SetHidden(true)
     if ShopkeeperMiniWindow:IsHidden() then
-      Shopkeeper.DisplayRows()
+      Shopkeeper:DisplayRows()
       SetGameCameraUIMode(true)
     end

@@ -441,14 +472,60 @@ end

 -- Set the visibility status of the stats window to the opposite of its current status
 function Shopkeeper.ToggleShopkeeperStatsWindow()
-  if ShopkeeperStatsWindow:IsHidden() then Shopkeeper.UpdateStatsWindow("SK_STATS_TOTAL") end
+  if ShopkeeperStatsWindow:IsHidden() then Shopkeeper:UpdateStatsWindow("SK_STATS_TOTAL") end
   ShopkeeperStatsWindow:SetHidden(not ShopkeeperStatsWindow:IsHidden())
 end

+-- Switch between all sales and your sales
+function Shopkeeper:SwitchViewMode()
+  if self.viewMode == "self" then
+    ShopkeeperSwitchViewButton:SetText(GetString(SK_VIEW_YOUR_SALES))
+    ShopkeeperWindowTitle:SetText("Shopkeeper - " .. GetString(SK_ALL_SALES_TITLE))
+    ShopkeeperMiniSwitchViewButton:SetText(GetString(SK_VIEW_YOUR_SALES))
+    ShopkeeperMiniWindowTitle:SetText("Shopkeeper - " .. GetString(SK_ALL_SALES_TITLE))
+    self.viewMode = "all"
+  else
+    ShopkeeperSwitchViewButton:SetText(GetString(SK_VIEW_ALL_SALES))
+    ShopkeeperWindowTitle:SetText("Shopkeeper - " .. GetString(SK_YOUR_SALES_TITLE))
+    ShopkeeperMiniSwitchViewButton:SetText(GetString(SK_VIEW_ALL_SALES))
+    ShopkeeperMiniWindowTitle:SetText("Shopkeeper - " .. GetString(SK_YOUR_SALES_TITLE))
+    self.viewMode = "self"
+  end
+
+  if Shopkeeper:ActiveSettings().viewSize == "full" then
+    self:DoSearch(ShopkeeperWindowSearchBox:GetText())
+  else
+    self:DoSearch(ShopkeeperMiniWindowSearchBox:GetText())
+  end
+end
+
+-- Switch between total price mode and unit price mode
+function Shopkeeper:SwitchPriceMode()
+  local settingsToUse = Shopkeeper:ActiveSettings()
+  if settingsToUse.showUnitPrice then
+    settingsToUse.showUnitPrice = false
+    ShopkeeperPriceSwitchButton:SetText(GetString(SK_SHOW_UNIT))
+    ShopkeeperWindowPrice:SetText(GetString(SK_PRICE_COLUMN))
+    ShopkeeperMiniPriceSwitchButton:SetText(GetString(SK_SHOW_UNIT))
+    ShopkeeperMiniWindowPrice:SetText(GetString(SK_PRICE_COLUMN))
+  else
+    settingsToUse.showUnitPrice = true
+    ShopkeeperPriceSwitchButton:SetText(GetString(SK_SHOW_TOTAL))
+    ShopkeeperWindowPrice:SetText(GetString(SK_PRICE_EACH_COLUMN))
+    ShopkeeperMiniPriceSwitchButton:SetText(GetString(SK_SHOW_TOTAL))
+    ShopkeeperMiniWindowPrice:SetText(GetString(SK_PRICE_EACH_COLUMN))
+  end
+
+  if self.curSort[1] == "price" then
+    self:SortByPrice(self.curSort[2], self.SearchTable)
+  else
+    self:DisplayRows()
+  end
+end
+
 -- Handle scrolling the main window
 function Shopkeeper.OnSliderMouseWheel(self, delta)
-  if (Shopkeeper.acctSavedVariables.allSettingsAccount and Shopkeeper.acctSavedVariables.viewSize == "full") or
-     (not Shopkeeper.acctSavedVariables.allSettingsAccount and Shopkeeper.savedVariables.viewSize == "full") then
+  if Shopkeeper:ActiveSettings().viewSize == "full" then
     local oldSliderLevel = ShopkeeperWindowSlider:GetValue()
     local newSliderLevel = oldSliderLevel - delta
     ShopkeeperWindowSlider:SetValue(newSliderLevel)
@@ -461,7 +538,7 @@ end

 -- Update the table if the slider moved
 function Shopkeeper.OnSliderMoved(self, sliderLevel, eventReason)
-  Shopkeeper.DisplayRows()
+  Shopkeeper:DisplayRows()
 end

 -- Update the stats window if the slider in it moved
@@ -469,5 +546,169 @@ function Shopkeeper.OnStatsSliderMoved(self, sliderLevel, eventReason)
   local guildDropdown = ZO_ComboBox_ObjectFromContainer(ShopkeeperStatsGuildChooser)
   local selectedGuild = guildDropdown:GetSelectedItem()
   if selectedGuild == GetString(SK_STATS_ALL_GUILDS) then selectedGuild = "SK_STATS_TOTAL" end
-  Shopkeeper.UpdateStatsWindow(selectedGuild)
+  Shopkeeper:UpdateStatsWindow(selectedGuild)
+end
+
+-- Set up the labels and tooltips from translation files and do a couple other UI
+-- setup routines
+function Shopkeeper:SetupShopkeeperWindow()
+  local settingsToUse = Shopkeeper:ActiveSettings()
+  -- Shopkeeper button in guild store screen
+  local reopenShopkeeper = CreateControlFromVirtual("ShopkeeperReopenButton", ZO_TradingHouseLeftPane, "ZO_DefaultButton")
+  reopenShopkeeper:SetAnchor(CENTER, ZO_TradingHouseLeftPane, BOTTOM, 0, 5)
+  reopenShopkeeper:SetWidth(200)
+  reopenShopkeeper:SetText("Shopkeeper")
+  reopenShopkeeper:SetHandler("OnClicked", self.ToggleShopkeeperWindow)
+
+  -- Shopkeeper button in mail screen
+  local shopkeeperMail = CreateControlFromVirtual("ShopkeeperMailButton", ZO_MailInbox, "ZO_DefaultButton")
+  shopkeeperMail:SetAnchor(TOPLEFT, ZO_MailInbox, TOPLEFT, 100, 4)
+  shopkeeperMail:SetWidth(200)
+  shopkeeperMail:SetText("Shopkeeper")
+  shopkeeperMail:SetHandler("OnClicked", self.ToggleShopkeeperWindow)
+
+  -- Stats dropdown choice box
+  local shopkeeperStatsGuild = CreateControlFromVirtual("ShopkeeperStatsGuildChooser", ShopkeeperStatsWindow, "ShopkeeperStatsGuildDropdown")
+  shopkeeperStatsGuild:SetDimensions(270,25)
+  shopkeeperStatsGuild:SetAnchor(LEFT, ShopkeeperStatsWindowGuildChooserLabel, RIGHT, 5, 0)
+  shopkeeperStatsGuild.m_comboBox:SetSortsItems(false)
+
+  -- Set column headers and search label from translation
+  ShopkeeperWindowBuyer:SetText(GetString(SK_BUYER_COLUMN))
+  ShopkeeperWindowGuild:SetText(GetString(SK_GUILD_COLUMN))
+  ShopkeeperWindowItemName:SetText(GetString(SK_ITEM_COLUMN))
+  ShopkeeperWindowSellTime:SetText(GetString(SK_TIME_COLUMN))
+  ShopkeeperMiniWindowGuild:SetText(GetString(SK_GUILD_COLUMN))
+  ShopkeeperMiniWindowItemName:SetText(GetString(SK_ITEM_COLUMN))
+  ShopkeeperMiniWindowSellTime:SetText(GetString(SK_TIME_COLUMN))
+
+  if settingsToUse.showUnitPrice then
+    ShopkeeperWindowPrice:SetText(GetString(SK_PRICE_EACH_COLUMN))
+    ShopkeeperMiniWindowPrice:SetText(GetString(SK_PRICE_EACH_COLUMN))
+  else
+    ShopkeeperWindowPrice:SetText(GetString(SK_PRICE_COLUMN))
+    ShopkeeperMiniWindowPrice:SetText(GetString(SK_PRICE_COLUMN))
+  end
+
+  -- Set second half of window title from translation
+  ShopkeeperWindowTitle:SetText("Shopkeeper - " .. GetString(SK_YOUR_SALES_TITLE))
+  ShopkeeperMiniWindowTitle:SetText("Shopkeeper - " .. GetString(SK_YOUR_SALES_TITLE))
+
+  -- And set the stats window title and slider label from translation
+  ShopkeeperStatsWindowTitle:SetText("Shopkeeper " .. GetString(SK_STATS_TITLE))
+  ShopkeeperStatsWindowGuildChooserLabel:SetText(GetString(SK_GUILD_COLUMN) .. ": ")
+  ShopkeeperStatsWindowSliderLabel:SetText(GetString(SK_STATS_DAYS))
+
+  -- Set up some helpful tooltips for the Buyer, Item, Time, and Price column headers
+  ShopkeeperWindowBuyer:SetHandler("OnMouseEnter", function(self)
+    ZO_Tooltips_ShowTextTooltip(self, TOP, GetString(SK_BUYER_TOOLTIP)) end)
+
+  ShopkeeperWindowItemName:SetHandler("OnMouseEnter", function(self)
+    ZO_Tooltips_ShowTextTooltip(self, TOP, GetString(SK_ITEM_TOOLTIP)) end)
+
+  ShopkeeperMiniWindowItemName:SetHandler("OnMouseEnter", function(self)
+    ZO_Tooltips_ShowTextTooltip(self, TOP, GetString(SK_ITEM_TOOLTIP)) end)
+
+  ShopkeeperWindowSellTime:SetHandler("OnMouseEnter", function(self)
+    ZO_Tooltips_ShowTextTooltip(self, TOP, GetString(SK_SORT_TIME_TOOLTIP)) end)
+
+  ShopkeeperMiniWindowSellTime:SetHandler("OnMouseEnter", function(self)
+    ZO_Tooltips_ShowTextTooltip(self, TOP, GetString(SK_SORT_TIME_TOOLTIP)) end)
+
+  ShopkeeperWindowPrice:SetHandler("OnMouseEnter", function(self)
+    ZO_Tooltips_ShowTextTooltip(self, TOP, GetString(SK_SORT_PRICE_TOOLTIP)) end)
+
+  ShopkeeperMiniWindowPrice:SetHandler("OnMouseEnter", function(self)
+    ZO_Tooltips_ShowTextTooltip(self, TOP, GetString(SK_SORT_PRICE_TOOLTIP)) end)
+
+  -- View switch button
+  ShopkeeperSwitchViewButton:SetText(GetString(SK_VIEW_ALL_SALES))
+  ShopkeeperMiniSwitchViewButton:SetText(GetString(SK_VIEW_ALL_SALES))
+
+  -- Total / unit price switch button
+  if settingsToUse.showUnitPrice then
+    ShopkeeperPriceSwitchButton:SetText(GetString(SK_SHOW_TOTAL))
+    ShopkeeperMiniPriceSwitchButton:SetText(GetString(SK_SHOW_TOTAL))
+  else
+    ShopkeeperPriceSwitchButton:SetText(GetString(SK_SHOW_UNIT))
+    ShopkeeperMiniPriceSwitchButton:SetText(GetString(SK_SHOW_UNIT))
+  end
+
+	ShopkeeperWindowLoadingIcon.animation = ANIMATION_MANAGER:CreateTimelineFromVirtual("LoadIconAnimation", ShopkeeperWindowLoadingIcon)
+	ShopkeeperMiniWindowLoadingIcon.animation = ANIMATION_MANAGER:CreateTimelineFromVirtual("LoadIconAnimation", ShopkeeperMiniWindowLoadingIcon)
+
+  -- Refresh button
+  ShopkeeperRefreshButton:SetText(GetString(SK_REFRESH_LABEL))
+  ShopkeeperMiniRefreshButton:SetText(GetString(SK_REFRESH_LABEL))
+
+
+  -- Reset button and confirmation dialog
+  ShopkeeperResetButton:SetText(GetString(SK_RESET_LABEL))
+  ShopkeeperMiniResetButton:SetText(GetString(SK_RESET_LABEL))
+  local confirmDialog = {
+    title = { text = GetString(SK_RESET_CONFIRM_TITLE) },
+    mainText = { text = GetString(SK_RESET_CONFIRM_MAIN) },
+    buttons = {
+      {
+        text = SI_DIALOG_ACCEPT,
+        callback = function() self:DoReset() end
+      },
+      { text = SI_DIALOG_CANCEL }
+    }
+  }
+  ZO_Dialogs_RegisterCustomDialog("ShopkeeperResetConfirmation", confirmDialog)
+
+  -- Make the 15 rows that comprise the visible table
+  if #self.DataRows == 0 then
+    local dataRowOffsetX = 5
+    local dataRowOffsetY = 74
+    for i = 1, 15 do
+      local dRow = CreateControlFromVirtual("ShopkeeperDataRow", ShopkeeperWindow, "ShopkeeperDataRow", i)
+      dRow:SetSimpleAnchorParent(dataRowOffsetX, dataRowOffsetY+((dRow:GetHeight()+2)*(i-1)))
+      self.DataRows[i] = dRow
+    end
+  end
+
+  -- And 8 for the mini window
+  if #self.MiniDataRows == 0 then
+    local dataRowOffsetX = 10
+    local dataRowOffsetY = 74
+    for i = 1, 8 do
+      local dRow = CreateControlFromVirtual("ShopkeeperMiniDataRow", ShopkeeperMiniWindow, "ShopkeeperMiniDataRow", i)
+      dRow:SetSimpleAnchorParent(dataRowOffsetX, dataRowOffsetY+((dRow:GetHeight()+2)*(i-1)))
+      self.MiniDataRows[i] = dRow
+    end
+  end
+
+  -- Stats buttons
+  ShopkeeperWindowStatsButton:SetHandler("OnMouseEnter", function(self)
+    ZO_Tooltips_ShowTextTooltip(self, TOP, GetString(SK_STATS_TOOLTIP))
+  end)
+  ShopkeeperMiniWindowStatsButton:SetHandler("OnMouseEnter", function(self)
+    ZO_Tooltips_ShowTextTooltip(self, TOP, GetString(SK_STATS_TOOLTIP))
+  end)
+
+  -- View size change buttons
+  ShopkeeperWindowViewSizeButton:SetHandler("OnMouseEnter", function(self)
+    ZO_Tooltips_ShowTextTooltip(self, TOP, GetString(SK_SIZE_TOOLTIP))
+  end)
+  ShopkeeperMiniWindowViewSizeButton:SetHandler("OnMouseEnter", function(self)
+    ZO_Tooltips_ShowTextTooltip(self, TOP, GetString(SK_SIZE_TOOLTIP))
+  end)
+
+  -- Slider setup
+  ShopkeeperWindow:SetHandler("OnMouseWheel", self.OnSliderMouseWheel)
+  ShopkeeperWindowSlider:SetValue(0)
+  ShopkeeperMiniWindow:SetHandler("OnMouseWheel", self.OnSliderMouseWheel)
+  ShopkeeperMiniWindowSlider:SetValue(0)
+  ShopkeeperStatsWindowSlider:SetValue(0)
+
+  -- Search handler
+  ZO_PreHookHandler(ShopkeeperWindowSearchBox, "OnTextChanged", function(self) Shopkeeper:DoSearch(ShopkeeperWindowSearchBox:GetText()) end)
+  ZO_PreHookHandler(ShopkeeperMiniWindowSearchBox, "OnTextChanged", function(self) Shopkeeper:DoSearch(ShopkeeperMiniWindowSearchBox:GetText()) end)
+
+  -- We're all set, so make sure we're using the right font and then update the UI
+  self.windowFont = settingsToUse.windowFont
+  self:UpdateFonts()
+  self:DisplayRows()
 end
\ No newline at end of file
diff --git a/Shopkeeper_Util.lua b/Shopkeeper_Util.lua
index 53b46d0..1751164 100644
--- a/Shopkeeper_Util.lua
+++ b/Shopkeeper_Util.lua
@@ -1,14 +1,14 @@
 -- Shopkeeper Utility Functions File
--- Last Updated August 18, 2014
+-- Last Updated August 26, 2014
 -- Written August 2014 by Dan Stone (@khaibit) - dankitymao@gmail.com
 -- Released under terms in license accompanying this file.
 -- Distribution without license is prohibited!

-function Shopkeeper.localizedNumber(numberValue)
+function Shopkeeper.LocalizedNumber(numberValue)
   local stringPrice = numberValue
-  -- Insert thousands separators for the price
-  -- local stringPrice = numberValue
   local subString = "%1" .. GetString(SK_THOUSANDS_SEP) .."%2"
+
+  -- Insert thousands separators for the price
   while true do
     stringPrice, k = string.gsub(stringPrice, "^(-?%d+)(%d%d%d)", subString)
     if (k == 0) then break end
@@ -20,12 +20,12 @@ end
 -- Create a textual representation of a time interval
 -- (X and Y) or Z in LUA is the equivalent of C-style
 -- ternary syntax X ? Y : Z so long as Y is not false or nil
-function Shopkeeper.textTimeSince(theTime, useLowercase)
+function Shopkeeper.TextTimeSince(theTime, useLowercase)
   local secsSince = GetTimeStamp() - theTime
-  if secsSince < 90 then
+  if secsSince < 75 then
     return ((useLowercase and zo_strformat(GetString(SK_TIME_SECONDS_LC), secsSince)) or
              zo_strformat(GetString(SK_TIME_SECONDS), secsSince))
-  elseif secsSince < 5400 then
+  elseif secsSince < 4500 then
     return ((useLowercase and zo_strformat(GetString(SK_TIME_SECONDS_LC), math.floor(secsSince / 60.0))) or
              zo_strformat(GetString(SK_TIME_MINUTES), math.floor(secsSince / 60.0)))
   elseif secsSince < 86400 then
@@ -37,19 +37,36 @@ function Shopkeeper.textTimeSince(theTime, useLowercase)
   end
 end

+-- Grabs the first and last events in guildID's sales history and compares the secsSince
+-- values returned.  Returns true if the first event (ID 1) is newer than the last event,
+-- false otherwise.
+function Shopkeeper.IsNewestFirst(guildID)
+  local numEvents = GetNumGuildEvents(guildID, GUILD_HISTORY_SALES)
+  local _, secsSinceFirst, _, _, _, _, _, _ = GetGuildEventInfo(guildID, GUILD_HISTORY_SALES, 1)
+  local _, secsSinceLast, _, _, _, _, _, _ = GetGuildEventInfo(guildID, GUILD_HISTORY_SALES, numEvents)
+  return (secsSinceFirst < secsSinceLast)
+end
+
+-- A simple utility function to return which set of settings are active,
+-- based on the allSettingsAccount option setting.
+function Shopkeeper:ActiveSettings()
+  if self.acctSavedVariables.allSettingsAccount then return self.acctSavedVariables
+  else return self.savedVariables end
+end
+
 -- A utility function to grab all the keys of the sound table
 -- to populate the options dropdown
-function Shopkeeper.soundKeys()
+function Shopkeeper:SoundKeys()
   local keyList = {}
-  for i = 1, #Shopkeeper.alertSounds do table.insert(keyList, Shopkeeper.alertSounds[i].name) end
+  for i = 1, #self.alertSounds do table.insert(keyList, self.alertSounds[i].name) end
   return keyList
 end

 -- A utility function to find the key associated with a given value in
 -- the sounds table.  Best we can do is a linear search unfortunately,
 -- but it's a small table.
-function Shopkeeper.searchSounds(sound)
-  for i, theSound in ipairs(Shopkeeper.alertSounds) do
+function Shopkeeper:SearchSounds(sound)
+  for i, theSound in ipairs(self.alertSounds) do
     if theSound.sound == sound then return theSound.name end
   end

@@ -58,8 +75,8 @@ function Shopkeeper.searchSounds(sound)
 end

 -- Same as searchSounds, above, but compares names instead of sounds.
-function Shopkeeper.searchSoundNames(name)
-  for i,theSound in ipairs(Shopkeeper.alertSounds) do
+function Shopkeeper:SearchSoundNames(name)
+  for i,theSound in ipairs(self.alertSounds) do
     if theSound.name == name then return theSound.sound end
   end
 end
\ No newline at end of file
diff --git a/i18n/DE.lua b/i18n/DE.lua
index 0b9ba8f..231af08 100644
--- a/i18n/DE.lua
+++ b/i18n/DE.lua
@@ -1,5 +1,5 @@
 -- Shopkeeper German Localization File
--- Last Updated August 19, 2014
+-- Last Updated August 26, 2014
 -- Written July 2014 by Dan Stone (@khaibit) - dankitymao@gmail.com
 -- Released under terms in license.txt accompanying this file.
 -- Distribution without license is prohibited!
@@ -30,6 +30,8 @@ ZO_CreateStringId("SK_ALERT_CHAT_NAME", "Meldungen im Chat")
 ZO_CreateStringId("SK_ALERT_CHAT_TIP", "Zeigt Meldungen \195\188ber Verk\195\164ufe im Chat-Fenster an.")
 ZO_CreateStringId("SK_ACCOUNT_WIDE_NAME", "Account-Wide Settings")
 ZO_CreateStringId("SK_ACCOUNT_WIDE_TIP", "Makes all settings apply to all characters on your account.")
+ZO_CreateStringId("SK_OFFLINE_SALES_NAME", "Offline Sales Report")
+ZO_CreateStringId("SK_OFFLINE_SALES_TIP", "Show alerts in chat for items you sold while offline when you log in next.")

 -- Main Window
 ZO_CreateStringId("SK_VIEW_ALL_SALES", "Zeigt alle Verk\195\164ufe")
@@ -66,6 +68,8 @@ ZO_CreateStringId("SK_REFRESH_START", "Manuelle Aktualisierung der Verka\195\164
 ZO_CreateStringId("SK_REFRESH_DONE", "Aktualisierung der Verka\195\164ufe abgeschlossen.")
 ZO_CreateStringId("SK_REFRESH_WAIT", "Bitte mindesten eine Minute zwischen den Aktualisierungen warten.")
 ZO_CreateStringId("SK_RESET_LABEL", "Zur\195\188cksetzen")
+ZO_CreateStringId("SK_RESET_CONFIRM_TITLE", "Confirm Reset")
+ZO_CreateStringId("SK_RESET_CONFIRM_MAIN", "Are you sure you wish to reset your sales history?  All data will be replaced with fresh server data.")
 ZO_CreateStringId("SK_RESET_DONE", "L\195\182scht alle gespeicherten Verk\195\164ufe.")
 ZO_CreateStringId("SK_SALES_ALERT", "%d mal %s f\195\188r %s |t16:16:EsoUI/Art/currency/currency_gold.dds|t wurden \195\188ber die Gilde %s %s verkauft.")
 ZO_CreateStringId("SK_SALES_ALERT_COLOR", "%d mal %s f\195\188r |cD5B526%s |t16:16:EsoUI/Art/currency/currency_gold.dds|t |cFFFFFFwurden \195\188ber die Gilde %s %s verkauft.")
@@ -73,6 +77,8 @@ ZO_CreateStringId("SK_SALES_ALERT_SINGLE", "%s f\195\188r %s |t16:16:EsoUI/Art/c
 ZO_CreateStringId("SK_SALES_ALERT_SINGLE_COLOR", "%s f\195\188r |cD5B526%s |t16:16:EsoUI/Art/currency/currency_gold.dds|t |cFFFFFFwurde \195\188ber die Gilde %s %s verkauft.")
 ZO_CreateStringId("SK_SALES_ALERT_GROUP", "%d Gegenst\195\164nde wurden verkauft f\195\188r einen Gesammtwert von %s |t16:16:EsoUI/Art/currency/currency_gold.dds|t.")
 ZO_CreateStringId("SK_SALES_ALERT_GROUP_COLOR", "%d Gegenst\195\164nde wurden verkauft f\195\188r einen Gesammtwert von |cD5B526%s |t16:16:EsoUI/Art/currency/currency_gold.dds|t.")
+ZO_CreateStringId("SK_SALES_REPORT", "Umsatzbericht:")
+ZO_CreateStringId("SK_SALES_REPORT_END", "Ende des Berichts.")

 -- Stats Window
 ZO_CreateStringId("SK_STATS_TITLE", "Sales Statistics")
diff --git a/i18n/EN.lua b/i18n/EN.lua
index a99ffed..695fdb3 100644
--- a/i18n/EN.lua
+++ b/i18n/EN.lua
@@ -1,5 +1,5 @@
 -- Shopkeeper English Localization File
--- Last Updated August 19, 2014
+-- Last Updated August 26, 2014
 -- Written July 2014 by Dan Stone (@khaibit) - dankitymao@gmail.com
 -- Released under terms in license accompanying this file.
 -- Distribution without license is prohibited!
@@ -29,6 +29,8 @@ ZO_CreateStringId("SK_ALERT_CHAT_NAME", "Chat Alerts")
 ZO_CreateStringId("SK_ALERT_CHAT_TIP", "Show sales alerts in your chat box.")
 ZO_CreateStringId("SK_ACCOUNT_WIDE_NAME", "Account-Wide Settings")
 ZO_CreateStringId("SK_ACCOUNT_WIDE_TIP", "Makes all settings apply to all characters on your account.")
+ZO_CreateStringId("SK_OFFLINE_SALES_NAME", "Offline Sales Report")
+ZO_CreateStringId("SK_OFFLINE_SALES_TIP", "Show alerts in chat for items you sold while offline when you log in next.")

 -- Main window
 ZO_CreateStringId("SK_VIEW_ALL_SALES", "Show All Sales")
@@ -65,6 +67,8 @@ ZO_CreateStringId("SK_REFRESH_START", "Starting refresh.")
 ZO_CreateStringId("SK_REFRESH_DONE", "Refresh complete.")
 ZO_CreateStringId("SK_REFRESH_WAIT", "Please wait a minute or so between refreshes.")
 ZO_CreateStringId("SK_RESET_LABEL", "Reset")
+ZO_CreateStringId("SK_RESET_CONFIRM_TITLE", "Confirm Reset")
+ZO_CreateStringId("SK_RESET_CONFIRM_MAIN", "Are you sure you wish to reset your sales history?  All data will be replaced with fresh server data.")
 ZO_CreateStringId("SK_RESET_DONE", "Sales history reset.")
 ZO_CreateStringId("SK_SALES_ALERT", "You have sold %s x%d for %s |t16:16:EsoUI/Art/currency/currency_gold.dds|t from %s %s.")
 ZO_CreateStringId("SK_SALES_ALERT_COLOR", "You have sold %s x%d for |cD5B526%s |t16:16:EsoUI/Art/currency/currency_gold.dds|t |cFFFFFFfrom %s %s.")
@@ -72,6 +76,8 @@ ZO_CreateStringId("SK_SALES_ALERT_SINGLE", "You have sold %s for %s |t16:16:EsoU
 ZO_CreateStringId("SK_SALES_ALERT_SINGLE_COLOR", "You have sold %s for |cD5B526%s |t16:16:EsoUI/Art/currency/currency_gold.dds|t |cFFFFFFfrom %s %s.")
 ZO_CreateStringId("SK_SALES_ALERT_GROUP", "You have sold %d items totaling %s |t16:16:EsoUI/Art/currency/currency_gold.dds|t from guild stores.")
 ZO_CreateStringId("SK_SALES_ALERT_GROUP_COLOR", "You have sold %d items totaling |cD5B526%s |t16:16:EsoUI/Art/currency/currency_gold.dds|t |cFFFFFFfrom guild stores.")
+ZO_CreateStringId("SK_SALES_REPORT", "Sales Report:")
+ZO_CreateStringId("SK_SALES_REPORT_END", "End of report.")

 -- Stats Window
 ZO_CreateStringId("SK_STATS_TITLE", "Sales Statistics")
diff --git a/i18n/FR.lua b/i18n/FR.lua
index 30444bc..e43dbb2 100644
--- a/i18n/FR.lua
+++ b/i18n/FR.lua
@@ -1,5 +1,5 @@
 -- Shopkeeper French Localization File
--- Last Updated August 19, 2014
+-- Last Updated August 26, 2014
 -- Written July 2014 by Dan Stone (@khaibit) - dankitymao@gmail.com
 -- Released under terms in license accompanying this file.
 -- Distribution without license is prohibited!
@@ -28,8 +28,10 @@ ZO_CreateStringId("SK_ALERT_TYPE_NAME", "Son de L'alerte")
 ZO_CreateStringId("SK_ALERT_TYPE_TIP", "Le son \195\160 jouer quand vous vendez un objet (optionnel).")
 ZO_CreateStringId("SK_ALERT_CHAT_NAME", "Alertes de Chat")
 ZO_CreateStringId("SK_ALERT_CHAT_TIP", "Afficher les alertes de ventes dans la fen\195\170tre de discussion.")
-ZO_CreateStringId("SK_ACCOUNT_WIDE_NAME", "Account-Wide Settings")
-ZO_CreateStringId("SK_ACCOUNT_WIDE_TIP", "Makes all settings apply to all characters on your account.")
+ZO_CreateStringId("SK_ACCOUNT_WIDE_NAME", "Param\195\168tres Globaux du Compte")
+ZO_CreateStringId("SK_ACCOUNT_WIDE_TIP", "Applique les param\195\168tres \195\160 tous les personnages de votre compte.")
+ZO_CreateStringId("SK_OFFLINE_SALES_NAME", "Rapport des Ventes Hors-ligne")
+ZO_CreateStringId("SK_OFFLINE_SALES_TIP", "Lorque vous-vous connectez, affiche dans le chat des alertes reportant les ventes faites lorsque vous \195\170tiez hors-ligne.")

 -- Main window
 ZO_CreateStringId("SK_VIEW_ALL_SALES", "Toutes Les Ventes")
@@ -43,7 +45,7 @@ ZO_CreateStringId("SK_GUILD_COLUMN", "Guilde")
 ZO_CreateStringId("SK_ITEM_COLUMN", "Bien Vendu")
 ZO_CreateStringId("SK_TIME_COLUMN", "Heure de Vente")
 ZO_CreateStringId("SK_PRICE_COLUMN", "Prix")
-ZO_CreateStringId("SK_PRICE_EACH_COLUMN", "Prix Unitaire")
+ZO_CreateStringId("SK_PRICE_EACH_COLUMN", "Prix/Unit\195\169")
 ZO_CreateStringId("SK_ITEM_TOOLTIP", "Double-clickez sur un objet pour y faire une r\195\169f\195\169rence dans le chat.")
 ZO_CreateStringId("SK_BUYER_TOOLTIP", "Double-clickez sur un vendeur pour le contacter.")
 ZO_CreateStringId("SK_SORT_TIME_TOOLTIP", "Clickez pour trier par heure de vente.")
@@ -66,6 +68,8 @@ ZO_CreateStringId("SK_REFRESH_START", "Rafraichissement des donn\195\169es en co
 ZO_CreateStringId("SK_REFRESH_DONE", "Rafraichissement des donn\195\169es termin\195\169.")
 ZO_CreateStringId("SK_REFRESH_WAIT", "Veuillez attendre une minute entre les rafraichissements.")
 ZO_CreateStringId("SK_RESET_LABEL", "R\195\169initialiser")
+ZO_CreateStringId("SK_RESET_CONFIRM_TITLE", "Confirmer la r\195\170initialisation")
+ZO_CreateStringId("SK_RESET_CONFIRM_MAIN", "\195\171tes vous s\195\187r de vouloir r\195\170initialiser votre historique de ventes? Toutes vos donn\195\170es seront remplac\195\170es par les nouvelles donn\195\170es du serveur.")
 ZO_CreateStringId("SK_RESET_DONE", "R\195\169initialiser l'historique des ventes.")
 ZO_CreateStringId("SK_SALES_ALERT", "Vous avez vendu %s x%d pour %s |t16:16:EsoUI/Art/currency/currency_gold.dds|t \195\160 %s %s.")
 ZO_CreateStringId("SK_SALES_ALERT_COLOR", "Vous avez vendu %s x%d pour |cD5B526%s |t16:16:EsoUI/Art/currency/currency_gold.dds|t |cFFFFFF\195\160 %s %s.")
@@ -73,6 +77,8 @@ ZO_CreateStringId("SK_SALES_ALERT_SINGLE", "Vous avez vendu %s pour %s |t16:16:E
 ZO_CreateStringId("SK_SALES_ALERT_SINGLE_COLOR", "Vous avez vendu |cD5B526%s pour %s |t16:16:EsoUI/Art/currency/currency_gold.dds|t |cFFFFFF\195\160 %s %s.")
 ZO_CreateStringId("SK_SALES_ALERT_GROUP", "Vous avez vendu %d biens pour un total de %s |t16:16:EsoUI/Art/currency/currency_gold.dds|t dans les magasins de guildes.")
 ZO_CreateStringId("SK_SALES_ALERT_GROUP_COLOR", "Vous avez vendu %d biens pour un total de |cD5B526%s |t16:16:EsoUI/Art/currency/currency_gold.dds|t |cFFFFFFdans les magasins de guildes.")
+ZO_CreateStringId("SK_SALES_REPORT", "Rapport des ventes:")
+ZO_CreateStringId("SK_SALES_REPORT_END", "Fin du rapport.")

 -- Stats Window
 ZO_CreateStringId("SK_STATS_TITLE", "Statistiques de Ventes")
@@ -85,5 +91,5 @@ ZO_CreateStringId("SK_STATS_DAYS", "Jours: ")
 ZO_CreateStringId("SK_STATS_ALL_GUILDS", "Toutes les guildes")

 -- Keybindings
-ZO_CreateStringId("SI_BINDING_NAME_SHOPKEEPER_TOGGLE", "Afficher/Cacher La Fen\195\170tre de Shopkeeper")
-ZO_CreateStringId("SI_BINDING_NAME_SHOPKEEPER_STATS_TOGGLE", "Afficher/Cacher La Fen\195\170tre de Statistiques")
\ No newline at end of file
+ZO_CreateStringId("SI_BINDING_NAME_SHOPKEEPER_TOGGLE", "Afficher/Masquer La Fen\195\170tre de Shopkeeper")
+ZO_CreateStringId("SI_BINDING_NAME_SHOPKEEPER_STATS_TOGGLE", "Afficher/Masquer La Fen\195\170tre de Statistiques")
\ No newline at end of file
diff --git a/readme b/readme
index 5f9334a..4ee568d 100644
--- a/readme
+++ b/readme
@@ -3,6 +3,17 @@ Inc. or its affiliates. The Elder Scrolls
 trademarks or trademarks of ZeniMax Media Inc. in the United States and/or
 other countries. All rights reserved.

+Changelog for 0.9.4
+  Offline sales report (optional report in chat of what you sold while offline)
+  Reset button now has a confirmation dialog associated with it
+  Reset and Refresh buttons will now be disabled (dimmed out) and a 'wait' animation will play when a scan is in progress
+  Fixed bugs related to me making a typo in the sorting functions
+  Fixed bugs related to the search box, updating the slider range, and correctly carrying over your search between full and mini windows
+  Further refined the store searching - login search will be faster again now, and better handle the upcoming changes in Update 4
+  Increased maximum history size to 15000 - if you use several other memory intensive addons this may cause issues!
+  Optimized searching and sorting routines to be a little more efficient with large sales histories
+  French localization updates (thanks jupi!)
+
 Changelog for 0.9.3
   Fix for statistics window throwing an error if you have sales events in your history from guilds you're no longer in
   (Possible) fix for the "occasional item duplication upon login" bug