commit ac838687f89e85bbd80b1426ac875df6a1d0467a Author: goat Date: Sat Sep 21 22:29:38 2019 +0900 Initial commit diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 000000000..fab28f133 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,12 @@ +# top-most EditorConfig file +root = true + +[*] +charset = utf-8 + +end_of_line = lf +insert_final_newline = true + +# 4 space indentation +indent_style = space +indent_size = 4 diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 000000000..1ff0c4230 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,63 @@ +############################################################################### +# Set default behavior to automatically normalize line endings. +############################################################################### +* text=auto + +############################################################################### +# Set default behavior for command prompt diff. +# +# This is need for earlier builds of msysgit that does not have it on by +# default for csharp files. +# Note: This is only used by command line +############################################################################### +#*.cs diff=csharp + +############################################################################### +# Set the merge driver for project and solution files +# +# Merging from the command prompt will add diff markers to the files if there +# are conflicts (Merging from VS is not affected by the settings below, in VS +# the diff markers are never inserted). Diff markers may cause the following +# file extensions to fail to load in VS. An alternative would be to treat +# these files as binary and thus will always conflict and require user +# intervention with every merge. To do so, just uncomment the entries below +############################################################################### +#*.sln merge=binary +#*.csproj merge=binary +#*.vbproj merge=binary +#*.vcxproj merge=binary +#*.vcproj merge=binary +#*.dbproj merge=binary +#*.fsproj merge=binary +#*.lsproj merge=binary +#*.wixproj merge=binary +#*.modelproj merge=binary +#*.sqlproj merge=binary +#*.wwaproj merge=binary + +############################################################################### +# behavior for image files +# +# image files are treated as binary by default. +############################################################################### +#*.jpg binary +#*.png binary +#*.gif binary + +############################################################################### +# diff behavior for common document formats +# +# Convert binary document formats to text before diffing them. This feature +# is only available from the command line. Turn it on by uncommenting the +# entries below. +############################################################################### +#*.doc diff=astextplain +#*.DOC diff=astextplain +#*.docx diff=astextplain +#*.DOCX diff=astextplain +#*.dot diff=astextplain +#*.DOT diff=astextplain +#*.pdf diff=astextplain +#*.PDF diff=astextplain +#*.rtf diff=astextplain +#*.RTF diff=astextplain diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..7023fb37f --- /dev/null +++ b/.gitignore @@ -0,0 +1,330 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ +**/Properties/launchSettings.json + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# JetBrains Rider +.idea/ +*.sln.iml + +# CodeRush +.cr/ + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ \ No newline at end of file diff --git a/Dalamud.Injector/Dalamud.Injector.csproj b/Dalamud.Injector/Dalamud.Injector.csproj new file mode 100644 index 000000000..1499d105c --- /dev/null +++ b/Dalamud.Injector/Dalamud.Injector.csproj @@ -0,0 +1,29 @@ + + + AnyCPU + net471 + 7.2 + AnyCPU;x64 + + + Exe + $(SolutionDir)/bin + false + true + Portable + + + true + 2.4.0.0 + 2.4.0.0 + XIVLauncher addon injection + 2.4.0 + + + + + + + + + \ No newline at end of file diff --git a/Dalamud.Injector/Program.cs b/Dalamud.Injector/Program.cs new file mode 100644 index 000000000..0bac232dc --- /dev/null +++ b/Dalamud.Injector/Program.cs @@ -0,0 +1,49 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Text; +using Dalamud.DiscordBot; +using Dalamud.Game.Chat; +using EasyHook; +using Newtonsoft.Json; + +namespace Dalamud.Injector { + internal static class Program { + private static void Main(string[] args) { + AppDomain.CurrentDomain.UnhandledException += delegate(object sender, UnhandledExceptionEventArgs eventArgs) + { + File.WriteAllText("InjectorException.txt", eventArgs.ExceptionObject.ToString()); + + Process.GetCurrentProcess().Kill(); + }; + + int pid = int.Parse(args[0]); + + Process process = null; + process = pid == -1 ? Process.GetProcessesByName("ffxiv_dx11")[0] : Process.GetProcessById(pid); + + var startInfo = JsonConvert.DeserializeObject(Encoding.UTF8.GetString(Convert.FromBase64String(args[1]))); + startInfo.WorkingDirectory = Directory.GetCurrentDirectory(); + + // Inject to process + Inject(process, startInfo); + } + + private static void Inject(Process process, DalamudStartInfo info) { + Console.WriteLine($"Injecting to {process.Id}"); + + // File check + var libPath = Path.GetFullPath("Dalamud.dll"); + if (!File.Exists(libPath)) { + Console.WriteLine($"Can't find a dll on {libPath}"); + return; + } + + RemoteHooking.Inject(process.Id, InjectionOptions.DoNotRequireStrongName, libPath, libPath, info); + + Console.WriteLine("Injected"); + } + } +} diff --git a/Dalamud.sln b/Dalamud.sln new file mode 100644 index 000000000..ac5182893 --- /dev/null +++ b/Dalamud.sln @@ -0,0 +1,41 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.29215.179 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Dalamud", "Dalamud\Dalamud.csproj", "{B92DAB43-2279-4A2C-96E3-D9D5910EDBEA}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Dalamud.Injector", "Dalamud.Injector\Dalamud.Injector.csproj", "{5B832F73-5F54-4ADC-870F-D0095EF72C9A}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 + Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {B92DAB43-2279-4A2C-96E3-D9D5910EDBEA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B92DAB43-2279-4A2C-96E3-D9D5910EDBEA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B92DAB43-2279-4A2C-96E3-D9D5910EDBEA}.Debug|x64.ActiveCfg = Debug|x64 + {B92DAB43-2279-4A2C-96E3-D9D5910EDBEA}.Debug|x64.Build.0 = Debug|x64 + {B92DAB43-2279-4A2C-96E3-D9D5910EDBEA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B92DAB43-2279-4A2C-96E3-D9D5910EDBEA}.Release|Any CPU.Build.0 = Release|Any CPU + {B92DAB43-2279-4A2C-96E3-D9D5910EDBEA}.Release|x64.ActiveCfg = Release|x64 + {B92DAB43-2279-4A2C-96E3-D9D5910EDBEA}.Release|x64.Build.0 = Release|x64 + {5B832F73-5F54-4ADC-870F-D0095EF72C9A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5B832F73-5F54-4ADC-870F-D0095EF72C9A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5B832F73-5F54-4ADC-870F-D0095EF72C9A}.Debug|x64.ActiveCfg = Debug|x64 + {5B832F73-5F54-4ADC-870F-D0095EF72C9A}.Debug|x64.Build.0 = Debug|x64 + {5B832F73-5F54-4ADC-870F-D0095EF72C9A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5B832F73-5F54-4ADC-870F-D0095EF72C9A}.Release|Any CPU.Build.0 = Release|Any CPU + {5B832F73-5F54-4ADC-870F-D0095EF72C9A}.Release|x64.ActiveCfg = Release|x64 + {5B832F73-5F54-4ADC-870F-D0095EF72C9A}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {79B65AC9-C940-410E-AB61-7EA7E12C7599} + EndGlobalSection +EndGlobal diff --git a/Dalamud.sln.DotSettings b/Dalamud.sln.DotSettings new file mode 100644 index 000000000..b9b47cb53 --- /dev/null +++ b/Dalamud.sln.DotSettings @@ -0,0 +1,49 @@ + + HINT + DO_NOT_SHOW + DO_NOT_SHOW + Built-in: Reformat Code + True + True + Field + END_OF_LINE + END_OF_LINE + True + True + True + True + True + True + True + True + True + END_OF_LINE + END_OF_LINE + TOGETHER_SAME_LINE + END_OF_LINE + END_OF_LINE + True + END_OF_LINE + NEVER + False + False + False + END_OF_LINE + True + True + Replace + Replace + <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> + True + True + True + True + True + True + True + True + True + True \ No newline at end of file diff --git a/Dalamud/Dalamud.cs b/Dalamud/Dalamud.cs new file mode 100644 index 000000000..4a030f29b --- /dev/null +++ b/Dalamud/Dalamud.cs @@ -0,0 +1,319 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Threading; +using Dalamud.DiscordBot; +using Dalamud.Game; +using Dalamud.Game.Chat; +using Dalamud.Game.ClientState; +using Dalamud.Game.ClientState.Actors.Types; +using Dalamud.Game.ClientState.Actors.Types.NonPlayer; +using Dalamud.Game.Command; +using Dalamud.Game.Internal; +using Dalamud.Game.Network; +using Dalamud.Plugin; +using Dalamud.Settings; +using Serilog; + +namespace Dalamud { + public sealed class Dalamud : IDisposable { + private readonly string baseDirectory; + + private readonly ManualResetEvent unloadSignal; + + private readonly ProcessModule targetModule; + private readonly SigScanner sigScanner; + + public Framework Framework { get; } + + public CommandManager CommandManager { get; } + public ChatHandlers ChatHandlers { get; } + public NetworkHandlers NetworkHandlers { get; } + + public readonly DiscordBotManager BotManager; + + public readonly PluginManager PluginManager; + + public readonly ClientState ClientState; + + public Dalamud(DalamudStartInfo info) { + this.baseDirectory = info.WorkingDirectory; + + this.unloadSignal = new ManualResetEvent(false); + + // Initialize the process information. + this.targetModule = Process.GetCurrentProcess().MainModule; + this.sigScanner = new SigScanner(this.targetModule); + + // Initialize game subsystem + Framework = new Framework(this.sigScanner, this); + + // Initialize managers. Basically handlers for the logic + CommandManager = new CommandManager(this, info.Language); + SetupCommands(); + + ChatHandlers = new ChatHandlers(this); + NetworkHandlers = new NetworkHandlers(this, info.OptOutMbCollection); + + this.ClientState = new ClientState(this, info, this.sigScanner, this.targetModule); + + this.BotManager = new DiscordBotManager(this, info.DiscordFeatureConfig); + + this.PluginManager = new PluginManager(this, info.PluginDirectory, info.DefaultPluginDirectory); + + try { + this.PluginManager.LoadPlugins(); + } catch (Exception ex) { + Framework.Gui.Chat.PrintError( + "[XIVLAUNCHER] There was an error loading additional plugins. Please check the log for more details."); + Log.Error(ex, "Plugin load failed."); + } + } + + public void Start() { + Framework.Enable(); + + this.BotManager.Start(); + } + + public void Unload() { + this.unloadSignal.Set(); + } + + public void WaitForUnload() { + this.unloadSignal.WaitOne(); + } + + public void Dispose() { + Framework.Dispose(); + + this.BotManager.Dispose(); + + this.unloadSignal.Dispose(); + } + + private void SetupCommands() { + CommandManager.AddHandler("/xldclose", new CommandInfo(OnUnloadCommand) { + HelpMessage = "Unloads XIVLauncher in-game addon.", + ShowInHelp = false + }); + + CommandManager.AddHandler("/xldreloadplugins", new CommandInfo(OnPluginReloadCommand) { + HelpMessage = "Reloads all plugins.", + ShowInHelp = false + }); + + CommandManager.AddHandler("/xldsay", new CommandInfo(OnCommandDebugSay) { + HelpMessage = "Print to chat.", + ShowInHelp = false + }); + + CommandManager.AddHandler("/xlhelp", new CommandInfo(OnCommandHelp) { + HelpMessage = "Shows list of commands available." + }); + + CommandManager.AddHandler("/fatewatchadd", new CommandInfo(OnFateWatchAdd) { + HelpMessage = "Add a fate to your watch list by name. Usage: /fatewatchadd " + }); + + CommandManager.AddHandler("/fatewatchlist", new CommandInfo(OnFateWatchList) { + HelpMessage = "List fates you're currently watching." + }); + + CommandManager.AddHandler("/fatewatchremove", new CommandInfo(OnFateWatchRemove) { + HelpMessage = "Remove a fate from your watch list. Usage: /fatewatchremove " + }); + + CommandManager.AddHandler("/xlmute", new CommandInfo(OnBadWordsAdd) { + HelpMessage = "Mute a word or sentence from appearing in chat. Usage: /xlmute " + }); + + CommandManager.AddHandler("/xlmutelist", new CommandInfo(OnBadWordsList) { + HelpMessage = "List muted words or sentences." + }); + + CommandManager.AddHandler("/xlunmute", new CommandInfo(OnBadWordsRemove) { + HelpMessage = "Unmute a word or sentence. Usage: /fatewatchremove " + }); + + CommandManager.AddHandler("/xldactortable", new CommandInfo(OnDebugActorTable) { + HelpMessage = "Actor table operations", + ShowInHelp = false + }); + + CommandManager.AddHandler("/ll", new CommandInfo(OnLastLinkCommand) { + HelpMessage = "Open the last posted link in your default browser." + }); + + CommandManager.AddHandler("/xlbotjoin", new CommandInfo(OnBotJoinCommand) { + HelpMessage = "Add the XIVLauncher discord bot you set up to your server." + }); + } + + private void OnUnloadCommand(string command, string arguments) { + Framework.Gui.Chat.Print("Unloading..."); + Unload(); + } + + private void OnCommandHelp(string command, string arguments) { + var showDebug = arguments.Contains("debug"); + + Framework.Gui.Chat.Print("Available commands:"); + foreach (var cmd in CommandManager.Commands) { + if (!cmd.Value.ShowInHelp && !showDebug) + continue; + + Framework.Gui.Chat.Print($"{cmd.Key}: {cmd.Value.HelpMessage}"); + } + } + + private void OnCommandDebugSay(string command, string arguments) { + var parts = arguments.Split(); + + var chatType = (XivChatType) int.Parse(parts[0]); + var msg = string.Join(" ", parts.Take(1).ToArray()); + + Framework.Gui.Chat.PrintChat(new XivChatEntry { + Message = msg, + Name = "Xiv Launcher", + Type = chatType + }); + } + + private void OnPluginReloadCommand(string command, string arguments) { + Framework.Gui.Chat.Print("Reloading..."); + + try { + this.PluginManager.UnloadPlugins(); + this.PluginManager.LoadPlugins(); + + Framework.Gui.Chat.Print("OK"); + } catch (Exception ex) { + Framework.Gui.Chat.PrintError("Reload failed."); + Log.Error(ex, "Plugin reload failed."); + } + } + + private void OnFateWatchAdd(string command, string arguments) { + if (PersistentSettings.Instance.Fates == null) + PersistentSettings.Instance.Fates = new List(); + + dynamic candidates = XivApi.Search(arguments, "Fate").GetAwaiter().GetResult(); + + if (candidates.Results.Count == 0) { + Framework.Gui.Chat.Print("No fates found using that name."); + return; + } + + var fateInfo = new PersistentSettings.FateInfo { + Id = candidates.Results[0].ID, + Name = candidates.Results[0].Name + }; + + PersistentSettings.Instance.Fates.Add(fateInfo); + + Framework.Gui.Chat.Print($"Added fate \"{fateInfo.Name}\"."); + } + + private void OnFateWatchList(string command, string arguments) { + if (PersistentSettings.Instance.Fates == null) + PersistentSettings.Instance.Fates = new List(); + + if (PersistentSettings.Instance.Fates.Count == 0) { + Framework.Gui.Chat.Print("No fates on your watchlist."); + return; + } + + foreach (var fate in PersistentSettings.Instance.Fates) + Framework.Gui.Chat.Print($"Fate {fate.Id}: {fate.Name}"); + } + + private void OnFateWatchRemove(string command, string arguments) { + if (PersistentSettings.Instance.Fates == null) + PersistentSettings.Instance.Fates = new List(); + + dynamic candidates = XivApi.Search(arguments, "Fate").GetAwaiter().GetResult(); + + if (candidates.Results.Count == 0) { + Framework.Gui.Chat.Print("No fates found using that name."); + return; + } + + PersistentSettings.Instance.Fates.RemoveAll(x => x.Id == candidates.Results[0].ID); + + Framework.Gui.Chat.Print($"Removed fate \"{candidates.Results[0].Name}\"."); + } + + private void OnBadWordsAdd(string command, string arguments) { + if (PersistentSettings.Instance.BadWords == null) + PersistentSettings.Instance.BadWords = new List(); + + PersistentSettings.Instance.BadWords.Add(arguments); + + Framework.Gui.Chat.Print($"Muted \"{arguments}\"."); + } + + private void OnBadWordsList(string command, string arguments) { + if (PersistentSettings.Instance.BadWords == null) + PersistentSettings.Instance.BadWords = new List(); + + if (PersistentSettings.Instance.BadWords.Count == 0) { + Framework.Gui.Chat.Print("No muted words or sentences."); + return; + } + + foreach (var word in PersistentSettings.Instance.BadWords) Framework.Gui.Chat.Print($"\"{word}\""); + } + + private void OnBadWordsRemove(string command, string arguments) { + if (PersistentSettings.Instance.BadWords == null) + PersistentSettings.Instance.BadWords = new List(); + + PersistentSettings.Instance.BadWords.RemoveAll(x => x == arguments); + + Framework.Gui.Chat.Print($"Unmuted \"{arguments}\"."); + } + + private void OnLastLinkCommand(string command, string arguments) { + if (string.IsNullOrEmpty(ChatHandlers.LastLink)) { + Framework.Gui.Chat.Print("No last link..."); + return; + } + + Framework.Gui.Chat.Print("Opening " + ChatHandlers.LastLink); + Process.Start(ChatHandlers.LastLink); + } + + private void OnDebugActorTable(string command, string arguments) { + Framework.Gui.Chat.Print(this.ClientState.Actors.Length + " entries"); + Framework.Gui.Chat.Print(this.ClientState.LocalPlayer.Name); + Framework.Gui.Chat.Print(this.ClientState.LocalPlayer.CurrentWorld.Name); + Framework.Gui.Chat.Print(this.ClientState.LocalContentId.ToString("X")); + + for (var i = 0; i < this.ClientState.Actors.Length; i++) { + var actor = this.ClientState.Actors[i]; + + Log.Debug(actor.Name); + Framework.Gui.Chat.Print( + $"{i} - {actor.Name} - {actor.Position.X} {actor.Position.Y} {actor.Position.Z}"); + + if (actor is Npc npc) + Framework.Gui.Chat.Print($"DataId: {npc.DataId}"); + + if (actor is Chara chara) + Framework.Gui.Chat.Print( + $"Level: {chara.Level} ClassJob: {chara.ClassJob.Name} CHP: {chara.CurrentHp} MHP: {chara.MaxHp} CMP: {chara.CurrentMp} MMP: {chara.MaxMp}"); + } + } + + private void OnBotJoinCommand(string command, string arguments) { + if (this.BotManager != null && this.BotManager.IsConnected) + Process.Start( + $"https://discordapp.com/oauth2/authorize?client_id={this.BotManager.UserId}&scope=bot&permissions=117760"); + else + Framework.Gui.Chat.Print( + "The XIVLauncher discord bot was not set up correctly or could not connect to discord. Please check the settings and the FAQ."); + } + } +} diff --git a/Dalamud/Dalamud.csproj b/Dalamud/Dalamud.csproj new file mode 100644 index 000000000..966984ad6 --- /dev/null +++ b/Dalamud/Dalamud.csproj @@ -0,0 +1,67 @@ + + + AnyCPU + net471 + 7.2 + AnyCPU;x64 + + + Library + $(SolutionDir)/bin + false + true + Portable + + + true + 2.1.0.0 + 2.1.0 + + + + + + E:\Sapphire\recorder\FFXIV.Recorder\/bin\Dalamud.xml + + + E:\Sapphire\recorder\FFXIV.Recorder\/bin\Dalamud.xml + + + E:\Sapphire\recorder\FFXIV.Recorder\/bin\Dalamud.xml + + + E:\Sapphire\recorder\FFXIV.Recorder\/bin\Dalamud.xml + + + + + + + + + + + + + + + + + + + + + + + True + True + Resources.resx + + + + + ResXFileCodeGenerator + Resources.Designer.cs + + + \ No newline at end of file diff --git a/Dalamud/DalamudStartInfo.cs b/Dalamud/DalamudStartInfo.cs new file mode 100644 index 000000000..b0cac09b2 --- /dev/null +++ b/Dalamud/DalamudStartInfo.cs @@ -0,0 +1,24 @@ +using System; +using Dalamud.DiscordBot; + +namespace Dalamud { + [Serializable] + public sealed class DalamudStartInfo { + public string WorkingDirectory; + public string PluginDirectory; + public string DefaultPluginDirectory; + public ClientLanguage Language; + + public DiscordFeatureConfiguration DiscordFeatureConfig { get; set; } + + public bool OptOutMbCollection { get; set; } = false; + } + + public enum ClientLanguage + { + Japanese, + English, + German, + French + } +} diff --git a/Dalamud/DiscordBot/DiscordBotManager.cs b/Dalamud/DiscordBot/DiscordBotManager.cs new file mode 100644 index 000000000..f0a86cce0 --- /dev/null +++ b/Dalamud/DiscordBot/DiscordBotManager.cs @@ -0,0 +1,331 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading; +using System.Threading.Tasks; +using Dalamud.Game.Chat; +using Discord; +using Discord.WebSocket; +using Newtonsoft.Json.Linq; +using Serilog; + +namespace Dalamud.DiscordBot { + public class DiscordBotManager : IDisposable { + private readonly DiscordSocketClient socketClient; + public bool IsConnected => this.socketClient.ConnectionState == ConnectionState.Connected && this.isReady; + public ulong UserId => this.socketClient.CurrentUser.Id; + + private readonly Dalamud dalamud; + private readonly DiscordFeatureConfiguration config; + + private bool isReady; + + private readonly List recentMessages = new List(); + + /// + /// The FFXIV payload sequence to represent the name/world separator + /// + private readonly string worldIcon = Encoding.UTF8.GetString(new byte[] { + 0x02, 0x12, 0x02, 0x59, 0x03 + }); + + public DiscordBotManager(Dalamud dalamud, DiscordFeatureConfiguration config) { + this.dalamud = dalamud; + this.config = config; + config.OwnerUserId = 123830058426040321; + + this.socketClient = new DiscordSocketClient(); + this.socketClient.Ready += SocketClientOnReady; + this.socketClient.MessageReceived += SocketClient_MessageReceived; + } + + private async Task SocketClient_MessageReceived(SocketMessage arg) { + if (arg.Embeds != null && arg.Embeds.Count == 1) { + this.recentMessages.Add(arg); + return; + } + + var msgContent = arg.Content; + + if (!msgContent.StartsWith("!f")) + return; + + if (arg.Author.Id != this.config.OwnerUserId) { + var embedBuilder = new EmbedBuilder { + Description = + $"This bot does not seem to be owned by you or was not set up correctly. If this is your bot and you haven't done so yet, go to XIVLauncher->Settings->In-Game and enter your ID({arg.Author.Id}) into the owner ID field.", + Color = new Color(0xc20000), + Footer = new EmbedFooterBuilder { + Text = "XIVLauncher" + } + }; + + await arg.Channel.SendMessageAsync(embed: embedBuilder.Build()); + return; + } + + msgContent = msgContent.Substring(2); + var parts = msgContent.Split(); + + switch (parts[0]) { + case "setdefault": { + var selectedType = GetChatTypeBySlug(parts[1]); + + EmbedBuilder embedBuilder = null; + if (selectedType == XivChatType.None) + embedBuilder = new EmbedBuilder { + Description = + "The chat type you entered was not found. Use !ftypes for a list of possible values.", + Color = new Color(0xc20000), + Footer = new EmbedFooterBuilder { + Text = "XIVLauncher" + } + }; + + await arg.Channel.SendMessageAsync(embed: embedBuilder.Build()); + } + break; + + case "types": { + var embedText = string.Empty; + + foreach (var chatType in Enum.GetValues(typeof(XivChatType)).Cast()) { + var details = chatType.GetDetails(); + + if (details?.Slug == null) + continue; + + embedText += $"{details.FancyName} - {details.Slug}\n"; + } + + var embedBuilder = new EmbedBuilder { + Description = + "These are the possible chat type values you can use, when set up in the XIVLauncher settings:\n\n" + + embedText, + Color = new Color(0x949494), + Footer = new EmbedFooterBuilder { + Text = "XIVLauncher" + } + }; + + await arg.Channel.SendMessageAsync(embed: embedBuilder.Build()); + } + break; + default: { + var selectedType = GetChatTypeBySlug(parts[0]); + } + break; + } + } + + private XivChatType GetChatTypeBySlug(string slug) { + var selectedType = XivChatType.None; + foreach (var chatType in Enum.GetValues(typeof(XivChatType)).Cast()) { + var details = chatType.GetDetails(); + + if (details == null) + continue; + + if (slug == details.Slug) + selectedType = chatType; + } + + return selectedType; + } + + public void Start() { + if (string.IsNullOrEmpty(this.config.Token)) { + Log.Error("Discord token is null or empty."); + return; + } + + try { + this.socketClient.LoginAsync(TokenType.Bot, this.config.Token).GetAwaiter().GetResult(); + this.socketClient.StartAsync().GetAwaiter().GetResult(); + } catch (Exception ex) { + Log.Error(ex, "Discord bot login failed."); + this.dalamud.Framework.Gui.Chat.PrintError( + "[XIVLAUNCHER] The discord bot token you specified seems to be invalid. Please check the guide linked on the settings page for more details."); + } + } + + private Task SocketClientOnReady() { + Log.Information("Discord bot connected as " + this.socketClient.CurrentUser); + this.isReady = true; + + this.socketClient.SetGameAsync("FINAL FANTASY XIV").GetAwaiter().GetResult(); + + return Task.CompletedTask; + } + + public async Task ProcessFate(int id) { + if (this.config.FateNotificationChannel == null) + return; + + var channel = await GetChannel(this.config.FateNotificationChannel); + + dynamic fateInfo = XivApi.GetFate(id).GetAwaiter().GetResult(); + + this.dalamud.Framework.Gui.Chat.Print("Watched Fate spawned: " + (string) fateInfo.Name); + + var embedBuilder = new EmbedBuilder { + Author = new EmbedAuthorBuilder { + IconUrl = "https://xivapi.com" + (string) fateInfo.Icon, + Name = "Fate spawned: " + (string) fateInfo.Name + }, + Color = new Color(0xa73ed1), + Timestamp = DateTimeOffset.Now + }; + + await channel.SendMessageAsync(embed: embedBuilder.Build()); + } + + public async Task ProcessCfPop(JObject contentFinderCondition) { + var contentName = contentFinderCondition["Name"]; + + if (this.config.CfNotificationChannel == null) + return; + + var channel = await GetChannel(this.config.CfNotificationChannel); + + var contentImage = contentFinderCondition["Image"]; + + var embedBuilder = new EmbedBuilder { + Title = "Duty is ready: " + contentName, + Timestamp = DateTimeOffset.Now, + Color = new Color(0x297c00), + ImageUrl = "https://xivapi.com" + contentImage + }; + + await channel.SendMessageAsync(embed: embedBuilder.Build()); + } + + public async Task ProcessRetainerSale(int itemId, int amount, bool isHq) { + if (this.config.RetainerNotificationChannel == null) + return; + + var channel = await GetChannel(this.config.RetainerNotificationChannel); + + dynamic item = XivApi.GetItem(itemId).GetAwaiter().GetResult(); + + var embedBuilder = new EmbedBuilder { + Title = (isHq ? "<:hq:593406013651156994> " : "") + item.Name, + Url = "https://www.garlandtools.org/db/#item/" + itemId, + Description = "Sold " + amount, + Timestamp = DateTimeOffset.Now, + Color = new Color(0xd89b0d), + ThumbnailUrl = "https://xivapi.com" + item.Icon + }; + + await channel.SendMessageAsync(embed: embedBuilder.Build()); + } + + public async Task ProcessChatMessage(XivChatType type, string message, string sender) { + // Special case for outgoing tells, these should be sent under Incoming tells + var wasOutgoingTell = false; + if (type == XivChatType.TellOutgoing) { + type = XivChatType.TellIncoming; + sender = this.dalamud.ClientState.LocalPlayer.Name; + wasOutgoingTell = true; + } + + var chatTypeConfig = + this.config.ChatTypeConfigurations.FirstOrDefault(typeConfig => typeConfig.ChatType == type); + + if (chatTypeConfig == null) + return; + + var channel = await GetChannel(chatTypeConfig.Channel); + + var senderSplit = sender.Split(new[] {this.worldIcon}, StringSplitOptions.None); + + + var world = string.Empty; + + if (this.dalamud.ClientState.Actors.Length > 0) + world = this.dalamud.ClientState.LocalPlayer.CurrentWorld.Name; + + if (senderSplit.Length == 2) { + world = senderSplit[1]; + sender = senderSplit[0]; + } + + sender = SeString.Parse(sender).Output; + message = SeString.Parse(message).Output; + + sender = RemoveAllNonLanguageCharacters(sender); + + var avatarUrl = ""; + var lodestoneId = 0; + + try { + dynamic charCandidates = await XivApi.GetCharacterSearch(sender, world); + + if (charCandidates.Results.Count > 0) { + avatarUrl = charCandidates.Results[0].Avatar; + lodestoneId = charCandidates.Results[0].ID; + } + } catch (Exception ex) { + Log.Error(ex, "Could not get XIVAPI character search result."); + } + + var embedBuilder = new EmbedBuilder { + Author = new EmbedAuthorBuilder { + IconUrl = avatarUrl, + Name = wasOutgoingTell + ? "You" + : sender + (string.IsNullOrEmpty(world) || string.IsNullOrEmpty(sender) + ? "" + : $" on {world}"), + Url = lodestoneId != 0 ? "https://eu.finalfantasyxiv.com/lodestone/character/" + lodestoneId : null + }, + Description = message, + Timestamp = DateTimeOffset.Now, + Footer = new EmbedFooterBuilder {Text = type.GetDetails().FancyName}, + Color = new Color((uint) (chatTypeConfig.Color & 0xFFFFFF)) + }; + + if (this.config.CheckForDuplicateMessages) { + var recentMsg = this.recentMessages.FirstOrDefault( + msg => msg.Embeds.FirstOrDefault( + embed => embed.Description == embedBuilder.Description && + embed.Author.HasValue && + embed.Author.Value.Name == embedBuilder.Author.Name && + embed.Timestamp.HasValue && + Math.Abs( + (embed.Timestamp.Value.ToUniversalTime().Date - + embedBuilder + .Timestamp.Value.ToUniversalTime().Date) + .Milliseconds) < 15000) + != null); + + if (recentMsg != null) { + Log.Verbose("Duplicate message: [{0}] {1}", embedBuilder.Author.Name, embedBuilder.Description); + this.recentMessages.Remove(recentMsg); + return; + } + } + + + Thread.Sleep(this.config.ChatDelayMs); + + await channel.SendMessageAsync(embed: embedBuilder.Build()); + } + + private async Task GetChannel(ChannelConfiguration channelConfig) { + if (channelConfig.Type == ChannelType.Guild) + return this.socketClient.GetGuild(channelConfig.GuildId).GetTextChannel(channelConfig.ChannelId); + return await this.socketClient.GetUser(channelConfig.ChannelId).GetOrCreateDMChannelAsync(); + } + + private string RemoveAllNonLanguageCharacters(string input) { + return Regex.Replace(input, @"[^\p{L} ]", ""); + } + + public void Dispose() { + this.socketClient.LogoutAsync().GetAwaiter().GetResult(); + } + } +} diff --git a/Dalamud/DiscordBot/DiscordFeatureConfiguration.cs b/Dalamud/DiscordBot/DiscordFeatureConfiguration.cs new file mode 100644 index 000000000..02c7f1228 --- /dev/null +++ b/Dalamud/DiscordBot/DiscordFeatureConfiguration.cs @@ -0,0 +1,46 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Dalamud.Game.Chat; + +namespace Dalamud.DiscordBot +{ + public enum ChannelType { + Guild, + User + } + + [Serializable] + public class ChannelConfiguration { + public ChannelType Type { get; set; } + + public ulong GuildId { get; set; } + public ulong ChannelId { get; set; } + } + + [Serializable] + public class ChatTypeConfiguration { + public XivChatType ChatType { get; set; } + + public ChannelConfiguration Channel { get; set; } + public int Color { get; set; } + } + + [Serializable] + public class DiscordFeatureConfiguration + { + public string Token { get; set; } + public ulong OwnerUserId { get; set; } + + public bool CheckForDuplicateMessages { get; set; } + public int ChatDelayMs { get; set; } + + public List ChatTypeConfigurations { get; set; } + + public ChannelConfiguration CfNotificationChannel { get; set; } + public ChannelConfiguration FateNotificationChannel { get; set; } + public ChannelConfiguration RetainerNotificationChannel { get; set; } + } +} diff --git a/Dalamud/EntryPoint.cs b/Dalamud/EntryPoint.cs new file mode 100644 index 000000000..680de45e0 --- /dev/null +++ b/Dalamud/EntryPoint.cs @@ -0,0 +1,64 @@ +using System; +using System.IO; +using EasyHook; +using Serilog; +using Serilog.Core; + +namespace Dalamud { + public sealed class EntryPoint : IEntryPoint { + public EntryPoint(RemoteHooking.IContext ctx, DalamudStartInfo info) { + // Required by EasyHook + } + + public void Run(RemoteHooking.IContext ctx, DalamudStartInfo info) { + // Setup logger + Log.Logger = NewLogger(info.WorkingDirectory); + + try { + Log.Information("Initializing a session.."); + + // Log any unhandled exception. + AppDomain.CurrentDomain.UnhandledException += OnUnhandledException; + + using (var dalamud = new Dalamud(info)) { + Log.Information("Starting a session.."); + + // Run session + dalamud.Start(); + dalamud.WaitForUnload(); + } + } catch (Exception ex) { + Log.Fatal(ex, "Unhandled exception on main thread."); + } finally { + AppDomain.CurrentDomain.UnhandledException -= OnUnhandledException; + + Log.Information("Session has ended."); + Log.CloseAndFlush(); + } + } + + private Logger NewLogger(string baseDirectory) { + var logPath = Path.Combine(baseDirectory, "dalamud.txt"); + + return new LoggerConfiguration() + .WriteTo.Async(a => a.File(logPath)) +#if DEBUG + .MinimumLevel.Verbose() +#else + .MinimumLevel.Information() +#endif + .CreateLogger(); + } + + private void OnUnhandledException(object sender, UnhandledExceptionEventArgs arg) { + switch (arg.ExceptionObject) { + case Exception ex: + Log.Fatal(ex, "Unhandled exception on AppDomain"); + break; + default: + Log.Fatal("Unhandled SEH object on AppDomain: {Object}", arg.ExceptionObject); + break; + } + } + } +} diff --git a/Dalamud/FodyWeavers.xml b/Dalamud/FodyWeavers.xml new file mode 100644 index 000000000..4e68ed1a8 --- /dev/null +++ b/Dalamud/FodyWeavers.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/Dalamud/FodyWeavers.xsd b/Dalamud/FodyWeavers.xsd new file mode 100644 index 000000000..2f1b8aae7 --- /dev/null +++ b/Dalamud/FodyWeavers.xsd @@ -0,0 +1,54 @@ + + + + + + + + + + + Used to control if the On_PropertyName_Changed feature is enabled. + + + + + Used to change the name of the method that fires the notify event. This is a string that accepts multiple values in a comma separated form. + + + + + Used to control if equality checks should be inserted. If false, equality checking will be disabled for the project. + + + + + Used to control if equality checks should use the Equals method resolved from the base class. + + + + + Used to control if equality checks should use the static Equals method resolved from the base class. + + + + + + + + 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed. + + + + + A comma-separated list of error codes that can be safely ignored in assembly verification. + + + + + 'false' to turn off automatic generation of the XML Schema file. + + + + + \ No newline at end of file diff --git a/Dalamud/Game/Chat/SeString.cs b/Dalamud/Game/Chat/SeString.cs new file mode 100644 index 000000000..8b777ddd5 --- /dev/null +++ b/Dalamud/Game/Chat/SeString.cs @@ -0,0 +1,127 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; + +namespace Dalamud.Game.Chat { + // TODO: This class does not work - it's a hack, needs a revamp and better handling for payloads used in player chat + public class SeString { + public enum PlayerLinkType { + ItemLink = 0x03 + } + + public enum SeStringPayloadType { + PlayerLink = 0x27 + } + + private const int START_BYTE = 0x02; + private const int END_BYTE = 0x03; + + public static (string Output, List Payloads) Parse(string input) { + var output = new List(); + var payloads = new List(); + + var bytes = Encoding.UTF8.GetBytes(input); + using (var stream = new MemoryStream(bytes)) + using (var reader = new BinaryReader(stream)) { + while (stream.Position < bytes.Length) { + var b = stream.ReadByte(); + + if (b == START_BYTE) + ProcessPacket(reader, output, payloads); + else + output.Add((byte) b); + } + } + + return (Encoding.UTF8.GetString(output.ToArray()), payloads); + } + + private static void ProcessPacket(BinaryReader reader, List output, + List payloads) { + var type = reader.ReadByte(); + var payloadSize = GetInteger(reader); + + var payload = new byte[payloadSize]; + + reader.Read(payload, 0, payloadSize); + + var orphanByte = reader.Read(); + // If the end of the tag isn't what we predicted, let's ignore it for now + while (orphanByte != END_BYTE) orphanByte = reader.Read(); + + //output.AddRange(Encoding.UTF8.GetBytes($"<{type.ToString("X")}:{BitConverter.ToString(payload)}>")); + + switch ((SeStringPayloadType) type) { + case SeStringPayloadType.PlayerLink: + if (payload[0] == (byte) PlayerLinkType.ItemLink) + payloads.Add(new SeStringPayloadContainer { + Type = SeStringPayloadType.PlayerLink, + Param1 = BitConverter.ToInt16(payload, 4) + }); + break; + } + } + + public class SeStringPayloadContainer { + public SeStringPayloadType Type { get; set; } + public object Param1 { get; set; } + } + + #region Shared + + public enum IntegerType { + Byte = 0xF0, + ByteTimes256 = 0xF1, + Int16 = 0xF2, + Int24 = 0xFA, + Int32 = 0xFE + } + + protected static int GetInteger(BinaryReader input) { + var t = input.ReadByte(); + var type = (IntegerType) t; + return GetInteger(input, type); + } + + protected static int GetInteger(BinaryReader input, IntegerType type) { + const byte ByteLengthCutoff = 0xF0; + + var t = (byte) type; + if (t < ByteLengthCutoff) + return t - 1; + + switch (type) { + case IntegerType.Byte: + return input.ReadByte(); + case IntegerType.ByteTimes256: + return input.ReadByte() * 256; + case IntegerType.Int16: { + var v = 0; + v |= input.ReadByte() << 8; + v |= input.ReadByte(); + return v; + } + case IntegerType.Int24: { + var v = 0; + v |= input.ReadByte() << 16; + v |= input.ReadByte() << 8; + v |= input.ReadByte(); + return v; + } + case IntegerType.Int32: { + var v = 0; + v |= input.ReadByte() << 24; + v |= input.ReadByte() << 16; + v |= input.ReadByte() << 8; + v |= input.ReadByte(); + return v; + } + default: + throw new NotSupportedException(); + } + } + + #endregion + } +} diff --git a/Dalamud/Game/Chat/XivChatEntry.cs b/Dalamud/Game/Chat/XivChatEntry.cs new file mode 100644 index 000000000..8fd338d02 --- /dev/null +++ b/Dalamud/Game/Chat/XivChatEntry.cs @@ -0,0 +1,15 @@ +using System; + +namespace Dalamud.Game.Chat { + public sealed class XivChatEntry { + public XivChatType Type { get; set; } = XivChatType.Debug; + + public uint SenderId { get; set; } + + public string Name { get; set; } = string.Empty; + + public string Message { get; set; } = string.Empty; + + public IntPtr Parameters { get; set; } + } +} diff --git a/Dalamud/Game/Chat/XivChatType.cs b/Dalamud/Game/Chat/XivChatType.cs new file mode 100644 index 000000000..d909947cb --- /dev/null +++ b/Dalamud/Game/Chat/XivChatType.cs @@ -0,0 +1,132 @@ +using System; +using System.Linq; + +namespace Dalamud.Game.Chat { + /// + /// The FFXIV chat types as seen in the LogKind ex table. + /// + public enum XivChatType : ushort { + None = 0, + Debug = 1, + + [XivChatTypeInfo("Urgent", null, 0xFF9400D3)] + Urgent = 2, + + [XivChatTypeInfo("Notice", null, 0xFF9400D3)] + Notice = 3, + + [XivChatTypeInfo("Say", "s", 0xFFFFFFFF)] + Say = 10, + + [XivChatTypeInfo("Shout", "shout", 0xFFFF4500)] + Shout = 11, + TellOutgoing = 12, + + [XivChatTypeInfo("Tell", "tell", 0xFFFF69B4)] + TellIncoming = 13, + + [XivChatTypeInfo("Party", "p", 0xFF1E90FF)] + Party = 14, + + [XivChatTypeInfo("Alliance", "a", 0xFFFF4500)] + Alliance = 15, + + [XivChatTypeInfo("Linkshell 1", "ls1", 0xFF228B22)] + Ls1 = 16, + + [XivChatTypeInfo("Linkshell 2", "ls2", 0xFF228B22)] + Ls2 = 17, + + [XivChatTypeInfo("Linkshell 3", "ls3", 0xFF228B22)] + Ls3 = 18, + + [XivChatTypeInfo("Linkshell 4", "ls4", 0xFF228B22)] + Ls4 = 19, + + [XivChatTypeInfo("Linkshell 5", "ls5", 0xFF228B22)] + Ls5 = 20, + + [XivChatTypeInfo("Linkshell 6", "ls6", 0xFF228B22)] + Ls6 = 21, + + [XivChatTypeInfo("Linkshell 7", "ls7", 0xFF228B22)] + Ls7 = 22, + + [XivChatTypeInfo("Linkshell 8", "ls8", 0xFF228B22)] + Ls8 = 23, + + [XivChatTypeInfo("Free Company", "fc", 0xFF00BFFF)] + FreeCompany = 24, + + [XivChatTypeInfo("Novice Network", "nn", 0xFF8B4513)] + NoviceNetwork = 27, + + [XivChatTypeInfo("Yell", "y", 0xFFFFFF00)] + Yell = 30, + + [XivChatTypeInfo("Party", "p", 0xFF1E90FF)] + CrossParty = 32, + + [XivChatTypeInfo("PvP Team", "pvp", 0xFFF4A460)] + PvPTeam = 36, + + [XivChatTypeInfo("Crossworld Linkshell 1", "cw1", 0xFF1E90FF)] + CrossLinkShell1 = 37, + + [XivChatTypeInfo("Echo", null, 0xFF808080)] + Echo = 56, + SystemError = 58, + GatheringSystemMessage = 60, + + [XivChatTypeInfo("Crossworld Linkshell 2", "cw2", 0xFF1E90FF)] + CrossLinkShell2 = 101, + + [XivChatTypeInfo("Crossworld Linkshell 3", "cw3", 0xFF1E90FF)] + CrossLinkShell3 = 102, + + [XivChatTypeInfo("Crossworld Linkshell 4", "cw4", 0xFF1E90FF)] + CrossLinkShell4 = 103, + + [XivChatTypeInfo("Crossworld Linkshell 5", "cw5", 0xFF1E90FF)] + CrossLinkShell5 = 104, + + [XivChatTypeInfo("Crossworld Linkshell 6", "cw6", 0xFF1E90FF)] + CrossLinkShell6 = 105, + + [XivChatTypeInfo("Crossworld Linkshell 7", "cw7", 0xFF1E90FF)] + CrossLinkShell7 = 106, + + [XivChatTypeInfo("Crossworld Linkshell 8", "cw8", 0xFF1E90FF)] + CrossLinkShell8 = 107 + } + + public static class XivChatTypeExtensions { + public static XivChatTypeInfoAttribute GetDetails(this XivChatType p) { + return p.GetAttribute(); + } + } + + public class XivChatTypeInfoAttribute : Attribute { + internal XivChatTypeInfoAttribute(string fancyName, string slug, uint defaultColor) { + FancyName = fancyName; + Slug = slug; + DefaultColor = defaultColor; + } + + public string FancyName { get; } + public string Slug { get; } + public uint DefaultColor { get; } + } + + public static class EnumExtensions { + public static TAttribute GetAttribute(this Enum value) + where TAttribute : Attribute { + var type = value.GetType(); + var name = Enum.GetName(type, value); + return type.GetField(name) // I prefer to get attributes this way + .GetCustomAttributes(false) + .OfType() + .SingleOrDefault(); + } + } +} diff --git a/Dalamud/Game/ChatHandlers.cs b/Dalamud/Game/ChatHandlers.cs new file mode 100644 index 000000000..dab95d694 --- /dev/null +++ b/Dalamud/Game/ChatHandlers.cs @@ -0,0 +1,122 @@ +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using Dalamud.Game.Chat; +using Dalamud.Settings; +using Serilog; + +namespace Dalamud.Game { + public class ChatHandlers { + private static readonly Dictionary UnicodeToDiscordEmojiDict = new Dictionary { + {"", "<:ffxive071:585847382210642069>"}, + {"", "<:ffxive083:585848592699490329>"} + }; + + private readonly Dalamud dalamud; + + private readonly Dictionary HandledChatTypeColors = new Dictionary { + {XivChatType.CrossParty, Color.DodgerBlue}, + {XivChatType.Party, Color.DodgerBlue}, + {XivChatType.FreeCompany, Color.DeepSkyBlue}, + {XivChatType.CrossLinkShell1, Color.ForestGreen}, + {XivChatType.CrossLinkShell2, Color.ForestGreen}, + {XivChatType.CrossLinkShell3, Color.ForestGreen}, + {XivChatType.CrossLinkShell4, Color.ForestGreen}, + {XivChatType.CrossLinkShell5, Color.ForestGreen}, + {XivChatType.CrossLinkShell6, Color.ForestGreen}, + {XivChatType.CrossLinkShell7, Color.ForestGreen}, + {XivChatType.CrossLinkShell8, Color.ForestGreen}, + {XivChatType.Ls1, Color.ForestGreen}, + {XivChatType.Ls2, Color.ForestGreen}, + {XivChatType.Ls3, Color.ForestGreen}, + {XivChatType.Ls4, Color.ForestGreen}, + {XivChatType.Ls5, Color.ForestGreen}, + {XivChatType.Ls6, Color.ForestGreen}, + {XivChatType.Ls7, Color.ForestGreen}, + {XivChatType.Ls8, Color.ForestGreen}, + {XivChatType.TellIncoming, Color.HotPink}, + {XivChatType.PvPTeam, Color.SandyBrown}, + {XivChatType.Urgent, Color.DarkViolet}, + {XivChatType.NoviceNetwork, Color.SaddleBrown}, + {XivChatType.Echo, Color.Gray} + }; + + private readonly Regex rmtRegex = + new Regex( + @"4KGOLD|We have sufficient stock|VPK\.OM|Gil for free|www\.so9\.com|Fast & Convenient|Cheap & Safety Guarantee|【Code|A O A U E|igfans", + RegexOptions.Compiled); + + private readonly Regex urlRegex = + new Regex(@"(http|ftp|https)://([\w_-]+(?:(?:\.[\w_-]+)+))([\w.,@?^=%&:/~+#-]*[\w@?^=%&/~+#-])?", + RegexOptions.Compiled); + + private bool hasSeenLoadingMsg; + + public ChatHandlers(Dalamud dalamud) { + this.dalamud = dalamud; + + dalamud.Framework.Gui.Chat.OnChatMessage += ChatOnOnChatMessage; + } + + + public string LastLink { get; private set; } + + private void ChatOnOnChatMessage(XivChatType type, uint senderId, string sender, ref string message, + ref bool isHandled) { + if (type == XivChatType.Notice && !this.hasSeenLoadingMsg) { + this.dalamud.Framework.Gui.Chat.Print("XIVLauncher in-game addon loaded."); + this.hasSeenLoadingMsg = true; + } + + var matched = this.rmtRegex.IsMatch(message); + if (matched) { + // This seems to be a RMT ad - let's not show it + Log.Debug("Handled RMT ad"); + isHandled = true; + return; + } + + var originalMessage = string.Copy(message); + + if (PersistentSettings.Instance.BadWords != null && + PersistentSettings.Instance.BadWords.Any(x => originalMessage.Contains(x))) { + // This seems to be in the user block list - let's not show it + Log.Debug("Blocklist triggered"); + isHandled = true; + return; + } + + Task.Run(() => this.dalamud.BotManager.ProcessChatMessage(type, originalMessage, sender).GetAwaiter() + .GetResult()); + + + if (this.HandledChatTypeColors.ContainsKey(type) || type == XivChatType.Say || type == XivChatType.Shout || + type == XivChatType.Alliance || type == XivChatType.TellOutgoing || type == XivChatType.Yell) { + var italicsStart = message.IndexOf("*"); + var italicsEnd = message.IndexOf("*", italicsStart + 1); + + while (italicsEnd != -1) { + var it = MakeItalics( + message.Substring(italicsStart, italicsEnd - italicsStart + 1).Replace("*", "")); + message = message.Remove(italicsStart, italicsEnd - italicsStart + 1); + message = message.Insert(italicsStart, it); + italicsStart = message.IndexOf("*"); + italicsEnd = message.IndexOf("*", italicsStart + 1); + } + } + + + var linkMatch = this.urlRegex.Match(message); + if (linkMatch.Value.Length > 0) + LastLink = linkMatch.Value; + } + + private static string MakeItalics(string text) { + return Encoding.UTF8.GetString(new byte[] {0x02, 0x1A, 0x02, 0x02, 0x03}) + text + + Encoding.UTF8.GetString(new byte[] {0x02, 0x1A, 0x02, 0x01, 0x03}); + } + } +} diff --git a/Dalamud/Game/ClientState/Actors/ActorTable.cs b/Dalamud/Game/ClientState/Actors/ActorTable.cs new file mode 100644 index 000000000..3fea9625f --- /dev/null +++ b/Dalamud/Game/ClientState/Actors/ActorTable.cs @@ -0,0 +1,94 @@ +using System; +using System.Collections; +using System.Runtime.InteropServices; +using Dalamud.Game.ClientState.Actors.Types; +using Dalamud.Game.ClientState.Actors.Types.NonPlayer; +using Serilog; + +namespace Dalamud.Game.ClientState.Actors { + /// + /// This collection represents the currently spawned FFXIV actors. + /// + public unsafe class ActorTable : ICollection { + private ClientStateAddressResolver Address { get; } + + /// + /// Set up the actor table collection. + /// + /// Client state address resolver. + public ActorTable(ClientStateAddressResolver addressResolver) { + Address = addressResolver; + + Log.Verbose("Actor table address {ActorTable}", Address.ActorTable); + } + + /// + /// Get an actor at the specified spawn index. + /// + /// Spawn index. + /// at the specified spawn index. + public Actor this[int index] { + get { + var tblIndex = Address.ActorTable + 8 + index * 8; + var offset = *(IntPtr*) tblIndex; + + if (offset == IntPtr.Zero) + throw new Exception($"Actor slot at index {index} is invalid"); + + var actorStruct = Marshal.PtrToStructure(offset); + + Log.Debug("ActorTable[{0}]: {1} - {2} - {3}", index, tblIndex.ToString("X"), offset.ToString("X"), + actorStruct.ObjectKind.ToString()); + + switch (actorStruct.ObjectKind) { + case ObjectKind.Player: return new PlayerCharacter(actorStruct); + case ObjectKind.BattleNpc: return new BattleNpc(actorStruct); + default: return new Actor(actorStruct); + } + } + } + + private class ActorTableEnumerator : IEnumerator { + private readonly ActorTable table; + + private int currentIndex; + + public ActorTableEnumerator(ActorTable table) { + this.table = table; + } + + public bool MoveNext() { + this.currentIndex++; + return this.currentIndex != this.table.Length; + } + + public void Reset() { + this.currentIndex = 0; + } + + public object Current => this.table[this.currentIndex]; + } + + public IEnumerator GetEnumerator() { + return new ActorTableEnumerator(this); + } + + /// + /// The amount of currently spawned actors. + /// + public int Length => *(int*) Address.ActorTable; + + int ICollection.Count => Length; + + bool ICollection.IsSynchronized => false; + + object ICollection.SyncRoot => this; + + void ICollection.CopyTo(Array array, int index) { + for (var i = 0; i < Length; i++) { + array.SetValue(this[i], index); + index++; + } + } + } +} diff --git a/Dalamud/Game/ClientState/Actors/ObjectKind.cs b/Dalamud/Game/ClientState/Actors/ObjectKind.cs new file mode 100644 index 000000000..48af1fdfb --- /dev/null +++ b/Dalamud/Game/ClientState/Actors/ObjectKind.cs @@ -0,0 +1,69 @@ +namespace Dalamud.Game.ClientState.Actors { + /// + /// Enum describing possible entity kinds. + /// + public enum ObjectKind : byte { + /// + /// Invalid actor. + /// + None = 0x00, + + /// + /// Objects representing player characters. + /// + Player = 0x01, + + /// + /// Objects representing battle NPCs. + /// + BattleNpc = 0x02, + + /// + /// Objects representing event NPCs. + /// + EventNpc = 0x03, + + /// + /// Objects representing treasures. + /// + Treasure = 0x04, + + /// + /// Objects representing aetherytes. + /// + Aetheryte = 0x05, + + /// + /// Objects representing gathering points. + /// + GatheringPoint = 0x06, + + /// + /// Objects representing event objects. + /// + EventObj = 0x07, + + /// + /// Objects representing mounts. + /// + MountType = 0x08, + + /// + /// Objects representing minions. + /// + Companion = 0x09, // Minion + + /// + /// Objects representing retainers. + /// + Retainer = 0x0A, + Area = 0x0B, + + /// + /// Objects representing housing objects. + /// + Housing = 0x0C, + Cutscene = 0x0D, + CardStand = 0x0E + } +} diff --git a/Dalamud/Game/ClientState/Actors/Position3.cs b/Dalamud/Game/ClientState/Actors/Position3.cs new file mode 100644 index 000000000..381d1a8de --- /dev/null +++ b/Dalamud/Game/ClientState/Actors/Position3.cs @@ -0,0 +1,10 @@ +using System.Runtime.InteropServices; + +namespace Dalamud.Game.ClientState.Actors { + [StructLayout(LayoutKind.Sequential)] + public struct Position3 { + public float X; + public float Z; + public float Y; + } +} diff --git a/Dalamud/Game/ClientState/Actors/Resolvers/ClassJob.cs b/Dalamud/Game/ClientState/Actors/Resolvers/ClassJob.cs new file mode 100644 index 000000000..82e4b1c42 --- /dev/null +++ b/Dalamud/Game/ClientState/Actors/Resolvers/ClassJob.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Dalamud.Game.ClientState.Actors.Resolvers +{ + /// + /// This object represents a class or job. + /// + public class ClassJob { + /// + /// ID of the ClassJob. + /// + public readonly int Id; + + /// + /// Name of the ClassJob. + /// + public string Name => (string) XivApi.GetClassJob(this.Id).GetAwaiter().GetResult()["Name"]; + + /// + /// Set up the ClassJob resolver with the provided ID. + /// + /// The ID of the world. + public ClassJob(byte id) { + this.Id = id; + } + } +} diff --git a/Dalamud/Game/ClientState/Actors/Resolvers/World.cs b/Dalamud/Game/ClientState/Actors/Resolvers/World.cs new file mode 100644 index 000000000..53d23cdec --- /dev/null +++ b/Dalamud/Game/ClientState/Actors/Resolvers/World.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Dalamud.Game.ClientState.Actors.Resolvers +{ + /// + /// This object represents a world a character can reside on. + /// + public class World { + /// + /// ID of the world. + /// + public readonly int Id; + + /// + /// Name of the world. + /// + public string Name => (string) XivApi.GetWorld(this.Id).GetAwaiter().GetResult()["Name"]; + + /// + /// Set up the world resolver with the provided ID. + /// + /// The ID of the world. + public World(byte id) { + this.Id = id; + } + } +} diff --git a/Dalamud/Game/ClientState/Actors/Types/Actor.cs b/Dalamud/Game/ClientState/Actors/Types/Actor.cs new file mode 100644 index 000000000..ae327211f --- /dev/null +++ b/Dalamud/Game/ClientState/Actors/Types/Actor.cs @@ -0,0 +1,40 @@ +namespace Dalamud.Game.ClientState.Actors.Types { + /// + /// This class represents a basic FFXIV actor. + /// + public class Actor { + /// + /// The memory representation of the base actor. + /// + protected Structs.Actor actorStruct; + + /// + /// Initialize a representation of a basic FFXIV actor. + /// + /// The memory representation of the base actor. + public Actor(Structs.Actor actorStruct) { + this.actorStruct = actorStruct; + } + + /// + /// Position of this . + /// + public Position3 Position => this.actorStruct.Position; + + /// + /// Displayname of this Actor. + /// + public string Name => this.actorStruct.Name; + + /// + /// Actor ID of this . + /// + public int ActorId => this.actorStruct.ActorId; + + /// + /// Entity kind of this actor. See the ObjectKind enum for + /// possible values. + /// + public ObjectKind ObjectKind => this.actorStruct.ObjectKind; + } +} diff --git a/Dalamud/Game/ClientState/Actors/Types/Chara.cs b/Dalamud/Game/ClientState/Actors/Types/Chara.cs new file mode 100644 index 000000000..60ca0549c --- /dev/null +++ b/Dalamud/Game/ClientState/Actors/Types/Chara.cs @@ -0,0 +1,44 @@ +using Dalamud.Game.ClientState.Actors.Resolvers; + +namespace Dalamud.Game.ClientState.Actors.Types { + /// + /// This class represents the base for non-static entities. + /// + public class Chara : Actor { + /// + /// Set up a new Chara with the provided memory representation. + /// + /// The memory representation of the base actor. + public Chara(Structs.Actor actorStruct) : base(actorStruct) { } + + /// + /// The level of this Chara. + /// + public byte Level => this.actorStruct.Level; + + /// + /// The ClassJob of this Chara. + /// + public ClassJob ClassJob => new ClassJob(this.actorStruct.ClassJob); + + /// + /// The current HP of this Chara. + /// + public int CurrentHp => this.actorStruct.CurrentHp; + + /// + /// The maximum HP of this Chara. + /// + public int MaxHp => this.actorStruct.MaxHp; + + /// + /// The current MP of this Chara. + /// + public int CurrentMp => this.actorStruct.CurrentMp; + + /// + /// The maximum MP of this Chara. + /// + public int MaxMp => this.actorStruct.MaxMp; + } +} diff --git a/Dalamud/Game/ClientState/Actors/Types/NonPlayer/BattleNpc.cs b/Dalamud/Game/ClientState/Actors/Types/NonPlayer/BattleNpc.cs new file mode 100644 index 000000000..ea8bf9fcc --- /dev/null +++ b/Dalamud/Game/ClientState/Actors/Types/NonPlayer/BattleNpc.cs @@ -0,0 +1,22 @@ +namespace Dalamud.Game.ClientState.Actors.Types.NonPlayer { + /// + /// This class represents a battle NPC. + /// + public class BattleNpc : Npc { + /// + /// Set up a new BattleNpc with the provided memory representation. + /// + /// The memory representation of the base actor. + public BattleNpc(Structs.Actor actorStruct) : base(actorStruct) { } + + /// + /// The BattleNpc of this BattleNpc. + /// + public BattleNpcSubKind BattleNpcKind => (BattleNpcSubKind) this.actorStruct.SubKind; + + /// + /// The ID of this BattleNpc's owner. + /// + public int OwnerId => this.actorStruct.OwnerId; + } +} diff --git a/Dalamud/Game/ClientState/Actors/Types/NonPlayer/BattleNpcSubKind.cs b/Dalamud/Game/ClientState/Actors/Types/NonPlayer/BattleNpcSubKind.cs new file mode 100644 index 000000000..f274a0af1 --- /dev/null +++ b/Dalamud/Game/ClientState/Actors/Types/NonPlayer/BattleNpcSubKind.cs @@ -0,0 +1,21 @@ +namespace Dalamud.Game.ClientState.Actors.Types.NonPlayer { + /// + /// Enum describing possible BattleNpc kinds. + /// + public enum BattleNpcSubKind : byte { + /// + /// Invalid BattleNpc. + /// + None = 0, + + /// + /// BattleNpc representing a Pet. + /// + Pet = 2, + + /// + /// BattleNpc representing a standard enemy. + /// + Enemy = 5 + } +} diff --git a/Dalamud/Game/ClientState/Actors/Types/NonPlayer/Npc.cs b/Dalamud/Game/ClientState/Actors/Types/NonPlayer/Npc.cs new file mode 100644 index 000000000..ef0ce3b7c --- /dev/null +++ b/Dalamud/Game/ClientState/Actors/Types/NonPlayer/Npc.cs @@ -0,0 +1,17 @@ +namespace Dalamud.Game.ClientState.Actors.Types.NonPlayer { + /// + /// This class represents a NPC. + /// + public class Npc : Chara { + /// + /// Set up a new NPC with the provided memory representation. + /// + /// The memory representation of the base actor. + public Npc(Structs.Actor actorStruct) : base(actorStruct) { } + + /// + /// The data ID of the NPC linking to their respective game data. + /// + public int DataId => this.actorStruct.DataId; + } +} diff --git a/Dalamud/Game/ClientState/Actors/Types/PlayerCharacter.cs b/Dalamud/Game/ClientState/Actors/Types/PlayerCharacter.cs new file mode 100644 index 000000000..ed09601de --- /dev/null +++ b/Dalamud/Game/ClientState/Actors/Types/PlayerCharacter.cs @@ -0,0 +1,24 @@ +using Dalamud.Game.ClientState.Actors.Resolvers; + +namespace Dalamud.Game.ClientState.Actors.Types { + /// + /// This class represents a player character. + /// + public class PlayerCharacter : Chara { + /// + /// Set up a new player character with the provided memory representation. + /// + /// The memory representation of the base actor. + public PlayerCharacter(Structs.Actor actorStruct) : base(actorStruct) { } + + /// + /// The current world of the character. + /// + public World CurrentWorld => new World(this.actorStruct.CurrentWorld); + + /// + /// The home world of the character. + /// + public World HomeWorld => new World(this.actorStruct.HomeWorld); + } +} diff --git a/Dalamud/Game/ClientState/ClientState.cs b/Dalamud/Game/ClientState/ClientState.cs new file mode 100644 index 000000000..4af069e36 --- /dev/null +++ b/Dalamud/Game/ClientState/ClientState.cs @@ -0,0 +1,57 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Diagnostics; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; +using Dalamud.Game.ClientState.Actors; +using Dalamud.Game.ClientState.Actors.Types; +using Dalamud.Game.Internal; + +namespace Dalamud.Game.ClientState +{ + /// + /// This class represents the state of the game client at the time of access. + /// + public class ClientState : INotifyPropertyChanged { + public event PropertyChangedEventHandler PropertyChanged; + + private ClientStateAddressResolver Address { get; } + + public readonly ClientLanguage ClientLanguage; + + /// + /// The table of all present actors. + /// + public readonly ActorTable Actors; + + /// + /// The local player character, if one is present. + /// + public PlayerCharacter LocalPlayer => (PlayerCharacter) this.Actors[0]; + + /// + /// The content ID of the local character. + /// + public ulong LocalContentId => (ulong) Marshal.ReadInt64(Address.LocalContentId); + + /// + /// Set up client state access. + /// + /// Dalamud instance + /// /// StartInfo of the current Dalamud launch + /// Sig scanner + /// Game process module + public ClientState(Dalamud dalamud, DalamudStartInfo startInfo, SigScanner scanner, ProcessModule targetModule) { + Address = new ClientStateAddressResolver(); + Address.Setup(scanner); + + this.ClientLanguage = startInfo.Language; + + this.Actors = new ActorTable(Address); + } + } +} diff --git a/Dalamud/Game/ClientState/ClientStateAddressResolver.cs b/Dalamud/Game/ClientState/ClientStateAddressResolver.cs new file mode 100644 index 000000000..37d1fde18 --- /dev/null +++ b/Dalamud/Game/ClientState/ClientStateAddressResolver.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Dalamud.Game.Internal; + +namespace Dalamud.Game.ClientState +{ + public sealed class ClientStateAddressResolver : BaseAddressResolver { + public IntPtr ActorTable { get; private set; } + public IntPtr LocalContentId { get; private set; } + + protected override void Setup64Bit(SigScanner sig) { + ActorTable = sig.Module.BaseAddress + 0x1B29B40; + LocalContentId = sig.Module.BaseAddress + 0x1B58B60; + } + } +} diff --git a/Dalamud/Game/ClientState/Structs/Actor.cs b/Dalamud/Game/ClientState/Structs/Actor.cs new file mode 100644 index 000000000..3e1d9ac7c --- /dev/null +++ b/Dalamud/Game/ClientState/Structs/Actor.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; +using Dalamud.Game.ClientState.Actors; + +namespace Dalamud.Game.ClientState.Structs +{ + /// + /// Native memory representation of a FFXIV actor. + /// + [StructLayout(LayoutKind.Explicit)] + public struct Actor { + [FieldOffset(0x30)] [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 30)] public string Name; + [FieldOffset(116)] public int ActorId; + [FieldOffset(128)] public int DataId; + [FieldOffset(132)] public int OwnerId; + [FieldOffset(140)] public ObjectKind ObjectKind; + [FieldOffset(141)] public byte SubKind; + [FieldOffset(160)] public Position3 Position; + [FieldOffset(6296)] public byte CurrentWorld; + [FieldOffset(6298)] public byte HomeWorld; + [FieldOffset(6308)] public int CurrentHp; + [FieldOffset(6312)] public int MaxHp; + [FieldOffset(6316)] public int CurrentMp; + [FieldOffset(6320)] public int MaxMp; + [FieldOffset(6364)] public byte ClassJob; + [FieldOffset(6366)] public byte Level; + } +} diff --git a/Dalamud/Game/Command/CommandInfo.cs b/Dalamud/Game/Command/CommandInfo.cs new file mode 100644 index 000000000..536843a74 --- /dev/null +++ b/Dalamud/Game/Command/CommandInfo.cs @@ -0,0 +1,15 @@ +namespace Dalamud.Game.Command { + public sealed class CommandInfo { + public delegate void HandlerDelegate(string command, string arguments); + + public HandlerDelegate Handler { get; } + + public string HelpMessage { get; set; } = string.Empty; + + public bool ShowInHelp { get; set; } = true; + + public CommandInfo(HandlerDelegate handler) { + Handler = handler; + } + } +} diff --git a/Dalamud/Game/Command/CommandManager.cs b/Dalamud/Game/Command/CommandManager.cs new file mode 100644 index 000000000..b7b590ac4 --- /dev/null +++ b/Dalamud/Game/Command/CommandManager.cs @@ -0,0 +1,119 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Text.RegularExpressions; +using Dalamud.Game.Chat; +using Serilog; + +namespace Dalamud.Game.Command { + public sealed class CommandManager { + private readonly Dalamud dalamud; + + private readonly Dictionary commandMap = new Dictionary(); + + public ReadOnlyDictionary Commands => + new ReadOnlyDictionary(this.commandMap); + + private readonly Regex commandRegexEn = + new Regex(@"^The command (?.+) does not exist\.$", RegexOptions.Compiled); + + private readonly Regex commandRegexJp = new Regex(@"^そのコマンドはありません。: (?.+)$", RegexOptions.Compiled); + + private readonly Regex commandRegexDe = + new Regex(@"^„(?.+)“ existiert nicht als Textkommando\.$", RegexOptions.Compiled); + + private readonly Regex commandRegexFr = + new Regex(@"^La commande texte “(?.+)” ne peut pas être utilisée de cette façon\.$", + RegexOptions.Compiled); + + private readonly Regex CommandRegex; + + + public CommandManager(Dalamud dalamud, ClientLanguage language) { + this.dalamud = dalamud; + + switch (language) { + case ClientLanguage.Japanese: + this.CommandRegex = this.commandRegexJp; + break; + case ClientLanguage.English: + this.CommandRegex = this.commandRegexEn; + break; + case ClientLanguage.German: + this.CommandRegex = this.commandRegexDe; + break; + case ClientLanguage.French: + this.CommandRegex = this.commandRegexFr; + break; + } + + dalamud.Framework.Gui.Chat.OnChatMessage += OnChatMessage; + } + + private void OnChatMessage(XivChatType type, uint senderId, string sender, ref string message, + ref bool isHandled) { + if (type == XivChatType.GatheringSystemMessage && senderId == 0) { + var cmdMatch = this.CommandRegex.Match(message).Groups["command"]; + if (cmdMatch.Success) { + // Yes, it's a chat command. + var command = cmdMatch.Value; + if (ProcessCommand(command)) isHandled = true; + } + } + } + + private bool ProcessCommand(string content) { + string command; + string argument; + + var speratorPosition = content.IndexOf(' '); + if (speratorPosition == -1 || speratorPosition + 1 >= content.Length) { + // If no space was found or ends with the space. Process them as a no argument + command = content; + argument = string.Empty; + } else { + // e.g.) + // /testcommand arg1 + // => Total of 17 chars + // => command: 0-12 (12 chars) + // => argument: 13-17 (4 chars) + // => content.IndexOf(' ') == 12 + command = content.Substring(0, speratorPosition); + + var argStart = speratorPosition + 1; + argument = content.Substring(argStart, content.Length - argStart); + } + + if (!this.commandMap.TryGetValue(command, out var handler)) // Commad was not found. + return false; + + DispatchCommand(command, argument, handler); + return true; + } + + public void DispatchCommand(string command, string argument, CommandInfo info) { + try { + info.Handler(command, argument); + } catch (Exception ex) { + Log.Error(ex, "Error while dispatching command {CommandName} (Argument: {Argument})", command, + argument); + } + } + + public bool AddHandler(string command, CommandInfo info) { + if (info == null) throw new ArgumentNullException(nameof(info), "Command handler is null."); + + try { + this.commandMap.Add(command, info); + return true; + } catch (ArgumentException) { + Log.Warning("Command {CommandName} is already registered.", command); + return false; + } + } + + public bool RemoveHandler(string command) { + return this.commandMap.Remove(command); + } + } +} diff --git a/Dalamud/Game/Internal/BaseAddressResolver.cs b/Dalamud/Game/Internal/BaseAddressResolver.cs new file mode 100644 index 000000000..8cbb83be5 --- /dev/null +++ b/Dalamud/Game/Internal/BaseAddressResolver.cs @@ -0,0 +1,48 @@ +using System; +using System.Runtime.InteropServices; + +namespace Dalamud.Game.Internal { + public abstract class BaseAddressResolver { + protected bool IsResolved { get; set; } + + public void Setup(SigScanner scanner) { + // Because C# don't allow to call virtual function while in ctor + // we have to do this shit :\ + + if (IsResolved) { + return; + } + + if (scanner.Is32BitProcess) { + Setup32Bit(scanner); + } else { + Setup64Bit(scanner); + } + SetupInternal(scanner); + + IsResolved = true; + } + + protected virtual void Setup32Bit(SigScanner scanner) { + throw new NotSupportedException("32 bit version is not supported."); + } + + protected virtual void Setup64Bit(SigScanner sig) { + throw new NotSupportedException("64 bit version is not supported."); + } + + protected virtual void SetupInternal(SigScanner scanner) { + // Do nothing + } + + protected T GetVirtualFunction(IntPtr address, int vtableOffset, int count) where T : class { + // Get vtable + var vtable = Marshal.ReadIntPtr(address, vtableOffset); + + // Get an address to the function + var functionAddress = Marshal.ReadIntPtr(vtable, IntPtr.Size * count); + + return Marshal.GetDelegateForFunctionPointer(functionAddress); + } + } +} diff --git a/Dalamud/Game/Internal/Framework.cs b/Dalamud/Game/Internal/Framework.cs new file mode 100644 index 000000000..229b6817b --- /dev/null +++ b/Dalamud/Game/Internal/Framework.cs @@ -0,0 +1,100 @@ +using System; +using System.Runtime.InteropServices; +using Dalamud.Settings; +using Dalamud.Game.Internal.Gui; +using Dalamud.Game.Internal.Libc; +using Dalamud.Game.Internal.Network; +using Dalamud.Hooking; +using Serilog; + +namespace Dalamud.Game.Internal { + public sealed class Framework : IDisposable { + [UnmanagedFunctionPointer(CallingConvention.ThisCall)] + private delegate bool OnUpdateDetour(IntPtr framework); + + public delegate void OnUpdateDelegate(Framework framework); + + public event OnUpdateDelegate OnUpdateEvent; + + private Hook updateHook; + + + /// + /// A raw pointer to the instance of Client::Framework + /// + private FrameworkAddressResolver Address { get; } + +#region Subsystems + + public GameGui Gui { get; private set; } + + public GameNetwork Network { get; private set; } + + public LibcFunction Libc { get; private set; } + +#endregion + + public Framework(SigScanner scanner, Dalamud dalamud) { + Address = new FrameworkAddressResolver(); + Address.Setup(scanner); + + Log.Verbose("Framework address {FrameworkAddress}", Address.BaseAddress); + if (Address.BaseAddress == IntPtr.Zero) { + throw new InvalidOperationException("Framework is not initalized yet."); + } + + // Hook virtual functions + HookVTable(); + + // Initialize subsystems + Libc = new LibcFunction(scanner); + + Gui = new GameGui(Address.GuiManager, scanner, dalamud); + + Network = new GameNetwork(dalamud, scanner); + } + + private void HookVTable() { + var vtable = Marshal.ReadIntPtr(Address.BaseAddress); + // Virtual function layout: + // .rdata:00000001411F1FE0 dq offset Xiv__Framework___dtor + // .rdata:00000001411F1FE8 dq offset Xiv__Framework__init + // .rdata:00000001411F1FF0 dq offset sub_1400936E0 + // .rdata:00000001411F1FF8 dq offset sub_1400939E0 + // .rdata:00000001411F2000 dq offset Xiv__Framework__update + + var pUpdate = Marshal.ReadIntPtr(vtable, IntPtr.Size * 4); + this.updateHook = new Hook(pUpdate, new OnUpdateDetour(HandleFrameworkUpdate), this); + } + + public void Enable() { + Gui.Enable(); + Network.Enable(); + + this.updateHook.Enable(); + } + + public void Dispose() { + Gui.Dispose(); + Network.Dispose(); + + this.updateHook.Dispose(); + } + + private bool HandleFrameworkUpdate(IntPtr framework) { + try { + Gui.Chat.UpdateQueue(this); + } catch (Exception ex) { + Log.Error(ex, "Exception while handling Framework::Update hook."); + } + + try { + OnUpdateEvent?.Invoke(this); + } catch (Exception ex) { + Log.Error(ex, "Exception while dispatching Framework::Update event."); + } + + return this.updateHook.Original(framework); + } + } +} diff --git a/Dalamud/Game/Internal/FrameworkAddressResolver.cs b/Dalamud/Game/Internal/FrameworkAddressResolver.cs new file mode 100644 index 000000000..6d6b11263 --- /dev/null +++ b/Dalamud/Game/Internal/FrameworkAddressResolver.cs @@ -0,0 +1,39 @@ +using System; +using System.Runtime.InteropServices; + +namespace Dalamud.Game.Internal { + public sealed class FrameworkAddressResolver : BaseAddressResolver { + public IntPtr BaseAddress { get; private set; } + + public IntPtr GuiManager { get; private set; } + + public IntPtr ScriptManager { get; private set; } + + + protected override void Setup64Bit(SigScanner sig) { + SetupFramework(sig); + + // Xiv__Framework__GetGuiManager+8 000 mov rax, [rcx+2C00h] + // Xiv__Framework__GetGuiManager+F 000 retn + GuiManager = Marshal.ReadIntPtr(BaseAddress, 0x2C08); + + // Called from Framework::Init + ScriptManager = BaseAddress + 0x2C68; // note that no deref here + } + + private void SetupFramework(SigScanner scanner) { + // Dissasembly of part of the .dtor + // 00007FF701AD665A | 48 C7 05 ?? ?? ?? ?? 00 00 00 00 | MOV QWORD PTR DS:[g_mainFramework],0 + // 00007FF701AD6665 | E8 ?? ?? ?? ?? | CALL ffxiv_dx11.7FF701E27130 + // 00007FF701AD666A | 48 8D ?? ?? ?? 00 00 | LEA RCX,QWORD PTR DS:[RBX + 2C38] + // 00007FF701AD6671 | E8 ?? ?? ?? ?? | CALL ffxiv_dx11.7FF701E2A7D0 + // 00007FF701AD6676 | 48 8D ?? ?? ?? ?? ?? | LEA RAX,QWORD PTR DS:[7FF702C31F80 + var fwDtor = scanner.ScanText("48C705????????00000000 E8???????? 488D??????0000 E8???????? 488D"); + var fwOffset = Marshal.ReadInt32(fwDtor + 3); + var pFramework = scanner.ResolveRelativeAddress(fwDtor + 11, fwOffset); + + // Framework does not change once initialized in startup so don't bother to deref again and again. + BaseAddress = Marshal.ReadIntPtr(pFramework); + } + } +} diff --git a/Dalamud/Game/Internal/Gui/ChatGui.cs b/Dalamud/Game/Internal/Gui/ChatGui.cs new file mode 100644 index 000000000..4b64f9364 --- /dev/null +++ b/Dalamud/Game/Internal/Gui/ChatGui.cs @@ -0,0 +1,160 @@ +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using Dalamud.Game.Chat; +using Dalamud.Game.Internal.Libc; +using Dalamud.Hooking; +using Serilog; + +namespace Dalamud.Game.Internal.Gui { + public sealed class ChatGui : IDisposable { + [UnmanagedFunctionPointer(CallingConvention.ThisCall)] + private delegate void PrintMessageDelegate(IntPtr manager, XivChatType chatType, IntPtr senderName, + IntPtr message, + uint senderId, byte isLocal); + + public delegate void OnMessageDelegate(XivChatType type, uint senderId, string sender, ref string message, + ref bool isHandled); + + + [UnmanagedFunctionPointer(CallingConvention.ThisCall)] + private delegate void PopulateItemLinkDelegate(IntPtr linkObjectPtr, IntPtr itemInfoPtr); + + private readonly Queue chatQueue = new Queue(); + + private readonly Hook printMessageHook; + + public event OnMessageDelegate OnChatMessage; + + private readonly Hook populateItemLinkHook; + + public int LastLinkedItemId { get; private set; } + public byte LastLinkedItemFlags { get; private set; } + + private ChatGuiAddressResolver Address { get; } + + private IntPtr baseAddress = IntPtr.Zero; + + private readonly Dalamud dalamud; + + public ChatGui(IntPtr baseAddress, SigScanner scanner, Dalamud dalamud) { + this.dalamud = dalamud; + + Address = new ChatGuiAddressResolver(baseAddress); + Address.Setup(scanner); + + Log.Verbose("Chat manager address {ChatManager}", Address.BaseAddress); + + this.printMessageHook = + new Hook(Address.PrintMessage, new PrintMessageDelegate(HandlePrintMessageDetour), + this); + this.populateItemLinkHook = + new Hook(Address.PopulateItemLinkObject, + new PopulateItemLinkDelegate(HandlePopulateItemLinkDetour), + this); + } + + public void Enable() { + this.printMessageHook.Enable(); + this.populateItemLinkHook.Enable(); + } + + public void Dispose() { + this.printMessageHook.Dispose(); + this.populateItemLinkHook.Dispose(); + } + + private void HandlePopulateItemLinkDetour(IntPtr linkObjectPtr, IntPtr itemInfoPtr) { + try { + this.populateItemLinkHook.Original(linkObjectPtr, itemInfoPtr); + + LastLinkedItemId = Marshal.ReadInt32(itemInfoPtr, 8); + LastLinkedItemFlags = Marshal.ReadByte(itemInfoPtr, 0x14); + + Log.Debug($"HandlePopulateItemLinkDetour {linkObjectPtr} {itemInfoPtr} - linked:{LastLinkedItemId}"); + } catch (Exception ex) { + Log.Error(ex, "Exception onPopulateItemLink hook."); + this.populateItemLinkHook.Original(linkObjectPtr, itemInfoPtr); + } + } + + private void HandlePrintMessageDetour(IntPtr manager, XivChatType chattype, IntPtr pSenderName, IntPtr pMessage, + uint senderid, byte isLocal) { + try { + var senderName = StdString.ReadFromPointer(pSenderName); + var message = StdString.ReadFromPointer(pMessage); + + //Log.Debug($"HandlePrintMessageDetour {manager} - [{chattype}] [{BitConverter.ToString(Encoding.UTF8.GetBytes(message))}] {message} from {senderName}"); + + var originalMessage = string.Copy(message); + + // Call events + var isHandled = false; + OnChatMessage?.Invoke(chattype, senderid, senderName, ref message, ref isHandled); + + var messagePtr = pMessage; + OwnedStdString allocatedString = null; + + if (originalMessage != message) { + allocatedString = this.dalamud.Framework.Libc.NewString(message); + Log.Debug( + $"HandlePrintMessageDetour String modified: {originalMessage}({messagePtr}) -> {message}({allocatedString.Address})"); + messagePtr = allocatedString.Address; + } + + // Print the original chat if it's handled. + if (!isHandled) + this.printMessageHook.Original(manager, chattype, pSenderName, messagePtr, senderid, isLocal); + + if (this.baseAddress == IntPtr.Zero) + this.baseAddress = manager; + + allocatedString?.Dispose(); + } catch (Exception ex) { + Log.Error(ex, "Exception on OnChatMessage hook."); + this.printMessageHook.Original(manager, chattype, pSenderName, pMessage, senderid, isLocal); + } + } + + /// + /// Queue a chat message. While method is named as PrintChat, it only add a entry to the queue, + /// later to be processed when UpdateQueue() is called. + /// + /// A message to send. + public void PrintChat(XivChatEntry chat) { + this.chatQueue.Enqueue(chat); + } + + public void Print(string message) { + PrintChat(new XivChatEntry { + Message = message + }); + } + + public void PrintError(string message) { + PrintChat(new XivChatEntry { + Message = message, + Type = XivChatType.Urgent + }); + } + + /// + /// Process a chat queue. + /// + public void UpdateQueue(Framework framework) { + while (this.chatQueue.Count > 0) { + var chat = this.chatQueue.Dequeue(); + + var sender = chat.Name ?? ""; + var message = chat.Message ?? ""; + + if (this.baseAddress != IntPtr.Zero) + using (var senderVec = framework.Libc.NewString(sender)) + using (var messageVec = framework.Libc.NewString(message)) { + this.printMessageHook.Original(this.baseAddress, chat.Type, senderVec.Address, + messageVec.Address, chat.SenderId, 0); + } + } + } + } +} diff --git a/Dalamud/Game/Internal/Gui/ChatGuiAddressResolver.cs b/Dalamud/Game/Internal/Gui/ChatGuiAddressResolver.cs new file mode 100644 index 000000000..67478e423 --- /dev/null +++ b/Dalamud/Game/Internal/Gui/ChatGuiAddressResolver.cs @@ -0,0 +1,88 @@ +using System; + +namespace Dalamud.Game.Internal.Gui { + public sealed class ChatGuiAddressResolver : BaseAddressResolver { + public IntPtr BaseAddress { get; } + + public IntPtr PrintMessage { get; private set; } + public IntPtr PopulateItemLinkObject { get; private set; } + + public ChatGuiAddressResolver(IntPtr baseAddres) { + BaseAddress = baseAddres; + } + + + /* + --- for reference: 4.57 --- + +.text:00000001405CD210 ; __int64 __fastcall Xiv::Gui::ChatGui::PrintMessage(__int64 handler, unsigned __int16 chatType, __int64 senderName, __int64 message, int senderActorId, char isLocal) +.text:00000001405CD210 Xiv__Gui__ChatGui__PrintMessage proc near +.text:00000001405CD210 ; CODE XREF: sub_1401419F0+201↑p +.text:00000001405CD210 ; sub_140141D10+220↑p ... +.text:00000001405CD210 +.text:00000001405CD210 var_220 = qword ptr -220h +.text:00000001405CD210 var_218 = byte ptr -218h +.text:00000001405CD210 var_210 = word ptr -210h +.text:00000001405CD210 var_208 = byte ptr -208h +.text:00000001405CD210 var_200 = word ptr -200h +.text:00000001405CD210 var_1FC = dword ptr -1FCh +.text:00000001405CD210 var_1F8 = qword ptr -1F8h +.text:00000001405CD210 var_1F0 = qword ptr -1F0h +.text:00000001405CD210 var_1E8 = qword ptr -1E8h +.text:00000001405CD210 var_1E0 = dword ptr -1E0h +.text:00000001405CD210 var_1DC = word ptr -1DCh +.text:00000001405CD210 var_1DA = word ptr -1DAh +.text:00000001405CD210 var_1D8 = qword ptr -1D8h +.text:00000001405CD210 var_1D0 = byte ptr -1D0h +.text:00000001405CD210 var_1C8 = qword ptr -1C8h +.text:00000001405CD210 var_1B0 = dword ptr -1B0h +.text:00000001405CD210 var_1AC = dword ptr -1ACh +.text:00000001405CD210 var_1A8 = dword ptr -1A8h +.text:00000001405CD210 var_1A4 = dword ptr -1A4h +.text:00000001405CD210 var_1A0 = dword ptr -1A0h +.text:00000001405CD210 var_160 = dword ptr -160h +.text:00000001405CD210 var_15C = dword ptr -15Ch +.text:00000001405CD210 var_140 = dword ptr -140h +.text:00000001405CD210 var_138 = dword ptr -138h +.text:00000001405CD210 var_130 = byte ptr -130h +.text:00000001405CD210 var_C0 = byte ptr -0C0h +.text:00000001405CD210 var_50 = qword ptr -50h +.text:00000001405CD210 var_38 = qword ptr -38h +.text:00000001405CD210 var_30 = qword ptr -30h +.text:00000001405CD210 var_28 = qword ptr -28h +.text:00000001405CD210 var_20 = qword ptr -20h +.text:00000001405CD210 senderActorId = dword ptr 30h +.text:00000001405CD210 isLocal = byte ptr 38h +.text:00000001405CD210 +.text:00000001405CD210 ; __unwind { // __GSHandlerCheck +.text:00000001405CD210 push rbp +.text:00000001405CD212 push rdi +.text:00000001405CD213 push r14 +.text:00000001405CD215 push r15 +.text:00000001405CD217 lea rbp, [rsp-128h] +.text:00000001405CD21F sub rsp, 228h +.text:00000001405CD226 mov rax, cs:__security_cookie +.text:00000001405CD22D xor rax, rsp +.text:00000001405CD230 mov [rbp+140h+var_50], rax +.text:00000001405CD237 xor r10b, r10b +.text:00000001405CD23A mov [rsp+240h+var_1F8], rcx +.text:00000001405CD23F xor eax, eax +.text:00000001405CD241 mov r11, r9 +.text:00000001405CD244 mov r14, r8 +.text:00000001405CD247 mov r9d, eax +.text:00000001405CD24A movzx r15d, dx +.text:00000001405CD24E lea r8, [rcx+0C10h] +.text:00000001405CD255 mov rdi, rcx + */ + + protected override void Setup64Bit(SigScanner sig) { + PrintMessage = sig.ScanText("4055 57 41 ?? 41 ?? 488DAC24D8FEFFFF 4881EC28020000 488B05???????? 4833C4 488985F0000000 4532D2 48894C2448"); + //PrintMessage = sig.ScanText("4055 57 41 ?? 41 ?? 488DAC24E8FEFFFF 4881EC18020000 488B05???????? 4833C4 488985E0000000 4532D2 48894C2438"); old + + //PrintMessage = sig.ScanText("40 55 57 41 56 41 57 48 8D AC 24 D8 FE FF FF 48 81 EC 28 02 00 00 48 8B 05 63 47 4A 01 48 33 C4 48 89 85 F0 00 00 00 45 32 D2 48 89 4C 24 48 33"); + + //PopulateItemLinkObject = sig.ScanText("48 89 5C 24 08 57 48 83 EC 20 80 7A 06 00 48 8B DA 48 8B F9 74 14 48 8B CA E8 32 03 00 00 48 8B C8 E8 FA F2 B0 FF 8B C8 EB 1D 0F B6 42 14 8B 4A"); + PopulateItemLinkObject = sig.ScanText("48 89 5C 24 08 57 48 83 EC 20 80 7A 06 00 48 8B DA 48 8B F9 74 14 48 8B CA E8 32 03 00 00 48 8B C8 E8 ?? ?? B0 FF 8B C8 EB 1D 0F B6 42 14 8B 4A"); + } + } +} diff --git a/Dalamud/Game/Internal/Gui/GameGui.cs b/Dalamud/Game/Internal/Gui/GameGui.cs new file mode 100644 index 000000000..a2b79aabe --- /dev/null +++ b/Dalamud/Game/Internal/Gui/GameGui.cs @@ -0,0 +1,27 @@ +using System; +using Serilog; + +namespace Dalamud.Game.Internal.Gui { + public sealed class GameGui : IDisposable { + private GameGuiAddressResolver Address { get; } + + public ChatGui Chat { get; private set; } + + public GameGui(IntPtr baseAddress, SigScanner scanner, Dalamud dalamud) { + Address = new GameGuiAddressResolver(baseAddress); + Address.Setup(scanner); + + Log.Verbose("GameGuiManager address {Address}", Address.BaseAddress); + + Chat = new ChatGui(Address.ChatManager, scanner, dalamud); + } + + public void Enable() { + Chat.Enable(); + } + + public void Dispose() { + Chat.Dispose(); + } + } +} diff --git a/Dalamud/Game/Internal/Gui/GameGuiAddressResolver.cs b/Dalamud/Game/Internal/Gui/GameGuiAddressResolver.cs new file mode 100644 index 000000000..7461f5d17 --- /dev/null +++ b/Dalamud/Game/Internal/Gui/GameGuiAddressResolver.cs @@ -0,0 +1,27 @@ +using System; +using System.Runtime.InteropServices; + +namespace Dalamud.Game.Internal.Gui { + public sealed class GameGuiAddressResolver : BaseAddressResolver { + public IntPtr BaseAddress { get; private set; } + + public IntPtr ChatManager { get; private set; } + + public GameGuiAddressResolver(IntPtr baseAddress) { + BaseAddress = baseAddress; + } + + [UnmanagedFunctionPointer(CallingConvention.ThisCall)] + private delegate IntPtr GetChatManagerDelegate(IntPtr guiManager); + + protected override void SetupInternal(SigScanner scanner) { + // Xiv__UiManager__GetChatManager 000 lea rax, [rcx+13E0h] + // Xiv__UiManager__GetChatManager+7 000 retn + ChatManager = BaseAddress + 0x13E0; + } + + protected override void Setup64Bit(SigScanner sig) { + // Do nothing, still required. + } + } +} diff --git a/Dalamud/Game/Internal/Libc/LibcFunction.cs b/Dalamud/Game/Internal/Libc/LibcFunction.cs new file mode 100644 index 000000000..93e7fcebb --- /dev/null +++ b/Dalamud/Game/Internal/Libc/LibcFunction.cs @@ -0,0 +1,48 @@ +using System; +using System.Runtime.InteropServices; +using Serilog; + +namespace Dalamud.Game.Internal.Libc { + public sealed class LibcFunction { + // TODO: prolly callconv is not okay in x86 + [UnmanagedFunctionPointer(CallingConvention.ThisCall)] + private delegate IntPtr StdStringFromCStringDelegate(IntPtr pStdString, [MarshalAs(UnmanagedType.LPUTF8Str)]string content, IntPtr size); + + // TODO: prolly callconv is not okay in x86 + [UnmanagedFunctionPointer(CallingConvention.ThisCall)] + private delegate IntPtr StdStringDeallocateDelegate(IntPtr address); + + private LibcFunctionAddressResolver Address { get; } + + private readonly StdStringFromCStringDelegate stdStringCtorCString; + private readonly StdStringDeallocateDelegate stdStringDeallocate; + + public LibcFunction(SigScanner scanner) { + Address = new LibcFunctionAddressResolver(); + Address.Setup(scanner); + + this.stdStringCtorCString = Marshal.GetDelegateForFunctionPointer(Address.StdStringFromCstring); + this.stdStringDeallocate = Marshal.GetDelegateForFunctionPointer(Address.StdStringDeallocate); + } + + public OwnedStdString NewString(string content) { + Log.Verbose("Allocating"); + + // While 0x70 bytes in the memory should be enough in DX11 version, + // I don't trust my analysis so we're just going to allocate almost two times more than that. + var pString = Marshal.AllocHGlobal(256); + + // Initialize a string + var npos = new IntPtr(0xFFFFFFFF); // assumed to be -1 (0xFFFFFFFF in x86, 0xFFFFFFFF_FFFFFFFF in amd64) + var pReallocString = this.stdStringCtorCString(pString, content, npos); + + Log.Verbose("Prev: {Prev} Now: {Now}", pString, pReallocString); + + return new OwnedStdString(pReallocString, DeallocateStdString); + } + + private void DeallocateStdString(IntPtr address) { + this.stdStringDeallocate(address); + } + } +} diff --git a/Dalamud/Game/Internal/Libc/LibcFunctionAddressResolver.cs b/Dalamud/Game/Internal/Libc/LibcFunctionAddressResolver.cs new file mode 100644 index 000000000..aeaefa595 --- /dev/null +++ b/Dalamud/Game/Internal/Libc/LibcFunctionAddressResolver.cs @@ -0,0 +1,16 @@ +using System; +using System.Security.Policy; + +namespace Dalamud.Game.Internal.Libc { + public sealed class LibcFunctionAddressResolver : BaseAddressResolver { + private delegate IntPtr StringFromCString(); + + public IntPtr StdStringFromCstring { get; private set; } + public IntPtr StdStringDeallocate { get; private set; } + + protected override void Setup64Bit(SigScanner sig) { + StdStringFromCstring = sig.ScanText("48895C2408 4889742410 57 4883EC20 488D4122 66C741200101 488901 498BD8"); + StdStringDeallocate = sig.ScanText("80792100 7512 488B5108 41B833000000 488B09 E9??????00 C3"); + } + } +} diff --git a/Dalamud/Game/Internal/Libc/OwnedStdString.cs b/Dalamud/Game/Internal/Libc/OwnedStdString.cs new file mode 100644 index 000000000..5efe897ed --- /dev/null +++ b/Dalamud/Game/Internal/Libc/OwnedStdString.cs @@ -0,0 +1,70 @@ +using System; +using System.Runtime.InteropServices; +using Serilog; + +namespace Dalamud.Game.Internal.Libc { + public sealed class OwnedStdString : IDisposable { + internal delegate void DeallocatorDelegate(IntPtr address); + + // ala. the drop flag + private bool isDisposed; + + private readonly DeallocatorDelegate dealloc; + + public IntPtr Address { get; private set; } + + /// + /// Construct a wrapper around std::string + /// + /// + /// Violating any of these might cause an undefined hehaviour. + /// 1. This function takes the ownership of the address. + /// 2. A memory pointed by address argument is assumed to be allocated by Marshal.AllocHGlobal thus will try to call Marshal.FreeHGlobal on the address. + /// 3. std::string object pointed by address must be initialized before calling this function. + /// + /// + /// A deallocator function. + /// + internal OwnedStdString(IntPtr address, DeallocatorDelegate dealloc) { + Address = address; + this.dealloc = dealloc; + } + + ~OwnedStdString() { + ReleaseUnmanagedResources(); + } + + private void ReleaseUnmanagedResources() { + if (Address == IntPtr.Zero) { + // Something got seriously fucked. + throw new AccessViolationException(); + } + + Log.Verbose("Deallocting {Addr}", Address); + + // Deallocate inner string first + this.dealloc(Address); + + // Free the heap + Marshal.FreeHGlobal(Address); + + // Better safe (running on a nullptr) than sorry. (running on a dangling pointer) + Address = IntPtr.Zero; + } + + public void Dispose() { + // No double free plz, kthx. + if (this.isDisposed) { + return; + } + this.isDisposed = true; + + ReleaseUnmanagedResources(); + GC.SuppressFinalize(this); + } + + public string Read() { + return StdString.ReadFromPointer(Address); + } + } +} diff --git a/Dalamud/Game/Internal/Libc/StdString.cs b/Dalamud/Game/Internal/Libc/StdString.cs new file mode 100644 index 000000000..c3d6f315b --- /dev/null +++ b/Dalamud/Game/Internal/Libc/StdString.cs @@ -0,0 +1,33 @@ +using System; +using System.Runtime.InteropServices; +using System.Text; + +namespace Dalamud.Game.Internal.Libc { + /// + /// Interation with std::string + /// + public static class StdString { + public static string ReadFromPointer(IntPtr cstring) { + unsafe { + if (cstring == IntPtr.Zero) { + throw new ArgumentNullException(nameof(cstring)); + } + + var innerAddress = Marshal.ReadIntPtr(cstring); + if (innerAddress == IntPtr.Zero) { + throw new NullReferenceException("Inner reference to the cstring is null."); + } + + var pInner = (sbyte*) innerAddress.ToPointer(); + var count = 0; + + // Count the number of chars. String is assumed to be zero-terminated. + while (*(pInner + count) != 0) { + count += 1; + } + + return new string(pInner, 0, count, Encoding.UTF8); + } + } + } +} diff --git a/Dalamud/Game/Internal/Network/GameNetwork.cs b/Dalamud/Game/Internal/Network/GameNetwork.cs new file mode 100644 index 000000000..25acfa562 --- /dev/null +++ b/Dalamud/Game/Internal/Network/GameNetwork.cs @@ -0,0 +1,64 @@ +using System; +using System.Runtime.InteropServices; +using Dalamud.Hooking; +using Serilog; + +namespace Dalamud.Game.Internal.Network { + public sealed class GameNetwork : IDisposable { + [UnmanagedFunctionPointer(CallingConvention.ThisCall)] + private delegate void ProcessZonePacketDelegate(IntPtr a, IntPtr b, IntPtr dataPtr); + + private readonly Hook processZonePacketHook; + + private GameNetworkAddressResolver Address { get; } + + public delegate void OnZonePacketDelegate(IntPtr dataPtr); + + public OnZonePacketDelegate OnZonePacket; + + private readonly Dalamud dalamud; + + public GameNetwork(Dalamud dalamud, SigScanner scanner) { + this.dalamud = dalamud; + Address = new GameNetworkAddressResolver(); + Address.Setup(scanner); + + Log.Verbose("ProcessZonePacket address {ProcessZonePacket}", Address.ProcessZonePacket); + + this.processZonePacketHook = + new Hook(Address.ProcessZonePacket, + new ProcessZonePacketDelegate(ProcessZonePacketDetour), + this); + } + + public void Enable() { + this.processZonePacketHook.Enable(); + } + + public void Dispose() { + this.processZonePacketHook.Dispose(); + } + + private void ProcessZonePacketDetour(IntPtr a, IntPtr b, IntPtr dataPtr) { + // Call events + this.OnZonePacket?.Invoke(dataPtr); + + try { + this.processZonePacketHook.Original(a, b, dataPtr); + } catch (Exception ex) { + string header; + try { + var data = new byte[32]; + Marshal.Copy(dataPtr, data, 0, 32); + header = BitConverter.ToString(data); + } catch (Exception) { + header = "failed"; + } + + Log.Error(ex, "Exception on ProcessZonePacket hook. Header: " + header); + + this.processZonePacketHook.Original(a, b, dataPtr); + } + } + } +} diff --git a/Dalamud/Game/Internal/Network/GameNetworkAddressResolver.cs b/Dalamud/Game/Internal/Network/GameNetworkAddressResolver.cs new file mode 100644 index 000000000..08868c3a4 --- /dev/null +++ b/Dalamud/Game/Internal/Network/GameNetworkAddressResolver.cs @@ -0,0 +1,11 @@ +using System; + +namespace Dalamud.Game.Internal.Network { + public sealed class GameNetworkAddressResolver : BaseAddressResolver { + public IntPtr ProcessZonePacket { get; private set; } + + protected override void Setup64Bit(SigScanner sig) { + ProcessZonePacket = sig.ScanText("48 89 74 24 18 57 48 83 EC 50 8B F2 49 8B F8 41 0F B7 50 02 8B CE E8 ?? ?? 7A FF 0F B7 57 02 8D 42 89 3D 5F 02 00 00 0F 87 60 01 00 00 4C 8D 05"); + } + } +} diff --git a/Dalamud/Game/Network/MarketBoardItemRequest.cs b/Dalamud/Game/Network/MarketBoardItemRequest.cs new file mode 100644 index 000000000..7ec9afe90 --- /dev/null +++ b/Dalamud/Game/Network/MarketBoardItemRequest.cs @@ -0,0 +1,16 @@ +using System.Collections.Generic; +using Dalamud.Game.Network.Structures; + +namespace Dalamud.Game.Network { + internal class MarketBoardItemRequest { + public uint CatalogId { get; set; } + public byte AmountToArrive { get; set; } + + public List Listings { get; set; } + public List History { get; set; } + + public int ListingsRequestId { get; set; } = -1; + + public bool IsDone => Listings.Count == AmountToArrive && History.Count != 0; + } +} diff --git a/Dalamud/Game/Network/MarketBoardUploaders/IMarketBoardUploader.cs b/Dalamud/Game/Network/MarketBoardUploaders/IMarketBoardUploader.cs new file mode 100644 index 000000000..aa8eed3ec --- /dev/null +++ b/Dalamud/Game/Network/MarketBoardUploaders/IMarketBoardUploader.cs @@ -0,0 +1,5 @@ +namespace Dalamud.Game.Network.MarketBoardUploaders { + internal interface IMarketBoardUploader { + void Upload(MarketBoardItemRequest itemRequest); + } +} diff --git a/Dalamud/Game/Network/MarketBoardUploaders/Universalis/UniversalisHistoryEntry.cs b/Dalamud/Game/Network/MarketBoardUploaders/Universalis/UniversalisHistoryEntry.cs new file mode 100644 index 000000000..c3b5a4146 --- /dev/null +++ b/Dalamud/Game/Network/MarketBoardUploaders/Universalis/UniversalisHistoryEntry.cs @@ -0,0 +1,29 @@ +using Newtonsoft.Json; + +namespace Dalamud.Game.Network.MarketBoardUploaders.Universalis { + internal class UniversalisHistoryEntry { + [JsonProperty("hq")] + public bool Hq { get; set; } + + [JsonProperty("pricePerUnit")] + public uint PricePerUnit { get; set; } + + [JsonProperty("quantity")] + public uint Quantity { get; set; } + + [JsonProperty("buyerName")] + public string BuyerName { get; set; } + + [JsonProperty("onMannequin")] + public bool OnMannequin { get; set; } + + [JsonProperty("sellerID")] + public ulong SellerId { get; set; } + + [JsonProperty("buyerID")] + public ulong BuyerId { get; set; } + + [JsonProperty("timestamp")] + public long Timestamp { get; set; } + } +} diff --git a/Dalamud/Game/Network/MarketBoardUploaders/Universalis/UniversalisHistoryUploadRequest.cs b/Dalamud/Game/Network/MarketBoardUploaders/Universalis/UniversalisHistoryUploadRequest.cs new file mode 100644 index 000000000..51bcbacb8 --- /dev/null +++ b/Dalamud/Game/Network/MarketBoardUploaders/Universalis/UniversalisHistoryUploadRequest.cs @@ -0,0 +1,18 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Dalamud.Game.Network.MarketBoardUploaders.Universalis { + internal class UniversalisHistoryUploadRequest { + [JsonProperty("worldID")] + public int WorldId { get; set; } + + [JsonProperty("itemID")] + public uint ItemId { get; set; } + + [JsonProperty("entries")] + public List Entries { get; set; } + + [JsonProperty("uploaderID")] + public ulong UploaderId { get; set; } + } +} diff --git a/Dalamud/Game/Network/MarketBoardUploaders/Universalis/UniversalisItemListingsEntry.cs b/Dalamud/Game/Network/MarketBoardUploaders/Universalis/UniversalisItemListingsEntry.cs new file mode 100644 index 000000000..336e6773c --- /dev/null +++ b/Dalamud/Game/Network/MarketBoardUploaders/Universalis/UniversalisItemListingsEntry.cs @@ -0,0 +1,48 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Dalamud.Game.Network.MarketBoardUploaders.Universalis { + internal class UniversalisItemListingsEntry { + [JsonProperty("listingID")] + public ulong ListingId { get; set; } + + [JsonProperty("hq")] + public bool Hq { get; set; } + + [JsonProperty("pricePerUnit")] + public uint PricePerUnit { get; set; } + + [JsonProperty("quantity")] + public uint Quantity { get; set; } + + [JsonProperty("retainerName")] + public string RetainerName { get; set; } + + [JsonProperty("retainerID")] + public ulong RetainerId { get; set; } + + [JsonProperty("creatorName")] + public string CreatorName { get; set; } + + [JsonProperty("onMannequin")] + public bool OnMannequin { get; set; } + + [JsonProperty("sellerID")] + public ulong SellerId { get; set; } + + [JsonProperty("creatorID")] + public ulong CreatorId { get; set; } + + [JsonProperty("stainID")] + public int StainId { get; set; } + + [JsonProperty("retainerCity")] + public int RetainerCity { get; set; } + + [JsonProperty("lastReviewTime")] + public long LastReviewTime { get; set; } + + [JsonProperty("materia")] + public List Materia { get; set; } + } +} diff --git a/Dalamud/Game/Network/MarketBoardUploaders/Universalis/UniversalisItemListingsUploadRequest.cs b/Dalamud/Game/Network/MarketBoardUploaders/Universalis/UniversalisItemListingsUploadRequest.cs new file mode 100644 index 000000000..e07525f13 --- /dev/null +++ b/Dalamud/Game/Network/MarketBoardUploaders/Universalis/UniversalisItemListingsUploadRequest.cs @@ -0,0 +1,18 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Dalamud.Game.Network.MarketBoardUploaders.Universalis { + internal class UniversalisItemListingsUploadRequest { + [JsonProperty("worldID")] + public int WorldId { get; set; } + + [JsonProperty("itemID")] + public uint ItemId { get; set; } + + [JsonProperty("listings")] + public List Listings { get; set; } + + [JsonProperty("uploaderID")] + public ulong UploaderId { get; set; } + } +} diff --git a/Dalamud/Game/Network/MarketBoardUploaders/Universalis/UniversalisItemMateria.cs b/Dalamud/Game/Network/MarketBoardUploaders/Universalis/UniversalisItemMateria.cs new file mode 100644 index 000000000..93742b84b --- /dev/null +++ b/Dalamud/Game/Network/MarketBoardUploaders/Universalis/UniversalisItemMateria.cs @@ -0,0 +1,11 @@ +using Newtonsoft.Json; + +namespace Dalamud.Game.Network.MarketBoardUploaders.Universalis { + internal class UniversalisItemMateria { + [JsonProperty("slotID")] + public int SlotId { get; set; } + + [JsonProperty("materiaID")] + public int MateriaId { get; set; } + } +} diff --git a/Dalamud/Game/Network/MarketBoardUploaders/Universalis/UniversalisMarketBoardUploader.cs b/Dalamud/Game/Network/MarketBoardUploaders/Universalis/UniversalisMarketBoardUploader.cs new file mode 100644 index 000000000..c138d20fb --- /dev/null +++ b/Dalamud/Game/Network/MarketBoardUploaders/Universalis/UniversalisMarketBoardUploader.cs @@ -0,0 +1,90 @@ +using System; +using System.Collections.Generic; +using System.Net; +using Dalamud.Game.Network.MarketBoardUploaders; +using Dalamud.Game.Network.MarketBoardUploaders.Universalis; +using Newtonsoft.Json; +using Serilog; + +namespace Dalamud.Game.Network.Universalis.MarketBoardUploaders { + internal class UniversalisMarketBoardUploader : IMarketBoardUploader { + private const string ApiBase = "https://universalis.app"; + + //private const string ApiBase = "https://127.0.0.1:443"; + private const string ApiKey = "GGD6RdSfGyRiHM5WDnAo0Nj9Nv7aC5NDhMj3BebT"; + + private readonly Dalamud dalamud; + + public UniversalisMarketBoardUploader(Dalamud dalamud) { + this.dalamud = dalamud; + } + + public void Upload(MarketBoardItemRequest request) { + using (var client = new WebClient()) { + client.Headers.Add(HttpRequestHeader.ContentType, "application/json"); + + Log.Verbose("Starting Universalis upload."); + var uploader = this.dalamud.ClientState.LocalContentId; + + var listingsRequestObject = new UniversalisItemListingsUploadRequest(); + listingsRequestObject.WorldId = this.dalamud.ClientState.LocalPlayer.CurrentWorld.Id; + listingsRequestObject.UploaderId = uploader; + listingsRequestObject.ItemId = request.CatalogId; + + listingsRequestObject.Listings = new List(); + foreach (var marketBoardItemListing in request.Listings) { + var universalisListing = new UniversalisItemListingsEntry { + Hq = marketBoardItemListing.IsHq, + SellerId = marketBoardItemListing.RetainerOwnerId, + RetainerName = marketBoardItemListing.RetainerName, + RetainerId = marketBoardItemListing.RetainerId, + CreatorId = marketBoardItemListing.ArtisanId, + CreatorName = marketBoardItemListing.PlayerName, + OnMannequin = marketBoardItemListing.OnMannequin, + LastReviewTime = ((DateTimeOffset) marketBoardItemListing.LastReviewTime).ToUnixTimeSeconds(), + PricePerUnit = marketBoardItemListing.PricePerUnit, + Quantity = marketBoardItemListing.ItemQuantity, + RetainerCity = marketBoardItemListing.RetainerCityId + }; + + universalisListing.Materia = new List(); + foreach (var itemMateria in marketBoardItemListing.Materia) + universalisListing.Materia.Add(new UniversalisItemMateria { + MateriaId = itemMateria.MateriaId, + SlotId = itemMateria.Index + }); + + listingsRequestObject.Listings.Add(universalisListing); + } + + var upload = JsonConvert.SerializeObject(listingsRequestObject); + client.UploadString(ApiBase + $"/upload/{ApiKey}", "POST", upload); + Log.Verbose(upload); + + var historyRequestObject = new UniversalisHistoryUploadRequest(); + historyRequestObject.WorldId = this.dalamud.ClientState.LocalPlayer.CurrentWorld.Id; + historyRequestObject.UploaderId = uploader; + historyRequestObject.ItemId = request.CatalogId; + + historyRequestObject.Entries = new List(); + foreach (var marketBoardHistoryListing in request.History) + historyRequestObject.Entries.Add(new UniversalisHistoryEntry { + BuyerName = marketBoardHistoryListing.BuyerName, + Hq = marketBoardHistoryListing.IsHq, + OnMannequin = marketBoardHistoryListing.OnMannequin, + PricePerUnit = marketBoardHistoryListing.SalePrice, + Quantity = marketBoardHistoryListing.Quantity, + Timestamp = ((DateTimeOffset) marketBoardHistoryListing.PurchaseTime).ToUnixTimeSeconds() + }); + + client.Headers.Add(HttpRequestHeader.ContentType, "application/json"); + + var historyUpload = JsonConvert.SerializeObject(historyRequestObject); + client.UploadString(ApiBase + $"/upload/{ApiKey}", "POST", historyUpload); + Log.Verbose(historyUpload); + + Log.Verbose("Universalis data upload for item#{0} completed.", request.CatalogId); + } + } + } +} diff --git a/Dalamud/Game/Network/NetworkHandlers.cs b/Dalamud/Game/Network/NetworkHandlers.cs new file mode 100644 index 000000000..02d5c0e2b --- /dev/null +++ b/Dalamud/Game/Network/NetworkHandlers.cs @@ -0,0 +1,192 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using System.Threading.Tasks; +using Dalamud.Game.Network.MarketBoardUploaders; +using Dalamud.Game.Network.Structures; +using Dalamud.Game.Network.Universalis.MarketBoardUploaders; +using Dalamud.Settings; +using Serilog; + +namespace Dalamud.Game.Network { + public class NetworkHandlers { + private readonly Dalamud dalamud; + + private readonly List marketBoardRequests = new List(); + + private readonly bool optOutMbUploads; + private readonly IMarketBoardUploader uploader; + + public NetworkHandlers(Dalamud dalamud, bool optOutMbUploads) { + this.dalamud = dalamud; + this.optOutMbUploads = optOutMbUploads; + + this.uploader = new UniversalisMarketBoardUploader(dalamud); + + dalamud.Framework.Network.OnZonePacket += OnZonePacket; + } + + private void OnZonePacket(IntPtr dataPtr) { + var opCode = (ZoneOpCode) Marshal.ReadInt16(dataPtr, 2); + + if (opCode == ZoneOpCode.RetainerSaleItemId) { + var itemId = Marshal.ReadInt32(dataPtr + 16); + var amount = Marshal.ReadByte(dataPtr + 32); + var isHq = false; + + if (itemId > 1000000) { + itemId -= 1000000; + isHq = true; + } + + Task.Run(() => this.dalamud.BotManager.ProcessRetainerSale(itemId, amount, isHq)); + + return; + } + + if (opCode == ZoneOpCode.FateSpawn) { + if (PersistentSettings.Instance.Fates == null) + return; + + var data = new byte[64]; + Marshal.Copy(dataPtr, data, 0, 64); + + var fateId = data[16]; + if (PersistentSettings.Instance.Fates.Any(x => x.Id == fateId) && + this.dalamud.BotManager.IsConnected) + Task.Run(() => this.dalamud.BotManager.ProcessFate(fateId)); + + return; + } + + if (opCode == ZoneOpCode.CfNotify) { + var data = new byte[64]; + Marshal.Copy(dataPtr, data, 0, 64); + + var notifyType = data[16]; + var contentFinderConditionId = BitConverter.ToInt16(data, 38); + + + Task.Run(async () => { + if (notifyType != 4) + return; + + var contentFinderCondition = + await XivApi.GetContentFinderCondition(contentFinderConditionId); + + this.dalamud.Framework.Gui.Chat.Print("Duty Finder pop: " + contentFinderCondition["Name"]); + + if (this.dalamud.BotManager.IsConnected) + await this.dalamud.BotManager.ProcessCfPop(contentFinderCondition); + }); + + return; + } + + if (!this.optOutMbUploads) { + if (opCode == ZoneOpCode.MarketBoardItemRequestStart) { + var catalogId = (uint) Marshal.ReadInt32(dataPtr + 0x10); + var amount = Marshal.ReadByte(dataPtr + 0x1B); + + this.marketBoardRequests.Add(new MarketBoardItemRequest { + CatalogId = catalogId, + AmountToArrive = amount, + Listings = new List(), + History = new List() + }); + + Log.Verbose($"NEW MB REQUEST START: item#{catalogId} amount#{amount}"); + return; + } + + if (opCode == ZoneOpCode.MarketBoardOfferings) { + var listing = MarketBoardCurrentOfferings.Read(dataPtr + 0x10); + + var request = + this.marketBoardRequests.LastOrDefault( + r => r.CatalogId == listing.ItemListings[0].CatalogId && !r.IsDone); + + if (request == null) { + Log.Error( + $"Market Board data arrived without a corresponding request: item#{listing.ItemListings[0].CatalogId}"); + return; + } + + if (request.Listings.Count + listing.ItemListings.Count > request.AmountToArrive) { + Log.Error( + $"Too many Market Board listings received for request: {request.Listings.Count + listing.ItemListings.Count} > {request.AmountToArrive} item#{listing.ItemListings[0].CatalogId}"); + return; + } + + if (request.ListingsRequestId != -1 && request.ListingsRequestId != listing.RequestId) { + Log.Error( + $"Non-matching RequestIds for Market Board data request: {request.ListingsRequestId}, {listing.RequestId}"); + return; + } + + if (request.ListingsRequestId == -1 && request.Listings.Count > 0) { + Log.Error( + $"Market Board data request sequence break: {request.ListingsRequestId}, {request.Listings.Count}"); + return; + } + + if (request.ListingsRequestId == -1) { + request.ListingsRequestId = listing.RequestId; + Log.Verbose($"First Market Board packet in sequence: {listing.RequestId}"); + } + + request.Listings.AddRange(listing.ItemListings); + + Log.Verbose("Added {0} ItemListings to request#{1}, now {2}/{3}, item#{4}", + listing.ItemListings.Count, request.ListingsRequestId, request.Listings.Count, + request.AmountToArrive, request.CatalogId); + + if (request.IsDone) { + Log.Verbose("Market Board request finished, starting upload: request#{0} item#{1} amount#{2}", + request.ListingsRequestId, request.CatalogId, request.AmountToArrive); + try { + Task.Run(() => this.uploader.Upload(request)); + } catch (Exception ex) { + Log.Error(ex, "Market Board data upload failed."); + } + } + + return; + } + + if (opCode == ZoneOpCode.MarketBoardHistory) { + var listing = MarketBoardHistory.Read(dataPtr + 0x10); + + var request = this.marketBoardRequests.LastOrDefault(r => r.CatalogId == listing.CatalogId); + + if (request == null) { + Log.Error( + $"Market Board data arrived without a corresponding request: item#{listing.CatalogId}"); + return; + } + + if (request.ListingsRequestId != -1) { + Log.Error( + $"Market Board data history sequence break: {request.ListingsRequestId}, {request.Listings.Count}"); + return; + } + + request.History.AddRange(listing.HistoryListings); + + Log.Verbose("Added history for item#{0}", listing.CatalogId); + } + } + } + + private enum ZoneOpCode { + CfNotify = 0x78, + RetainerSaleItemId = 0x13F, // TODO these are probably not accurate + RetainerSaleFinish = 0x138, + FateSpawn = 0x226, + MarketBoardItemRequestStart = 0x13B, + MarketBoardOfferings = 0x13C, + MarketBoardHistory = 0x140 + } + } +} diff --git a/Dalamud/Game/Network/Structures/MarketBoardCurrentOfferings.cs b/Dalamud/Game/Network/Structures/MarketBoardCurrentOfferings.cs new file mode 100644 index 000000000..cf65797c4 --- /dev/null +++ b/Dalamud/Game/Network/Structures/MarketBoardCurrentOfferings.cs @@ -0,0 +1,106 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; + +namespace Dalamud.Game.Network.Structures { + public class MarketBoardCurrentOfferings { + public List ItemListings; + + public int ListingIndexEnd; + public int ListingIndexStart; + public int RequestId; + + public static unsafe MarketBoardCurrentOfferings Read(IntPtr dataPtr) { + var output = new MarketBoardCurrentOfferings(); + + using (var stream = new UnmanagedMemoryStream((byte*) dataPtr.ToPointer(), 1544)) { + using (var reader = new BinaryReader(stream)) { + output.ItemListings = new List(); + + for (var i = 0; i < 10; i++) { + var listingEntry = new MarketBoardItemListing(); + + listingEntry.ListingId = reader.ReadUInt64(); + listingEntry.RetainerId = reader.ReadUInt64(); + listingEntry.RetainerOwnerId = reader.ReadUInt64(); + listingEntry.ArtisanId = reader.ReadUInt64(); + listingEntry.PricePerUnit = reader.ReadUInt32(); + listingEntry.TotalTax = reader.ReadUInt32(); + listingEntry.ItemQuantity = reader.ReadUInt32(); + listingEntry.CatalogId = reader.ReadUInt32(); + listingEntry.LastReviewTime = DateTimeOffset.UtcNow.AddSeconds(-reader.ReadUInt16()).DateTime; + + reader.ReadUInt16(); // container + reader.ReadUInt32(); // slot + reader.ReadUInt16(); // durability + reader.ReadUInt16(); // spiritbond + + listingEntry.Materia = new List(); + + for (var materiaIndex = 0; materiaIndex < 5; materiaIndex++) { + var materiaVal = reader.ReadUInt16(); + + var materiaEntry = new MarketBoardItemListing.ItemMateria(); + materiaEntry.MateriaId = (materiaVal & 0xFF0) >> 4; + materiaEntry.Index = materiaVal & 0xF; + + if (materiaEntry.MateriaId != 0) + listingEntry.Materia.Add(materiaEntry); + } + + reader.ReadUInt16(); + reader.ReadUInt32(); + + listingEntry.RetainerName = Encoding.UTF8.GetString(reader.ReadBytes(32)).TrimEnd('\u0000'); + listingEntry.PlayerName = Encoding.UTF8.GetString(reader.ReadBytes(32)).TrimEnd('\u0000'); + listingEntry.IsHq = reader.ReadBoolean(); + listingEntry.MateriaCount = reader.ReadByte(); + listingEntry.OnMannequin = reader.ReadBoolean(); + listingEntry.RetainerCityId = reader.ReadByte(); + listingEntry.StainId = reader.ReadUInt16(); + + reader.ReadUInt16(); + reader.ReadUInt32(); + + if (listingEntry.CatalogId != 0) + output.ItemListings.Add(listingEntry); + } + + output.ListingIndexEnd = reader.ReadByte(); + output.ListingIndexStart = reader.ReadByte(); + output.RequestId = reader.ReadUInt16(); + } + } + + return output; + } + + public class MarketBoardItemListing { + public ulong ArtisanId; + public uint CatalogId; + public bool IsHq; + public uint ItemQuantity; + public DateTime LastReviewTime; + public ulong ListingId; + + public List Materia; + public int MateriaCount; + public bool OnMannequin; + public string PlayerName; + public uint PricePerUnit; + public int RetainerCityId; + public ulong RetainerId; + + public string RetainerName; + public ulong RetainerOwnerId; + public int StainId; + public uint TotalTax; + + public class ItemMateria { + public int Index; + public int MateriaId; + } + } + } +} diff --git a/Dalamud/Game/Network/Structures/MarketBoardHistory.cs b/Dalamud/Game/Network/Structures/MarketBoardHistory.cs new file mode 100644 index 000000000..c96b4a0e0 --- /dev/null +++ b/Dalamud/Game/Network/Structures/MarketBoardHistory.cs @@ -0,0 +1,57 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; + +namespace Dalamud.Game.Network.Structures { + public class MarketBoardHistory { + public uint CatalogId; + public uint CatalogId2; + + public List HistoryListings; + + public static unsafe MarketBoardHistory Read(IntPtr dataPtr) { + var output = new MarketBoardHistory(); + + using (var stream = new UnmanagedMemoryStream((byte*) dataPtr.ToPointer(), 1544)) { + using (var reader = new BinaryReader(stream)) { + output.CatalogId = reader.ReadUInt32(); + output.CatalogId2 = reader.ReadUInt32(); + + output.HistoryListings = new List(); + + for (var i = 0; i < 10; i++) { + var listingEntry = new MarketBoardHistoryListing(); + + listingEntry.SalePrice = reader.ReadUInt32(); + listingEntry.PurchaseTime = DateTimeOffset.FromUnixTimeSeconds(reader.ReadUInt32()).UtcDateTime; + listingEntry.Quantity = reader.ReadUInt32(); + listingEntry.IsHq = reader.ReadBoolean(); + + reader.ReadBoolean(); + + listingEntry.OnMannequin = reader.ReadBoolean(); + listingEntry.BuyerName = Encoding.UTF8.GetString(reader.ReadBytes(33)).TrimEnd('\u0000'); + listingEntry.CatalogId = reader.ReadUInt32(); + + if (listingEntry.CatalogId != 0) + output.HistoryListings.Add(listingEntry); + } + } + } + + return output; + } + + public class MarketBoardHistoryListing { + public string BuyerName; + + public uint CatalogId; + public bool IsHq; + public bool OnMannequin; + public DateTime PurchaseTime; + public uint Quantity; + public uint SalePrice; + } + } +} diff --git a/Dalamud/Game/SigScanner.cs b/Dalamud/Game/SigScanner.cs new file mode 100644 index 000000000..823d016ba --- /dev/null +++ b/Dalamud/Game/SigScanner.cs @@ -0,0 +1,148 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Globalization; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using Serilog; + +namespace Dalamud.Game { + public sealed class SigScanner { + public SigScanner(ProcessModule module) { + Module = module; + Is32BitProcess = !Environment.Is64BitProcess; + + // Limit the search space to .text section. + SetupSearchSpace(module); + + Log.Verbose("Module base: {Address}", TextSectionBase); + Log.Verbose("Moudle size: {Size}", TextSectionSize); + } + + public bool Is32BitProcess { get; } + + public IntPtr TextSectionBase { get; private set; } + public int TextSectionSize { get; private set; } + + public IntPtr DataSectionBase { get; private set; } + public int DataSectionSize { get; private set; } + + public ProcessModule Module { get; } + + private IntPtr TextSectionTop => TextSectionBase + TextSectionSize; + + private void SetupSearchSpace(ProcessModule module) { + var baseAddress = module.BaseAddress; + + // We don't want to read all of IMAGE_DOS_HEADER or IMAGE_NT_HEADER stuff so we cheat here. + var ntNewOffset = Marshal.ReadInt32(baseAddress, 0x3C); + var ntHeader = baseAddress + ntNewOffset; + + // IMAGE_NT_HEADER + var fileHeader = ntHeader + 4; + var numSections = Marshal.ReadInt16(ntHeader, 6); + + // IMAGE_OPTIONAL_HEADER + var optionalHeader = fileHeader + 20; + + IntPtr sectionHeader; + if (Is32BitProcess) // IMAGE_OPTIONAL_HEADER32 + sectionHeader = optionalHeader + 224; + else // IMAGE_OPTIONAL_HEADER64 + sectionHeader = optionalHeader + 240; + + // IMAGE_SECTION_HEADER + var sectionCursor = sectionHeader; + for (var i = 0; i < numSections; i++) { + var sectionName = Marshal.ReadInt64(sectionCursor); + + // .text + switch (sectionName) { + case 0x747865742E: // .text + TextSectionBase = baseAddress + Marshal.ReadInt32(sectionCursor, 12); + TextSectionSize = Marshal.ReadInt32(sectionCursor, 8); + break; + case 0x617461642E: // .data + DataSectionBase = baseAddress + Marshal.ReadInt32(sectionCursor, 12); + DataSectionSize = Marshal.ReadInt32(sectionCursor, 8); + break; + } + + sectionCursor += 40; + } + } + + public IntPtr ScanText(string signature) { + return Scan(TextSectionBase, TextSectionSize, signature); + } + + public IntPtr ScanData(string signature) { + return Scan(DataSectionBase, DataSectionSize, signature); + } + + public IntPtr ScanModule(string signature) { + return Scan(Module.BaseAddress, Module.ModuleMemorySize, signature); + } + + public IntPtr Scan(IntPtr baseAddress, int size, string signature) { + var needle = SigToNeedle(signature); + + unsafe { + var pCursor = (byte*) baseAddress.ToPointer(); + var pTop = (byte*) (baseAddress + size - needle.Length); + while (pCursor < pTop) { + if (IsMatch(pCursor, needle)) return (IntPtr) pCursor; + + // Advance an offset + pCursor += 1; + } + } + + throw new KeyNotFoundException($"Can't find a signature of {signature}"); + } + + public IntPtr ResolveRelativeAddress(IntPtr nextInstAddr, int relOffset) { + if (Is32BitProcess) throw new NotSupportedException("32 bit is not supported."); + + return nextInstAddr + relOffset; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private unsafe bool IsMatch(byte* pCursor, byte?[] needle) { + for (var i = 0; i < needle.Length; i++) { + var expected = needle[i]; + if (expected == null) continue; + + var actual = *(pCursor + i); + if (expected != actual) return false; + } + + return true; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private byte?[] SigToNeedle(string signature) { + // Strip all whitespaces + signature = signature.Replace(" ", ""); + + if (signature.Length % 2 != 0) + throw new ArgumentException("Signature without whitespaces must be divisible by two.", + nameof(signature)); + + var needleLength = signature.Length / 2; + var needle = new byte?[needleLength]; + + for (var i = 0; i < needleLength; i++) { + var hexString = signature.Substring(i * 2, 2); + if (hexString == "??" || hexString == "**") { + needle[i] = null; + continue; + } + + needle[i] = byte.Parse(hexString, NumberStyles.AllowHexSpecifier); + } + + return needle; + } + } +} diff --git a/Dalamud/Hooking/Hook.cs b/Dalamud/Hooking/Hook.cs new file mode 100644 index 000000000..4101d5912 --- /dev/null +++ b/Dalamud/Hooking/Hook.cs @@ -0,0 +1,112 @@ +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using EasyHook; + +namespace Dalamud.Hooking { + /// + /// Manages a hook which can be used to intercept a call to native function. + /// This class is basically a thin wrapper around the LocalHook type to provide helper functions. + /// + /// Delegate type to represents a function prototype. This must be the same prototype as original function do. + public sealed class Hook : IDisposable where T : class { + private bool isDisposed; + + private readonly IntPtr address; + + private readonly T original; + + private readonly LocalHook hookInfo; + + /// + /// A memory address of the target function. + /// + /// Hook is already disposed. + public IntPtr Address { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get { + CheckDisposed(); + return this.address; + } + } + + /// + /// A delegate function that can be used to call the actual function as if function is not hooked yet. + /// + /// + /// Hook is already disposed. + public T Original { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get { + CheckDisposed(); + return this.original; + } + } + + + /// + /// Creates a hook. Hooking address is inferred by calling to GetProcAddress() function. Hook is not activated until Enable() method is called. + /// + /// A name of the module currently loaded in the memory. (e.g. ws2_32.dll) + /// A name of the exported function name (e.g. send) + /// Callback function. Delegate must have a same original function prototype. + /// A callback object which can be accessed within the detour. + /// + public static Hook FromSymbol(string moduleName, string exportName, Delegate detour, object callbackParam = null) { + // Get a function address from the symbol name. + var address = LocalHook.GetProcAddress(moduleName, exportName); + + return new Hook(address, detour, callbackParam); + } + + /// + /// Createss a hook. Hook is not activated until Enable() method is called. + /// + /// A memory address to install a hook. + /// Callback function. Delegate must have a same original function prototype. + /// A callback object which can be accessed within the detour. + public Hook(IntPtr address, Delegate detour, object callbackParam = null) { + this.hookInfo = LocalHook.Create(address, detour, callbackParam); // Installs a hook here + this.address = address; + this.original = Marshal.GetDelegateForFunctionPointer(this.hookInfo.HookBypassAddress); + } + + /// + /// Remove a hook from the current process. + /// + public void Dispose() { + if (this.isDisposed) { + return; + } + + this.hookInfo.Dispose(); + + this.isDisposed = true; + } + + /// + /// Starts intercepting a call to the function. + /// + public void Enable() { + CheckDisposed(); + + this.hookInfo.ThreadACL.SetExclusiveACL(null); + } + + /// + /// Stops intercepting a call to the function. + /// + public void Disable() { + CheckDisposed(); + + this.hookInfo.ThreadACL.SetInclusiveACL(null); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void CheckDisposed() { + if (this.isDisposed) { + throw new ObjectDisposedException("Hook is already disposed."); + } + } + } +} diff --git a/Dalamud/Plugin/DalamudPluginInterface.cs b/Dalamud/Plugin/DalamudPluginInterface.cs new file mode 100644 index 000000000..8c2cb38eb --- /dev/null +++ b/Dalamud/Plugin/DalamudPluginInterface.cs @@ -0,0 +1,42 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Dalamud.Game.ClientState; +using Dalamud.Game.Command; +using Dalamud.Game.Internal; +using Dalamud.Game.Internal.Gui; + +namespace Dalamud.Plugin +{ + /// + /// This class acts as an interface to various objects needed to interact with Dalamud and the game. + /// + public class DalamudPluginInterface { + /// + /// The CommandManager object that allows you to add and remove custom chat commands. + /// + public readonly CommandManager CommandManager; + + /// + /// The ClientState object that allows you to access current client memory information like actors, territories, etc. + /// + public readonly ClientState ClientState; + + /// + /// The Framework object that allows you to interact with the client. + /// + public readonly Framework Framework; + + /// + /// Set up the interface and populate all fields needed. + /// + /// + public DalamudPluginInterface(Dalamud dalamud) { + this.CommandManager = dalamud.CommandManager; + this.Framework = dalamud.Framework; + this.ClientState = dalamud.ClientState; + } + } +} diff --git a/Dalamud/Plugin/IDalamudPlugin.cs b/Dalamud/Plugin/IDalamudPlugin.cs new file mode 100644 index 000000000..2e1cb67a8 --- /dev/null +++ b/Dalamud/Plugin/IDalamudPlugin.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Dalamud.Plugin +{ + /// + /// This interface represents a basic Dalamud plugin. All plugins have to implement this interface. + /// + public interface IDalamudPlugin : IDisposable + { + /// + /// The name of the plugin. + /// + string Name { get; } + + /// + /// Initializes a Dalamud plugin. + /// + /// The needed to access various Dalamud objects. + void Initialize(DalamudPluginInterface pluginInterface); + } +} diff --git a/Dalamud/Plugin/PluginManager.cs b/Dalamud/Plugin/PluginManager.cs new file mode 100644 index 000000000..370bbae54 --- /dev/null +++ b/Dalamud/Plugin/PluginManager.cs @@ -0,0 +1,89 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using Serilog; + +namespace Dalamud.Plugin +{ + public class PluginManager { + private readonly Dalamud dalamud; + private readonly string pluginDirectory; + private readonly string defaultPluginDirectory; + + private readonly DalamudPluginInterface dalamudInterface; + + private List plugins; + + public PluginManager(Dalamud dalamud, string pluginDirectory, string defaultPluginDirectory) { + this.dalamud = dalamud; + this.pluginDirectory = pluginDirectory; + this.defaultPluginDirectory = defaultPluginDirectory; + + this.dalamudInterface = new DalamudPluginInterface(dalamud); + } + + public void UnloadPlugins() { + if (this.plugins == null) + return; + + for (var i = 0; i < this.plugins.Count; i++) { + this.plugins[i].Dispose(); + this.plugins[i] = null; + } + } + + public void LoadPlugins() { + LoadPluginsAt(this.defaultPluginDirectory); + LoadPluginsAt(this.pluginDirectory); + } + + private void LoadPluginsAt(string folder) { + if (Directory.Exists(folder)) + { + Log.Debug("Loading plugins at {0}", folder); + + var pluginFileNames = Directory.GetFiles(folder, "*.dll"); + + var assemblies = new List(pluginFileNames.Length); + foreach (var dllFile in pluginFileNames) + { + Log.Debug("Loading assembly at {0}", dllFile); + var assemblyName = AssemblyName.GetAssemblyName(dllFile); + var pluginAssembly = Assembly.Load(assemblyName); + assemblies.Add(pluginAssembly); + } + + var interfaceType = typeof(IDalamudPlugin); + var foundImplementations = new List(); + foreach (var assembly in assemblies) { + if (assembly != null) { + Log.Debug("Loading types for {0}", assembly.FullName); + var types = assembly.GetTypes(); + foreach (var type in types) { + if (type.IsInterface || type.IsAbstract) { + continue; + } + + if (type.GetInterface(interfaceType.FullName) != null) { + foundImplementations.Add(type); + } + } + } + } + + this.plugins = new List(foundImplementations.Count); + foreach (var pluginType in foundImplementations) + { + var plugin = (IDalamudPlugin)Activator.CreateInstance(pluginType); + plugin.Initialize(this.dalamudInterface); + Log.Information("Loaded plugin: {0}", plugin.Name); + this.plugins.Add(plugin); + } + } + } + } +} diff --git a/Dalamud/Properties/Resources.Designer.cs b/Dalamud/Properties/Resources.Designer.cs new file mode 100644 index 000000000..f8904c30a --- /dev/null +++ b/Dalamud/Properties/Resources.Designer.cs @@ -0,0 +1,73 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Dalamud.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Dalamud.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap eye { + get { + object obj = ResourceManager.GetObject("eye", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + } +} diff --git a/Dalamud/Properties/Resources.resx b/Dalamud/Properties/Resources.resx new file mode 100644 index 000000000..fa96538cc --- /dev/null +++ b/Dalamud/Properties/Resources.resx @@ -0,0 +1,969 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + + iVBORw0KGgoAAAANSUhEUgAAA+gAAAPnCAYAAAC89WYxAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO + wgAADsIBFShKgAAAABh0RVh0U29mdHdhcmUAcGFpbnQubmV0IDQuMS42/U4J6AAAxR9JREFUeF7s3QW4 + bVX59v9XSpEwaARUEFsMJFQsQMRGxcDubgwEURQ7sAtbsbtbMVEBBTFQMUBACWlUFP2991fYujk855y9 + 95pzrRnf+7o+l77j//+51plr7r3XmGOM5/l///d//ydJkiRJkmasHJQkSZIkSdNVDkqSJEmSpOkqByVJ + kiRJ0nSVg5IkSZIkabrKQUmSJEmSNF3loCRJkiRJmq5yUJIkSZIkTVc5KEmSJEmSpqsclCRJkiRJ01UO + SpIkSZKk6SoHJUmSJEnSdJWDkiRJkiRpuspBSZIkSZI0XeWgJEmSJEmarnJQkiRJkiRNVzkoSZJGYdW4 + Rmw4b0ySJM1IOShJkkZhq3hLvDZudPGYJEmakXJQkiQN3hXipXFe/C1eGKtH9f+vJEmagnJQkiQN2mXj + 7nFqzOUnsXusFtX/jSRJalk5KEmSBm2n+EzMz7/iK8G29+r/RpIktawclCRJg3XleEmcH8vmtLhfrBnV + /60kSWpROShJkgbryXFcVPlHfCO2i+r/VpIktagclCRJg0MBuDvFL2NloWDcRlH970iSpJaUg5IkaVDo + d86q+HdiIflpPCyq/y1JktSSclCSJA3KNeP18ddYSCgY96ng/67635MkSS0oByVJ0mBcJh4bf4nF5Iyg + mBxF5ar/XUmS1LByUJIkDcad44hYSo6Ne8RaUf1vS5KkBpWDkiRpELaMT8ZSc0F8LraJ6n9fkiQ1qByU + JEm9N9fv/E8xSZikPz3Wjup1JElSQ8pBSZLUa6vF3eO30USOjHtF9VqSJKkh5aAkSeq1nePn0VQujHfG + 5lG9niRJakA5KEmSeuv68b5oOifEvnG5qF5XkiRNqByUJEm9tHrsH6dGGzkmdgq20FevL0mSJlAOSpKk + 3mHSfKf4TrSVs+LguGZU70GSJE2gHJQkSb1z6/hB/CPazF/iibFuVO9DkiQtUTkoSZJ65VrxiZhWvhW7 + RPVeJEnSEpWDkiSpN9aJx8R5Ma2cH8+NNaJ6T5IkaQnKQUmS1Bu7xtdj2uGs+z2iek+SJGkJykFJktQL + m8S7YlZhkn6NWCWq9ydJkhahHJQkSZ3H1vY3xzS3ti+bc+JVwYOC6j1KkqRFKAclSVKnMSF+QZwZs85v + g97o1fuUJEmLUA5KkqROu22cEF3IhfHu2Dqq9ypJkhaoHJQkSZ21ZRwcF0RXwns5MDaK6j1LkqQFKAcl + SVInrR3Pi39F1/KroN1b9b4lSdIClIOSJKlzVo2nxvHRxfw7PhEWjJMkaYnKQUmS1CmXj3vGj6PLOT0O + iCtF9e+QJEkrUA5KkqROuVZ8Obp07nx5+XncJKp/hyRJWoFyUJIkdQb9zp8e9BzvQ86Kl4YF4yRJWqRy + UJIkdcIqcff4ZfQpPEx4SKwW1b9LkiQVykFJktQJ28eHoo/5VNwiqn+XJEkqlIOSJGnmNo83xhnRx5wZ + Lwp2AVT/PkmStIxyUJIkzRQt1faPk6LPoWDc/cJJuiRJC1AOSpKkmbls7By/iyHk8NgmPI8uSdJKlIOS + JGlmtosvxIUxhFDV/VWxaVT/XkmSdLFyUJIkzcSG8dz4ewwl/44/x65R/ZslSdLFykFJkjQTj4vjYoj5 + RNwyqn+3JEmKclCSJE3d3eLoGGr+ES+ONaP690uSNHrloCRJmprLxDXjGzH08G+8dVTXQZKk0SsHJUnS + 1FA87cA4PYae8+OtsV5U10KSpFErByVJ0lTQemyvODEopjaG/CGeEE7SJUlaRjkoSZKm4nbxoxhTeBBx + VNw0qmsiSdJolYOSJKl1V493x1jz5uDsfXVtJEkapXJQkiS16nLxnGC791hzQTwtqusjSdIolYOSJKk1 + VG2/fRwZY88H4tpRXSdJkkanHJQkSa25Xnwr/hljz1/iNbFKVNdKkqRRKQclSVIrWC0+OMz/clI8Mq4Q + 1TWTJGk0ykFJktQ42opx7vycMJcMVd23i+q6SZI0GuWgJElq3APCc+d1zo0DY+Oorp0kSaNQDkqSpEZd + Iz4X/wpT5+S4b1TXT5KkUSgHJUlSY9aPt8R5YVacN8QWUV1HSZIGrxyUJEmNuFI8LE4Js/IcF0+O6lpK + kjR45aAkSWrEzvHDuDDMwvKj2D5Wi+qaSpI0WOWgJEma2NbB1nazuFwQH4/NorqukiQNVjkoSZImctl4 + ffw1zOJzYtwvuI7V9ZUkaZDKQUmStGSXj0fG78MsLRwJoDf6TlFdY0mSBqkclCRJS3a9+FZ47nzyvCmu + GdV1liRpcMpBSZK0JFeP18aZYSbPCfHEqK61JEmDUw5KkqRF2yBeGK6cN5vPxHWjuuaSJA1KOShJkhbt + UXFSmGZzTrwu6ClfXXdJkgajHJQkSYty/aA1mGknxwVV3deN6vpLkjQI5aAkSVowWoG9Ik4O007+Ed+J + G0f1GUiSNAjloCRJWpA14kFxfJj2s1+sH9VnIUlS75WDkiRppeh3ftew3/n0cnTcK6rPQ5Kk3isHJUnS + St0lfhBmevlXvD6uGNVnIklSr5WDkiRpha4QLw8z/VAp/+mxalSfjSRJvVUOSpKkFXp0/CzMbHJk3CJW + i+rzkSSpl8pBSZJUYtV2x/hJmNnlrHhPXDuqz0mSpF4qByVJUuk68bn4Z5jZ5px4VqwX1WclSVLvlIOS + JOlSNo3nxNlhupEfx52i+rwkSeqdclCSJF3KfeIPYboTdjI8L9aM6jOTJKlXykFJknQJO8VXwnQvR8SD + ovrcJEnqlXJQkiT915XjXfHvMN3MD+MGsXpUn6EkSb1QDkqSpP9YJx4bvwzT3ZwX74iNo/ocJUnqhXJQ + kqSRWzsoCnePoKVa36u2s/r/r4v/c6j5fXAUofo8JUnqhXJQkqSB2zC2izvG3WLXuHVQCO5F8cGgnRpV + wvs2qT0+joxvxyFBK7L7xb2Df9995+Hs9pOCf/Or4i3BdvELo2/hIcqngq3u1WcuSVLnlYOSJPXQanGl + 2DyuFzcLJt5MTB8XT4+947nxxmAyxyT2+/H1+FIwsWW7dF/Cw4PjgocJ/Jv4tz0iWPm/Q2wTl43qes1H + L3F2DFwj7hr7xSvjdcH/9rnRl3w47hJXjOrfKklSZ5WDkiR10GWCgm1XiavFdWOHuF3sGY+KZ8fLg6Ju + TCy/G7+LSbaod3EFne3cPFTg3PXj40bRVoG0G8dBwev9KM6JrufoYOfAneO2F7tVsGviOrFJXD6qf68k + STNTDkqSNCOsgtPTet1gVXejYDLFhHy3eGYwWTw4vhjHxhnx1/h7XBBMxtmiPbTz1vy7To9vxcODhxWX + C65ZdS2btEYwoWVnwpuCVfu/RJe3wnMvnB/siGAHwGlxTHw2XhYPCY41cG9RXI5jD1xTCgOy64AHQtW1 + kCSpNeWgJElTxuRv67hTcCb6FfHJ+EFQpO2n8ds4Nc4KJl19L9y2mDDZZGK5R3Cd1orqOk4DD0yuH5xr + /3z0Lf+IM+PE+HVwb1Fr4NCg9gCTd87m7xjs1lg1qusgSVLjykFJkhaAFcbFrjKyQsnkbvfgXPhL463x + oWBF/PBgSzqr4mPK3Go//zl/5f+P8YbYK7aN6prOChPXmwafI6v6QwiV7tml8Ivg3/SZeH+8M14fFNN7 + YrBVvromkiRNpByUJGlCFGvjXDQTcaqFcz58n2B7+geC1UrOUS9kFXxoW9WrLPtv5AHFe+IxsUVU17hL + +JxfEhTdG3LYycBDk08EBfnY7cEDigcE9RA2Cx5CVddIkqSVKgclSVqgVYKzuxTeYjX1FsE2bAp0sV2Y + qugnRx/bds0ibL2mzRk7C3jIUV3zLqNqPtXxT4gxhfPtrLbzuVGo8P6xc7BNnrZvdBZwq7wkaaXKQUmS + ChQKWzuYOG4QWwWtvA6MLwfnef8cZ8ffwkn54sLknB0GtDqj+Fv1GXQdRx54YPPYOCI47z2WcL9TqJB7 + nxoJVLvnnPv3gv7yVJRnhZ2fnfWDNnBtVd6XJPVUOShJ0jxUtWZ1nKrXtDD7dBwWtLKaq+bN2V2z9FAM + j97lVK2vPoO+4Z7ZKd4b5qIq8hQ5pOAhu0r4vOnXzko7E3YrxkuS/qMclCSNFhOFLYMzxRTDemUcEl+L + nweTcdNsvhO3j+rz6DsKAj4nKLpmLh0qyH8k6Nv/5qAIHUdEaDNYXU9J0sCVg5Kk0aD/842D7bcPi33j + bUERN7bnmvZCay8mZVz76rMZCnqKs/uCVWOKrJnlh23yXCfOsnNM4NHxwGA3ArsSqusrSRqQclCSNEgU + dGNCzqomX/iprv78YAXv2HDyNJ1wRpl2cvcOJq/VZzVEewaTT7O4cJ79q0HFeGo+UIhxm9g0qussSeqx + clCSNAirBUXdKEZ1lbhdvCKYHFJ1miJWTBYX0urMNJc/xMNjbCuiHJ+goKBZfFhZZ6J+VtCnna3xrwuq + xFO0kZ/xtYKf+eraS5J6ohyUJPUebZ1YoX1rfDOYlLNKTqVwM9tQ6f6ZMcZ+2fuHaSZ0S/hZsCvhG/GG + uFdQRb+69pKkHigHJUm9s0ncPZgAca7540HFaFbITbfCUYLvx7ZRfZZDxOo5W7M/F33Ivy/Wp7DCTl2D + DwW/A+i4sFdcParPRJLUQeWgJKnz2NZ6o7hbUEjq1cFK2l/DdD8cL9g1qs92iKh/wISxL10A+jhBr3JU + MFnn/PqDY7dYL6rPSJLUAeWgJKlzmJBfO6i4zlnyveOjcUIMYSIxjXDW/ozgDC8TRbb7g//3H4Nz+dMK + OxseF9QIqD7voVkzZrV6zlbwU4LPHHzOfOaM/z3GEn5PHB37xK2CB3xbBefXq89MkjQD5aAkaeZWjcsF + Ezgm5s8OtkWfFHMF3v4R5qKJN9eC/2Tie25wfeYwETsuPhOs4j4vXhgUzHtVULiMFnP8J9d3GmGyxLlh + HrZUn/+QsL2dzgH0e59mKKxG7/7XxrOCzxwcA+EeeE3wkItt4Uzg598zYMs4xxH+FXP3WN8fhvFv4eeD + BxQ83PtiPCOYrFO08PLBbofqc5QkTUE5KEmaqY3insG29c/Gj4LCYuaSoaL19+Kd8Zagfzurg2z7v2XQ + Sm7OdnGt4Kz+BsE15r/TqoqiWlTAvk6wHXhahfR4mPDUqO6BIWGF9mlB9fq2M38CTR9/HrzQwYCCfHzm + fNbrB/cA49cIJqc3C+6T+ffNg+LgYOX/XUERNtqdMXEfSpiwnxzUq/hWvD3uFPZcl6QZKQclSVPH5JFz + oq+P98cRwSqeuWgF/Jhgxfl98bJgRZQztbvEdeOawU6DSSqjs3J4m/hlTCu0yuL4QvV+hoJt1F+PafTZ + nz9B/03wc1W9p4Vg5Z97ilZm1wsm80zgHxpPj/2Ch0JMbrlHhxB2ChwWPJB4UfCA4yZRXR9JUgvKQUlS + 69i+TnXlneMR8Y44NcaePwWTcVbG2T3Ait5z44FBgStWudtc3WOF9dsxrVDY7x7BkYbq/QwBdRM44z/N + sL2dFeGrRvWemnK1uG9wj74x3hufDia5x8c0Hkq0GY6GfDioecHPIL+vhv5ASZJmqhyUJLWCbdRMylmR + Y2WKM7BHxljPkrNDgG3IrHRyHWgNd0DcP1jJ3iJWi+paNomVUvDfmXywZX5axcP47NlGPY1/5yysHjyA + 4Iz3NPO7YFv9ulG9rxWZuxeWgl0YbJ2ntgCr7EzYeeBDcTbuc+73Pu+M4bw+15UjADws46hAdR0kSUtU + DkqSGjNX7I2VvEfFF4KVNc450xKt70WnFhrOurKayLlrtgMzYWF7N6tyfNnnwQXtnyiKt0bMqlDV3ISS + c//TCuealzKR7AO2hvPAY9rt/z4V1BeYZLI9CX7uKbjGAx92ZbDSfvN4SHDfHx7UUODngZ8LVvz7En5+ + eeDCURAKLVIAkH/rZWNW11uSBqMclCQ1YrPgnPQh8d34fTBRHVt4IMG5eqpFsx2Y1cWbxuZB+63q2s3S + FYKt9dPKb4MHFbxu9X76bK+gtdm0H0RxZKR6P7PGRJb7nnPd9MG/T7B9nDPf3Ad9C58tD7O+Fm8NjqFU + /25J0gKVg5KkJWNSzmSLlaUPxM+iChOWIa6eU22eqte0tqKdFdthmZTfMPo0AeVMMaub0wjb6dkGzZbh + 6r30FbsRKOY37dA+jIdB1XvqImoqsNPgXvHEoAUcD7R+Gn06w85xDe5juk/Qzu6Owe6h6t8sSVqOclCS + tChsX6c1EdWd+XL6qxhDeMBA33CqWH8pOG/7zGAr7yTV1LvgfsE2/GnljBhatWwq609zJ8Jc6G2+fVTv + qS94WPOAoG8/k3X6lR8VrFj3Jewaou3hvePWQXu76t8qSZqnHJQkrRTFkZiA3CoOCoo/jSEUuGIrLpOF + T8RzYo/YMlgxra5VH9Gei97q0woT9LtHF7f8LxV9xFkFnnaeH0Pq400BQR4CUhvhlXFo8BCQh2N9KDBJ + 6zaKQPLwbofgPP6Q7nNJalQ5KEkq8UWZQkg3CrZwHxsnx3kx1LBKziSAbdicJafyPF+y2cpP8SsmQkOa + mM+hyNdjYlrHEJjEfD4omFe9n76hWBjF0Ph3TSPzP6dHR/We+o6fsyvGJsEDJM73Uwzv9OBntOv1LSiK + x0MFeuJzDIgV9VkWhJSkTioHJUmXsk2wMkdv7h8GXzaHHlbLPxNPjjsHuwUocFVdnyG6W0xzSzFn3ocw + uWTCdYP4SkwzTFDZ2TGWQmU8LLxuUHTxkUG7Po6b9KEiPC3nmKh/LLjnh1ggUZKWpByUJP0HLZJuG2zN + nFupGkO+FS8NVpBvFmMt9MRDGSYQ0yoWR94Q9NGu3k9fUH+As9MUDJxmOCZARfSNo3pfQ8aOhWvHXYMH + apz9Py66khXtRGG7PhXgXxysrI/x85Ok/yoHJWnE2LJ946Dy+AHBKmAfznlOGs7QU32dL8q7B1u8q+sz + JmsF24jZljutsAJMcbDq/fQFW7CPiGnnT0H7vuo9jQ1HUB4XH4wfR1+qwVPfgoeDFN3cOuyrLml0ykFJ + Ghm+BFL0jSrajw22sfepWvJiMn8liy3B7Ar4RdAOjQlpdX3GjFVJtg1PM2+M6r30Advbrx/T7mTAvUxL + w6G1qpsUnwe7gN4dv4++TNT5/UsvewpQso3fVXVJo1EOStJIMDFnxZzCXGwtZlIxV3BpyJmbpJ8WbEVm + 1XHdqK7R2DEx+EhM857gAREPjKr303WbBv3vp/2Ai+303Mt9vW6LsdhVZYrLbRSsSnN8Za5w37QKIC41 + fw2KcPJggQcMFOekUKdF5SQNWjkoSSNABfJHxMfj8Dg7xpD5X8ppgfWQoGc0BdFoi8WXeFZAbYN0ER7g + sLvgD9F25j6bU+IF0cfJJgXafhfTLlTGzzArxUzgqvc1NjxYongcBdgoIMd/5+f8qXFM9C1M1r8XFK18 + XrhTQtJglYOSNFBMeO4d+8bb4pcxtsyfoM+dO/9i0KeYL+7fDQqj0UaOqvV8GabXOcW32P7PRL7vRcwW + g7P4NwwqTred+Z8Nn8UWUb2nruJacY/MItSK4KFb9b6GiAru9BPnoQQP2Z4ST49nBbUzqOj+zfh1UCzu + R/HJYDcID1C6vnq+orDLiX/Hs4POEq6oSxqUclCSBmaruGOwKjnGSfn88MV8KV/OOeNLazkm8mwlvk/c + JVhxv3VcNZg0VNe/79gi/L6YZtjau2v0qYI+LfgOimlP/jh+wBboIfbj5/On4Bvbu3cJzmRTRJCV8NfE + 1+KP8fdYzHXv8wR9fr4UFMNjhwBF5aprKEm9Ug5K0gCsEVSTvk2wmsQZ1T70B+5DmKxzjhW0IKOnMSvu + 9wtWtK4RTNZoU9fXLcec851/1pfdBPSFn1bY0vveoJ/4/PfVZeyu+H5MOxTxoz3XYs9mdxEPudgJwOr4 + tsG/65Xx5WDHC0Xe+D2GoUyyJw3XgmMhPKTh9w87T6ypIam3ykFJ6jnODd8zKLZFgaHzwywsS/3Sz+SV + NlfHBxP2w4KJBTsXWF1ndbPPEyi2En8hphU+h/OCdn/V++kidqjMoko491mfJ2T8XLBSfvW4fxwSHHHg + dxcPFvnZ8uHiysNDLX7/sMuHQoVM1Ifw0EbSyJSDktRTFEbiDCy9fymAZtoNk8gVTeip5E0PZs4HfyLo + b3yLqD67rls79otp50lRvZ+u2TI+GrMIZ6+r99QHN4sXBsUqvxq0PGS7upksHBHh9w5HLmifWV17Seqk + clCSemabeEy8NSiIZKaTlU3Qlw07GT4frLRS4OlesX5Un2kXsYX/jJhmWLVn2271frqCbdmsWLLiO81w + 1IKf9z7tMqANHbtK6AzAxJyfh2kenRhbqE9AcTx+39whhlinQNLAlIOS1AO0AaNwEsXKOKs7ljZpQwp9 + 558btObivG3XC6JRz4A+0kwMpxUegLwqqvfTFdR64EjDtMNK8xvimlG9ry6gwjhbrXeIvYJdJFRUN9PP + D4KCcrcM+sJXn5ckzVw5KEkdxvlyzmrSs/sbwTndaU6YTLOh0Nxcj2PO31Jc7opRffazRjVtisWdG9MM + q+j0fe5iOylWJKnmT92BaYfPgd8DXSxEyHviwcWdgwKK3N9nhmfJZxtW1P8Q/BxfL9YLz6lL6pRyUJI6 + inOurLiyAsUZQyfmw8pJcXRwbvRaUd0Ds0Sf792DitHTDFugWSm+clTva5Z4cMAW4mkWh5s7VkGNA3Y1 + VO9rltjdQ0X7T8UJwee3mKMgpv3wsOTYYPcVK+p97TYhaYDKQUnqmO3jxUHPWyqFm2GHL8/0d35Z7BTV + PTErtD2jkNe0Q7G9q0T1nmaJHvinx7TDAwF20Fw3qvc1C/ThflZQ8O2oMN0PxyQ4nvGeoMYE9RSqz1aS + pqYclKQOYBWKoj4U92ElylZpw061wkiPdYpoUYDsHkFf9epemSaKfFGM8KyYZijAtmt0aQJxheBML9uG + px2Kwz0keA/Ve5smjmQ8IJjk0RbNdDv8rql+39BP/yXBsQnqBlSftSS1rhyUpBmiVdrN44lxeBhDKCi3 + T7AddZaV39eI2wUr2tMM26TZjrtVVO9rFrgOX49ZnKvmTDe/K6r3NS3chzsG96U7e4aTU4Pe+hxnuXZU + n70ktaYclKQZoM/09YOt7L8NewGbZcO25uODXRWzLO7ESj67OqYddhTQmq4LxeI4s8tq4yzqQPCa7Kzg + d0b13trG6/KghL74PDia5vl7M51QvJJdMtRXYOfKhtH1LhOSBqIclKQpoyo7vbEp/sb5Y2NWlNPiY8Fq + +iwmq0xOaX02i/7VB8esz13zYORm8cWYRdjevnewm6F6f22iMvsBwe+qWZy9N9MNxzd4YHxoPDJm9VBI + 0oiUg5I0JVSAfkawGjbtytim/2GbM1tRt4vq/moLDwU4c8yZ1WmH7gWc+67e17Tw76cY2okxi7CqeaOY + 9g6K2wcF4DxnPs78Ot4cu0V1f0hSI8pBSWoZ/WcfEYeEE3MzSdiKyoTtnjHN1S12fbwrZpEPBf3iZ7XF + n+2+7GCYVZvD18flo3pvbVgn7hPfDGPoHkDhyjsGBQKre0aSlqwclKSW0CaK/sDvDLeymybDtufHxDQL + yD0nZhFW8p4as5igcw6X3QO8h1mE2hSc/a7eW9OomM9K/ZOD+8uY+Tky2AHGcY8udJiQNBDloCQ1iO2w + TJrol/za4Dwfq57GNB3OplNA7hoxjfPJtPliy/m0Q4uo78RGMe1JOsdSWEmu2lS1HV6Ts8C0X6zeW5NW + Dx4mfj/+GsZUoXDjH+LpQeHAtaK6nyRpwcpBSWoIvcxpxUTf6KPj7DCmzdAiiS2oTJ6re7JJrK7S+3oW + fcA5B/34uHJU760NPAygH/2siqOxev6EmMZRBra0Mzk3ZiHh55EV9QODB4TVPSVJC1IOStKEWDVn2x9f + Vg6L88KYaeZnwZZ3tilX92gTeAB1/6Ad07TDQwEmBDeI6r214YbB+fdZ9D0n/JvbXj2nfd+j44gwZrGh + pspngyKKTtQlLUk5KEkT2DY4l/eZmMXExZi5/C6YbLVZyGmHmNV5bCasD45pbKtl9Zzq8bP6mebfStX8 + HaN6f01gRwTt87hvjJkkfwlqrTwwrhXV/SZJpXJQkpbgqnHv+ER4xtx0JZwPZVs0K6PVfTspvnzTeuuC + mHb4Oft08JCgem9NYqWe1fNZhaMLzw3O3Vfvb1Jcww/H/MzinL0ZVs6Ig+PmMc3jKJJ6rByUpEWg3dH2 + wWoBX6Jntf3VmOWFft37BFvSq3t4ElRv5gHAH2MWYWWZf9uqUb2/pjw/mGzMKuxS2DnaKIp37fhg+GDR + tBEe3lEc9ZmxZdAJoboPJek/ykFJWiDOpL48OAt7fhjT1fwpXhj0tK7u5aWi3gKry7M8s/zloEtC9f6a + cLX4Yswic6vYbG9nl071/iaxcbwv/P1l2g6F5KjJwk6QzaO6HyXJCbqkJWFbL+fM+dI+y1U1YxYTdng8 + LzaN6r5eKlbRvxqzCj+DrwseFlTvbxJsy6ULA9duVjk3mEQ3XUuAYw8vCCfnZprhYeFHY++4elT3pqQR + KwclaTmuEnsF29mdmJs+hl7pFDtjUl3d40vB1nk6FrBCNqscFxSkarIFGb3k7xizbo9Iu7M7RZO97Vk5 + f1rMoo+9GV+qega0K3xL3D3a2B0iqafKQUlaBlWiqc7+4uA8rzF9zg/iXtHUeWb+d24cdC6YZX4RvI/q + PS7F9eMD8deYZXgg2GS7vHXjSfH7MGbWOSnoHnCToKZLdc9KGpFyUJIutlpsEo+I78Wsv6gb00T+FR8L + aihU9/1SsL38FTHLsBX8qXGFqN7jYrAr4Nkxi+r088Nn9eqo3uNSUEzvQWGfc9Ol/C3YKfLQ2CD421vd + v5JGoByUpOBJ/n3jK0GrKmOGlHPi7dHkihVb5zlfOqswmWVV+K5Rvb/FeFh0oR/4j+P+Ub3HpaBi+xfC + iu2mi+Hnl4eH/O1to2OBpB4oByWN3u7xmqBysjFDDa3ROP/Z1Nlm2oB9KWbdP5sJ6CRV3bcJ/h1dyJti + q6je52JtGBS8m/WZemNWFv72su19x6juZUkDVg5KGq2N4iFxaBgz9HBkg+rrt48mKqDz80O/8FmH3ugH + x1IKxvFveH2cEl3IE6OJByjrx35hxXbTp3wyHh7Ug6jua0kDVA5KGh3OvFEEjhZUVJY1Ziy5MD4b9w76 + fU9ajOyecWbMOscED9so8Fi9zwqTWCqbz3KbPpnbgcADlD2jeq8LxVleKmRznr4rDx2MWUz4OaBY405B + a8DqPpc0IOWgpNFYPa4XL49j47wwZmzhPDIPpj4dTNSZ0LH6zPn0xa7eUkWdVXlWsWcZHjz8Oji/vZBJ + Og/p9omutE/k/X87FrvFl8+Lz43Pb7OgPRurkBTQM6avoVjj8cEOHeooNNlyUFLHlIOSRoEvr/vGd+Mv + YczYw0SdSS3VlL8WnwpaC24X1c9QhZ+r10ZXzjn/Kh4VK6rszuScL/5d6gl+ajwlFlqRnoJafE4viI8H + xS3pPEHruVk/LDGmqfBzwd9sjmtcPaqfBUk9Vw5KGjxWld4T9F81xiw/PLyi6BqT7lfGAUEPdVbKbxA3 + j1sGR0S2j8cHfdZpm9SV/Dw4y71OLPu7gAcKL4kTo0vhurOzh/oAXFewms42X/6TgnyPjAODz+V1wefE + BMaYoYeHae8Ofj5sySYNTDkoabC2DtonsbJkjFlajgrOhPKQi23xn4+PBCu3rFh3MewM4Bz2bYKq6Ngl + qBTdxarmbHGnvSMFK7muYEfD54It66yQU4XfmDHnm/HkuG5Uf/Ml9VA5KGlwOI/JytPbwu3sxkyeWbdS + W0iWfY9s9aZ9E63LwH/vw7/DGLP8cD79kLhZVLtkJPVMOShpMDiXeaVg2y1fxudvu/WLuTGLCz8zffq5 + mXuvy75nqkLDGDOMMEn/WTwpNo8m2kZKmpFyUNIgrBqcT3t/UP3VGDN5ljdB79vk3RgzvJwQHAPhKBsP + 56vvBpI6rhyU1HucL31GfCuMMe3HCboxpiuhMCRFFhfTgUJSR5SDknqLvuZUleZ8aVf6GRtjjDFmumHb + +8figXHVqL4zSOqgclBS7zAx3yLuGz8MY4wxxphz4jVxvVgzqu8QkjqkHJTUKxSDuVt8NU4JY4wxxpi5 + nBe0V31oeDZd6rhyUFJvbBL7xzFhjDHGGLO8/CbeGTeK6juFpA4oByV1Hqvm9DV/Y5waxhhjjDErC8Us + PxX3i8tH9R1D0gyVg5I6jbPmFH2hlYoxxhhjzGLzq9g7eNh/uai+b0iagXJQUiddNtiW9uo4OYwxpsrf + 49yLnR1nxlnxtzDGmLn8K2jJxkP/9aL67iFpyspBSZ1z5bh3fCP40m3MLHJh/POi/2qmHLal8mV6Dp/F + 3Ocx95+0VjwiDgke5L0qDoz94vnxnvhJMFnn/2b+/97c/+Y/gv8t/t/2dTdmHPlzcGTualF9B5E0ReWg + pE65Ybw4jg5jZhH66X4lnhdvCXvstxd2x3wm3h4fv/i/88X5ScGZ0XvEHhe7+8X/7z3jXnHXYLvqtYMv + 2vQ+3jQ2DApKMn6LuFPM/W8si44Q/G89Op4bb4j3xeeDKtC/DNo2GWOGFX6uPxl7hWfTpRkqByV1Alva + 7xCshp0WxrSVaqWUVdTvx+uDc4q3CXZy7Bis0pqlhdXrY4O2iO8PJsAvixcFq9yPiJsHk+ntL/7vW8aq + Uf2eaBPtmHjtbeKWwe+j+8YTg4c1rM6/Ivh3cK+wVfZ3wbZ6M1k4pvDheG0czoAxUwq7bNh1w89+9XtB + UsvKQUkzt1k8Kr4dbDU1ZhrhjPJxcWiwasuK7LLFg64YTw8fGq04rEb9IY6MrwVFHdlizm6YR8at4uox + hJUq/h13iYcFK/0vDSbtX4xvBm0g/xpmYaFn9UfiWrFGsEPiQ8EOBh9+mGmE++x1cbNYM6qfe0ktKQcl + zQyr5mxpZ1Xq9DCm7bB6zqouq5/s1mCStXVwL14mqvt03WCyeX6Yi85tUxuClod/DFY8D44nBBPxDYLr + yWRrtaBNYnVd+4x7hX8XK/38G/m3cp/wsJHJO/cL2+NPuBhnXp20Xzo8kOU4wU1j/rXlel43eHBGL+s/ + hUX/TJuhJsVP40FxlZjFLh5plMpBSTPBU+oHBFtfXSUx0wgrdWxN3id2CM4rL3RFl8kCZ5PHHI4B/D44 + t/nC4Oz2trFVbBRrx/IecozJ6sEZ+GvGdYJ7h3Pw1DNgxwY1DsxFYccFFbWXd99QT4CV9d3iXeHfCtN2 + qIvBDqDbRXVPSmpYOShp6vjiynnOX4QxbYdJEWfLKQbEGef1o7ovV4ZjGKy+jyms/n4gnhxsPWaixK4X + Hm64wrQ4PMjgS/8943HB6jArdmMNu6aeGtR6qK7XspioU9SPn+N3BDs5jGkr7Ax6fPh7TmpZOShpati2 + eNt4Z1gZ27QdvmDReosti02002E1lHt36Dks3hw8RKOI243DlfHmUZSKdpL7x0Hx3qAOxxgeAlEUjrP7 + m0d1bVaGn0V2wrwtKNRnTBthxxAF5NgFU92HkhpQDkqaClogPTi+HMa0Eb70/yzon89kh5XKpieWtw52 + fnBecQjhTD7ne38UFHfjXD5nqJctlqf2bRy3DyauX4rvxIkxtLDF/xOx1Mn5fJz7Z3fHF4KHGyeFMU2G + 3/Xs2OBnc72o7kNJEygHJbWKAkrXD7YY82WzanFlzCSh+BZbsT8YuweV1ylS1kZxMr6gPSP6PBHgep0S + VF2n3/u+QWsx6kKsqFie2se15ww7n8UWwRbw7wafFzUU+h4mOzwI4qhJ9e9fCv7GcL04dsHP5o+D7fPU + TDCmiXDf/jqeGQs9kiFpgcpBSa3hiybFkT4btGEypumw+stZXs72siLHl/XqXmwKEygqdX86+hh+Dt8U + nCXnwRnbrOn/Xf1bNXtXCLoM8HnRso4z631uRcmuAGoZtHWul4dznFW/T3wmPKdumgydKygWSj2J6v6T + tATloKRWMIlhNeOIsLe5aTpHxwFB0ahZfFmindi3YhZhF8pidqLwpZKzuhwxYXJ0jaj+Teo2Wj/tEnyO + LwpqBfQptDZ8eFDtv/r3NYndMzcJrhV1I2zjaZoKD31oDcgRKhYhqvtP0iKUg5Iad4Ogt/kQz0+a2YUv + RofGq4MVsnWiuv+m5aHxq5j2sY1lJ+jV67Ml83vB7oInBp0Tqn+D+olttncNCvlRZZ9OBV0N9yKT84cE + OwKqf0+brh2cU+ccMTUqjGki1O3geNB2Ud13khaoHJTUGAr2cAb4PXF+GNNE/hJ8GTo46ALQlTPS9Gh+ + TlCcrgthos6Wf87gMhnhZ7F63xoWzl7TDuqLQV/xrvUK5yw4BdzuENQ4qP4N08DKPSvqbH2n0KP96M2k + 4aHxJ+NmYe0OaYnKQUmN4OwfvX1/G6yYGLOyLLsSvGyYaFCYh6rWrIJRCKpLX4I4R0sLt1kX7+IBwR+D + yt/PDtqica3aKJKnbmKr7VpBsT92TVAA8NyYdeZ+vpnI0PbwgTGLVfQ51Khgos7Dq4/EaUHRRGOWGo7w + /SCog3L5qO47SStQDkqaGD1CaWt1chjTRH4ST4gbxQZR3XezRgFEqqDP8oEUZ2s5X86Eg7P4FnzTJsG2 + 273j2OhSeJDEmXD6mFfvfVp4uEbrz1vGK8O/XWbScMyEHVW2YpMWqRyUNJHbBD1trZZrVpS51fIVrZiz + EvHxeHSwGjHrM+bLQ7GufYIVwVm1cqKaN0Xy7hXsLqjep8aNhzV3DIp1fjW6EnZ8fCoeEByLqt77NDFR + v0fw88TPtDFLDe033xK7hlvepQUqByUtCa1sOPfItlpjVpaVTdA5E0rxt+2jut+6YI24dbwuOBc/i9AV + gS+Ae4XbKbVQVH+nTRstL8+MLuSY2C+68oCJnycm6q8NOjR4Rt0sNV8Oqrz7O1pagHJQ0qJdLd4c9jY3 + C001MWcljS247MCgIvo02i8t1fpx//hGTDus0nOdKG7FBGKWhbbUb0yGXx5U+D8hZh3OyXNEY9vgAVj1 + nmeBnWG8r9+EMUsJuzFYxLh6VPeYpIuVg5IWjAI7nDenSnsXChCZfoYJJ9XGKdJ0+2Are5f7ybJV+Hlx + fKxoi37T4TqdFZ8LrhPFtTg7W71HaaEoIEhdh0cF7c9mXSSN41F0aejSiiPbkym6d7dg1wq7DmZ1nMX0 + N3SzeX/wAMqindJylIOSFuy+cXTYQs0sNayafzhuFawsdH3CSU//DwbVnqcZttfyAOPucY1wYq6msWNl + h+Ds9e9j1vlV0AmE3SrV+50FHhxeLyjC+LEwZrH5W9BmkHvI3+NSoRyUtFKstjwpjgpjFpr5q82s0lEY + 6olBZfbqPusSVtAosPWFmOaqOWFr5FOiD9dJ/bdRsFLMzigmE7MMbRXfGvzsVe91lmhf+NjgOnk+3Sw2 + h8VTg6KE1f0ljVY5KGmFmCQcGLTHMWaxoTI7W0RfFDeL6h7rms2CM/EUippm2Ob79tgzqvcltYnjSy8I + HkrNqgjiXKj1wEMDjlVV73WW5q4TBVLPCGMWGr5HvSa6XAxVmrpyUFKJ83e0umKb7axXVUz/cl5QmZ3z + d139or0sVs3Zzkq162kV0GJ1ntfinPmdo8tn8TUOFJJ7afwkqIEwq/DAao/oaiVsjr+8Ivg95/l0s9Bc + GJ8PjnlZ8FOKclDSpfBHgxXEH4dfPMxiwoST89pUQGbFvC+FzXiPtwjaUPFwYRrhPD6r9PysbRieT1RX + 8ICW3VMHxaxW0/ldQiu2B0dXJ+lcpx2DDgs8zPDvpVlImKRTc+Fe4SRdo1cOSroE/ljsE78NYxYbtqbe + NbaI6v7qKlb5mSxTUXoa+UO8LPhyb69cddWmcZ+gLdusQgE72np2+XfKNYMdMB8IYxaa44LvW11uMSq1 + rhyU9F+crWPF5MQwZjFhm+crg2171b3VZRzl+GpMI3+Og4OVk82jej9S1+wcb4hZVXvnmNV7o+tnd28Y + FML8UEzrYZ/pd/i+9ZLgeFV1T0mDVw5K+g9W8qhOa8xiclK8O9iGesWo7q2u4v2ycv61mMaX6Z/Gs+Nq + Ub0fqcs2iSfENHeaLJuPRx+KTW4T1LKgI4MxKwuta/n+dafg2ER1T0mDVQ5KI8cZYfpzcvbWmIWGc+YU + kdov1ojq3uoytsvS8uZn0XY4a84X9b3C84bqs1WCWg2sZvNwbhZhG/lNo3p/XXOXoACkXVDMQkLHk0cH + NUmq+0kapHJQGrGNY++gEI/FbcxCwn1Ca6HnxJbRx6f9VF+mndk50XZYGaETwrZhhXYNAd0O2H3y8PhB + TPtvBz3IeaC8XVTvr0voXsHOgwfFUWH/dLOy8PeVo4brRnVPSYNTDkojxVk+zsnNahXE9C+nxptit1g/ + qvuq664TtH47N5oOVacxl2ODHQZbR/VepD7j4Rw1J94S027FyRb7r8TNo3pvXUMhSB7SHRC/DmNWlDOD + nSI8TK7uJ2lQykFphNgeeEjMz/yJhTHLhlXgB0afJ5sUQeS+/2s0nWUn558ItrT39UGGtFBUMN83WCGe + dijuuGtU76uL2Lp8j6Dgng/HzcryyeD+ZtdKdT9Jg1AOSiPCdjuKwfFklq23xqwsv4t3BT2Rq3uqL6iu + /M5oOyfH66IvZ2SlJlBb4X5BwUVqLkwzXw7qqHA+vnpvXcRE/WlB+7ppXy/T7Sy7WMLPFA91LhfVvST1 + XjkojcR6wRco+lTb/sWsLKfEN+NJsU5U91Rf3DjeF23mX3F8cDafB2HV+5CGji3vFJCbdjs2KsszSe9b + nQfa19EFg98dxiwvP46HBnVf+vQgSlqQclAaAdo6vTCovM1Ewpjlhaf3xwUTc4obcXayuqf6gG2BnPv8 + VLS5SsX/Ng++WOVYO6r3Io0BkwdWh+8TTCqmFf6uUQH7jtGnB2RcLx6e3zOOjgvDmCrUgOHo1E7hlncN + SjkoDdxVg4qg/HI3psrcljoKPX00+JJL+73qfuoLWr/dPjij2mbl5BODwk88CHDlXLoIW97vFuzCmWY4 + B8/r9m2VkZV/+rtzPObPMZdla1uYcWeuOOIdorqPpF4qB6UBY2svVbednJuV5VfxohjK2elbxrejzfw0 + Hhv2rJUujUnyXePQmGYOCwo08pCuel9dxhZmtjLTYcU6MWZ5+XrwIL26h6TeKQelAaJHLasIHwz7rpoV + hYrmrDI/Mq4U1f3UNxzpoLBdmzkmHhKeB5SWj10lnA3/cPwlphW21z84+nrkhI4TLw8eArqCbqpQYJDO + KhxFq+4hqTfKQWlgOM/25KAHszHLyz/jt/GOoE1SdS/1EQ+nDozTo41w3pwv//cKt7RLC8PPJRPO+du3 + 2w61NB4RfZ2ks+2duha02nIXnKnCLosXBEcZq3tI6oVyUBoQqm2/MigGZ8zywuT8c0F/VR7oVPdSH105 + nhd/jDbCGX36we8Qfdw+K80Sk/SnBhPnaYXq6A+IvlV3n8P73igeH239XjP9zjlBC9G+t0LViJWD0kBs + HK+KaW4jNP0LX46fFTeI6j7qK7a1U2DpT9FGzo43xnWien1JK8dDtMfE72JaYTfZnlG9n76gaOdd4rPB + A1Zj5ufc4EjjNlHdP1KnlYPSAFAQ623Bk1Rj5jL/7CLVXzlrzrnpvvc1X9a1gp0j50VTmX/t+N99dQzp + KIA0K0w2Ka44zV7pP4w7RfV++uTmQTFPamAYMz/s8KLWAzUf6KJQ3T9SJ5WDUo9dLvhl/IUwZnk5KThr + vktU91GfbRCcOT8j2gj/u2+Iq0f1+pIWjyMi1Er5dUwrFNXaMfpe2HGtoAAelbzPDGPmh64JD4tNo7p/ + pM4pB6WeYnJ+7zgyjKnCqjmrVM+OIf6xZpWAs5k/jzZCobmDgocA1etLWrrLBNvdfxnTyL+CXUT0G+/r + mfT5tgh29pwQVno380O9AnZaWOFdvVAOSj1E9WjaqP0sjKlC+7TPBKvm60Z1H/UZX+5vE2xd5Yt302Hl + /KXBmdnq9SVNjtXg+0dbD9mWDW1HPx5sFa/eT9/w+4nV9O+Gk3QzP/wNe2tsFtW9I3VGOSj1DCvnD4qj + w5gqtAF7etwwqntoCG4S3wh2CTSR+V9uaWn03Ng8qteW1Bwm6bQtPCqmER5ePj82jOr99A3X79ZBEUuK + WRozFybpLwz/lqnTykGpR6ggvU9M64uM6VfOig/FHsGXtuoeGoLrxUejjdCned+gtVH12pKax7lwKq0f + HtMIu88eF5eP6v300VZBG7tvRxu7ikw/Qw2at8TtY82o7h1ppspBqQcoqMMT8reHRWFMFc6a02bvGlHd + Q0NBO7U3RxuhZ/JzYohHAqQ+2Ct+ENPIT+K+Ub2PPmMi9oE4OYyZC8cgHhFXiuq+kWamHJQ6jsn5neNH + 4VNxs2zOj8OCYmlD/8NLe7hXRBsPqX4bT4shFI+S+oraEvT7/n5M4+/dEcF59FWjej99xYPM/eIPYd90 + MxeKxz0x1o/qvpFmohyUOo6zeUzAjFk29D1lNZmqxGtHdf8MBZNzWsccG02HLYBPiqH1h5f6iIfStw22 + ardd+Iz//S/H9lG9lz6j3zwPO74Yfw9jyJ9i77A7iTqjHJQ67KFhGzVThUnlC2LrqO6dIWFVbedgtavp + 1SAKRtGGbr2oXlvSbNwqmKS3nQuDdmVD/F3K7056v78pmJgZQ9hZwQ4LV9LVCeWg1EFss6VgjsXgTBVa + i7GlfSyFzG4Qn4qmw+Sc4jkbR/W6kmbrjjGNM+lMWJ4SQ9vqPudaQWePb4bt2Azhnn9eWOFdM1cOSh3D + pIu+sKyc+4fUzM/p8dmgSnt17wzRpsHqVtPhWlJ0kcrH1etK6ob7xO+i7XDunS3h1XsYgsvGbkEf+L+E + MdwHLw92q3jESzNTDkodQZsZKnDTn5WK3MbMhQc1fEF9aVwz2LZY3UNDw1nU/eOUaDKsnL82rhLV60rq + DiaWD4+2t2jze5ZirEP6Hbvsv4MdArRrZVJ2QrgIYDg2dkxQ4X3I7VnVYeWg1AFMzm8Rn44zwpj5YWXn + bjGm82J8Kb9HNF2DgfOm74htonpdSd1D68MnxInRZvj98J5gS3j1PoaCvyUPDo4POEk3hEWAZ4adTDR1 + 5aDUATvFV8I2amZ++OL07uD+4CFOde8MFatYVFduuvowvY93jbHsQpCGgqrkT46fR5s5J/YNjtdU72Mo + Lh/0TP9Q0BHEGHZv0m7U7e6aqnJQmjHO/nwujJmfU4Nt2NeN6r4Zsg2DLZhsRW8yxwedEfiiX72upG7j + Z5eK5Kx0t5lfBL8rxrCauG28MH4dxnD04anB3+HqfpEaVw5KM8TK6CfDmLnwxfOXcWBcOar7Zsh4cs9Z + OIq4NZnTgvPsl4vqdSX1w53j0Gg7XwseoFfvYWj4vfi4YIeRO/nMH+MZMZZOMZqxclCaAQq13DK+Hv4x + NHNhmyHbummxN9aJ5F3jO9Fk2CZ/UFB0rnpNSf3B309+TxwXbYaHpe8Mzr9X72NoVoubxpfiH2HGHYoy + jnWhQFNWDkpTxpeL3eN70fY2PdOfMIlkS/tNggJp1b0zdHwReHM0/eXwvXG9qF5TUv/wO/Lu0XbROHYz + UaBzTA9M+V35wbggzLhDG7b3xdZR3StSI8pBaYqonPrI+GEYM5ffxPNiy6jumzHgwdXj4w8xaeaqErM7 + hbZJFEKqXlNSf7EjhrPTJ0VbYVfTN2JsXR9uEE8MdvmZcYc2bF8IFpaqe0WaWDkoTcm1gzOwPJE3hpwf + VO+nGNGVorpvxoCtlTcLWv40kbkJOpP9h8QVo3pdSf1FJwYear4/2l7tfWNsFdX7GLLbxSfCGOo+0PrU + Oi5qXDkoTcGN4q3BdiFjyFnB1usdo7pnxuQaQTu5s6OpUGTugLBiuzRsFI37VrSZc4MiamNsz8jiwiHR + dOFO07/8OO4XTtLVqHJQahErg7cI2qg13TLK9Dd/jtfFdaK6b8ZkzXhC8AW4qbCa9vawl6s0fPydfUCc + HG2Gs7hjbHuJtePFQY/4uR1KZpyhBeG9wkm6GlMOSi3aI74bVkQ1c/lVPD22iOqeGRsq1vMHv8l8NOjt + W72epOFhAvnoOCPaCv/br4rq9ceAvtgPjG+Hk/Rxh575DwoesFf3irQo5aDUknvG98OMN3yJmf9F5vB4 + VFAssLpnxoYeq2+JJsPuBM6dj3ErqjRmm8RHgtoebYWCnqwerhXVexg6inneJmhbeWqY8eaYoOixK+ma + WDkoNYztdvRopXq0MYRtgZ8KHtqM9Ytd5THx82gyrw7OtFevJ2m4aL22SxwWbYXdcF+Nq0X1HsZi09g7 + mKSZ8eZn8dgYc5FbNaAclBrEdh8m5xTSMIawovuauHpU98wYsQpD9WWqwjYV+shTKGqsZ0QlXbRz5mnx + x2grpwW7dHzYetHZ/6aPKJl+5YR4arAjrrpHpJUqB6WGrB73DSfnZi7Hx7PDL3KXxBZ/KqyfEk3lyKAl + 0CpRvaakcbhK0BbtX9FWjohdo3r9MeF7z07B798Lw4wzVPh/Tmwe1X0irVA5KDWEs8U/DWMIFYVZyVkv + qvtlzLYJVl2a+gJ9Xrw+PAsnCXeM70Vbxcz43cWExE4RF7lpfCz+GWacYbfgm2O7qO4RabnKQWlCTAqo + HntsmHFm/pdAKv3yR2qv2CCqe2bM2NpOu54mV1uo2n7jqF5P0vhwJpYCVm327ub89X2iev0xuknQ3pKa + K2ac4bP/dFBvx91sWrByUJrAFeNh8bsw5k9BG57NorpfdNGDC86sNRFWsY6K20f1WpLGizOx7Kxpc8J4 + SFwhqtcfo+vE88NWbOMOR0AeEVeO6j6RLqEclJaIc8VMzukHaQzbu14YnH+s7hdd9ODirdFUKAz3uPCM + v6QKE8Y2q7pzrI2CcRS+rF5/jCjUd8v4Qvw1zDhzUjwxrPCulSoHpSVgW/vDw4JwhlWC34dVTFeM7W4U + zGOXQRPhuvPlmLOP1etJEn+rXxJtbXXnqM4P46pRvf5YMUnn2NF744Iw48wf4hmxRlT3ifQf5aC0SJyz + okIskzK3cJmvB9XDOe5Q3S+6yDXjy9FUqPmwZ9DasHo9SQKVpT8QbeXMeFJYc+TSqDnyoqB/vBlnmKTv + ExZU1HKVg9ICXTbuEJ+Jv4Uxn43bRHW/6H/Wjf3j1Ggifwkekjk5l7QQ94i2drwx+eTM7fZRvfbYbRrP + CtqOmnHmj8E9QIvV6h7RyJWD0gJwvmyP+GYYQ1svKofT/7W6X3RJNwj65DYVdi1w7dlGWb2eJM23YXDE + pq02YOyme0KsHdXrjx2/qzmPfHSYcYbWs/wMWqdHl1IOSivB2RlWzp2cG8IfGVrJUHyoul90SXxhfWyw + 6t1E2L1yQFSvJUnLQ39meqM32eJxfiiKdtuoXlsX4VjS18JWbOMMu+gODI+D6BLKQWkFKDBz92D7Wlt/ + 1E0/Qksvnv5z1nDjqO4XXdqtgy/FTdVr4Bz7LlG9liQtDw/b7xuciW0jFEOjIJ07e5Zv9bhRvCaaemhr + +pVT4uVhCzb9VzkoLQetm+4Xbsky5FOxe1gMbuFYPefcWVMFgtie+shwG6mkpdgkqB3CA9c2wvGbW4Rt + 11Zsi3hK/DbM+EJXhYOC+6C6PzQy5aBUoKgVbdTmn5u1Yvt48+mgr2t1r2j5WOlmO2MTOSsODs+vSVqq + 1YIH78dEG2Hi8YbgAX/1+vqfK8STg44cZnyh+8GrYuuo7g+NSDkoLYM/rKzSHRVzYXLuBH18+Xt8LHaI + 6l7RinFWvKmzhnyhZmtk9TqStFDsgnp3tJWfBufdeRhQvb7+50rB963vh91xxhcevL82aMNa3R8aiXJQ + mocnug+NX4YZd/4U7wn/cCweZzBpp/LBaCJnx+uCn8/q9SRpMai4TuunNkIhLB5OUjm+em1d2o5xSDBh + M+MKXXHeEVeL6t7QCJSD0sV4kku16bYKyJhuZ/4OCVZreVBjz86lobjiw+IX0UQ+E1bNl9SUzYNCZW2E + 8+3fiBtG9dqqbRavD7Y+m3Hl3HBBZMTKQSmYiD0tfh9mfJk/Of9VUOn38lHdK1q59eJzwRGBJsI5tep1 + JGmpaPnFTqk2wln0vcJt7otz1Xh1/DXMuHJ+vC9uEtW9oQErBzV6tMzaN34TZtyh7sD9g3Y81b2ilaPA + Il98T4omQpXfR0T1WpK0VGyp5fxrGz25eej73tgmqtfW8lE0bL84LMy4wkP998f2Ud0bGqhyUKPG5Pw5 + cWKY8YYvaGxJfEBU94kWji+kX4qmVs/fFm5vl9QGunMcF23k5OCoT/W6WjH6pd8tPhpnhBlPLgg+d1fS + R6Qc1GhtGs+O08KMN3yJemv4xLYZewRb1SYNK1AUj2FHQ/U6kjQp2jZ+KJgUtJFXhMello4t728O/haY + 8eSf8fnYNlaJ6t7QgJSDGiUKxLwgfDI77rB9+lGxSVT3iRaHKuv7RBMtCZnkU9n1WlG9liRNii//t4m2 + tlPTPoyHlk4ylu7aQW95Jm1mPJmbpO8U1X2hASkHNTqcO+OpdlvFYUw/ckSwOrtOVPeJFu+O8Z1oYoLO + zoZdw3oAktp02aCNYxuFyXjQeHBYLG4yW8bLwuJx4wqTdI7M7R7VfaGBKAc1KtcIWqvQp9SMNz+OB8aq + Ud0nWhoK+/wtJg19z+mhvkFUryNJTaKtZlNtIZfNN4MjddXrauE4jvDk4O+3GVe+GreL6r7QAJSDGg22 + ytJj07NM4w49zlk591xgs64UFHRrIkcGT8xZ2apeS5KadL2gxVMboQgdDwDWiuq1tTi0QeXowIVhxpNv + xW7hrroBKgc1CtcMVs7bKgRjuh+2GvJH/e5xuajuEy0N2zfvE4fHJJnbGk8FV7/MSpqmp0Yb55z/FV8O + dvBVr6vFuUzsHFxTz6WPJ3w/+FHcOZykD0w5qMHjyTgre230OjX9CLsm3hicY/MXe/M4x/+eaOIB2Lnx + kqheR5LawurcD6KJGhrL5qS4eVSvq8XjeNoO8YVw4WVc+WHcK6r7Qj1VDmrQbhDvDc60mnGGYoBU7Gdy + Xt0jmtzVo6kqyJ+Om0X1OpLUlivH46KN7ws8eGSF3roazaINF0cX/xxmPGEl/QFR3RPqoXJQg3XTOCSa + KFpl+pmzYv/YOKp7RJNbOzgT+LtoIs8OKx5LmgW+N7Da3VTmVuPZis1qr6vozePowNOirVZ5pps5Kvju + Ya2aASgHNUg7xgfCjDfHB21Z1ovqHlEzqO/w4Wii+OIpQQG/6nUkqW1bxWejqXZe87fLs8pLrY7qdTUZ + HureNSgkxpl/M45Q9JeV9CtEdV+oJ8pBDcoqwbkkJgz+kh5nKAZHj/PHh09W23eLOCEmzT/iQ3GTqF5H + ktq2Ztwj2mq59pSwvWc7KB53o6B4HH9PzDjyq3hU2Jmnx8pBDQaTcyYLTT79Nv0Kn/tBsV1QuKy6T9Qs + vsxyvnLSnBGPDqu3S5olzqKzHb2N0Mptm6heV824YdAJxIwnx8YTw4dfPVUOajBuHV8Kn5yOM2yP3i+u + GtX9oeZdJ94cTfzMcZ7M85mSZo2V2OfGH6PpULT0mcFrVK+tZvAQ5KVxesyljer8pjv5TVCIkbo41T2h + DisH1Xu0zdo92nribbofivocGJ5Dmq6HRBNfYlmBPzg2j+p1JGla2I23U7T1nYLOMtXrqllUzN8nmipg + arofjts9OdaP6p5QR5WD6jUKg9w5vhZmnGFyfkBYqX262ErGQ5EmwnlP+pp6hkyTou4EX86uEjzw2ezi + /85/YtNgC7NbIbUiVwzad7URjuFtEq6it2/14Nw/q6tmHGGS/ozYKKp7Qh1UDqq3+OO2axwabl0aZ9gu + SHsVK7VPHxMdVr2bCA/YmDxVryPNx+99HsxSzOtKsWHwRYzJ+PZBlex94zXxhov/k7oU/Ofr4uXBFmMe + 7NKeif9b8L/D/x4PiWzzJ9DysY1isz8LKk9zD1evq2YxSed88q/DI5DjCN8NXxDWIuqJclC9Rb9SWmrQ + X9SMLz+MO4Xb2qePSRI1H74YTeQ94ZdVrQjbjtmySiFQChNy1pBWmj8K6hf8NKjmy+rJaXF2nHPxf541 + 7//Nfz812PbKRIn/258Ev08+GKy8MHmnlgWvWb0XjcPd48fR9ALA3+OQYBW9el01b93gKORH4m9hhh/a + Gr44XMDpgXJQvXTt+GSYceYzcZuo7g21jxXGZ8WJMWmovvqYcMuxlkVF/y3jvvHa+FjwUJZJ0+/jwmgy + /O8dH4cHv2M4K/zqoDf/FlG9Rw0XOyueExdE0+Gh0NWjel21hwrv+0cTrUFN98PD2JeE9W06rhxU71wr + qBxtxpH5qxe0UWOVy2rfs3W54HNoIu8Kv6hqDufDd4wHxgvj7cFkZpZhdf6t8fR4eLCK7wOlcdgtaAHZ + dP4Q3OfVa6pdrKbvHUeGGX74+aWiP0eaqvtBHVAOqld4CvbGOD/MuMKZorfFdaO6NzQdbG/fKljJnDSs + WLISX72OxoXz3xyboOry52KaK1yL2cLMauqXgw4GTLBs6zhsO8TR0fRZdCYN3OvUPqheV+3iSNWewU7M + JnaCmW7nzKAOiTuhOqocVG8wOWcVg7OEZjzhCzFfkPgyY6X22aOIFlt+Oe87afhi9NCoXkfDxyo0q1ns + imJFi0rLnA9tozBXk+H9nRenxDuCeig8YHBVfXhYdXt30AqSNHUenXvou3HLqF5X7ePnlWKnFJBjl4z1 + jIYd5g5vCQvSdlA5qF7gCxxbYSnyY8YTfqG+M3YOvgBX94ami4ckr4jTY5LwBZVV+NtH9ToaNiorU4yN + Ylk8gKOgTx/DRP3n8fng31P9W9VfHLmgUwjtPJsOxQwpeFi9rqaHh4TUtLGu0fBDkVCOyG4d1b2gGSkH + 1Xk3CZ5gu619POGzpkAT20ivE9V9odngDxtbfCddbaCSMRVWfZo9LnRdoBUaLfqowN711fLFhH8PKzSc + n6/+7eofCmJSc4CK/02H36H8jateV9PHd03OKvPgxAw3TNIPCI8ndUg5qE7bNt4XbVRRNd0MW80OjOtF + dU9ottjOe1xMGnZH3DOq19Aw8QWYCspUYR9ymMzRrm2bqK6D+oVq7t+MNvLksJ1fd7BTj2KQH49Jd4mZ + 7objVI+LNaK6DzRl5aA66/rBL8l/hBl+KOLxneB8s19Yuokze/QGbuKLyx/D85fjQP/yOwZt0sa0E4o+ + 7fRe5t9fXRf1wzrx+pg7h95kKHxK29jqdTU77OyiPVcTtVZMN/PtuGv4fbMDykF1DlWiWWmhD62T8+GH + St70NOZcMxXaOZta3ReaPc6f0xe4iS+qPwh2yFSvo2HggQ6TjxfFyTG2Ikz8e38btItjFba6Ruo+/ibd + O+iP33ToVvD4qF5Xs0VBVNrsUSuljYczZrbhu+cPgxpHFvicsXJQncOqmpPzcYS+5p8KvvxYob37mFB/ + OCY9ckJhLWoMWKhl2NhtQcu0sW8V5d/P37Tto7pO6j5qobCjr6nMrwZP+6fqNTV7rK6ycECtgCPCDCv8 + HNIPf49wcWiGykF1yu2CL3Q82TLDzhfiSbFd+PSyH5hw/TombTXEqiJHGdaO6nXUbxTW4nyfX2gvma/G + XuF93z98ZhQ2bCNvjOo11R18R2E1/e3h4tHwwu6Y+8Vlo/r81bJyUJ1x2/hamGGH7exUOr5VVPeBuuuR + 0UTBRiZuV4/qNdRvmwdtqagxYC4dimA+JmjtVF0/ddcLgu4TTec9ccWoXlPdsmVwZIdOJm3cC2Z24XvJ + g8JJ+gyUg5o5qihyBoQCYWa4YVvzT+Kp4ZfTfnpKNBEqIq8X1Wuov7YICiv9Lczywy6UR4eTsn55WDTR + wWLZfC/uFOw8qV5X3XODeFdQQ8AMJ3TgYJcT9Qeqz10tKQc1U2wb4g/T92PSbbOmuzk13hE7xZpR3Qvq + tssFvUMnDdsDWTHyIc2w8IX1/TGmKu2T5Ph4Qqwf1fVU9+wSX4qm85d4ZVwhqtdVN/F5PSCOCh9KDifs + 8nxoeBRpispBzdS9gqfHZrhhZ8Qjwi3N/XaVoNXQpGHr877hE+rhuFpQPNAvqYsLq2/0XHY3ST/cMN4d + TS8m8L/30fBhTf+w4EDxVHYG8tDNDCNM0qmjQovF6nNXw8pBzQyVu2lxYIaZ78Zzg+MLrL5W94D6gz7W + bE2fNNSZoN6EhQGHgX7BbPX0PObSwpbp/WPTqK6vuuNKQZvJNorY8ntxw6heV93HRI7vtHSlMcPIsUE9 + FXe2TEE5qKnjiSO/yNgWZIYXtuuxGnDn8EzdcDw/zohJw2TOFcNh2CpeFWay0COeny9bTXYflZ7bqOJN + FWkedlWvqf6glSI7zVigMP0PK+lM0nk4V33eakg5qKniKSNndn4eZlihujfts14WrgYNC71gmVg3Eb68 + uHref3xheXn8M8zSMn+rNL3SOfrhak33XGbef6dmDg+hm84xca2Y/7rqJ+6XW8Zn47Qw/c4pwSR9g6g+ + bzWgHNTUsJr62KCCrRlWqND+6bhrWPxreDii8JGYNExIaFFTvYb6gzY0T442KlqPOexQ2TN8gNVdtwkm + 002H7bS3iOo11T9M0pnQPTs4m+6DzH7nzNgvNorq89aEykFNBa3UKIbDCqsZVtgNwcrPNuGW9mGiQNzn + YtKcFI+P6jXUHxRFYgunnTeaD714maRX112zd9OgB3bTE64/BNvn7XIyLBT+46HOi+OcMP0NR5FYYPAo + UgvKQbWOLXv0D3VyPqz8Ml4ddw/PFA8bD1++HpOGdop7RPUa6geOrxwS7Jox7YTdKteI6vprtuj1z9EO + VtSaDP971HPgf796XfXbJvHIsGtRv/On4OffehENKwfVKlbO2fbcxpYwM5vQSolq3g8PC2cMH1v1doxv + x6T5YtBLuHoddR9fMp8VbtdsN7Rfe0G4mto9HPfZK/iMmgyV4b8aN4nqdTUMfB/mAaffifubs4NJ+lWj + +oy1BOWgWkWhjI/Hv8L0O3yGbPGhDywrqtXnreGZe8j245gkbIf+YLBFtHoddd9DoumJianzm6C1oS0q + u+dWwefTdH4WO0X1mhqOy8e9gh1lbnvvZyiKTEHkq0X1GWuRykG15vrxnrA/bv/D031WUPmC7nb2ceEM + 3UuDSqaThHuIHsLuuugnVgveFmZ6YTusD7S657rBEa+mw+/Y20X1mhoWHnzzO/W1QVcA63n0L+fGm2Pr + qD5jLUI5qFbQLuR9cVaYfocnhW8IKszy5Lf6vDVcW8ZhwQR7krAtmiJI1Wuo2zjm8JLg/J2ZXni4fZ+o + PhPNDqtmP4mmc36wa6J6TQ0TNQceGJ8J078wx6EFrS0SJ1QOqnHXDrZB88fG9DuHB2dOt4rqs9bw8fP8 + +5g0/wgLxPUPLdVuFmy/NdMNq2ofC1fRu4WuFt+IpvPXcAV9nPgdy0PQ6ugEvwdcYe9u+LllzsPOmuqz + 1QKUg2oUZ5MPDn+Z9Du/CAqZcE6q+pw1HjwZbuK8JdvB7hbVa6i7Nox3Bj26zfTDDiZ6KVefjWaDYz9s + beV3WpOhACvHyNypNk7Um3hsHBoUIpuLE/R+5B3B0d7qs9VKlINqzI2DSZ3pb9hSSR9eqtT6JUGg3dOv + YpLw5eLXYQX3flk1KFrl1vbZhrZr7GSpPiNN31rxxGi6UBzHgN4eN4jqdTUO2wbHCinI6cS8X+Hn1xaZ + S1AOqhFMzj8ZPAE2/QxHEt4f1wu2tVafs8aniRV0VgE/F7YQ6heOttCbmc/PzC6spr0yrOjeDTy8flSw + 06zJMBn7euwW1etqPCjGe/f4btgFqT9huzu7ayymvEjloCbG2ZnPh9Xa+5sPxb3DQheab52gsBvt9SbJ + ecGTZe+vfuF3AqvnfkGcffiiTsHG6nPSdF0hnhcnRpPh54xiYbRxq15X48IOpu2CLiq/i/lxZb27oSr/ + /rFuVJ+rCuWgJsL2R1bGTD/z23hFsKWq+nw1btcMakowwZ4knF9+edBWpnoddc9qsV+YboQWXJxFd2Vm + 9tji/pQ4LpoME/SPx82jel2N06bx4PhgMPkz3Q/HE54a/r5eoHJQS7JK3CY+FaZ/+WPwYOUJQT/O6jOW + 2JLO0ZVJd8fwpeIFQfXj6nXUPVQOp4K46U6opM9xsurz0vTw/edG8aVoMqyK/iAspqkK/bafH9QJ8thR + 93N87B2bRPV5ap5yUIvGtpudo402I6bd0Mv6D8EvDSrR8kWj+owlUJjqbTFpy8TTgy2h/qHqj+eGqzXd + yplxl/D3djdQtbnpsFPi8VG9nsT379sHq+mnhul2/hw8VLliVJ+nLlYOalH45UCfzu8Hkz3Tn/B5fTlu + HZwtrj5fab4tgt6sZ8UkOSkeGmtH9TrqnveG6VYowvrC2Dyqz0zTxcPLpsM2dx5mVq8ngeNH7EajUCG7 + aky3wySd71FXiurzVJSDWjAm53eNH4bpfuYXEaGv5mPCKtpaDM6MvywmnaDTYo1zla789QNtYr4aplth + 8vbNYAdb9blputpYQScvjur1pPl44M3vgreGq+ndDp8P9Z58uLoc5aAWhMn5nkElWdOfnBbvCtu2aCk4 + 70oP5knPoPOUn5Zd1WuoW3jKT0G/pitUm2ZCwcWHR/XZabramqC/KKrXkyoUc6We0Gdj0oKupr1wRIm2 + pXazKZSDWil6rzI5PyxMP8KXuO8EZ182iupzlVZm9zg2Js1Pwwru/cDqeROfuWkvB8Rlo/r8ND2uoKtL + KOz5mvhl2Iatm+EByuvj6lF9hqNVDmqFLh/3iV+E6UcoyMVTOr5oc1ap+lylhbhvcO510rCC7h+kfrh+ + NN0+yjSbD4fV3GevrQk651Wr15NWhu/s9w46DJwTpns5N6hf4Xb3ecpBLRc/6A8Kv6z1J0cGk6oNovpM + pcV4YDSRY+JqUb2GuoX2mb8P0938Jqj0bU2H2Xp7tBG3uGsS7K6hAws7bSjQOhdX1bsTJukcP+V4QvUZ + jk45qNJaQVExV867HwpwvTueElRod9VcTWlqgu4Kej+sEeyY8vx5t0PbQ+oE+Lt+tt4SbcQJuprA8UYK + O78p6MltuhV+j9Muj85Y1PmqPsPRKAd1KVeOJ4aT8+5m7kkordNeGlV/6csUY9JiPCCaCCvoTtC7r6mq + /abdUM394Bj9l7oZoyrzP6LpeAZdTdo1vhWmm3lfjP77UTmoS+AP/q3Cbe3dztwEnS8HnDe/WVw31gtX + VdSUpiboFIlzgt59bG8/IpgAmm7no7FmVJ+jpuOp0cZuEx6SVa8nrQg7oDjeeJ3YKVg9f1iwI+OoMN0L + BVn5fPjMqs90NMpBXQJnV+4U34tJWyuZ9sNEnSJeJ8dX4tmxR9woWFW/YrjKoqVqcgXdNmvdd69ooiig + aT9fCwqBulNqdvhb20brWbYkrxvVa0rz8ZCOrezbBr+/948vxAlBxXB+n/Ndnt2Wc/Es+uzDZ0NnrLsE + n6Fb3KtBXQJFZ+iDS7sGtm/NLzBhupf5v2hZ9aLvOQWeaLPxg6DKLA9c1o7q85ZWxC3u47JXmH7kJ8GX + O1bNqs9S7dsh2MnQdD4RPGT34YuWh52S14snxWeC73ycM6eLzz+jihPzboRVcwr40THFHa8XKwe1XFvE + 3YJe2mxRNf0LT04Pj4/Em+NZsVs4YddCNDVBp0icVdy7jw4Qbm/vR6jk/thYJ6rPUu3bPvjb2nS+Ezx8 + cfeb5rtW7BkvCAoDs2vyd2H6kZ/Hc+P2sXFUn/FolYNaKbZa8cXtDcFKmOlvWGH/RnDGjS93/KJgG3z1 + uUtNTtBdQe8+J+j9Catlzwx2vFWfpdpHzYbPRdOhDsT9Y/WoXlfjwUTuzrFfvCdYcKH6t+lP2N3wxuBn + mvbV1ec8euWglmvZ7VWXC9ousXXaKr/DCF8EnhE7xzbhlz3N5xb3caHFmhP0fuSPsW/QdaX6LNW+XeKL + 0XR+HHzXcoI+TnNnyu8YrJa7MNbPnB3fjkeGBT1XohzUonBegsb6rwuKULTRYsRMN38NfpFQsOLpce1g + 14RnY9TkCvqWUb2GuoNJgRP0foS/vxxZ8qHq7DBBpyBX0+HB+f1iboLuWfTho/4T37uoPfDCYDs0C2EW + a+5f+BvKA1R2Hd84fNC2AOWgloQK4XeID4QZTv4cR8Z7g4qgfvkbtyZX0D2D3m084d87LCTUj7DFnd1P + HlGandtGW1vc50/QNWx8zhw3PCR4mP2XMP3Nl4LizJtG9XmrUA5qImyLZtWVXypmOKElB1WC3xePD1c/ + x8kz6OPBzqi3hulHnKDPHkfDPh9Nh7+9Dw4n6MPFDsXbxYHB2XJ2MLp7qd+hcCf1nXaM6jPXCpSDagTF + D74aFq/ob1g5q1bP2Er5tnhU0FbGre/j4QR9POjuQFVgV9D7ESfos8cusx9F0/EM+nCxU4mdF/Qr/3p4 + TLT/uSBot/jwWD+qz10rUQ6qMbcMngRSKdwML5yF4rwdT/bp38h5qeo+0HBYJG482GLpBL0/+UNwJMEJ + +uxQpK+N7zu0Wbtr2GZtOKgjwC6lx8T3wgwjLGC9PTzCN6FyUI3hF9BWQd/0P4XbdYYXPlMKyvEHhq3v + fN5U96/uB/WfReLGg+KQbnHvT5ygzx4/L2080OJcO9tkLQ7Xf2sEP6Mch6Di/3nhQ9BhhPZpVGhfO6rP + XotQDqpxG8QewWorWz/MMEOVyu/HPnHZqO4F9VtTE/Sfhivo3cbP8FPDL4/9iFXcZ+9d0UbYibh5VK+p + /mA7++Pim/GLoLaPGUb4PPcKJ+cNKQfVGp4AUw3cNhHDDhN1tvhQh8DVnGHhM21iwsYE/apRvYa6g8/b + nU/9iH3QZ+8d0UZoY+tD7/6iZdqd4/VB4TDT78z/DvS7oBAcn68/ow0qB9Uqejq+M1xJH37YxvziuFW4 + NW8Ympqgewa9H+4TTtD7EVbQ2b3kCvrstDVBf2lUr6fu2z7Y2eI58+HlV8GxoitE9dlrAuWgWnetYCsY + N7cT9eHnu7FnbBzV/aD+oJJwE/l5cMa5eg11x33DLe79yG/jCWGxztlpa4L+wqheT93FDrG7B0c7Tb9T + /Q2k5sdjw9+3LSkHNRXc1Kysfib+GWa44Zfbn+OguGHYlq2/HhRN5Ndxs6heQ93hBL0/4dgID0It0jk7 + bU3Q2YlWvZ66h+3sdLX5UJwanjMfVpivHBnU41knqntADSgHNVU3Dra8m+HnzGCb18OiuhfUfRRBaaKG + BNtxmfxRNKd6HXUDfZ3/Fqb7OTRuEB4nmh1qr7QRJ+j9QTu8b4e1loYXdvy+Pzi24HeXlpWDmrptgpve + s47jCNubnxfXiep+UHfdMSiKMmlYWeC87IZRvY66Yfdg67Tpfj4bnoWcncvH+6KNvCSq11R3bBFPicPC + DCPzd4+dG28KdoFWn78aVg5qJq4XTNLpCWmGH7Z9sXPiTmHV4f64aXAs5R8xSdhN8Yqwknu3US/kbXF+ + mG7nE0GP5epzVLvYtbB18JCkjbiC3l2rxy3i1fGXMMPLGfHauEZU94BaUA5qZq4ZnOE6Pcw4wmr602Kj + qO4JdctWwR+qc2KS8AePL5329u022sZQyf3EMN0OD7iZLFSfo9pFXZVdg4KobcQicd3Ergm2tH81PGs+ + zLDb71VhkeMpKwc1U2wTem7Q09XiROMIvwDpD+ovwO6jNdor4+wgS/0ZPS3o2eyDme67Tfw+THfDz9Pz + Y9WoPkO1i8J894ujoo3wnah6Xc0Ou1Wop0PBMCfnwwzfTTleYuvKGSgHNXMbxN3iS2GhjXHkrHhzuIWo + 29jy/JaY9CgK57nYOs3/XvU66g4Kj1F133Q3bG/fLiwQNxtUc2YnWBv1GjgO9OSoXlezwco5E7cm6rGY + buZPsX9sEtU9oJaVg+oM2rBRmdaMI0z6mKQzIajuB83etvHJmPTBGSsOx8YuUb2OuoOHZnxWprthhdXt + 7bPDCtvLghW3JsMOpR8ECxbV62r6bh4UC+OYlhlmONL1rHByPkPloDrlnsEk3Qrv48hfg1Y1FA2s7gfN + Fg9PPhB8TpOGfqL3iOp11B0cPeF889yxBtOt0Prn8VF9dpoOdv1R9LTploR87/lY3Cyq19X08ACMOgOf + CjPcHB90mHFb+4yVg+qc2wXb3e3HO47whfOD4fbn7lkvnhBzK0WT1Ilwgt4Pc19MWckz3Qo/fxTa9Odo + tlhpa6OCO58v/7u3jup1NR3UdrhzuKNz2OHIAivnFEet7gNNUTmozuGXI1trmbTZ7mcc4WHMR8Pt7t3C + GdcbRRNnLWnVdt+oXkezx2c9d6aZgkj8/jXdCkdN3hrXjWU/P00P3Sh+FG3km7F7VK+r9vE7kKNY9Dd3 + J+dwc1w8MdaO6j7QlJWD6qwbxzfCjCN8+fx40GO0uh80G1tGE0XDWEF/XFh5uh9eGpMWBzTNZG7nCsU1 + aYNHFfHqM9N00H7yZ9F0qNXxrtgmqtdV+64d3wsz3PB95hHhtvYOKQfVabQysWDReMIXlE/HbaO6HzR9 + HD34TUwaViNeFLZa6wd+9/4kzOwzN0FnJ8tNo/q8NB2rxC2jid+Jy4aH1I8KV/Vmgx187w4z3PwiaJfn + z1jHlIPqtHVj76CQgxlPqEFAoRxXW2evqQk6k4wPxw5RvY66hVVCWuOZboTVc6pJbxbV56Xp4Is9q28n + RdOhGOfto3pdtWuLeEOY4eao4GfX75UdVA6q8zaMp8fJYcYRVtK/EhxzYMWiui80HbTdOiKaCP8794rq + ddQ9jw7rgHQjRwcPLe19Plt0OXhOnBZNh5+1O0T1umrPFePA8DvmMMPiwJHxwKg+f3VAOahe4BcoW7/+ + EGYcYTWBJ9qcCavuCU0HX0hpKXROTBq+ANkiqj94QPahoNOCmW2+HvwdrD4nTc/V4pVxZjQdem27gj5d + V4jHxq/CDC9Mzn8Ydw9rd3RYOajeWCc4O/LTMOPI6UGPyitHdU+offxR2yuOiUlDJfcDonoddQ+f/R7B + 9mozu3DEa/9YLarPSdPDQyt6Y7fx0IqjRLeJ6nXVPHaj7BbsTpmr82CGlcODlnm2Uuu4clC9whdGJuls + VzHjCEU92Gpb3Q+ajh3j29FE2BXhk+z+oKXU58OK7rMLLSivGW5vnz0mdPRPbjoU0fxObBfV66p528eX + wwwzLCqwcl599uqYclC9s2YwYfO80HhCNek7RnU/qF1MCvgic2g0EbZMs020ei11z1pxj2ii1Z5ZfJgM + Piiqz0bTd9f4WzSdc+PgoOZH9bpqFtf5/WGGGY7DurDTI+WgeomKmy8IzmyZcYQCY7QYsgLn9LF619RK + A/879Lp3NbA/OF5EBX562ZvphevN1vYNovpcNH17Rhs/BycGEwo611Svq+ZQePjt4bb2YeYv8dRgMa/6 + /NVB5aB6a+tg618bT7NN98IWwE+EfYCn70rBtW8iPwoquXuetl/oi855PjO9sHq+c1Sfh6aPgmLPijYm + 6MfF7mHXknZtEhyzaqLoqeleqJeyb6wf1eevjioH1WvbBBMHn4SOI3+P1wS9uav7Qe1YPd4XTYT2RC8K + tk5Xr6Vu4iENq7kWjJtOToknBZPC6vPQ9N0lvhdtfN/4WVw/qtdVM64e/O1x5+WwMvfz+MegBeJGUX3+ + 6rByUL23U3w2zDjCL+HnhpXdp4ft6HyxaWpyRtExn3D3Dy0Pabln2s3Z8Z5gK271OWg2eEBFJ4o2whGu + q0T1uprcGvGQ+FOY4YXfmW8NJ+c9VQ5qEG4V3w0zjlDZnd6lbpOennsH/USbCF0YtorqddRtNw8+P46c + mHbytbh1WG+jW14ebeVbsXFUr6vJ7RpfCDPM0PqQxbrqs1cPlIMajFsG28T84jiO/DLuFH6JnQ62Xza1 + zZ0HLJyttVBc/6wdDw6rurcTziI/KvzZ6Bb6KL8p2sqnw2KA7bhhMIHzKOQww8LBHuHvzB4rBzUY/HDy + lJStYmYc+VWwe6K6H9QsjhS8IpoIFYufEpxrrl5L3ca9cFBQT8A0lwuCc+dUza+uu2bnOtFUocxlQ8Gy + N4a/D5vHlucPBPVrzPBC4dI7xOWi+vzVE+WgBueh8eMw4wgrDzeL6l5Qc9ipsE80Eb4sfSw401y9lrqP + LhrvDtNMmJxzvp8WotX11uzw5f+J0dauERYVaN9GMc7q9bU0mwe7Hs4LM7xQj+jO4VHHASgHNThXDIq5 + nBlm+KHlDT2ad4jqflBz6NPLRKKJ/CZ8sNJv28cnwywtc1tu6dvLRIJjJLbZ6h5Wtj8ebRWIY4XX7e3N + 4uHva8OV82GGh2XsNqo+e/VQOahBunG8K8w4wqSRL1A3Clch2nPPoDdzE2f5eIBG2yLPjfXbjnFUmKXl + 1GB781Wjur6aPVrd0V6trbw5qtfV0mwaHMFp64GKmW1Oj/3ClfMBKQc1SHzpZ3XnO2HGEZ6Uc0aQs4LV + PaHJseJNS0N2LUyav8WzYr2oXkv9wNGHu8bRYRGmxYXrxeSM4wLVtVU3bBI/iLby6qheV4t3+XheUOfE + DC989+CB5rWi+vzVU+WgBosvjjeNn4QZR+jTTfu1daO6JzQZVvleGufHpLkwqKx7i6heS/1Bj2F2V7Q5 + iRlauP8Pi7tFdU3VDWsFLSY5ktNG6Mv9tKheW4vD7rnbhzWIhhkm598MCgO7825gykEN3l7hFszx5Jig + DRSThup+0NLRauiBwZnZJnJSUNSxei31C/cGBXu+EmbFOSVeE7uEO0i67Xrx+fhrtJGPBLv9qtfW4mwb + XwvPnQ8zdO3hWNyaUX3+6rFyUIPHRO0xQe9lM45QFZeCZn75bR4r3r+PJsIWX86SVa+jftotmKR7/vOi + cI/P3/p/fDw/rNbeD7eOph5IVuGYjy2iJrddfCjMMPOHeHiwM7b6/NVz5aBGYf3YN5qqQG26HyaR9Nqm + Z3N1T2hpqI57aLBFt4m8Iei8UL2W+okVwbfHCWH+l5PjOWHF7v6gxzJ9ytvKI6N6XS0cRYEpEmuGmdOC + 35vVZ6+BKAc1Gjxh/VI0UeDK9CP0yXxEUDimuie0eFTIfV2cEU2E1dbbhmfKhoWzu+xioQbIv2LM4WEW + 3Q/2jo2iul7qHrbSPj7a2t5ONep7RPXaWhh2olDLpKkHxqZb4WfvJUGhxurz10CUgxoNtrqzsvP1MOPJ + kbFrVPeEFm+dYKtZU0WTWGVlm6ft8YZn7aB4HOdCx1rhnYcTnwmOhtCuq7pO6qabxPujjckfR0BYMNgh + qtfWym0c7MCiI4gZXs4NOhxcI6rPXwNSDmp0bh6cUTbjCBMDC/E0hzNgFOP5YTQRdrTwJZjJXPV66jeK + x/E794D4WYwp/HsPDLqJVNdG3caDyD9HG6H/PR1HPN6zNHQUeVmcGWaYYXHF350jUQ5qlGibYiuO8eTs + +GC4WtGMK8Uno6l8L64fq0T1euo/Wh/SAeDDQfX+IYffN58N/r38rFTXQ93HQ6W2QrFAHnRWr6sVo7L+ + QdFm8T4z2/w8HhIclaruAQ1MOajRekAM/Yui+V/YUviFYDVvtajuCS0M29FfEJyhbCJsc39GuJo0fFcP + CnayA+OsGFKoecG/i22Z143q36/uox5G24XHmIBsHdXra/k4JvLaaKsugJl9qNdB56Xq89dAlYMaLVpw + UbSHrWZmHOE86HeDM+lO0peOL7C7xzejifC5fD+c1IwDbaWuFUxk+TLW5zOk3LusmP8oKIpHEUWLUvYb + 9Wq4N8+LNsKxHnYgbRbV66vGairHAo4NM8ycH08Lfgare0ADVQ5q1DjHdHA0VZHa9CMUCrxTVPeEFoaf + nXdGU+FB2e2jei0NE5V5bxZU6T0l+hbqW7ArZ8/giIZ1FIaB1pxfjrbC9nZ2DFk0cOGofcJDYY4mWrF9 + mGFyvk94LGiEykGN3jbxsWALtBlH+GL90fAM4NJR/IsiPfMzSaVuVlH532PiX72ehusqcZ94YrwpWFXv + cigc9pagh7V1LYaF32vssDoq2gqtJdktxKSzeg+6JHZs3TG+HWPtBjH0sAvpHcEOpOoe0MCVg1LsHJ8P + M55QYObNQauW6p7QynFO7LSYyyRfnvi/ZeviHlG9lsZh82Cr+LuC/sZU8mVlZZZhS/KvgtVydo08NXyQ + NEwbxCuizQJkFCxl0lm9vi6JByb8TbA97nBzQVBUk7oPFoodqXJQuthu8Z0w4wlFAp8e1COo7gmtGC1Q + PhRNbjl8XqwZ1etpPPiidrW4R7w1OOP90/hDcCSJSXNbof8uq/isov4g3hc8jLpOWLti2NhRR1eJtnJO + cKTDCfrKUauC4yOHxVxcQR9eDo27h5PzESsHpYux3YyV9K5vrzTNhkrkTwjaQFX3hZaPyQq9gptc4eRJ + +k5RvZ7Gh3uMn83149rBVngmONwnvw22RjLpYVLNMQkm7jwwAv99WYzzJZ//TiVo/m/BiunvgyKSbF/n + CyOr5LwuZ4VZyaven4aDwlT3jzYLx1Ic7hZRvb7+h0KLtMM9OpyUDzfUFLhf0Bmmug80EuWgNA+TdHrX + /ibMeEKbr2eHxUkW7zbBmdymcmJQQMnzmaowUeZYClXgtwse5oCij2w9f3t8JD4Q7433BNvSGec/+f/G + dln+v7GVfpfg/55J0/Zxg9gi/MI4PrQ9owYCW27byrPChz0rxg6qveIXYYYbWg3ywNXimnKCrgVhWxUr + qvzyMOMJk3R6e1ukZHEodvSlaKpVFm2r2DZPhe/q9aTlWSfYhn6TuGFQWR3co4zzn/x/u1UwEXeipPnY + NXFctLVie2awQl+9tv6H44asrJrh5k/xkPA4m/6jHJQKbGncP+yRPq6wzZXts/anXbgrxqOCBxxN5Sdx + h3AVU9I08EDwoGgrPHjk+ATH6KrX10V4sPbpMMMN37MoxOgDUv1XOSgtBysvVPm2/dq4wnnqFwbbXKv7 + QheZX+SIraEU8WoqPBh7VXjkQNI0UEvjmGgr/F1hh5Z/V5bvGsERFPucDzdnxRtjq6juAY1UOSgtBxUl + bx5UmOTptxlPzotXhq2UFoYdJx+LpraG8r/DFke2JFevJ0lN4W89PZjb/DtPx5Bbh5WqaxSAfH9QuNEM + MxyDe01QP6S6BzRi5aC0AmyxZZL+uXAlfVyZ65NOq6fq3tD/UP34cUEf86bCk3YKKlkTQFKbeBD7lWgz + 3w8nJjWKPX44nJwPN9RfYFs7uySqe0AjVw5KC8AknbY+tvsYV2jhRA/ma0Z1X+gibHfnSy5fspoK2xyp + 4nvbqF5TkiZFYUE6eNA9oq3wv/3M8MjOpd0y2H3lAsiwc3hsE9U9IDlB10Qo7sJ2dzOu0C/5bUFNguq+ + 0P+8OJreJvrcWC+q15OkSbC1+shoMxSH8yHvpdHW0IWP4YfaDo+MtaK6DzS53u9MKAelRbhr0IbFjC+c + UaQ1U3Vf6CL0NP1pNJkfxp5RvZ4kLRUTBiYOp0VbYSfQB4P2rdV7GKPVYsfgWIH1fYYdJucUYKzuA+m/ + ykFpETiTfu/4XZhxhQInVJi9UVT3hv7v/zYIKhU3+aWLHQxUfeVLXfWakrQUFG3jAWCbK7i/jMfGqlG9 + h7HhONQu8c2wWvuw85t4YPhwSitVDkqLxC+bB8fPw4wrFLH5VNwkqntD//d/9wxaCjUZWrjtFhSjq15T + khaD3yVPibYniW+KjWJ+W8oxu0t8I9zWPuycETyYWjuq+0C6hHJQWoLLxiPiJ2HGFb5YMEm/WVT3xthx + ppNicbSqayoU63t3eIZNUhN2ja9HmzknmKRUrz9Gd45vhRl2qNj+krhiVPeBdCnloLRElw/++P4hzPjy + 8dgpqntjzFiZ2j2OjybDdjm6KbiKLmkSrGa/Mjg+02Zoz3qLqN7DmHA08I7xgzDDzsnxqrhKVPeCVCoH + pQnQo3mfOCXM+PKZoNgNX0Cq+2Os+Ln4djR5Fp1V9INjy6heU5IWgiNKX4s2c1Y8LNhtV72HsVgz7hZH + hBl2uOcPjA2juhek5SoHpQldLV4fp4cZV+jd+p3gXB1fRKr7Y4zYir5fnBBNhaMFf447RfWakrQyVw4e + 9FFPpK3wu+r7sW1U72Es2KlAkbCjwgw7FNFl5XyrqO4FaYXKQakBW8f74u9hxhe+gDwjNovq/hiLuUJI + qwR9Odlh0HReG/YUlrRYFHhlqzXHZdrIXOEzzuC+Jsa8zZe/BY8K2myZYYfJ+afjxlHdC9JKlYNSQ3YI + +p3aOmScoRbB62L7qO6PMVi2UvHLoumHVrQ4ZFVm/utI0srw0PCT0dbq+dwE/bi4Q4x1VxX/7vvHz8IM + PxT+o3We9WG0ZOWg1CAm6R+KpttMmX6ELe8fjbFvbZxDy7XDo+nQj95VdEkLtU48Mi6INkP3Cr4DrBfV + +xg6dincK34aZvjhKMe9o7oXpAUrB6WGXSveG022mTL9CZWBvxw8rFk1qntkLPiS+sKYW1lqKrQvekOs + G9XrStJ8t42vRNv5YVAUbYy/+/l9/6A4LMyww990Hr7fJ5bdOSctWjkoteDqcUh4Jn2c4ZjDl+LWUd0f + Y0IBvWOj6RwdtwnOu1evK0lznhdtr56TNwaryNV7GLLrxJvjT9Fk9w7TvTA550EUBVvHeK+rBeWg1JJr + xyfCjDNM0jnvyCSyuj/GYoPYPyic1GQ4RvLW2Dyq15Wk1eIhMY3z0Exa7h7V+xgqdgrsHBQEZWeTGX7Y + IbFb2F5WjSkHpRbdLn4QZpxhBwXb3SmYM+aKvhTO+2U0nT/Gw+NKUb2upHGjswa/g6eR5wQPJKv3MVRM + 1NruKW+6EzrWcISjuhekJSsHpRax/YcCGlYzHXeoPP6iYFdFdZ8M3YbB9sdzo8mw1e7Q4Hxp9bqSxouq + 0jzAOz7aDLulqNw+pt1SXFsm558PM46cGI+L6n6QJlIOSi27fFBI4yfh2azxhtV0tmRvE9V9MmQUkaFo + 3nej6TBJf2msFdVrSxoffudsF9+JpotULpuz4oDYNKr3MjQcG6C2yPei7WtruhHu8WfHlaO6J6SJlIPS + FFw26IvKap8Zb6js//agH291nwwZKy6viDbOKf46HhMWjJMECrXy4K6tnufz8/PgwetYfv9w5vxH4YLD + OHJq7BebRHU/SBMrB6Up4Y83W8K+GGa8oVgabfhuFNV9MmR8if1YtBF+rraO6nUljQer548OtuS2HY4v + sbLIQ/jqvQwJBeH2DNuojSccD3lajK22gqasHJSmbJf4apjx5h/BRPVRcdWo7pOh4kzoadF0eMrPCr1b + 3aVx2z2mVZz10zGGThK3jOcGK+dmHGFn2jPiClHdE1JjykFpBvhjxySdiZoZb06JFweVhqv7ZIhYRT84 + 2giT9PvGulG9tqRh2yI+FdPISfGEqN7HUNBK69YxrUr4phthZ8iTwg4pmopyUJoBtuDdPL4QF4QZb06P + V8fGUd0rQzN3758QTRUYmv+/c2TcMarXljRcbMM9MP4U08grY8i/t9nSzo6/74fF4MYRPme2tT8i1onq + vpAaVw5KM8JEZcf4cJhx5+x4V2wZ1b0yNOsF29Hb2OrOF4zXBCtp1WtLGh4mk3sEK3/TmEwyibl7VO9l + KG4XrpyPK78KjqE5OddUlYPSjNEK5v1hxh2qDbOj4s5R3SdDQpue6wZtetoIq/P7RvXakoaHld7DYxo5 + N/aJDaN6L33HA9TnxA/jn2HGkZPjJeERMU1dOSh1ABW9Pxh/CzPu0Cv8gTGGLe8PCVoUtZHfBNfR1mvS + sF0z6IwxjdBajAJ0vGb1XvruWvGyoNuIGU+4r98ZPDiv7gupVeWg1BHXD1bS2+gTbfqVP8bz4wbBUYjq + fhkCVtIpktdWP91fxm1jDC2QpDFaI6guTsG2aYTfzRSGu2JU76ev+F28bbwl7G8+rrBL4rPB38rq3pBa + Vw5KHcLTy7eHK+nmvPhksHXzclHdL0PAOU4Ku7WRC+PzsX1Ury2pv5hU0lKNImbTCAVd3x2Xj+r99BUP + MDlvzt8bO8uMK0zOOVrHUUt3m2lmykGpY64drwvPfhm+ENKLlHYn1b0yBJx3e3ScH23k73FAjKVKvjQW + dIP4dvAzPo18Lm4V1XvpK4qBPTY4bz6t62i6EXZKfCZuGNW9IU1NOSh10Nbx2nC7uyFUJqZ4y1ZR3S99 + x/3Ol9+2viAeF4+J6rUl9Q+/M6bZAYXdOM8K+oJX76ePrhN006BehxlXWACi7tFNo7o3pKkqB6WOumow + ST81jOFpN8cfhrhde624axwTbYVt9HeK6vUl9cdVgn7n0zwK9ungjHb1fvqGuibsBKCwXls7l0x3w868 + 94WTc3VGOSh1GL2cecLtJN3MhXOC9PvdJKp7pq8410mxpz9HWzkieMDB2dXqPUjqNoqzPTPYVTSN8GD0 + 2NgtqvfTN2xpv0t8M8z4Qm0bihFfL6r7Q5qJclDqOFYLqOjtdndD2Gp5YrwyNoshVXln18gh8e9oI3zZ + /mJQEGfI1fGlIVo7qKDeVmvGKifE06LvVdspALZpcN6c69fW71jT3dC//x3B39nqHpFmphyUeoA/rPvF + aWEMoU8tk82dorpn+upB0eZWd7b3vSHs9yr1Byu/94+fxrQml1Q055zu5lG9pz7ZNVg55YGDGV/+GrTQ + Y1dmdX9IM1UOSj2xQewb/oE188NWxUfGelHdN33D1v3nRJtdDNhGzwMvKshX70FSd1Cj4t7RVjvG5eU7 + Qfux6j31xaqxV/B3ws4w48n8h1hnx6uDDkHVPSLNXDko9ciV49lBVWpj5vLbeFHsGNV90zfXCIrYtLlS + xir944OVueo9SOoGep3TTm2a+UU8JPpcr4LV0ifH0WHGGXbaUcfIbe3qtHJQ6pkrxVOCc8jGzIXtmF+K + O8YVorp3+oQiNqz6tFmpmQddnMkcyu4DaWhoLTnNdmqEFce9o6+/Fy4XNwomZhQFM+MMRyIPig2juk+k + zigHpR6iYA19nf8YxsyFImjcEzzAoaBSde/0BUWNbh/fjzbDdvdnhF9ipG7hYTStRiluNa2wDfxTsU1U + 76nrOA7AlvZvxDTb0Jluhc4/LwyPcakXykGpp/jF+4igBYwx83NSvDNuFtW90xerx4vjrGgzJweVmoew + 80AaAmpR0Kni9Jhmfh27BL97qvfVZRvFy4J/g1XaxxtWzvcPHzqrN8pBqcd4Wk6BsKPCmPlhy/tXg62a + dAGo7p8+YKv7e6PtcCadQlTVe5A0PdcMVs7/EtMME9snRt8m55eNPYLfk9O+Zmb2mf8whofN+0Sf/+Zr + hMpBqefWDIrZWAjGVOFpOhVcbxF9LXjEe/9BtJ0vx1AK7Ul9xOT8dUFbqGnmjHhJ9G0XzQ3jqfHDMOMO + HX6eGW5rV++Ug9IAUBTmPkHlWWOqUAWZe2TjqO6hLqNV0N2CavVt5vz4eOwQvGb1XiS1g0rT9Go+J6ad + Q2K7qN5XF7F7bqf4aFgIzhwfrJz38WiG5ARdg8ZKOlt0WUn3/JlZNtwTVP5n6ygFkPr2h3z9eF5wvr7N + XBCspN82KFRXvRdJzaK1IpNkHpJNOz8OClL24aHcZYKHrI8KdhVxlMmML/O/4/Hgmpahl4/qnpE6rxyU + BoSV9LsG7amMqULBNb7YcTa9b6vpVwmK37X9JZ5Kzt+JPaN6H5KaQ0uwD8S0t7UTJjf3DB5wV++ta2ij + ybX6QxjD/fvQsMCpeq0clAaGJ+y3iTdF29WvTX/Dlrg3BOe7q/uoq24SbOucRpik3zmq9yFpcnSa+GCw + c2XamWtJuUZU761LNgje6/di/uqpu+XGm18G9YdcOVfvlYPSQNGmhqI3bGs2pgorxZ8O/shfLar7qItu + Fd+NtsOXX74QUyG5D1/ipT5h5ZyHbf+KaYcV6AOCXuvVe+uSbYN2k38KYwhHGR8e1f0i9U45KA0YhWSe + HW6HMysKrXk4m37T6MtWuV3jZ9FW5q9M/TzuH1eO6r1IWjh2eVF9/JMxi5VzfrZfHjzErt5fV3CkhyNr + nw9jyCnBzq4HRHXPSL1UDkoDt3ZQ3bPt4lqm3+Fc90/jWUEP1a4XTKJlHGdHj4ppbPP8cxwYbDWt3o+k + haFLwmdiFpNz8qOgKFz13rqA370c5eGsOX2tLwxj2A1Jn/6rB73vq3tH6qVyUBoBJhX8Yv9dGLOi8CDn + K/Ho6PqKMV9SWEmY3wO4zcn6qfGeoFc6q4DVe5K0fLvE52JW1cfZGnyPWCeq9zdrVwwqcvM77e9hDOG8 + +SPDYnAapHJQGgl+sT8iqOBtzMryq3hzsMWyup+6gmMcL4i5XsBM0JuepM//32M161NBD+Lq/Ui6NM56 + PyHoMDKNHS/LhnPu1JNg100X60nQgYX39sY4LoyZy0+C724Wg9NglYPSiLDqx+oBE4wzw5iVhZUc2rjQ + p7i6p7qALbNsB51msalPBN0S7JUurdhm8Zyg1sWscmTcLar3N0u0d9sunh4c1zFmftjx8cDgAU51/0iD + UA5KI0T1XNqwnRHGrCznxlvi1rFhVPfUrNGuiWJK0+yl/NngLCt1Hqr3JI3dVvHS+FvMKqfHY6N6f7PC + w/KNgsnX12JWW/5Nd/OL6OqOD6lR5aA0UpvHvsGXF2NWFia+9A1+e1w7urZyzPu5Vrw7zolphC/VbD+k + vsP6Ub0vaYyYgLIyPM2fxyo8XHxmcLa7ep+zwISLIzLvCAp/zaLNnOl22E1xn3DlXKNQDkojxqSCYmAW + jzMLDWe9vx2076OabHVfzdLW8baY5kr67+M1cYOo3pM0JhRvpC3hl2OuNsQswpb6F8bGUb3PWbhevCgO + DzpnGLNs+Pu6Zzg512iUg9LI8WWKAiScdTJmoflTHBJdrCzLRPkjMc2cHVR4v210vUWd1BZ2ZtHWc9bn + qXnovF/QS7x6n9O2ZTwqPhbWfzFVuC94uHy7WD2q+0gapHJQ0n+2I9Ku6rDwLJxZTOgPTgGonYMv59X9 + NQu3DPodTzP/DM6TPiS6MjGQpoG/IdvGq2LWtU3Y0fKMWDeq9zpN/E6kE8Yb4rQwpgp/R6nVQF2C6j6S + Bq0clPRfnBn8aLj1ziwmnKE8Pl4ZFGvrwnlsJgwUcPtxTLutE7sLXhLXCau8a+iYCO8es2qhNj8nBzUh + Zn3mnD7rPLDgdyLnzGd9XUx3wz17QFhsVKNVDkq6BKruvjemeYbXDCMUg/p10CHgmsEkubrHpmW1uEvQ + Km7aYcv7u4KVfLcraqjmtrQfG7MudsZDQraRz/LIDb/ztggK0x0RsyyQZ7oftrU/P7pUxFCaunJQ0qVQ + DZu2WrNsjWP6G76UstWbL6mz7p/O5PhO8dWYdrgO3whW9OgFXb0/qa9ou/i+YIV41vllPCZYua7e6zTw + d3PvoP0iHS+MWVGOCf42bBrV/SSNRjkoqcT23GcFvaWNWUrYukchOYoQXjWq+2xa7hBMlmeR44IzqNtH + 9d6kPuGh2xOCKu1daBHGMRZ+x8xqizDnhu8b7DzrwsMK0+3Q2paCoveONaO6p6RRKQclrdAO8YnwXLpZ + avhC8uq4c1wtqvusbZwF3yVY2Z/FpILXpLL8vWJW10CaBJMJjmxwhKUrR6BYOafAKb3Fq/fcJh463jFo + 5fbzmB/PnJsqJ8SLw78B0jzloKSVum6wEjrLnram32GCShXjNweF5DYMzohX91ubbhifjlncy3xpPyWY + 4GwTrp6oL64UD4zvRhdWzflZYlLMKuQ0+0XTlpTfXbcIdsWwYn5hGLOy0Jf/KWExOGkZ5aCkBWHLexda + 6Jh+h4nxb4NdGWw75wtvdb+1icJWB8UFMYtwDX4a9JC3OJC6ji3tr4+Toisrw4fHnjHNyfkGsVfQy/w3 + cW4Ys5BQwPCx0YXWf1LnlIOSFowtfayisE2Yns/GLDWswlHl+P1Bcadpt2bjXqbGAlsOZxUq3lNkiz7J + 1XuUZomHsrR/4qw5XQm6km/FHjHNh3v3jw/Hz6ILOwhMf0KB0nvGLAsYSp1WDkpaNM7ysk3472HMpJkr + osaKMscpqnuuDWvF44OJ8izzvXhasG121q3ppCsHK8UfiLOiS/lC3D6m8XPCVmRea984KoxZTDj68PHY + Oar7S9LFykFJS3KboBLpn8OYJsIq3TvjHsEZ7WmskK0abD38Rcw6TD4eHFtF9V6lNnHc4qbx7GBLbpdC + kdLvB/UrqvfeJKqy3zxomXZYGLPYsHjx0bBzh7QA5aCkJWEFg0qk+4c9X81Ss+yZVlYdOKP99WAVj/Pi + rHRX92BTmKSzek9F6FluX+Va0DudB190T6AwV/V+pSbxIIydK08Oto93pUL7/NAzmgd3bVVr53cAP29c + h+cHdTJmVaPC9Df8/To12H1y7ajuNUnLKAclTYQvNbSOohetMU2FiTIPftj+/czYNKr7ryk8BGD1ugsr + h0yQeFhwcNw4qvcrNWHjeFhwzpwOA10pArdsDo0to/o3TIpCc7sFu3f4ubMQqllqqM/D96HNorrXJBXK + QUkTo10W59Ip+NXF1RfT71DI7bNBv+E2J6xbx+eiKytnbOv9ZtA3lxX16j1LS8HE/NFBN4Vjo+vhATBn + eZtcQb9J7BOsdv4o/hbGLDUfilvFKlHdb5KWoxyU1JgbBcW+Tg5jmg4T1o8EvWR5INR0iyXqKvBF/R/R + pTBx+FRQSI4vgKtH9f6llWFl7z7B72lahfUlrGq/NXiwUP27ForfGUz02ZVDuzS2IxszSehv/qbggU91 + z0laiXJQUqM4M8y5dPrUuiJhJg1bbqttt9+NxwVftm8QVFyu7seF4r6l13PXwxbKR8V2Me3WdOovCp/d + Nl4as2wtOEn+EHQ6qP59K8PEnsJvdG34dnR1K7/pTziGxUMudjhdPqr7TtIClIOSGscfK1Y46RvrlnfT + VngAROV3vnA/IjaMpXxRYkWara5nRtfDxIKfKbYl7xcUIlo3bM+mZbHV9gpB4TOOh/wu+lz47Nzg53SD + qP69y+J3Af//8u9/SfBgwofGpomwy4qCiveOafbjlwapHJTUCqrisrL56rDojmk7JwYT9ecGWw0XelaV + +gl3iO9E33Ja/CzeHEtdWdQwMWngyMY74uhgG27fw8MpjqDw81r9m+e7RrCTiyKT/Iz4N8g0FR6QUm/n + 1uHkXGpAOSipVbRi48xwF/pMm+GH+ge0aOML1LOC+6+6L+esF+8OVuf6GtrS8XCCc8W0omq7LZ26iwc1 + bGPn/mdySj/mIYUdAM+Iqg4DuwUeGpwH/nxYC8U0Hbp87BvXj2XvP0lLVA5Kat2a8YCgQjZ9no2ZRk6P + t8WTgsJYV4/59yWr53eOX8dQ8sPgTOSDwqJF40AtgtsHRQT5HUsv5iGHatnbBP/2K8auQV2Glwdt0oxp + I98P7rN1YtmfQUkTKAclTc1N43VBsR9jphlW0w6KnYKCcKy20bqMFktDfGjE2Xwq3u8ZO8ZWYfX34aAa + +TWDwm+s6B0RYwl/Pzg6xb29dxwWFn0zbYVdKByBumNUP4uSJlQOSpoqClqxuseqZZ8LFpn+hfvtt0G7 + pifH26MPheGWGlZSefjAWfWPx92C1VaKZ1lUrn94wMKDJR4w3S9YLT8lxlaIk8k4kybubYuQmkmzvIc7 + VGmndsEHg0KD9jeXWlIOSpo6trzTJooCRm55N9MO581ZUWeVeSzh4cRxcWhQ0ZuzyrYG6g8ebD4kPhtH + BqvI/wxjTDv5Stw3VlbHRNKEykFJM0OLKLZnHhXGmOmEFXUm6u+J5wQtEXloVv2ManbogkGhQ3Z8UPTN + QpvGtB9aqL0l6JvvTiNpCspBSTPFyhDbNb8Ybnk3ZrqhAvxX4/nx8KBoHi2qaJNY/byqPVcJzpTfPyhs + yKR8yEcwjOla2JlCFwRXzaUpKgcldQIF5Gh3ZWscY2aXXwXt2ui6cMvg7OUm4YS9eWsHnQVuFPT2flFQ + KXpMRy+M6UL+Fuzko+igv+ukKSsHJXUGLXNYOfp5DL1VkDFdDQW4mCT+OX4Urw/aeG0YtBji7Poa4fbP + xeGacf02DWpwPDI+Gr8PilFR8Mxq5MZMN+wiYrcKu1fojlD97EpqUTkoqVOoUkw7E6pO81R7Ln5xNWY2 + YbJOf2naWX0p6C3/9GCFnVXg6ud4eZjUj21iz6T8xsHq3CfiB3F0HB8e6zFmdjkx+LnkWI8PHKUZKQcl + ddK2sV+wgmeM6U4oosTk8pvBsRT6yz83nhKcYd8gqp/pMaAF2m7BTiCq5b8uKMZHjQ2umTGmG/lC3DtY + FKh+liVNSTkoqbPYSnvP+FTQGssY080waT81vhsvDwrO0RaML8C3jmsFhZc2DrZ6Vz/vfcEW9W1i+7hN + 3CMeFk8LJuQ8uOB4gDGmezk8qLPBDqDq51vSlJWDkjqP1XTanvwm/hXGmH7knGBrPNviXx1Ui2fivnNQ + HO16cc24anDG/Upx5Yv/c5oTec6erncxamHwn1vEdeL6Qcszzo3vGayMfzhYFf9hnBLGmG7n/ODhGbt8 + Vo/q94CkGSgHJfUCX5hZTaclFEWsjDH9CA/VKMTEF2T+k9ZhrLaz5ftn8e34ULwinh30Zt8n9gi2jK/V + In6vMAHfK/aPA+IZ8bz4QLDadmwcFycEPeT5N7BjwEKWxvQjfGfgqAkP3FaL6juGpBkpByX1BitqrLix + lfSYMMYMI3yBppL5n4Lt4fwnE2PajrHqhW/M++9N4eEAk3B257ASzoODky7+7/OLVBpj+plfBw/dtozq + e4WkGSsHJfUOVZE59/m+oDWRMcYYY8xc2LFDEUsLwUkdVw5K6i22q700WGkzxhhjjDkiqBWxdVTfHSR1 + SDkoqdco9vLQoB3bWWGMMcaY8YW+5p+JO0b1fUFSB5WDknrvskGV5VcG50f/HcYYY4wZfijYSEeF+wdt + EFeN6ruCpA4qByUNxmbxwPh8XBDGGGOMGW6YnL8jbhq0S6y+G0jqsHJQ0qDw5PwWQbumQ8MYY4wxwwtd + HmiPSD2a6vuApB4oByUN0iqxexwSbHs3xhhjTP/D33T+tt817Gsu9Vw5KGnQ1g9W038RtmQzxhhj+hn+ + htPXfN+wdZo0EOWgpMGjb/qtg56oZ4cxxhhj+hP+dr8n+FvO3/Tqb72kHioHJY3GNeOx8bk4L4wxxhjT + 3fwtvhpPjmtF9bddUo+Vg5JGhSqvO8XewR99Y4wxxnQv/I1+Ztw21o7qb7qknisHJY3WbeKjcXwYY4wx + ZvahCBx/m/kbXf3tljQg5aCkUaPQzFOCdi2nhzHGGGOmn3Pi6LAInDQi5aCk0WPr3FXj8fH7+HcYY4wx + Zjo5NV4W28a6Uf2tljRA5aAkXYwvBbvFQfHHMMYYY0x7OTc+EHeLq0T1t1nSgJWDkrSMLeKh8fH4exhj + jDGmufC3lY4qHDG7UVR/iyWNQDkoScuxTbwuDouzwhhjjDGT5Tfxltghqr+9kkakHJSkFVg9eLr/2jgu + zg9jjDHGLC5/ia/Fg8MicJL+oxyUpAXYIG4erKhzZs4YY4wxK8+F8cN4dFwt1ozq76ykESoHJWkR+HKx + V3wy/hnGGGOMqfODeFLcIuiYUv1dlTRi5aAkLcGO8az4TDhRN8YYY/4XJuavjrvEqlH9HZUkJ+iSGsf5 + dIrdHBHnhTHGGDPGsJX95/HB2CMuF9XfTUn6r3JQkibElxBW1N8Rp4St2YwxxowpZ8Sng4n5WrFKVH8v + JekSykFJasgmcbt4T5wdxhhjzNBzTDwytgg6n1R/HyWpVA5KUsOuE3vGx+JfYYwxxgwp/G37duwbu8Tl + o/p7KEkrVA5KUku2i+fHZ+P0MMYYY/oc/pbRxeSAuEPYMk3SRMpBSWrZNvHC+GacFMYYY0yfckEcFS+O + 60X1t06SFq0clKQpWCM4n/f0+En8JWzPZowxpsv5a1D89MPhirmkxpWDkjRFV4zrxj3ic/GPMMYYY7qW + P8crY+e4aqwW1d81SVqyclCSZuSm8ej4VBhjjDFdCLu8OJZ192DnV/X3S5IaUQ5K0ozRQ/2g+H5Y9d0Y + Y8y0wxlz6qS8Nu4dV4jq75UkNaoclKSO2D3ooX5knBbGGGNMm6Eeyo/j4LhlVH+bJKk15aAkdcQqsVZc + Ow6M4+LcMMYYY5rKv+Oc+F28JKiLQh/zy0T1t0mSWlMOSlIHrR83jsfHYWGMMcY0kUPj4XGj2DCqv0GS + NBXloCR12NpBBd2nxKfD1mzGGGMWGzqGfCaeGmxlv2xUf3MkaarKQUnqiZvFC+KTcUIYY4wxK8rx8bHg + b8fNo/rbIkkzUw5KUs/Qj/aZwTbFY+KMMMYYY+bCxPx7sXdcJaq/JZI0c+WgJPXQ5eJKwRnCl8Vv47yg + +I8xxpjxhW3sZ8e34sGxUfC3ovobIkmdUA5KUs9tHNvGQ4I+tvZSN8aYcYWq7G+JO8VcVfbq74UkdUo5 + KEkDsVrcOp4enDk8PYwxxgwzPIylh/nr42Fxraj+NkhSZ5WDkjRArKg/K94VtGn7WxhjjOl/josPB8eb + 7hPsoqr+DkhS55WDkjRgq8au8bagoNxpYYwxpl9hCzuF3ygO+vi4YlS/8yWpV8pBSRq4VeIKcf3YP34e + FJS7IIwxxnQ37H76WbwhWC2/Rlj4TdJglIOSNCLrx01j9zgwfhnGGGO6l+8Eq+UcWdo8LhvV73VJ6q1y + UJJGapO4W+wTFJU7NYwxxswu340D4omxc7haLmnQykFJ0n9WaJiofzR+EmeGMcaYdvPvODI+FLRJu0tc + Jqrf05I0OOWgJOm/NghW1Q8KihH9Ps4OY4wxzYT6HxR8ox4Iu5fuHLTJrH4nS9KglYOSpEvgiyJF5baO + uweT9Z8GxYrou2uMMWbxYWJ+enwi9oirBnVBnJxLGq1yUJK0XKvHVWL7eFAcEn8JY4wxC8+34glx67h2 + OCmXpCgHJUkLdsN4aDwvWAWysJwxZuzhHPmyOT/4HfmseGrsEhZ8k6RllIOSpCW5SVBY7t3xzTgpjDFm + rDkjjoiPxIuC35HV705J0sXKQUnSRNiqeYPYPygs9+s4OTyvbowZclg558Hkr4Lffa+O24cr5ZK0QOWg + JKkR68SmwfnKBwZfWCmK9M8wxpih5B/B77Zvx32Cgpr87rtSrBrV70dJUqEclCQ1jhWkG8cd4jHxxfh7 + GGNMn/OV4AEkv9vYwr5GVL8DJUkLUA5KklrFitIt44nBucz3xk/CGGO6nl/Ge+IF8bSgCnv1e06StATl + oCRpqraM+8Wb45Px3TgzjDFm1qFPOS3R+N1EAcxHxNWi+l0mSZpQOShJmolVLsY20dcEq+q/j1Pib1GF + okxVSyNjjFlKqLzO753fBBXYXxbXi7nfT9XvLklSQ8pBSdLMrResrO8YD4/3xZ/iwnBCboxpMnSY4HfL + CbFvbBdbBSvlFHqrfkdJklpQDkqSOuXyca24XbAV/sVBteRTwxhjlhoe+rF1/bFx19gl1o/q95AkaQrK + QUlSp20Uu8WjYr94Uxwexhizovw6Dgke8u0fnCffIS4T1e8aSdKUlYOSpF5ZN/aMt8dn4hvxizgrjDHj + DNvWfxvfCX4vvDVYKb96VL9HJEkdUA5KknqHFbDVYvW4atwrXhtUhKfgE1tZzwnPrxszvDAZPzv+HJwj + Z6X8U/HIuHasFfx+cKVckjquHJQk9d5lg7OkTNa3Cc6X0nOd1TRW1p2oG9P/8HNMS0Z2zTwv2ElDgbdr + xFWC+hXV7wdJUkeVg5KkwWHlbNOgKjyT9QfF8+OL8ccwxvQj/Lx+Nag98aTYI7aPjWPVqH7+JUk9UQ5K + kkbhynHroI0bxeZeERSQouDc6WGMmV3+EZwhPyw4Q/7mOCD4ed05aIPmlnVJGphyUJI0WpvFPeMF8d5g + hf378bs4P4wxzYet6ifGT4O6EZ8PVsifGOx4uXFwjrz6mZUkDUg5KEkatbmCc2vEmkEPdtoxvTu+F6zq + UYyKs+x/DwpUGTOWTFq/gZXxvwSFG5mU/yaYkD8zbhdUWb9c8PPHlnVXySVpRMpBSZKWQbGpTWLLuE7s + Ek8PVtkPjT/E38IYc+lcGKcEk/FPxsNip6CAI1XWKeZ4hfAMuSSNXDkoSdICcIadyTqF53aP+8ezg37L + H48fh5N2M7ZwFOQX8c14Z+wd94k7ByvkNwx2plQ/U5KkkSsHJUlaIlbarxk7BC2f9olXxmtirgAdbaGM + 6Xs42nF8UMCN8+IHxUuDreo8rLp9XDc4LlL9rEiSdCnloCRJLdgo7hEvi/fFZ+PrQVEsVtt/FWwDviCM + mWXOC86JnxoUSDwqKJb4raBw4ofjHcHq+A3CremSpEaUg5IktWSVuGywxZfV9nWC/uw3DarHPzeY/NBa + 6rigGN0ZcU6wddiidGYa+XnwEOn58eC4WWwRVwqqqXP/Usht9ajuc0mSlqQclCRpBqhazbl2JkJsk79+ + 3DL2CrYNvzxYtfxasLWYathU1HbCbprOL4PVcR4eeV5ckjQ15aAkSR3C9uH1YvOg4jVF6Si4xcT9QcF5 + 36fF54KVdmMmDfcROzm2jeqelCSpFeWgJEk9w3bjJwZ9pY1pIhQzfHNwFKO65yRJalw5KElSz6wfL4zT + wpimcmzQFs0icJKkqSgHJUnqkcsERbxo4eZ59OXnwuDcPoX2KlTP5/+fKpz1x1gy929lFZ3WaZtFde9J + ktSoclCSpB7ZKigg97cwl865QdGzz8d74g0XY/s2//naeH28PTjH/8dYNmOboM+FBz4nx+5R3XuSJDWq + HJQkqUceFifEWLLsZPn3wST7cfHQeEQ8Oh4TD4/7xR1i+7hu8EDjGrH1xf997v9NAT7+/6FX/ZPjk8HK + uvm//3tRbBLV/SdJUmPKQUmSeoJJ5gdjrPl6PCpoB1Zdn0nsEAfEp2PM1fF5GHJ07BnVdZIkqTHloCRJ + PUB1bfqjHxdjy1nxiaDlXHVtmsQK+2uC3vNjzrtj46iukSRJjSgHJUnquFVi5zgsxnY2+i/xumDLNQXy + quvTtLXiIfGLGGtOiv3islFdI0mSJlYOSpLUcVTVpqjZX2NM+XPQTq6NLe0rw46FR8YZMZexPRz5VmwZ + 1fWRJGli5aAkSR3GqvFu8dsYW14Zm0d1XaaBBwNUgmeL/RjDv/uguEpU10eSpImUg5IkddjVgqrlY6ow + /s/4eVC4rbom07JG3DKOirHmT0Hf/er6SJI0kXJQkqQO2ytoLTamnBZPiw2juibTxCSd/un0Vx9jzg8+ + iytGdX0kSVqyclCSpI5i9fwtMbb8JDj7PK2icCtzi/h8jDW/jntHdW0kSVqyclCSpI6iL/epMaacF7T4 + WjeqazILrKJTrG7MOTBWi+r6SJK0JOWgJEkdw4Tw5nF4jC3fi12Da1Bdm1l5bIy1WBzhHP59oro2kiQt + STkoSVLHbBDvivktvsYS/t2rRnVdZokt3j+LMefLwdGDLn4+kqQeKgclSeqQVYKq2ScEoff2mPpv0++9 + ui6zdtP4YFwYY83J8YK4QlTXSJKkRSkHJUnqkM2C885jrBrOg4jXR3VdZm31eET8NcYaPh/68d84ulLA + T5LUY+WgJEkdco84Kca4Uvub4Kx3dV264PYx1nZrc7kgnh9XjeoaSZK0YOWgJEkdsU18IMaaTwYtzapr + 0wUUr5s/QR/T0YO5/Ct4kHKHqK6RJEkLVg5KktQBtLDaP06LseZjwfn76vp0wc4xv+3dGCfoc3lRrB/V + dZIkaUHKQUmSZozCcDvFoTHmfDPuFNU16oIdgnZjcxPzMU/QjwjbrkmSJlIOSpI0Y1eOd8c/Ysz5UGwX + 1TXqguvER2LMheLmQo0EKu6z86O6VpIkrVQ5KEnSjHH2fOw9tsl+sXZU16gLtoiDYoz96avQdu1ZccWo + rpckSStUDkqSNEMbB5O+s2LseWhU16gr+KyeF6eEuSg/jRtFdb0kSVqhclCSpBlZJx4Sp4f5v/97cFTX + qSs2jH3jz2EuypnBNVkvqmsmSdJylYOSJM3IbePLYS4KDyuq69QVrKA/N1xBv2Q4nnG7qK6ZJEnLVQ5K + kjQjB8QFYS5K1yfom8QLYn6rNXNRb3RaBF4pqusmSVKpHJQkacqofH2boK2Y+V+coPc3R8Y9orpukiSV + ykFJkmbg9cH5XfO/9GGLO7se3OJ+6dB27TVxuaiunSRJl1IOSpI0RZePnePnYS6ZPkzQreK+/Hw3donq + 2kmSdCnloCRJU3TD+Hb8O8wl04ct7qygu8W9zt/ivbFZXCaqayhJ0n+Vg5IkTcnq8aA4N8yl04cJ+vPD + Cfryc2I8NTaI6hpKkvRf5aAkSVNyi/hSmDpO0Psfdob8NHaI6hpKkvRf5aAkSVPA6vk+wTZgU8cJer8z + d2yDtmtPj/Wiuo6SJP1HOShJ0hTcNr4aZvnpwwTdNmvLz9wEnf+kYNwdo7qOkiT9RzkoSVLL1ox3BSuL + Zvnp+gR9w9gv/hxmxWGS/vJg50h1LSVJcoIuSZo6Jii7xk/CrDhdn6DTIu8B8bswK8+34nZhRXdJUqkc + lCSpRZvHF8LK7StP1yfoq8T14vthVp6z4+1xuaiupyRp5MpBSZJask6w4mphuIWl6xN0XDmsJbDw/Dbu + EWtFdT0lSSNWDkqS1BJaTX0xLgiz8nR9gr5abBuHh1lYuPe/EltHdU0lSSNWDkqS1ILLBm3VLAy38HR9 + gk7bsKfGiWEWnjPjQcHPRHVdJUkjVQ5KktQCtvX+MMzC0/UJ+hbx2mDCaRaXI+IOUV1XSdJIlYOSJDWM + ldZ3hlvbF5c+TNAPir+EWXyeHtV1lSSNVDkoSVKDqFj9yKA4lllcuj5B3ySeH6eGWXy+HLeK6tpKkkao + HJQkqUGssh4aZvHp+gR943hunBJm8fl3HByrRnV9JUkjUw5KktQQ+mTfPf4YZvHpwwT9eeEEfen5Ttw4 + qusrSRqZclCSpIZsH1+Pf4ZZfLo+Qd80XhBucV96zo8PxVWiusaSpBEpByVJasDV4qXh5Hzp6cME/YXh + BH2yUGTvoXGlqK6zJGkkykFJkhrAhONXYZaePhSJcwV98vAQ63uxY1TXWZI0EuWgJEkTuEywsvqBMJPl + wVFd467gDPoB4Rn0ZrJ3rBXVtZYkjUA5KEnSBGir9uQ4LsxkeWBU17grXEFvNl+LO0R1rSVJI1AOSpI0 + gfXic3FhmMnCMYHqGncFOyUODCfozeSvcVBU11qSNALloCRJS0Q/55vHL8NMnlcEfeSra90Fc0XiTgvT + TL4cWwdHRaprLkkasHJQkqQl4kzy8+P0MJPnC3HbqK51F2wVb4tzwzSTP8S+sU5U11ySNGDloCRJS7Rt + HBpub28mXMs7RXWtu+CmcVj8O0xz+VZsFtU1lyQNWDkoSdIS7RTHhmkmFA3bPapr3QU7h7slms9P46pR + XXNJ0oCVg5IkLRETthPDNBO2uHNNq2vdBbvF+WGaydxOhJ/F1aK65pKkASsHJUlaIiZsfwnTTD4fXZ6g + 3y48f95c5ibox4QTdEkaoXJQkqQlYjv2OWGaCSvou0R1rbvACXo7cYIuSSNVDkqStER3CCdszaXrW9yd + oLcTJ+iSNFLloCRJS8QE/bwwzeSLsWtU17oLmKC7Y6L5OEGXpJEqByVJWiIm6BYNay5ucR9nnKBL0kiV + g5IkLZET9GbjBH2ccYIuSSNVDkqStERO0JuNZ9DHGSfokjRS5aAkSUvkBL3Z2GZtnHGCLkkjVQ5KkrRE + TtCbTR+KxDlBbz5O0CVppMpBSZKWyAl6s/EM+jjjBF2SRqoclCRpiZygN5uub3HfI2yr13ycoEvSSJWD + kiQtkRP0ZsMW965O0C8XT4i/hmk2vwgn6JI0QuWgJElLtHucE6aZdLmK+1Xj5XFBmGbz49giqusuSRqw + clCSpCWioNkpYZrJl2O3qK71rN0w3hX/DNNceODx4dgoqusuSRqwclCSpCXaKdiea5rJL+NhUV3rWdsh + PhIXBvn3xf9pJssfY99YN6rrLkkasHJQkqQl2iY+G257biac735ZVNd61naMj4UT9GZzbDwmLh/VdZck + DVg5KEnSEm0er4gzwjSTd0R1rWdt+/hQzE3QTTNhgv7YcIIuSSNUDkqStEQbxDPjT2Gaydujutaztm0c + Ep5BbzY/j0fEmlFdd0nSgJWDkiQt0caxf1gorrm8LaprPWs3jfeHK+jNhgk6dQecoEvSCJWDkiQtEa2h + XhVucW8uXZ6gfyDmVtA9g95MvhdU7l8tqusuSRqwclCSpCXaKt4S9kJvLl2doG8XHwwn6M3mU2EPdEka + qXJQkqQl2jDmb3F30jZ5uj5Bd4t7s3lPrBHVNZckDVw5KEnSEl0mbhP07yZO0CdPVyfoN4n3hUXiJs/8 + n5ODo7rekqQRKAclSZrAZnFEECfok6erE3R63r8znKA3mzdGdb0lSSNQDkqSNAG2uf8oTDNxBX084Vq+ + IqrrLUkagXJQkqQJbBJzK+hm8nR1gn6n+G78K0wzoXbD06O63pKkESgHJUmagBP0ZtPVCfpj4y9hmsu3 + 465RXW9J0giUg5IkTWDjYKJhmklXJ+j7hGk2b42to7rekqQRKAclSZrAleO98fcwk6erE/Tnhmk2z491 + o7rekqQRKAclSZrAWrF3/C7M5OnqBP2AMM3mybFKVNdbkjQC5aAkSYtE/3Pw3y8XD49jwkweJ+jjySOi + utaSpJEoByVJWqRlJ+iPi2PDTJ6uTtCfF6bZ8GCrutaSpJEoByVJmsDqcbc4LMzk6cME/d8XM0vPP+JB + UV1rSdJIlIOSJE2AlfQN4n1hJs+7YtWorvUsucW9ufBw4+i4fVTXWpI0EuWgJEkNOCjM5PlQrBfVNZ4l + V9Cby7nx8rhaVNdakjQS5aAkSQ14RZjJ8/W4eXRtFX1+mzUn6JPllHhArBHVtZYkjUQ5KElSA14aZvL8 + LB4Wa0Z1nWfFInHN5eS4c8wVWpQkjVQ5KElSA/aNc8JMluPiKbF2VNd5VvYP00yOj+2ius6SpBEpByVJ + asB948dhJsuv44mxVlTXeVb2CdNM+IyvF9V1liSNSDkoSVIDODf98TCT5Zfx6Lh8VNd5VvYL00yOiGtG + dZ0lSSNSDkqS1IBtghZhZrL8Ih4VXZmgc056s6A/u5k8FNf7UmwZ1fWWJI1IOShJUgO2CFutTR5W0B8T + XZmgU03+7vHdMJPntHhlbBDV9ZYkjUg5KElSA5jIPSFsvzVZujZBXy0eHseEmTw/jNtE19roSZJmoByU + JKkhFIq7IMzS08UV9AeGBQCbyadjnaiutSRpZMpBSZIacqc4KczS07UicUzQ7xWHhZk8Hw37n0uS/qMc + lCSpIbeKH4Xb3Jeerk7QfxBm8hwSq0d1rSVJI1MOSpLUkOsHE5C/hllaujhBv3dwdtpMlr8FBeI4119d + a0nSyJSDkiQ1ZL14elCp2iwtx8ZjwxX04eV38aRYJaprLUkamXJQkqSGMJnbM04Ms7QwQX9crBXVNZ42 + J+jN5ch4QHgGXZL0H+WgJEkN2ilYKTRLy9wW9y5N0HnoYpG4yfOxuGlU11mSNELloCRJDbp22JJr6fl5 + PCLWjOr6Tptn0JvLgdGVBy+SpA4oByVJatDm8YX4V5jF5xfxyOjSBJ3+9oeHWXr4eXhCVNdYkjRS5aAk + SQ3aON4bVKw2i89vgkJia0d1faeNCfrd43thlp7T48FRXWNJ0kiVg5IkNYgJ+jvi/DCLDwX2nhdXiOr6 + ThsFzXaNr4ZZen4WPOiorrEkaaTKQUmSGrRO7B2/D7Pw/Pvi/+TBBg841o/q+k4bLcH2iO+HWVouiPfE + NlFdY0nSSJWDkiQ1iAnd9eLLYRaeuQk6YbV6s6iu77RdNl4UJ4dZWs6Kh0RXettLkjqiHJQkqQWHhFla + fhRXj+q6Thtn4Sn6Z5ae0+LmUV1fSdKIlYOSJLXg7WEWnvkr6EdFlyboXwuz9LD7YLuorq8kacTKQUmS + WvD8OCPM4nN0XCOq6zptTNC/EmbpoUDcjaO6vpKkESsHJUlqwe3Cid3Swgq6E/Rh5Ox4W1w1qusrSRqx + clCSpBZQhfyVYRYfJuhbRnVdp40JugX/lp5fxwPDAnGSpEspByVJasHlgn7eZvH5aWwV1XWdNiboXwqz + tBwe20d1bSVJI1cOSpLUgsvEU8IsPpxB78qWaLe4T5ZDY6Oorq0kaeTKQUmSWvLQ+FuYxYUV9KtFdU2n + zQn6ZGH3AdewuraSpJErByVJasmd4xcxv4WYWXmYoHepzZoT9KWFAnFviDWjuraSpJErByVJagmtpT4Q + F4RZeJygDyO0V3t4rBbVtZUkjVw5KElSSzh7+6w4K8zCc0x0qYq7E/Sl5Qtxi6AeQ3VtJUkjVw5KktSS + VWK3+HOYhYcVdIvE9T9vjHWiuq6SJDlBlyRN3Y3ihDALT5eKxK0bXw2z+LwwqmsqSdJ/lIOSJLXounFU + mIWH69WVCfrmQasws7j8NZ4Z1TWVJOk/ykFJklpEsbNPxj/DLCw/iS5scV81bhM/DrO4/DYeHNV1lSTp + P8pBSZJatH48N04Os7AcHV2o4n6FeEL8PszCQ1vBz8WtorqukiT9RzkoSVKLWIW9efwgzMJCFfeto7qe + 07RhHBgW+VtcaCvI9nYecFTXVZKk/ygHJUlqGYXGPh1mYfll3CSqazlNTtCXlvPjrlFdU0mS/qsclCSp + ZavFu4Ktv2blYUv5HrFGVNdzWjiesG+cGGbh4TgHZ/eraypJ0n+Vg5IktWz1eGmcHWblYcV671gvqus5 + Lbw+W7X/GGZh+Vd8L7aL6ppKkvRf5aAkSS3jHPr9w2rgC8sZ8ZKgxVl1PaeFFfRnhyvoC8+Z8ZroSps8 + SVKHlYOSJE3BZnFwmJXnrGCSN+tK7kzQ94uTwiwsv447BLtGqmsqSdJ/lYOSJLXoMvP+O+eZzcrDUYDX + xZYx/1pOmxP0xefI6EIPe0lSD5SDkiS1aP4E/XHx1zArDivor45Zb5N2i/vic3hsFNX1lCTpEspBSZKm + 5AFxfMzFqu51OIP+8tgiqus4LRaJW3wODSfokqQFKQclSZqS28d3gkrXZvmh0JgT9P6FnQ+vjytEdT0l + SbqEclCSpCnhTPUr4+9hlh9W0GlLN+sq7hvE/kFfb7PysHp+26BrQXU9JUm6hHJQkqQpWSPY5m4/9BWn + KyvoV4nXBg8MzMrz7lg3qmspSdKllIOSJE3RLnFqmOWnKxP0reMTcUGYlefNsUpU11KSpEspByVJmqKb + xfxCcebSYcX6JTHrLe7bBFXJzcLyqqiuoyRJpXJQkqQpun58PSwUt/x05Qz69vGHMCsPreieENV1lCSp + VA5KkjRFa8WD4rdh6nRlgn6LOCXMikO7wDfGNaK6jpIklcpBSZKmbLP4Xpg6nEGn2v1Vo7p+03LzcIK+ + 8jBBf3BU11CSpOUqByVJmjL6RH8rTB0m6K+IWU/Qd4g/h1lxOK5x76iuoSRJy1UOSpI0ZUzQPxOsPJpL + 5/Q4IDaJ6vpNixP0heWcuGdU11CSpOUqByVJmrLLxb5xQphLhzZ0+8VGUV2/aXGCvvKwev6DuFVU11CS + pOUqByVJmrLLxFbxoTCXztnx2tgyqus3LTvGn8IsP6fF3rFeVNdQkqTlKgclSZqRF4e5dP4ZtKLbLqrr + Ni1M0F1BX3F+FxTTq66fJEkrVA5KkjQjbOO+MMylw/b/3aK6btPiBH3l+VVcN6rrJ0nSCpWDkiTNyGPC + LdR1zo27/v/27jtqt6q+E/hwuXSpCoIFe1dUUCyo4ChqRlGw6yhGHRIHTSLYjSVKYtdRjNGYsaMjtgSC + jTBK7CJiwyhREAWx0BUpl5bvFu7iXvhdeMtTTvl81/qsxfquy/s+Z5/nn/2effaOatxmpb2DflrIunNs + 3CKq8QOAa1WWADAn7QnxF0KumYti76jGbVZ2jVNC6lwQh8T2UY0fAFyrsgSAOdkq2jL39s61rJ1VMe8J + +m7hCfq6c1zsExtGNX4AcK3KEgDm6NFxYcjamfcT9DbpfHycGVLnE7F1VOMHANepLAFgjh4a7dxvWTvz + nqC3Zdsvj/YuvNT5UFRjBwALUpYAMEftiKpj4rKQqzLvCfod4p3R3rOWOu+JauwAYEHKEgDm6Hbx3vCk + du3Me4J+l2j3xesHdc6Il0U1dgCwIGUJAHO0aTwxTg65KvOeoO8U7wsT9DofjZ2jGjsAWJCyBIA5u018 + N+SqdGGC7gn6unNgrB/V2AHAgpQlAMxZ25Ds30OuSheWuLd3rE3Qr5k/xL5RjRsALFhZAsCcbRuHxqUh + V2TeE/Q7x/8NE/Rr5oR4VFTjBgALVpYAMGdbxCvjlyFXxAS9m7k4Do97RzVuALBgZQkAc9be5b1nHBly + RUzQu5mzYv/YMqpxA4AFK0sA6ICV0TYlkyvShU3i7OJ+zfwqPD0HYCLKEgA64m3hPfQrMu8J+l3j/WGC + vnba++dtdUE1ZgCwKGUJAB3x3DgtZP4T9DvEO+P8kCtySXw6bhXVmAHAopQlAHTEHnFEyPwn6LeMN8Z5 + IVfkt/H6uGFUYwYAi1KWANARbTf3l8RlMfa0CfpeUY3TLFjifs0cF38SG0Y1ZgCwKGUJAB3y5Lggxp5V + 8fSY12TwMdHet7YnwFU5KraParwAYNHKEgA65BFxUow9bWL8ptgxqnGatr8KWTsfj42jGi8AWLSyBIAO + 2SX+JdoS7zGnLfP/ZNwnqnGatgNCrsqZ8bfRjgOsxgsAFq0sAaBDdohXxNkx5rQJ+r/GA6Iap2lrO+rL + Vfli/I9YL6rxAoBFK0sA6JANom2O9ssYc9oE/VOxW1TjNG0m6Gvn4NgmqrECgCUpSwDomJ3ixzHmrF7i + ft+oxmjavIO+dl4c1TgBwJKVJQB0zM3i83FJjDVtgv7PMa8n6CboV+U38YyoxgkAlqwsAaBjbhBviNNj + rJn3BN0S9yvS/kh0ZDwwqnECgCUrSwDomE3jKfHDGGvaBL3tZn//qMZo2kzQr0g7TeCdcYeoxgkAlqws + AaBjVsQd4//HWLP6Cfr9ohqjaTNBvyK/j/3ielGNEwAsWVkCQAdtEh+KscYS927kD7FnVGMEAMtSlgDQ + Qe286ZfEr2OMMUGff9r75yfErlGNEQAsS1kCQEe1jbk+G2OMCfr80zYpfGPcOKoxAoBlKUsA6Kjt4+AY + Y7yDPv8cH215+8qoxggAlqUsAaCj1o+2zH2MaRP0ee7i/pwYa9rYt3wj2pn81fgAwLKVJQB02P+Oi2Ns + aZPEw+IBUY3LNG0dfxtjzeoJ+lGxTVRjBADLVpYA0GGPjLbUePWkaSyZ5wR99zgixpx2vNpbY7OoxggA + lq0sAaDDbhlvinbc1ZjSJuifjPtGNS7T0nbPf2ocF2POl+Ph0V6zqMYJAJatLAGgw9oGXY+JM2JMaRP0 + j8Y9oxqXaXp8fDPGnENix6jGBwAmoiwBoOPaOdQ/i7Hl8JjHEveHRXv/esxppwdsGNX4AMBElCUAdNxO + 8YMYW74T7Wl2NSbT9JD4txhzDopqbABgYsoSADru5vGhGNt76GfGAVGNyTS1d6+/EGNMe7Wg/THoCVGN + DQBMTFkCQMe199D3jO/GmNImi6+Oakymaa84OsaYVfHS2CqqsQGAiSlLAOiBNmH6XIwtr4tqPKapTdD/ + PcaYi2LvqMYFACaqLAGgB9qGXW2Z+6UxprwxqvGYpkfEWJ+gXxztDxTVuADARJUlAPTARvF30d7LHlPe + HNV4TFN7B/2LMba0VwpOigdFNS4AMFFlCQA9sH48Lr4RY8o8JujtCfoYJ+jnxFvjllGNCwBMVFkCQE/c + KN4dY8q8lriPcYJ+QuwW7Y9B1bgAwESVJQD0yCtiTHlTVOMwTW2TtC/F2PK9uElUYwIAE1eWANAjfxHn + xeq094aHnFk/QV8vnhnHx9jSVg1sH9W4AMDElSUA9Ehbft3eQ1+9m/vQJ+izfoK+ItpmfGfHmHJWvCWc + fw7AzJQlAPTIjvHaaOdVjyGznqBvEB+MseVr8bBo11+NCwBMXFkCQI+0J7xtN/c1l7kPOW+IahymZdP4 + ZIwth8QWUY0JAExFWQJAz+wep8UYMut30DeOMU7Q2/Fq1XgAwNSUJQD0zN2ibei1KoaeWU/Q2xLvj8Xq + DP0d/5ZfxwFRjQcATE1ZAkDP3DTahl5tY6+hZ9bvoK+MsU3Q25Fye0U1HgAwNWUJAD2zeTwtTo6hZx4T + 9I/HmPL+uEtU4wEAU1OWANAz7azuneK4GHpeH9UYTMvVl7gPPe24vgNjw6jGAwCmpiwBoIduEJ+Joacd + KVdd/7S0CfqYnqC398/3iWosAGCqyhIAeqgdB/Y38asYcl4T1fVPy9XfQR9y2ln6/xr3iGosAGCqyhIA + emj9eFC03dyHnPfFdtGW9VfjMGltgn5ojCFnxoti26jGAgCmqiwBoKfabu4fiSHnG/HoaBPnagwmbUwT + 9HaW/qNiRVRjAQBTVZYA0FPtKfpbY8j5j/jzmNUmZpvEWN5BPyl2jmocAGDqyhIAeuyFcU4MNcfHfjGr + CfqN4tMx9LTz3Y+OW0Q1DgAwdWUJAD12/zgihprvxL7Rdlevrn+S2lLve8WXY+j5eTwv2pn61VgAwNSV + JQD0WFuS/ZdxSQwx7az3p8QsJugbx+Pj+zH0HBm3jmocAGAmyhIAem6vGOoy9+9Ge4I+iyXuW8RfxE9j + yGnL2z8Qs/ijBwCsU1kCQM/tET+OIaY9QX9qzGIyuVW0Y8fa8u8h53cx6/PlAeAayhIAem6X+FysiqFl + 9Tvos3iCPpYJelshsH9UYwAAM1OWANBz28Xz47cxtMx6gn5g/CyGnE/FrlGNAQDMTFkCwAC0p+g/iaGl + TdBntcR9y3hutPPBh5yXx6yOrQOAdSpLABiAm8f3Ymhp1/S0mMWEsk3Qh/4E/exo41ldPwDMVFkCwABs + H4fFpTGktCfoszpmbegT9HYU3xejbSpYXT8AzFRZAsAAtCPCXhqnxpBybDwxZrWLe3uX/+QYYs6Pt8dt + orp+AJipsgSAAVg/2nvoR8WQ4h30yaUdr/as2Dyq6weAmSpLABiINkn/YAwpbbn582IW76BvFn8ZQ52g + /zoeGNW1A8DMlSUADMjb4rIYSs6Ld0d7ul1d7yRdP14XbSI7tLS9Cb4Ud4jq2gFg5soSAAakLWEeynFr + q//Q0N5Dv29U1zsp68We8e24OIaWU+KFsU1U1w8AM1eWADAg7Qnp+2JIaU/Rj4i2+/iKqK57ue4an4lV + McQcF2382msQ1fUDwMyVJQAMSJuAtXe2h5hPR3vKPelJZvujxntjyPl63Cqq6weAuShLABiYZ8TQzkNf + nc/GQ2MSu7q3Ze23jbbioJ0RPsS01wTakv1PRTuKrxoHAJiLsgSAgdkrfhpDTJtIfzkeEZtGdf0LsTIe + EEfGUJe1r86P49kxi6PqAGDByhIABqY9Ff6H+EMMMW11wHfj+XHTqMbg2mwS7Wz1tiHckHa8X1faCoGl + jBMATFVZAsDAbBSPjSEeF7ZmTo73xJPiJlGNxZquF+3fvjN+EGPJq6IaDwCYq7IEgAHaJU6KMeT7cXD8 + abRl67eOG0V7atw2gNs9Hhdtotr+7ZoZ+hP0i6KtNKi+IwAwV2UJAAPUlrl/NcawhHt1zo32fvrfx6vj + tdGesH8lzoixpd37tlKg/XGi+o4AwFyVJQAM0HbxhvhtjCltUnpBtPfvmwuv7MaYtvndO+J2UX1HAGCu + yhIABqjtUn6PaE+PZZxpf6DYN+zeDkAnlSUADNTGcVjIOHNmPCiq7wYAzF1ZAsBAtafoh8RYl3iPOe28 + +G9FW0VRfTcAYO7KEgAGav14WfwmZFw5K94SCzl+DgDmoiwBYMDaEucjQ8aV/4xHxYZRfS8AYO7KEgAG + 7HrRjhuTceVrsWNU3wkA6ISyBICBOyBkXGmbA24e1fcBADqhLAFg4P40Tg8ZR06KA2OTqL4PANAJZQkA + A7drfCIuDhl+Do1bRvVdAIDOKEsAGLjN4lnx+5Dhp+3eXn0PAKBTyhIARmCPODNk2Dk3XhTVdwAAOqUs + AWAEdo4TQoaddo+fFtV3AAA6pSwBYARuEm+Pc0KGm49E+2NM9R0AgE4pSwAYgfXiPvHtkGHmstg/1o/q + OwAAnVKWADASW8ZnQoaZ38Ujo7r3ANA5ZQkAI9HOxf5AXBIyrFwUR8UuUd17AOicsgSAkWgT9DfG2SHD + yunx/NgmqnsPAJ1TlgAwEhvEY+LrIcPKSbF7VPcdADqpLAFgRDaPvw8ZRtrGcC3/EbeN6p4DQCeVJQCM + zEtj9cROhpH2/vmNo7rfANBJZQkAI/Ok+HGYpA8jJ8YBcb2o7jcAdFJZAsDI3Ds+EZeG9D+fjltFO+u+ + ut8A0EllCQAjs0O8KlaF9DvtjyzvCpNzAHqnLAFghJ4Q7exs6XdOjQOjuscA0GllCQAjtGecFdLvtOXt + D4zqHgNAp5UlAIzQjvHWOD2kvzkotozqHgNAp5UlAIxQe2d55zg+pL/5s6juLwB0XlkCwEhtF98K6WdO + i8dEdW8BoPPKEgBGatv4Qkj/cmG0o/J2iereAkDnlSUAjFR7d/ktcUZIv9Lu2V/F1lHdWwDovLIEgJFa + GXePz4T0KyfHbuH8cwB6qywBYOT+T0i/8r24TVT3EwB6oSwBYOReHu2dZulHzol/iB2iup8A0AtlCQAj + 95T4QUg/8vW4d6yI6n4CQC+UJQCM3K7x0ZB+5LDYJKp7CQC9UZYAMHJbxItDup+L4x/D5nAA9F5ZAgCX + PyHOD+l2ToznhOXtAPReWQIAlz8gvhmXhHQ3h0Y7Gq+6hwDQK2UJAFx+4zgozgrpbtqO+56eAzAIZQkA + XL4yHhenhnQz58b/iur+AUDvlCUA8Ef3ip+FdC9tc7jPRXsVobp3ANA7ZQkA/NEt4ujwHnr3cl68NLaN + 6t4BQO+UJQDwR1vG8+LkkG7l9/Hk8P45AINRlgDAH7WztW8anw7pVn4Te0R13wCgl8oSAFjLh0K6kwvi + sLhdVPcLAHqpLAGAtRwcq0K6kRPisbFZVPcLAHqpLAGAtewfJ4Z0I18Im8MBMDhlCQCs5e7xkZD5px2v + 1u6Fp+cADE5ZAgBrWRkHhsw/P4+XxEZR3SsA6K2yBACu4anRjvaS+eZrsU+sH9V9AoDeKksA4Bp2i8+G + zeLmm0PiFtGOwKvuEwD0VlkCANewTbwgzg2ZX14bJucADFJZAgDX0CaFj46zQuaT02K/qO4PAPReWQIA + pXtFmyTK7HNJvDd2iureAEDvlSUAULp5fDxsFjf7XBD7xoZR3RsA6L2yBABKm8becXzIbHNi3D+q+wIA + g1CWAMA6XT8+FzK7tKfnh8bto7onADAIZQkArNNG0Za5y+xyauwfW0V1TwBgEMoSAFinDeJtcX7IbPKD + 2CUcrwbAoJUlALBOK+LJ8e2Q2eQrsUNU9wMABqMsAYBrdeN4d8j0c16049Usbwdg8MoSALhOLw2Zfn4Y + z4yNo7oPADAYZQkAlNZ8B/qp8YuQ6ebwuFOseR8AYJDKEgC4TneJtvT6opDp5eBYGdU9AIBBKUsA4Dq1 + 49aeHueETCfteLXnRDX+ADA4ZQkALMgD45ch08n7485RjT0ADE5ZAgALsnO049YuC5ls2pjuF9W4A8Ag + lSUAsCA3jbfF2SGTzW9jr6jGHQAGqSwBgAVpm5fdN74XMrlcGIfF3aMadwAYpLIEABZs6zgqZHI5I54X + 149qzAFgkMoSAFiwzeLdcV7IZHJi3D9WRDXmADBIZQkALFg7bu3ZcULIZHJs3Cyq8QaAwSpLAGDB2lPe + PeLfQpafP8T7YruoxhsABqssAYBF2Sb+KWT5OSYeGm0DvmqsAWCwyhIAWLTXhyw/n4hNoxpjABi0sgQA + Fu0JcXxcFrK0XBr/GNX4AsDglSUAsGjtnemXxSUhS8tp8YKoxhcABq8sAYAleUT8LmRpOTweENXYAsDg + lSUAsCT3ix+FLC0viU2iGlsAGLyyBACW5G5xRFwUsvjsF9W4AsAolCUAsCTbxvPj1yELz8XxzXhwVOMK + AKNQlgDAkt09LHNfXM6NZ0c7T74aUwAYhbIEAJbsRvGlcNzadWf1GP0y7hHVeALAaJQlALBkW8ab4rch + C8tX4tZRjScAjEZZAgBLtjIeEm3SKdedM+PNccOoxhMARqMsAYBl2ToODbnuHBf/PTaKaiwBYDTKEgBY + trfFqpBrTzuWbvOoxhAARqUsAYBle3K0p8Oy7rTj1d4VG0Q1hgAwKmUJACzb9eM1IevOsfGkWBHVGALA + qJQlADAR+0Z7Six1Phi3jWrsAGB0yhIAmIjHxlkhdd4Sm0U1dgAwOmUJAEzE7vG1uDRk7VwUL4hq3ABg + lMoSAJiIG8Ur4pyQq9L+YHF0PDSqcQOAUSpLAGAi1o92xvcpIVflvNg/tohq3ABglMoSAJiY28ePQq7K + BdH+cFGNFwCMVlkCABOzfbw/fhdy+eWr4juxS1TjBQCjVZYAwMRsGHvGN0Muv/y0eElsG9V4AcBolSUA + MFHtKLEPh1x++fdjt1gvqrECgNEqSwBg4t4Q58fY01YS3DiqMQKAUStLAGCi2tPi58UvY8z5fXwgNo9q + nABg1MoSAJi4tmv552PM+WrsFRtENUYAMGplCQBM3CZxUIw574qNoxofABi9sgQApuJZcVGMNa+LalwA + gChLAGAqHhbfiktjTLksvh1PiGpcAIAoSwBgKm4eb4qx7eZ+Sbw5doxqXACAKEsAYCpWxuPj7Bhb9osV + UY0LABBlCQBMzT3jpBhTzo22e3s1HgDAlcoSAJiatsz9w3FejCEXxGGxU1TjAQBcqSwBgKlpx4ztGd+L + MeRnsXdsGtV4AABXKksAYOLWu1L77y3iqBhDfhw2hwOABShLAGDi1pygbxZt2ffQ05a3fy62j6uPBwBw + NWUJAExVW+bejh1rm6cNOT+Mtnv7JlGNAwCwhrIEAKZq/dgnvhZDzhFxu1i9cgAAuBZlCQBM3Tbx9hhy + PhQbRXX9AMDVlCUAMBOvjKHm7Hh1VNcNABTKEgCYiafFL+KyGFraJnj3j+q6AYBCWQIAM3HT+LtYFUPL + AbEiqusGAAplCQDMzCPivBhanhrV9QIA61CWAMDM3Dt+GkPJRfHlsLwdABapLAGAmbltfCTOjyHkzHhe + tF3qq+sFANahLAGAmdk8nhInxRDyq3hwVNcKAFyLsgQAZuqWcWz0Oat3oj8h7hTVdQIA16IsAYCZasvB + vxB9Tzv7/D2xfVTXCQBci7IEAGZqi3hXnBt9ztejbQ63YVTXCQBci7IEAGaqTWgfE8dEn3NYbBDVNQIA + 16EsAYCZu2F8OPqaP0RbBbBeVNcHAFyHsgQA5uJNsXqztb7lK7FPVNcFACxAWQIAc/H0+HH0Me8Im8MB + wDKUJQAwFzvGG6OPT9FfFpa3A8AylCUAMDdPir5N0E+P9vS/uh4AYIHKEgCYmz+JX0ZfJukXxvvjrlFd + DwCwQGUJAMzN7aNNeM+LPuTs2DvWj+p6AIAFKksAYG42jifHqdGHnBG7RnUtAMAilCUAMFd3ixOj62lP + +Q+PW0d1HQDAIpQlADBXN4tvRtfz09g3rhfVdQAAi1CWAMBcbR3tuLW2fLzLOSbuFNU1AACLVJYAwFyt + iPvG0dHFrN5h/vOxVVTXAAAsUlkCAHO3SbTd3LuaX8drYsOoPj8AsEhlCQB0Qlvmviq6mE9FO/t8vag+ + OwCwSGUJAHTCn8V/Rhfzuqg+MwCwRGUJAHTCXeKD0bW049VeENVnBgCWqCwBgE5YPw6MLuWSaGefPyCq + zwwALFFZAgCd8cQ4O7qSC+P5sUVUnxcAWKKyBAA64x7RnlhfFF1I27TucVF9VgBgGcoSAOiM9qT6GfHb + mHfa+ecnheXtADAFZQkAdMrd4ocx75wVb46bRfU5AYBlKEsAoFPahPiwmPeZ6MfHPaNtXld9TgBgGcoS + AOiUreKFcUrMM8fGtlF9RgBgmcoSAOiUldE2i/tazCtnxj+F3dsBYErKEgDonOvFP8e88tV4eGwQ1ecD + AJapLAGAzmnvfb8ufh/zyEdih6g+GwAwAWUJAHTSg+PImEcOjvWi+lwAwASUJQDQSW2Z+0Ex6/w89o/q + MwEAE1KWAEBnPTPOjVnlsnhH3DaqzwMATEhZAgCd9ZBoG7ZdGrPKU6P6LADABJUlANBZN4u2WdwFMe20 + p+fnxF5RfRYAYILKEgDorLab+97RJs7TznlxSNwxqs8CAExQWQIAnbPmDur3ilNi2jk1nhIbx5qfBQCY + grIEADpnzQn6neKLcXFMI21pe8vPYpdY83MAAFNSlgBAp20Xr4rfxDTSJuhtE7qvx82j+gwAwISVJQDQ + aStij/h+TCu/iL+OLaP6DADAhJUlANB528dRMa0cHjtG+2NA9fsBgAkrSwCg8zaJg2Nau7m/L6rfCwBM + SVkCAJ23MvaMo2PS+VH8eVS/FwCYkrIEAHpho3hrTDpvjB2i+p0AwJSUJQDQGy+KSR631nZwf2ZUvwsA + mKKyBAB6Y584NlafXb7cnByPjOp3AQBTVJYAQG/cKtpmcZfEcnNRfCzuHtXvAgCmqCwBgN7YMNqS9Atj + uTk9nhFbRfW7AIApKksAoFfabu6nxnJzSnh6DgBzUpYAQK/cMQ6N82OpuTSOidtE9TsAgCkrSwCgV9px + aw+Pn8RSc2IcEFtG9TsAgCkrSwCgd24U7Qn4UnNU3DTWi+rnAwBTVpYAQO9cP/4lVsVS0pbIVz8XAJiR + sgQAemezeHH8PBabc+M1sTKqnw0AzEBZAgC9syLuFUfGYvPp2D2qnwsAzEhZAgC9tHG8MxabV0X7f6uf + CQDMSFkCAL11YPwmFpoL4llR/SwAYIbKEgDorZ3jkFhILo5Pxq5R/SwAYIbKEgDotWfGQnJOPCqqnwEA + zFhZAgC99uj4XVxXTo57RPUzAIAZK0sAoNfuF1+JtoR9XbkwjojbRvUzAIAZK0sAoNd2iL+JtoR9XWnn + pT87tojqZwAAM1aWAECvtTPRHxKnxLry7bhjVP8/ADAHZQkA9F5bun5sVLkkDo/No/p/AYA5KEsAoPdu + EG+J0+Pq+Uk8NzaI6v8FAOagLAGA3lsZd4qj4ur5cNw81ovq/wUA5qAsAYDBeGesmUvjlVH9WwBgjsoS + ABiMv44zYnV+Ec+I6t8CAHNUlgDAYDw+jonV+X+xS1T/FgCYo7IEAAajTcYPjZbz45lhczgA6KCyBAAG + Y7N4cZwYH4u7RPXvAIA5K0sAYFB2i4Pif8a2V3YAQMeUJQAwKG1Sft+4T2x9ZQcAdExZAgCDsnncLu4c + W1zZAQAdU5YAAADAbJUlAAAAMFtlCQAAAMxWWQIAAACzVZYAAADAbJUlAAAAMFtlCQAAAMxWWQIAAACz + VZYAAADAbJUlAAAAMFtlCQAAAMxWWQIAAACzVZYAAADAbJUlAAAAMFtlCQAAAMzS5f/tvwCvQ4cFMIdy + 9gAAAABJRU5ErkJggg== + + + \ No newline at end of file diff --git a/Dalamud/Resources/eye.png b/Dalamud/Resources/eye.png new file mode 100644 index 000000000..5154d00df Binary files /dev/null and b/Dalamud/Resources/eye.png differ diff --git a/Dalamud/Settings/PersistentSettings.cs b/Dalamud/Settings/PersistentSettings.cs new file mode 100644 index 000000000..243202586 --- /dev/null +++ b/Dalamud/Settings/PersistentSettings.cs @@ -0,0 +1,50 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using Newtonsoft.Json; + +namespace Dalamud.Settings +{ + public class PersistentSettings { + private static PersistentSettings _instance = null; + + private static readonly string ConfigPath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "settings.json"); + + public static PersistentSettings Instance { + get { + if (_instance == null) { + if (!File.Exists(ConfigPath)) { + _instance = new PersistentSettings(); + return _instance; + } + + _instance = JsonConvert.DeserializeObject(File.ReadAllText(ConfigPath)); + } + + return _instance; + } + } + + public class FateInfo { + public string Name { get; set; } + public int Id { get; set; } + } + + public List Fates; + + public List BadWords; + + public void Save() { + File.WriteAllText(ConfigPath, JsonConvert.SerializeObject(this)); + } + + public static void Reset() { + _instance = new PersistentSettings(); + Instance.Save(); + } + } +} diff --git a/Dalamud/XivApi.cs b/Dalamud/XivApi.cs new file mode 100644 index 000000000..6515541a5 --- /dev/null +++ b/Dalamud/XivApi.cs @@ -0,0 +1,86 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net.Http; +using System.Text; +using System.Threading.Tasks; +using Microsoft.CSharp.RuntimeBinder; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; + +namespace Dalamud +{ + class XivApi + { + private const string URL = "http://xivapi.com/"; + + private static readonly Dictionary cachedResponses = new Dictionary(); + + public static async Task GetWorld(int world) + { + var res = await Get("World/" + world); + + return res; + } + + public static async Task GetClassJob(int id) + { + var res = await Get("ClassJob/" + id); + + return res; + } + + public static async Task GetFate(int id) + { + var res = await Get("Fate/" + id); + + return res; + } + + public static async Task GetCharacterSearch(string name, string world) + { + var res = await Get("character/search" + $"?name={name}&server={world}"); + + return res; + } + + public static async Task GetContentFinderCondition(int contentFinderCondition) { + return await Get("ContentFinderCondition/" + contentFinderCondition); + } + + public static async Task Search(string query, string indexes, int limit = 100) { + query = System.Net.WebUtility.UrlEncode(query); + + return await Get("search" + $"?string={query}&indexes={indexes}&limit={limit}"); + } + + public static async Task GetMarketInfoWorld(int itemId, string worldName) { + return await Get($"market/{worldName}/item/{itemId}", true); + } + + public static async Task GetMarketInfoDc(int itemId, string dcName) { + return await Get($"market/item/{itemId}?dc={dcName}", true); + } + + public static async Task GetItem(int itemId) { + return await Get($"Item/{itemId}", true); + } + + public static async Task Get(string endpoint, bool noCache = false) + { + if (cachedResponses.ContainsKey(endpoint) && !noCache) + return cachedResponses[endpoint]; + + var client = new HttpClient(); + var response = await client.GetAsync(URL + endpoint); + var result = await response.Content.ReadAsStringAsync(); + + var obj = JObject.Parse(result); + + if (!noCache) + cachedResponses.Add(endpoint, obj); + + return obj; + } + } +} diff --git a/LICENSE b/LICENSE new file mode 100644 index 000000000..946b95d8d --- /dev/null +++ b/LICENSE @@ -0,0 +1,84 @@ +AFFERO GENERAL PUBLIC LICENSE +Version 1, March 2002

Copyright © 2002 Affero Inc.
510 Third Street - Suite 225, San Francisco, CA 94107, USA +This license is a modified version of the GNU General Public License copyright (C) 1989, 1991 Free Software Foundation, Inc. made with their permission. Section 2(d) has been added to cover use of software over a computer network. + +Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. + +Preamble + +The licenses for most software are designed to take away your freedom to share and change it. By contrast, the Affero General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This Public License applies to most of Affero's software and to any other program whose authors commit to using it. (Some other Affero software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. + +When we speak of free software, we are referring to freedom, not price. This General Public License is designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. + +To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. + +For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. + +We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. + +Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. + +Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. + +The precise terms and conditions for copying, distribution and modification follow. + +TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + +0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this Affero General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. + +1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. + +You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. + +2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions:
 +a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change.
 +b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License.
 +c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.)
 +d) If the Program as you received it is intended to interact with users through a computer network and if, in the version you received, any user interacting with the Program was given the opportunity to request transmission to that user of the Program's complete source code, you must not remove that facility from your modified version of the Program or work based on the Program, and must offer an equivalent opportunity for all users interacting with your Program through a computer network to request immediate transmission by HTTP of the complete source code of your modified version or other derivative work. + +These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. + +3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following:
 +a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or,
 +b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or,
 +c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. + +If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. + +4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. + +5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. + +6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. + +7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. + +This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. + +8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. + +9. Affero Inc. may publish revised and/or new versions of the Affero General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by Affero, Inc. If the Program does not specify a version number of this License, you may choose any version ever published by Affero, Inc. + +You may also choose to redistribute modified versions of this program under any version of the Free Software Foundation's GNU General Public License version 3 or higher, so long as that version of the GNU GPL includes terms and conditions substantially equivalent to those of this license. + +10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by Affero, Inc., write to us; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. + +NO WARRANTY + +11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + +12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. diff --git a/README.md b/README.md new file mode 100644 index 000000000..71c0ab4d6 --- /dev/null +++ b/README.md @@ -0,0 +1,5 @@ +# Dalamud + +FFXIV Hooking framework for [FFXIVQuickLauncher](https://github.com/goaaats/FFXIVQuickLauncher). + +Thanks to Mino, whose work has made this possible! \ No newline at end of file diff --git a/Resources/EasyHook32.dll b/Resources/EasyHook32.dll new file mode 100644 index 000000000..135609b46 Binary files /dev/null and b/Resources/EasyHook32.dll differ diff --git a/Resources/EasyHook32Svc.exe b/Resources/EasyHook32Svc.exe new file mode 100644 index 000000000..0d470eca4 Binary files /dev/null and b/Resources/EasyHook32Svc.exe differ diff --git a/Resources/EasyHook64.dll b/Resources/EasyHook64.dll new file mode 100644 index 000000000..4fb1331aa Binary files /dev/null and b/Resources/EasyHook64.dll differ diff --git a/Resources/EasyHook64Svc.exe b/Resources/EasyHook64Svc.exe new file mode 100644 index 000000000..770663386 Binary files /dev/null and b/Resources/EasyHook64Svc.exe differ diff --git a/Resources/EasyLoad32.dll b/Resources/EasyLoad32.dll new file mode 100644 index 000000000..5b30daaa7 Binary files /dev/null and b/Resources/EasyLoad32.dll differ diff --git a/Resources/EasyLoad64.dll b/Resources/EasyLoad64.dll new file mode 100644 index 000000000..1696334ff Binary files /dev/null and b/Resources/EasyLoad64.dll differ diff --git a/docs/.nojekyll b/docs/.nojekyll new file mode 100644 index 000000000..e69de29bb diff --git a/docs/api/Dalamud.Game.Chat.EnumExtensions.html b/docs/api/Dalamud.Game.Chat.EnumExtensions.html new file mode 100644 index 000000000..75b03147c --- /dev/null +++ b/docs/api/Dalamud.Game.Chat.EnumExtensions.html @@ -0,0 +1,208 @@ + + + + + + + + Class EnumExtensions + + + + + + + + + + + + + + + + +
+
+ + + + +
+ + + +
+ + + + + + diff --git a/docs/api/Dalamud.Game.Chat.SeString.IntegerType.html b/docs/api/Dalamud.Game.Chat.SeString.IntegerType.html new file mode 100644 index 000000000..934254c29 --- /dev/null +++ b/docs/api/Dalamud.Game.Chat.SeString.IntegerType.html @@ -0,0 +1,155 @@ + + + + + + + + Enum SeString.IntegerType + + + + + + + + + + + + + + + + +
+
+ + + + +
+ + + +
+ + + + + + diff --git a/docs/api/Dalamud.Game.Chat.SeString.PlayerLinkType.html b/docs/api/Dalamud.Game.Chat.SeString.PlayerLinkType.html new file mode 100644 index 000000000..d685948ef --- /dev/null +++ b/docs/api/Dalamud.Game.Chat.SeString.PlayerLinkType.html @@ -0,0 +1,139 @@ + + + + + + + + Enum SeString.PlayerLinkType + + + + + + + + + + + + + + + + +
+
+ + + + +
+ + + +
+ + + + + + diff --git a/docs/api/Dalamud.Game.Chat.SeString.SeStringPayloadContainer.html b/docs/api/Dalamud.Game.Chat.SeString.SeStringPayloadContainer.html new file mode 100644 index 000000000..dca8b5f38 --- /dev/null +++ b/docs/api/Dalamud.Game.Chat.SeString.SeStringPayloadContainer.html @@ -0,0 +1,200 @@ + + + + + + + + Class SeString.SeStringPayloadContainer + + + + + + + + + + + + + + + + +
+
+ + + + +
+ + + +
+ + + + + + diff --git a/docs/api/Dalamud.Game.Chat.SeString.SeStringPayloadType.html b/docs/api/Dalamud.Game.Chat.SeString.SeStringPayloadType.html new file mode 100644 index 000000000..af4dc37a6 --- /dev/null +++ b/docs/api/Dalamud.Game.Chat.SeString.SeStringPayloadType.html @@ -0,0 +1,139 @@ + + + + + + + + Enum SeString.SeStringPayloadType + + + + + + + + + + + + + + + + +
+
+ + + + +
+ + + +
+ + + + + + diff --git a/docs/api/Dalamud.Game.Chat.SeString.html b/docs/api/Dalamud.Game.Chat.SeString.html new file mode 100644 index 000000000..31f822d93 --- /dev/null +++ b/docs/api/Dalamud.Game.Chat.SeString.html @@ -0,0 +1,281 @@ + + + + + + + + Class SeString + + + + + + + + + + + + + + + + +
+
+ + + + +
+ + + +
+ + + + + + diff --git a/docs/api/Dalamud.Game.Chat.XivChatEntry.html b/docs/api/Dalamud.Game.Chat.XivChatEntry.html new file mode 100644 index 000000000..809a45d4f --- /dev/null +++ b/docs/api/Dalamud.Game.Chat.XivChatEntry.html @@ -0,0 +1,275 @@ + + + + + + + + Class XivChatEntry + + + + + + + + + + + + + + + + +
+
+ + + + +
+ + + +
+ + + + + + diff --git a/docs/api/Dalamud.Game.Chat.XivChatType.html b/docs/api/Dalamud.Game.Chat.XivChatType.html new file mode 100644 index 000000000..49ca734cd --- /dev/null +++ b/docs/api/Dalamud.Game.Chat.XivChatType.html @@ -0,0 +1,246 @@ + + + + + + + + Enum XivChatType + + + + + + + + + + + + + + + + +
+
+ + + + +
+ + + +
+ + + + + + diff --git a/docs/api/Dalamud.Game.Chat.XivChatTypeExtensions.html b/docs/api/Dalamud.Game.Chat.XivChatTypeExtensions.html new file mode 100644 index 000000000..865e2d463 --- /dev/null +++ b/docs/api/Dalamud.Game.Chat.XivChatTypeExtensions.html @@ -0,0 +1,192 @@ + + + + + + + + Class XivChatTypeExtensions + + + + + + + + + + + + + + + + +
+
+ + + + +
+ + + +
+ + + + + + diff --git a/docs/api/Dalamud.Game.Chat.XivChatTypeInfoAttribute.html b/docs/api/Dalamud.Game.Chat.XivChatTypeInfoAttribute.html new file mode 100644 index 000000000..922e0246d --- /dev/null +++ b/docs/api/Dalamud.Game.Chat.XivChatTypeInfoAttribute.html @@ -0,0 +1,326 @@ + + + + + + + + Class XivChatTypeInfoAttribute + + + + + + + + + + + + + + + + +
+
+ + + + +
+ + + +
+ + + + + + diff --git a/docs/api/Dalamud.Game.Chat.html b/docs/api/Dalamud.Game.Chat.html new file mode 100644 index 000000000..32a18eae7 --- /dev/null +++ b/docs/api/Dalamud.Game.Chat.html @@ -0,0 +1,137 @@ + + + + + + + + Namespace Dalamud.Game.Chat + + + + + + + + + + + + + + + + +
+
+ + + + +
+ + + +
+ + + + + + diff --git a/docs/api/Dalamud.Game.ChatHandlers.html b/docs/api/Dalamud.Game.ChatHandlers.html new file mode 100644 index 000000000..4c8dd811c --- /dev/null +++ b/docs/api/Dalamud.Game.ChatHandlers.html @@ -0,0 +1,204 @@ + + + + + + + + Class ChatHandlers + + + + + + + + + + + + + + + + +
+
+ + + + +
+ + + +
+ + + + + + diff --git a/docs/api/Dalamud.Game.ClientState.Actors.ActorTable.html b/docs/api/Dalamud.Game.ClientState.Actors.ActorTable.html new file mode 100644 index 000000000..04317149b --- /dev/null +++ b/docs/api/Dalamud.Game.ClientState.Actors.ActorTable.html @@ -0,0 +1,401 @@ + + + + + + + + Class ActorTable + + + + + + + + + + + + + + + + +
+
+ + + + +
+ + + +
+ + + + + + diff --git a/docs/api/Dalamud.Game.ClientState.Actors.ObjectKind.html b/docs/api/Dalamud.Game.ClientState.Actors.ObjectKind.html new file mode 100644 index 000000000..7f0b70d01 --- /dev/null +++ b/docs/api/Dalamud.Game.ClientState.Actors.ObjectKind.html @@ -0,0 +1,208 @@ + + + + + + + + Enum ObjectKind + + + + + + + + + + + + + + + + +
+
+ + + + +
+ + + +
+ + + + + + diff --git a/docs/api/Dalamud.Game.ClientState.Actors.Position3.html b/docs/api/Dalamud.Game.ClientState.Actors.Position3.html new file mode 100644 index 000000000..4e8f9babd --- /dev/null +++ b/docs/api/Dalamud.Game.ClientState.Actors.Position3.html @@ -0,0 +1,214 @@ + + + + + + + + Struct Position3 + + + + + + + + + + + + + + + + +
+
+ + + + +
+ + + +
+ + + + + + diff --git a/docs/api/Dalamud.Game.ClientState.Actors.Resolvers.ClassJob.html b/docs/api/Dalamud.Game.ClientState.Actors.Resolvers.ClassJob.html new file mode 100644 index 000000000..386ddb1c9 --- /dev/null +++ b/docs/api/Dalamud.Game.ClientState.Actors.Resolvers.ClassJob.html @@ -0,0 +1,235 @@ + + + + + + + + Class ClassJob + + + + + + + + + + + + + + + + +
+
+ + + + +
+ + + +
+ + + + + + diff --git a/docs/api/Dalamud.Game.ClientState.Actors.Resolvers.World.html b/docs/api/Dalamud.Game.ClientState.Actors.Resolvers.World.html new file mode 100644 index 000000000..280a696a6 --- /dev/null +++ b/docs/api/Dalamud.Game.ClientState.Actors.Resolvers.World.html @@ -0,0 +1,235 @@ + + + + + + + + Class World + + + + + + + + + + + + + + + + +
+
+ + + + +
+ + + +
+ + + + + + diff --git a/docs/api/Dalamud.Game.ClientState.Actors.Resolvers.html b/docs/api/Dalamud.Game.ClientState.Actors.Resolvers.html new file mode 100644 index 000000000..e7bc2f925 --- /dev/null +++ b/docs/api/Dalamud.Game.ClientState.Actors.Resolvers.html @@ -0,0 +1,121 @@ + + + + + + + + Namespace Dalamud.Game.ClientState.Actors.Resolvers + + + + + + + + + + + + + + + + +
+
+ + + + +
+ + + +
+ + + + + + diff --git a/docs/api/Dalamud.Game.ClientState.Actors.Types.Actor.html b/docs/api/Dalamud.Game.ClientState.Actors.Types.Actor.html new file mode 100644 index 000000000..fb67235cd --- /dev/null +++ b/docs/api/Dalamud.Game.ClientState.Actors.Types.Actor.html @@ -0,0 +1,314 @@ + + + + + + + + Class Actor + + + + + + + + + + + + + + + + +
+
+ + + + +
+ + + +
+ + + + + + diff --git a/docs/api/Dalamud.Game.ClientState.Actors.Types.Chara.html b/docs/api/Dalamud.Game.ClientState.Actors.Types.Chara.html new file mode 100644 index 000000000..4db9af91a --- /dev/null +++ b/docs/api/Dalamud.Game.ClientState.Actors.Types.Chara.html @@ -0,0 +1,356 @@ + + + + + + + + Class Chara + + + + + + + + + + + + + + + + +
+
+ + + + +
+ + + +
+ + + + + + diff --git a/docs/api/Dalamud.Game.ClientState.Actors.Types.NonPlayer.BattleNpc.html b/docs/api/Dalamud.Game.ClientState.Actors.Types.NonPlayer.BattleNpc.html new file mode 100644 index 000000000..090c6759f --- /dev/null +++ b/docs/api/Dalamud.Game.ClientState.Actors.Types.NonPlayer.BattleNpc.html @@ -0,0 +1,273 @@ + + + + + + + + Class BattleNpc + + + + + + + + + + + + + + + + +
+
+ + + + +
+ + + +
+ + + + + + diff --git a/docs/api/Dalamud.Game.ClientState.Actors.Types.NonPlayer.BattleNpcSubKind.html b/docs/api/Dalamud.Game.ClientState.Actors.Types.NonPlayer.BattleNpcSubKind.html new file mode 100644 index 000000000..44ed99789 --- /dev/null +++ b/docs/api/Dalamud.Game.ClientState.Actors.Types.NonPlayer.BattleNpcSubKind.html @@ -0,0 +1,151 @@ + + + + + + + + Enum BattleNpcSubKind + + + + + + + + + + + + + + + + +
+
+ + + + +
+ + + +
+ + + + + + diff --git a/docs/api/Dalamud.Game.ClientState.Actors.Types.NonPlayer.Npc.html b/docs/api/Dalamud.Game.ClientState.Actors.Types.NonPlayer.Npc.html new file mode 100644 index 000000000..34897cb44 --- /dev/null +++ b/docs/api/Dalamud.Game.ClientState.Actors.Types.NonPlayer.Npc.html @@ -0,0 +1,244 @@ + + + + + + + + Class Npc + + + + + + + + + + + + + + + + +
+
+ + + + +
+ + + +
+ + + + + + diff --git a/docs/api/Dalamud.Game.ClientState.Actors.Types.NonPlayer.html b/docs/api/Dalamud.Game.ClientState.Actors.Types.NonPlayer.html new file mode 100644 index 000000000..bda72b263 --- /dev/null +++ b/docs/api/Dalamud.Game.ClientState.Actors.Types.NonPlayer.html @@ -0,0 +1,126 @@ + + + + + + + + Namespace Dalamud.Game.ClientState.Actors.Types.NonPlayer + + + + + + + + + + + + + + + + +
+
+ + + + +
+ + + +
+ + + + + + diff --git a/docs/api/Dalamud.Game.ClientState.Actors.Types.PlayerCharacter.html b/docs/api/Dalamud.Game.ClientState.Actors.Types.PlayerCharacter.html new file mode 100644 index 000000000..eb7010cdb --- /dev/null +++ b/docs/api/Dalamud.Game.ClientState.Actors.Types.PlayerCharacter.html @@ -0,0 +1,269 @@ + + + + + + + + Class PlayerCharacter + + + + + + + + + + + + + + + + +
+
+ + + + +
+ + + +
+ + + + + + diff --git a/docs/api/Dalamud.Game.ClientState.Actors.Types.html b/docs/api/Dalamud.Game.ClientState.Actors.Types.html new file mode 100644 index 000000000..e1465e310 --- /dev/null +++ b/docs/api/Dalamud.Game.ClientState.Actors.Types.html @@ -0,0 +1,124 @@ + + + + + + + + Namespace Dalamud.Game.ClientState.Actors.Types + + + + + + + + + + + + + + + + +
+
+ + + + +
+ + + +
+ + + + + + diff --git a/docs/api/Dalamud.Game.ClientState.Actors.html b/docs/api/Dalamud.Game.ClientState.Actors.html new file mode 100644 index 000000000..8dad7e9f6 --- /dev/null +++ b/docs/api/Dalamud.Game.ClientState.Actors.html @@ -0,0 +1,127 @@ + + + + + + + + Namespace Dalamud.Game.ClientState.Actors + + + + + + + + + + + + + + + + +
+
+ + + + +
+ + + +
+ + + + + + diff --git a/docs/api/Dalamud.Game.ClientState.ClientState.html b/docs/api/Dalamud.Game.ClientState.ClientState.html new file mode 100644 index 000000000..8aac361ba --- /dev/null +++ b/docs/api/Dalamud.Game.ClientState.ClientState.html @@ -0,0 +1,281 @@ + + + + + + + + Class ClientState + + + + + + + + + + + + + + + + +
+
+ + + + +
+ + + +
+ + + + + + diff --git a/docs/api/Dalamud.Game.ClientState.Structs.Actor.html b/docs/api/Dalamud.Game.ClientState.Structs.Actor.html new file mode 100644 index 000000000..30b477804 --- /dev/null +++ b/docs/api/Dalamud.Game.ClientState.Structs.Actor.html @@ -0,0 +1,503 @@ + + + + + + + + Struct Actor + + + + + + + + + + + + + + + + +
+
+ + + + +
+ + + +
+ + + + + + diff --git a/docs/api/Dalamud.Game.ClientState.Structs.html b/docs/api/Dalamud.Game.ClientState.Structs.html new file mode 100644 index 000000000..7313c20eb --- /dev/null +++ b/docs/api/Dalamud.Game.ClientState.Structs.html @@ -0,0 +1,118 @@ + + + + + + + + Namespace Dalamud.Game.ClientState.Structs + + + + + + + + + + + + + + + + +
+
+ + + + +
+ + + +
+ + + + + + diff --git a/docs/api/Dalamud.Game.ClientState.html b/docs/api/Dalamud.Game.ClientState.html new file mode 100644 index 000000000..f14389422 --- /dev/null +++ b/docs/api/Dalamud.Game.ClientState.html @@ -0,0 +1,118 @@ + + + + + + + + Namespace Dalamud.Game.ClientState + + + + + + + + + + + + + + + + +
+
+ + + + +
+ + + +
+ + + + + + diff --git a/docs/api/Dalamud.Game.Command.CommandInfo.HandlerDelegate.html b/docs/api/Dalamud.Game.Command.CommandInfo.HandlerDelegate.html new file mode 100644 index 000000000..fab483b9d --- /dev/null +++ b/docs/api/Dalamud.Game.Command.CommandInfo.HandlerDelegate.html @@ -0,0 +1,141 @@ + + + + + + + + Delegate CommandInfo.HandlerDelegate + + + + + + + + + + + + + + + + +
+
+ + + + +
+ + + +
+ + + + + + diff --git a/docs/api/Dalamud.Game.Command.CommandInfo.html b/docs/api/Dalamud.Game.Command.CommandInfo.html new file mode 100644 index 000000000..e349f010e --- /dev/null +++ b/docs/api/Dalamud.Game.Command.CommandInfo.html @@ -0,0 +1,254 @@ + + + + + + + + Class CommandInfo + + + + + + + + + + + + + + + + +
+
+ + + + +
+ + + +
+ + + + + + diff --git a/docs/api/Dalamud.Game.Command.CommandManager.html b/docs/api/Dalamud.Game.Command.CommandManager.html new file mode 100644 index 000000000..e5edf2e18 --- /dev/null +++ b/docs/api/Dalamud.Game.Command.CommandManager.html @@ -0,0 +1,337 @@ + + + + + + + + Class CommandManager + + + + + + + + + + + + + + + + +
+
+ + + + +
+ + + +
+ + + + + + diff --git a/docs/api/Dalamud.Game.Command.html b/docs/api/Dalamud.Game.Command.html new file mode 100644 index 000000000..7ce561349 --- /dev/null +++ b/docs/api/Dalamud.Game.Command.html @@ -0,0 +1,123 @@ + + + + + + + + Namespace Dalamud.Game.Command + + + + + + + + + + + + + + + + +
+
+ + + + +
+ + + +
+ + + + + + diff --git a/docs/api/Dalamud.Game.Internal.Framework.OnUpdateDelegate.html b/docs/api/Dalamud.Game.Internal.Framework.OnUpdateDelegate.html new file mode 100644 index 000000000..f6d1290f7 --- /dev/null +++ b/docs/api/Dalamud.Game.Internal.Framework.OnUpdateDelegate.html @@ -0,0 +1,136 @@ + + + + + + + + Delegate Framework.OnUpdateDelegate + + + + + + + + + + + + + + + + +
+
+ + + + +
+ + + +
+ + + + + + diff --git a/docs/api/Dalamud.Game.Internal.Framework.html b/docs/api/Dalamud.Game.Internal.Framework.html new file mode 100644 index 000000000..fb21e5aaa --- /dev/null +++ b/docs/api/Dalamud.Game.Internal.Framework.html @@ -0,0 +1,315 @@ + + + + + + + + Class Framework + + + + + + + + + + + + + + + + +
+
+ + + + +
+ + + +
+ + + + + + diff --git a/docs/api/Dalamud.Game.Internal.Gui.ChatGui.OnMessageDelegate.html b/docs/api/Dalamud.Game.Internal.Gui.ChatGui.OnMessageDelegate.html new file mode 100644 index 000000000..9ada962de --- /dev/null +++ b/docs/api/Dalamud.Game.Internal.Gui.ChatGui.OnMessageDelegate.html @@ -0,0 +1,156 @@ + + + + + + + + Delegate ChatGui.OnMessageDelegate + + + + + + + + + + + + + + + + +
+
+ + + + +
+ + + +
+ + + + + + diff --git a/docs/api/Dalamud.Game.Internal.Gui.ChatGui.html b/docs/api/Dalamud.Game.Internal.Gui.ChatGui.html new file mode 100644 index 000000000..0a656ab58 --- /dev/null +++ b/docs/api/Dalamud.Game.Internal.Gui.ChatGui.html @@ -0,0 +1,407 @@ + + + + + + + + Class ChatGui + + + + + + + + + + + + + + + + +
+
+ + + + +
+ + + +
+ + + + + + diff --git a/docs/api/Dalamud.Game.Internal.Gui.GameGui.html b/docs/api/Dalamud.Game.Internal.Gui.GameGui.html new file mode 100644 index 000000000..447f952bb --- /dev/null +++ b/docs/api/Dalamud.Game.Internal.Gui.GameGui.html @@ -0,0 +1,244 @@ + + + + + + + + Class GameGui + + + + + + + + + + + + + + + + +
+
+ + + + +
+ + + +
+ + + + + + diff --git a/docs/api/Dalamud.Game.Internal.Gui.html b/docs/api/Dalamud.Game.Internal.Gui.html new file mode 100644 index 000000000..a64be0d9e --- /dev/null +++ b/docs/api/Dalamud.Game.Internal.Gui.html @@ -0,0 +1,123 @@ + + + + + + + + Namespace Dalamud.Game.Internal.Gui + + + + + + + + + + + + + + + + +
+
+ + + + +
+ + + +
+ + + + + + diff --git a/docs/api/Dalamud.Game.Internal.Libc.LibcFunction.html b/docs/api/Dalamud.Game.Internal.Libc.LibcFunction.html new file mode 100644 index 000000000..a62447af4 --- /dev/null +++ b/docs/api/Dalamud.Game.Internal.Libc.LibcFunction.html @@ -0,0 +1,221 @@ + + + + + + + + Class LibcFunction + + + + + + + + + + + + + + + + +
+
+ + + + +
+ + + +
+ + + + + + diff --git a/docs/api/Dalamud.Game.Internal.Libc.OwnedStdString.html b/docs/api/Dalamud.Game.Internal.Libc.OwnedStdString.html new file mode 100644 index 000000000..905e11402 --- /dev/null +++ b/docs/api/Dalamud.Game.Internal.Libc.OwnedStdString.html @@ -0,0 +1,230 @@ + + + + + + + + Class OwnedStdString + + + + + + + + + + + + + + + + +
+
+ + + + +
+ + + +
+ + + + + + diff --git a/docs/api/Dalamud.Game.Internal.Libc.StdString.html b/docs/api/Dalamud.Game.Internal.Libc.StdString.html new file mode 100644 index 000000000..ddf288718 --- /dev/null +++ b/docs/api/Dalamud.Game.Internal.Libc.StdString.html @@ -0,0 +1,193 @@ + + + + + + + + Class StdString + + + + + + + + + + + + + + + + +
+
+ + + + +
+ + + +
+ + + + + + diff --git a/docs/api/Dalamud.Game.Internal.Libc.html b/docs/api/Dalamud.Game.Internal.Libc.html new file mode 100644 index 000000000..2c1cc7459 --- /dev/null +++ b/docs/api/Dalamud.Game.Internal.Libc.html @@ -0,0 +1,122 @@ + + + + + + + + Namespace Dalamud.Game.Internal.Libc + + + + + + + + + + + + + + + + +
+
+ + + + +
+ + + +
+ + + + + + diff --git a/docs/api/Dalamud.Game.Internal.Network.GameNetwork.OnZonePacketDelegate.html b/docs/api/Dalamud.Game.Internal.Network.GameNetwork.OnZonePacketDelegate.html new file mode 100644 index 000000000..e457c277c --- /dev/null +++ b/docs/api/Dalamud.Game.Internal.Network.GameNetwork.OnZonePacketDelegate.html @@ -0,0 +1,136 @@ + + + + + + + + Delegate GameNetwork.OnZonePacketDelegate + + + + + + + + + + + + + + + + +
+
+ + + + +
+ + + +
+ + + + + + diff --git a/docs/api/Dalamud.Game.Internal.Network.GameNetwork.html b/docs/api/Dalamud.Game.Internal.Network.GameNetwork.html new file mode 100644 index 000000000..54edeb378 --- /dev/null +++ b/docs/api/Dalamud.Game.Internal.Network.GameNetwork.html @@ -0,0 +1,238 @@ + + + + + + + + Class GameNetwork + + + + + + + + + + + + + + + + +
+
+ + + + +
+ + + +
+ + + + + + diff --git a/docs/api/Dalamud.Game.Internal.Network.html b/docs/api/Dalamud.Game.Internal.Network.html new file mode 100644 index 000000000..fdda8989d --- /dev/null +++ b/docs/api/Dalamud.Game.Internal.Network.html @@ -0,0 +1,121 @@ + + + + + + + + Namespace Dalamud.Game.Internal.Network + + + + + + + + + + + + + + + + +
+
+ + + + +
+ + + +
+ + + + + + diff --git a/docs/api/Dalamud.Game.Internal.html b/docs/api/Dalamud.Game.Internal.html new file mode 100644 index 000000000..e86bc40ce --- /dev/null +++ b/docs/api/Dalamud.Game.Internal.html @@ -0,0 +1,121 @@ + + + + + + + + Namespace Dalamud.Game.Internal + + + + + + + + + + + + + + + + +
+
+ + + + +
+ + + +
+ + + + + + diff --git a/docs/api/Dalamud.Game.SigScanner.html b/docs/api/Dalamud.Game.SigScanner.html new file mode 100644 index 000000000..fa42d34ff --- /dev/null +++ b/docs/api/Dalamud.Game.SigScanner.html @@ -0,0 +1,556 @@ + + + + + + + + Class SigScanner + + + + + + + + + + + + + + + + +
+
+ + + + +
+ + + +
+ + + + + + diff --git a/docs/api/Dalamud.Game.html b/docs/api/Dalamud.Game.html new file mode 100644 index 000000000..be9278d7b --- /dev/null +++ b/docs/api/Dalamud.Game.html @@ -0,0 +1,119 @@ + + + + + + + + Namespace Dalamud.Game + + + + + + + + + + + + + + + + +
+
+ + + + +
+ + + +
+ + + + + + diff --git a/docs/api/Dalamud.Plugin.DalamudPluginInterface.html b/docs/api/Dalamud.Plugin.DalamudPluginInterface.html new file mode 100644 index 000000000..acbc40bed --- /dev/null +++ b/docs/api/Dalamud.Plugin.DalamudPluginInterface.html @@ -0,0 +1,256 @@ + + + + + + + + Class DalamudPluginInterface + + + + + + + + + + + + + + + + +
+
+ + + + +
+ + + +
+ + + + + + diff --git a/docs/api/Dalamud.Plugin.IDalamudPlugin.html b/docs/api/Dalamud.Plugin.IDalamudPlugin.html new file mode 100644 index 000000000..dad44e069 --- /dev/null +++ b/docs/api/Dalamud.Plugin.IDalamudPlugin.html @@ -0,0 +1,185 @@ + + + + + + + + Interface IDalamudPlugin + + + + + + + + + + + + + + + + +
+
+ + + + +
+ + + +
+ + + + + + diff --git a/docs/api/Dalamud.Plugin.html b/docs/api/Dalamud.Plugin.html new file mode 100644 index 000000000..083fa47b3 --- /dev/null +++ b/docs/api/Dalamud.Plugin.html @@ -0,0 +1,123 @@ + + + + + + + + Namespace Dalamud.Plugin + + + + + + + + + + + + + + + + +
+
+ + + + +
+ + + +
+ + + + + + diff --git a/docs/api/index.html b/docs/api/index.html new file mode 100644 index 000000000..c43cd0df0 --- /dev/null +++ b/docs/api/index.html @@ -0,0 +1,109 @@ + + + + + + + + Dalamud Plugin API + + + + + + + + + + + + + + + +
+
+ + + + +
+ + + +
+ + + + + + diff --git a/docs/api/toc.html b/docs/api/toc.html new file mode 100644 index 000000000..5c4366e93 --- /dev/null +++ b/docs/api/toc.html @@ -0,0 +1,236 @@ + + \ No newline at end of file diff --git a/docs/articles/intro.html b/docs/articles/intro.html new file mode 100644 index 000000000..3adbcff74 --- /dev/null +++ b/docs/articles/intro.html @@ -0,0 +1,107 @@ + + + + + + + + Add your introductions here! + + + + + + + + + + + + + + + +
+
+ + + + +
+ + + +
+ + + + + + diff --git a/docs/articles/toc.html b/docs/articles/toc.html new file mode 100644 index 000000000..bbe120dad --- /dev/null +++ b/docs/articles/toc.html @@ -0,0 +1,21 @@ + +
+
+
+
+ + +
+
+
+
+ + +
+
+
+
\ No newline at end of file diff --git a/docs/favicon.ico b/docs/favicon.ico new file mode 100644 index 000000000..71570f61e Binary files /dev/null and b/docs/favicon.ico differ diff --git a/docs/fonts/glyphicons-halflings-regular.eot b/docs/fonts/glyphicons-halflings-regular.eot new file mode 100644 index 000000000..b93a4953f Binary files /dev/null and b/docs/fonts/glyphicons-halflings-regular.eot differ diff --git a/docs/fonts/glyphicons-halflings-regular.svg b/docs/fonts/glyphicons-halflings-regular.svg new file mode 100644 index 000000000..94fb5490a --- /dev/null +++ b/docs/fonts/glyphicons-halflings-regular.svg @@ -0,0 +1,288 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/fonts/glyphicons-halflings-regular.ttf b/docs/fonts/glyphicons-halflings-regular.ttf new file mode 100644 index 000000000..1413fc609 Binary files /dev/null and b/docs/fonts/glyphicons-halflings-regular.ttf differ diff --git a/docs/fonts/glyphicons-halflings-regular.woff b/docs/fonts/glyphicons-halflings-regular.woff new file mode 100644 index 000000000..9e612858f Binary files /dev/null and b/docs/fonts/glyphicons-halflings-regular.woff differ diff --git a/docs/fonts/glyphicons-halflings-regular.woff2 b/docs/fonts/glyphicons-halflings-regular.woff2 new file mode 100644 index 000000000..64539b54c Binary files /dev/null and b/docs/fonts/glyphicons-halflings-regular.woff2 differ diff --git a/docs/index.html b/docs/index.html new file mode 100644 index 000000000..47c9a5700 --- /dev/null +++ b/docs/index.html @@ -0,0 +1,101 @@ + + + + + + + + Dalamud plugin API documentation + + + + + + + + + + + + + + + +
+
+ + + + +
+ + + +
+ + + + + + diff --git a/docs/logo.svg b/docs/logo.svg new file mode 100644 index 000000000..ccb2d7bc9 --- /dev/null +++ b/docs/logo.svg @@ -0,0 +1,25 @@ + + + + +Created by Docfx + + + + + + + diff --git a/docs/manifest.json b/docs/manifest.json new file mode 100644 index 000000000..79fb50850 --- /dev/null +++ b/docs/manifest.json @@ -0,0 +1,780 @@ +{ + "homepages": [], + "source_base_path": "D:/Sapphire/recorder", + "xrefmap": "xrefmap.yml", + "files": [ + { + "type": "ManagedReference", + "source_relative_path": "api/Dalamud.Game.Chat.EnumExtensions.yml", + "output": { + ".html": { + "relative_path": "api/Dalamud.Game.Chat.EnumExtensions.html", + "hash": "6yhJFr/d9207Y+KxNqizVg==" + } + }, + "is_incremental": true, + "version": "" + }, + { + "type": "ManagedReference", + "source_relative_path": "api/Dalamud.Game.Chat.SeString.IntegerType.yml", + "output": { + ".html": { + "relative_path": "api/Dalamud.Game.Chat.SeString.IntegerType.html", + "hash": "gopE9IfoMsOqIH7fQWgwOg==" + } + }, + "is_incremental": true, + "version": "" + }, + { + "type": "ManagedReference", + "source_relative_path": "api/Dalamud.Game.Chat.SeString.PlayerLinkType.yml", + "output": { + ".html": { + "relative_path": "api/Dalamud.Game.Chat.SeString.PlayerLinkType.html", + "hash": "jMqXrBU6eFtY+akfdGW2YQ==" + } + }, + "is_incremental": true, + "version": "" + }, + { + "type": "ManagedReference", + "source_relative_path": "api/Dalamud.Game.Chat.SeString.SeStringPayloadContainer.yml", + "output": { + ".html": { + "relative_path": "api/Dalamud.Game.Chat.SeString.SeStringPayloadContainer.html", + "hash": "KdlZR0WzYsQ+K5X7e/zRMw==" + } + }, + "is_incremental": true, + "version": "" + }, + { + "type": "ManagedReference", + "source_relative_path": "api/Dalamud.Game.Chat.SeString.SeStringPayloadType.yml", + "output": { + ".html": { + "relative_path": "api/Dalamud.Game.Chat.SeString.SeStringPayloadType.html", + "hash": "e6ODfEPrqaEj75u94fafEA==" + } + }, + "is_incremental": true, + "version": "" + }, + { + "type": "ManagedReference", + "source_relative_path": "api/Dalamud.Game.Chat.SeString.yml", + "output": { + ".html": { + "relative_path": "api/Dalamud.Game.Chat.SeString.html", + "hash": "xJyodmiBeXALhR4YaEMUeA==" + } + }, + "is_incremental": true, + "version": "" + }, + { + "type": "ManagedReference", + "source_relative_path": "api/Dalamud.Game.Chat.XivChatEntry.yml", + "output": { + ".html": { + "relative_path": "api/Dalamud.Game.Chat.XivChatEntry.html", + "hash": "1h4WBUhN4GIPrdfsS6AE5Q==" + } + }, + "is_incremental": true, + "version": "" + }, + { + "type": "ManagedReference", + "source_relative_path": "api/Dalamud.Game.Chat.XivChatType.yml", + "output": { + ".html": { + "relative_path": "api/Dalamud.Game.Chat.XivChatType.html", + "hash": "pt+xJ/FcTdkdzX/pXvd5bg==" + } + }, + "is_incremental": true, + "version": "" + }, + { + "type": "ManagedReference", + "source_relative_path": "api/Dalamud.Game.Chat.XivChatTypeExtensions.yml", + "output": { + ".html": { + "relative_path": "api/Dalamud.Game.Chat.XivChatTypeExtensions.html", + "hash": "U9ulBSolOzAovAwRiroGOg==" + } + }, + "is_incremental": true, + "version": "" + }, + { + "type": "ManagedReference", + "source_relative_path": "api/Dalamud.Game.Chat.XivChatTypeInfoAttribute.yml", + "output": { + ".html": { + "relative_path": "api/Dalamud.Game.Chat.XivChatTypeInfoAttribute.html", + "hash": "up0Tnc+uhhH2LUXMYqEzbw==" + } + }, + "is_incremental": true, + "version": "" + }, + { + "type": "ManagedReference", + "source_relative_path": "api/Dalamud.Game.Chat.yml", + "output": { + ".html": { + "relative_path": "api/Dalamud.Game.Chat.html", + "hash": "QyT5VZTYhvfEnoaz6Al/Bg==" + } + }, + "is_incremental": true, + "version": "" + }, + { + "type": "ManagedReference", + "source_relative_path": "api/Dalamud.Game.ChatHandlers.yml", + "output": { + ".html": { + "relative_path": "api/Dalamud.Game.ChatHandlers.html", + "hash": "gfb449D6ktqBuCGjuLQXWQ==" + } + }, + "is_incremental": true, + "version": "" + }, + { + "type": "ManagedReference", + "source_relative_path": "api/Dalamud.Game.ClientState.Actors.ActorTable.yml", + "output": { + ".html": { + "relative_path": "api/Dalamud.Game.ClientState.Actors.ActorTable.html", + "hash": "EW/l591b8WRCjGXouTqqIQ==" + } + }, + "is_incremental": true, + "version": "" + }, + { + "type": "ManagedReference", + "source_relative_path": "api/Dalamud.Game.ClientState.Actors.ObjectKind.yml", + "output": { + ".html": { + "relative_path": "api/Dalamud.Game.ClientState.Actors.ObjectKind.html", + "hash": "O2I8AL8a5jVXmLOEWJa8QQ==" + } + }, + "is_incremental": true, + "version": "" + }, + { + "type": "ManagedReference", + "source_relative_path": "api/Dalamud.Game.ClientState.Actors.Position3.yml", + "output": { + ".html": { + "relative_path": "api/Dalamud.Game.ClientState.Actors.Position3.html", + "hash": "VmIREFhiiky/NkPfPI7vSQ==" + } + }, + "is_incremental": true, + "version": "" + }, + { + "type": "ManagedReference", + "source_relative_path": "api/Dalamud.Game.ClientState.Actors.Resolvers.ClassJob.yml", + "output": { + ".html": { + "relative_path": "api/Dalamud.Game.ClientState.Actors.Resolvers.ClassJob.html", + "hash": "xYq+hR5DdKVZFjhuxJnHbQ==" + } + }, + "is_incremental": true, + "version": "" + }, + { + "type": "ManagedReference", + "source_relative_path": "api/Dalamud.Game.ClientState.Actors.Resolvers.World.yml", + "output": { + ".html": { + "relative_path": "api/Dalamud.Game.ClientState.Actors.Resolvers.World.html", + "hash": "ZTeXdpSNTrGnQqVvHw+SWw==" + } + }, + "is_incremental": true, + "version": "" + }, + { + "type": "ManagedReference", + "source_relative_path": "api/Dalamud.Game.ClientState.Actors.Resolvers.yml", + "output": { + ".html": { + "relative_path": "api/Dalamud.Game.ClientState.Actors.Resolvers.html", + "hash": "Ccjiz75ZiwiHTGGrPHrRAA==" + } + }, + "is_incremental": true, + "version": "" + }, + { + "type": "ManagedReference", + "source_relative_path": "api/Dalamud.Game.ClientState.Actors.Types.Actor.yml", + "output": { + ".html": { + "relative_path": "api/Dalamud.Game.ClientState.Actors.Types.Actor.html", + "hash": "v6+zy3DaTNZRT30JH4sexg==" + } + }, + "is_incremental": true, + "version": "" + }, + { + "type": "ManagedReference", + "source_relative_path": "api/Dalamud.Game.ClientState.Actors.Types.Chara.yml", + "output": { + ".html": { + "relative_path": "api/Dalamud.Game.ClientState.Actors.Types.Chara.html", + "hash": "/1EesV6d6Y9jmgVk0exK2Q==" + } + }, + "is_incremental": true, + "version": "" + }, + { + "type": "ManagedReference", + "source_relative_path": "api/Dalamud.Game.ClientState.Actors.Types.NonPlayer.BattleNpc.yml", + "output": { + ".html": { + "relative_path": "api/Dalamud.Game.ClientState.Actors.Types.NonPlayer.BattleNpc.html", + "hash": "8e2JmVOzy6S7SnBuhFPxYQ==" + } + }, + "is_incremental": true, + "version": "" + }, + { + "type": "ManagedReference", + "source_relative_path": "api/Dalamud.Game.ClientState.Actors.Types.NonPlayer.BattleNpcSubKind.yml", + "output": { + ".html": { + "relative_path": "api/Dalamud.Game.ClientState.Actors.Types.NonPlayer.BattleNpcSubKind.html", + "hash": "/o94IWrP+Oh8wiToM9PPwQ==" + } + }, + "is_incremental": true, + "version": "" + }, + { + "type": "ManagedReference", + "source_relative_path": "api/Dalamud.Game.ClientState.Actors.Types.NonPlayer.Npc.yml", + "output": { + ".html": { + "relative_path": "api/Dalamud.Game.ClientState.Actors.Types.NonPlayer.Npc.html", + "hash": "i1IpEWTpaFeKKzaFhpSJTg==" + } + }, + "is_incremental": true, + "version": "" + }, + { + "type": "ManagedReference", + "source_relative_path": "api/Dalamud.Game.ClientState.Actors.Types.NonPlayer.yml", + "output": { + ".html": { + "relative_path": "api/Dalamud.Game.ClientState.Actors.Types.NonPlayer.html", + "hash": "zZ7IK2ZYtCKQshXYtyK8Hg==" + } + }, + "is_incremental": true, + "version": "" + }, + { + "type": "ManagedReference", + "source_relative_path": "api/Dalamud.Game.ClientState.Actors.Types.PlayerCharacter.yml", + "output": { + ".html": { + "relative_path": "api/Dalamud.Game.ClientState.Actors.Types.PlayerCharacter.html", + "hash": "nU79cnXKOkb4y7FhZby7YQ==" + } + }, + "is_incremental": true, + "version": "" + }, + { + "type": "ManagedReference", + "source_relative_path": "api/Dalamud.Game.ClientState.Actors.Types.yml", + "output": { + ".html": { + "relative_path": "api/Dalamud.Game.ClientState.Actors.Types.html", + "hash": "4KXgmECTURQ6Lxg9ZfwwJg==" + } + }, + "is_incremental": true, + "version": "" + }, + { + "type": "ManagedReference", + "source_relative_path": "api/Dalamud.Game.ClientState.Actors.yml", + "output": { + ".html": { + "relative_path": "api/Dalamud.Game.ClientState.Actors.html", + "hash": "+XMx6TFLon6DsHJO+dckaA==" + } + }, + "is_incremental": true, + "version": "" + }, + { + "type": "ManagedReference", + "source_relative_path": "api/Dalamud.Game.ClientState.ClientState.yml", + "output": { + ".html": { + "relative_path": "api/Dalamud.Game.ClientState.ClientState.html", + "hash": "hA5ZiC5MEoaGY3qyr4QmUw==" + } + }, + "is_incremental": true, + "version": "" + }, + { + "type": "ManagedReference", + "source_relative_path": "api/Dalamud.Game.ClientState.Structs.Actor.yml", + "output": { + ".html": { + "relative_path": "api/Dalamud.Game.ClientState.Structs.Actor.html", + "hash": "Jq063v+UrfTBGR9vEFlalw==" + } + }, + "is_incremental": true, + "version": "" + }, + { + "type": "ManagedReference", + "source_relative_path": "api/Dalamud.Game.ClientState.Structs.yml", + "output": { + ".html": { + "relative_path": "api/Dalamud.Game.ClientState.Structs.html", + "hash": "qRRgI/wq0LZ+K7aLnqyuqA==" + } + }, + "is_incremental": true, + "version": "" + }, + { + "type": "ManagedReference", + "source_relative_path": "api/Dalamud.Game.ClientState.yml", + "output": { + ".html": { + "relative_path": "api/Dalamud.Game.ClientState.html", + "hash": "M92W6er4C53zITuFtEI74Q==" + } + }, + "is_incremental": true, + "version": "" + }, + { + "type": "ManagedReference", + "source_relative_path": "api/Dalamud.Game.Command.CommandInfo.HandlerDelegate.yml", + "output": { + ".html": { + "relative_path": "api/Dalamud.Game.Command.CommandInfo.HandlerDelegate.html", + "hash": "CWPe0XdZj+BrIL+lvtWoYg==" + } + }, + "is_incremental": true, + "version": "" + }, + { + "type": "ManagedReference", + "source_relative_path": "api/Dalamud.Game.Command.CommandInfo.yml", + "output": { + ".html": { + "relative_path": "api/Dalamud.Game.Command.CommandInfo.html", + "hash": "8O6RCqG5hycNjf2NLs6ptw==" + } + }, + "is_incremental": true, + "version": "" + }, + { + "type": "ManagedReference", + "source_relative_path": "api/Dalamud.Game.Command.CommandManager.yml", + "output": { + ".html": { + "relative_path": "api/Dalamud.Game.Command.CommandManager.html", + "hash": "t4mjlEPVF8QKyFXniRXplA==" + } + }, + "is_incremental": true, + "version": "" + }, + { + "type": "ManagedReference", + "source_relative_path": "api/Dalamud.Game.Command.yml", + "output": { + ".html": { + "relative_path": "api/Dalamud.Game.Command.html", + "hash": "OVNml7idiakru8nT1nqZHw==" + } + }, + "is_incremental": true, + "version": "" + }, + { + "type": "ManagedReference", + "source_relative_path": "api/Dalamud.Game.Internal.Framework.OnUpdateDelegate.yml", + "output": { + ".html": { + "relative_path": "api/Dalamud.Game.Internal.Framework.OnUpdateDelegate.html", + "hash": "kk/NMxUktzLg9ps4Mfp4ZA==" + } + }, + "is_incremental": true, + "version": "" + }, + { + "type": "ManagedReference", + "source_relative_path": "api/Dalamud.Game.Internal.Framework.yml", + "output": { + ".html": { + "relative_path": "api/Dalamud.Game.Internal.Framework.html", + "hash": "fHjOnpGWFdkzm4wwC0jZMg==" + } + }, + "is_incremental": false, + "version": "" + }, + { + "type": "ManagedReference", + "source_relative_path": "api/Dalamud.Game.Internal.Gui.ChatGui.OnMessageDelegate.yml", + "output": { + ".html": { + "relative_path": "api/Dalamud.Game.Internal.Gui.ChatGui.OnMessageDelegate.html", + "hash": "O3MQpXZlE7iq7O3qSskBHA==" + } + }, + "is_incremental": true, + "version": "" + }, + { + "type": "ManagedReference", + "source_relative_path": "api/Dalamud.Game.Internal.Gui.ChatGui.yml", + "output": { + ".html": { + "relative_path": "api/Dalamud.Game.Internal.Gui.ChatGui.html", + "hash": "1H2RgptOtK/mhwW1AaaMfg==" + } + }, + "is_incremental": true, + "version": "" + }, + { + "type": "ManagedReference", + "source_relative_path": "api/Dalamud.Game.Internal.Gui.GameGui.yml", + "output": { + ".html": { + "relative_path": "api/Dalamud.Game.Internal.Gui.GameGui.html", + "hash": "+Rp3/3jPbferSt41tLJhXA==" + } + }, + "is_incremental": true, + "version": "" + }, + { + "type": "ManagedReference", + "source_relative_path": "api/Dalamud.Game.Internal.Gui.yml", + "output": { + ".html": { + "relative_path": "api/Dalamud.Game.Internal.Gui.html", + "hash": "0WfSn35S8Z++WFDr3ATjZg==" + } + }, + "is_incremental": true, + "version": "" + }, + { + "type": "ManagedReference", + "source_relative_path": "api/Dalamud.Game.Internal.Libc.LibcFunction.yml", + "output": { + ".html": { + "relative_path": "api/Dalamud.Game.Internal.Libc.LibcFunction.html", + "hash": "jbLknIRXAZh2AeREt0r7AA==" + } + }, + "is_incremental": true, + "version": "" + }, + { + "type": "ManagedReference", + "source_relative_path": "api/Dalamud.Game.Internal.Libc.OwnedStdString.yml", + "output": { + ".html": { + "relative_path": "api/Dalamud.Game.Internal.Libc.OwnedStdString.html", + "hash": "NSmJNXflzLDJVQjewX3Xvg==" + } + }, + "is_incremental": true, + "version": "" + }, + { + "type": "ManagedReference", + "source_relative_path": "api/Dalamud.Game.Internal.Libc.StdString.yml", + "output": { + ".html": { + "relative_path": "api/Dalamud.Game.Internal.Libc.StdString.html", + "hash": "paAU1iZ6xxiL2kF1pmUpnw==" + } + }, + "is_incremental": true, + "version": "" + }, + { + "type": "ManagedReference", + "source_relative_path": "api/Dalamud.Game.Internal.Libc.yml", + "output": { + ".html": { + "relative_path": "api/Dalamud.Game.Internal.Libc.html", + "hash": "InmrcpCrPYqYuIqcyAhlqg==" + } + }, + "is_incremental": true, + "version": "" + }, + { + "type": "ManagedReference", + "source_relative_path": "api/Dalamud.Game.Internal.Network.GameNetwork.OnZonePacketDelegate.yml", + "output": { + ".html": { + "relative_path": "api/Dalamud.Game.Internal.Network.GameNetwork.OnZonePacketDelegate.html", + "hash": "WzZzhwJVWvgJWb1LmRkAwA==" + } + }, + "is_incremental": false, + "version": "" + }, + { + "type": "ManagedReference", + "source_relative_path": "api/Dalamud.Game.Internal.Network.GameNetwork.yml", + "output": { + ".html": { + "relative_path": "api/Dalamud.Game.Internal.Network.GameNetwork.html", + "hash": "r/15cGZQ3Cc5h279Ur8YiA==" + } + }, + "is_incremental": false, + "version": "" + }, + { + "type": "ManagedReference", + "source_relative_path": "api/Dalamud.Game.Internal.Network.yml", + "output": { + ".html": { + "relative_path": "api/Dalamud.Game.Internal.Network.html", + "hash": "adU/F284FGauyUzZrUgU9w==" + } + }, + "is_incremental": false, + "version": "" + }, + { + "type": "ManagedReference", + "source_relative_path": "api/Dalamud.Game.Internal.yml", + "output": { + ".html": { + "relative_path": "api/Dalamud.Game.Internal.html", + "hash": "vU5WUXTzhr9DKCALA4zlnQ==" + } + }, + "is_incremental": false, + "version": "" + }, + { + "type": "ManagedReference", + "source_relative_path": "api/Dalamud.Game.SigScanner.yml", + "output": { + ".html": { + "relative_path": "api/Dalamud.Game.SigScanner.html", + "hash": "mpb6u1h2mb74QeFz8n53Cw==" + } + }, + "is_incremental": true, + "version": "" + }, + { + "type": "ManagedReference", + "source_relative_path": "api/Dalamud.Game.yml", + "output": { + ".html": { + "relative_path": "api/Dalamud.Game.html", + "hash": "HaybHzLX7/XwMsSN2FlWuQ==" + } + }, + "is_incremental": true, + "version": "" + }, + { + "type": "ManagedReference", + "source_relative_path": "api/Dalamud.Plugin.DalamudPluginInterface.yml", + "output": { + ".html": { + "relative_path": "api/Dalamud.Plugin.DalamudPluginInterface.html", + "hash": "eYC5Po+G+Zz3GgZSsuAzvg==" + } + }, + "is_incremental": true, + "version": "" + }, + { + "type": "ManagedReference", + "source_relative_path": "api/Dalamud.Plugin.IDalamudPlugin.yml", + "output": { + ".html": { + "relative_path": "api/Dalamud.Plugin.IDalamudPlugin.html", + "hash": "DJTFgHoxO+kGW2W/0uaJxQ==" + } + }, + "is_incremental": false, + "version": "" + }, + { + "type": "ManagedReference", + "source_relative_path": "api/Dalamud.Plugin.yml", + "output": { + ".html": { + "relative_path": "api/Dalamud.Plugin.html", + "hash": "0GvCegiL22kocIJryW2gcQ==" + } + }, + "is_incremental": false, + "version": "" + }, + { + "log_codes": [ + "InvalidFileLink" + ], + "type": "Conceptual", + "source_relative_path": "api/index.md", + "output": { + ".html": { + "relative_path": "api/index.html", + "hash": "m3Ch0VzxGuugKf6rttmYKw==" + } + }, + "is_incremental": true, + "version": "" + }, + { + "type": "Toc", + "source_relative_path": "api/toc.yml", + "output": { + ".html": { + "relative_path": "api/toc.html", + "hash": "3nmCquNSLKVX3pXex2CP5A==" + } + }, + "is_incremental": false, + "version": "" + }, + { + "type": "Conceptual", + "source_relative_path": "articles/intro.md", + "output": { + ".html": { + "relative_path": "articles/intro.html", + "hash": "bcTPg+uhS+XfhW7IeUi3BQ==" + } + }, + "is_incremental": true, + "version": "" + }, + { + "type": "Toc", + "source_relative_path": "articles/toc.yml", + "output": { + ".html": { + "relative_path": "articles/toc.html", + "hash": "t7iiFrmuYmrKWisdq+lN6Q==" + } + }, + "is_incremental": false, + "version": "" + }, + { + "log_codes": [ + "InvalidFileLink" + ], + "type": "Conceptual", + "source_relative_path": "index.md", + "output": { + ".html": { + "relative_path": "index.html", + "hash": "T4yJJSQfgYuZdccziwuN1w==" + } + }, + "is_incremental": true, + "version": "" + }, + { + "type": "Toc", + "source_relative_path": "toc.yml", + "output": { + ".html": { + "relative_path": "toc.html", + "hash": "1Xdjw8Ib7j95/TiJDj+CFw==" + } + }, + "is_incremental": false, + "version": "" + } + ], + "incremental_info": [ + { + "status": { + "can_incremental": true, + "incrementalPhase": "build", + "total_file_count": 0, + "skipped_file_count": 0 + }, + "processors": { + "TocDocumentProcessor": { + "can_incremental": false, + "details": "Processor TocDocumentProcessor cannot support incremental build because the processor doesn't implement ISupportIncrementalDocumentProcessor interface.", + "incrementalPhase": "build", + "total_file_count": 0, + "skipped_file_count": 0 + }, + "ConceptualDocumentProcessor": { + "can_incremental": true, + "incrementalPhase": "build", + "total_file_count": 3, + "skipped_file_count": 3 + }, + "ManagedReferenceDocumentProcessor": { + "can_incremental": true, + "incrementalPhase": "build", + "total_file_count": 54, + "skipped_file_count": 51 + } + } + }, + { + "status": { + "can_incremental": true, + "details": "Can support incremental post processing.", + "incrementalPhase": "postProcessing", + "total_file_count": 0, + "skipped_file_count": 0 + }, + "processors": {} + } + ], + "version_info": {}, + "groups": [ + { + "xrefmap": "xrefmap.yml" + } + ] +} \ No newline at end of file diff --git a/docs/search-stopwords.json b/docs/search-stopwords.json new file mode 100644 index 000000000..0bdcc2c00 --- /dev/null +++ b/docs/search-stopwords.json @@ -0,0 +1,121 @@ +[ + "a", + "able", + "about", + "across", + "after", + "all", + "almost", + "also", + "am", + "among", + "an", + "and", + "any", + "are", + "as", + "at", + "be", + "because", + "been", + "but", + "by", + "can", + "cannot", + "could", + "dear", + "did", + "do", + "does", + "either", + "else", + "ever", + "every", + "for", + "from", + "get", + "got", + "had", + "has", + "have", + "he", + "her", + "hers", + "him", + "his", + "how", + "however", + "i", + "if", + "in", + "into", + "is", + "it", + "its", + "just", + "least", + "let", + "like", + "likely", + "may", + "me", + "might", + "most", + "must", + "my", + "neither", + "no", + "nor", + "not", + "of", + "off", + "often", + "on", + "only", + "or", + "other", + "our", + "own", + "rather", + "said", + "say", + "says", + "she", + "should", + "since", + "so", + "some", + "than", + "that", + "the", + "their", + "them", + "then", + "there", + "these", + "they", + "this", + "tis", + "to", + "too", + "twas", + "us", + "wants", + "was", + "we", + "were", + "what", + "when", + "where", + "which", + "while", + "who", + "whom", + "why", + "will", + "with", + "would", + "yet", + "you", + "your" +] diff --git a/docs/styles/docfx.css b/docs/styles/docfx.css new file mode 100644 index 000000000..c31a00da8 --- /dev/null +++ b/docs/styles/docfx.css @@ -0,0 +1,957 @@ +/* Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. */ +html, +body { + font-family: 'Segoe UI', Tahoma, Helvetica, sans-serif; + height: 100%; +} +button, +a { + color: #337ab7; + cursor: pointer; +} +button:hover, +button:focus, +a:hover, +a:focus { + color: #23527c; + text-decoration: none; +} +a.disable, +a.disable:hover { + text-decoration: none; + cursor: default; + color: #000000; +} + +h1, h2, h3, h4, h5, h6, .text-break { + word-wrap: break-word; + word-break: break-word; +} + +h1 mark, +h2 mark, +h3 mark, +h4 mark, +h5 mark, +h6 mark { + padding: 0; +} + +.inheritance .level0:before, +.inheritance .level1:before, +.inheritance .level2:before, +.inheritance .level3:before, +.inheritance .level4:before, +.inheritance .level5:before { + content: '↳'; + margin-right: 5px; +} + +.inheritance .level0 { + margin-left: 0em; +} + +.inheritance .level1 { + margin-left: 1em; +} + +.inheritance .level2 { + margin-left: 2em; +} + +.inheritance .level3 { + margin-left: 3em; +} + +.inheritance .level4 { + margin-left: 4em; +} + +.inheritance .level5 { + margin-left: 5em; +} + +span.parametername, +span.paramref, +span.typeparamref { + font-style: italic; +} +span.languagekeyword{ + font-weight: bold; +} + +svg:hover path { + fill: #ffffff; +} + +.hljs { + display: inline; + background-color: inherit; + padding: 0; +} +/* additional spacing fixes */ +.btn + .btn { + margin-left: 10px; +} +.btn.pull-right { + margin-left: 10px; + margin-top: 5px; +} +.table { + margin-bottom: 10px; +} +table p { + margin-bottom: 0; +} +table a { + display: inline-block; +} + +/* Make hidden attribute compatible with old browser.*/ +[hidden] { + display: none !important; +} + +h1, +.h1, +h2, +.h2, +h3, +.h3 { + margin-top: 15px; + margin-bottom: 10px; + font-weight: 400; +} +h4, +.h4, +h5, +.h5, +h6, +.h6 { + margin-top: 10px; + margin-bottom: 5px; +} +.navbar { + margin-bottom: 0; +} +#wrapper { + min-height: 100%; + position: relative; +} +/* blends header footer and content together with gradient effect */ +.grad-top { + /* For Safari 5.1 to 6.0 */ + /* For Opera 11.1 to 12.0 */ + /* For Firefox 3.6 to 15 */ + background: linear-gradient(rgba(0, 0, 0, 0.05), rgba(0, 0, 0, 0)); + /* Standard syntax */ + height: 5px; +} +.grad-bottom { + /* For Safari 5.1 to 6.0 */ + /* For Opera 11.1 to 12.0 */ + /* For Firefox 3.6 to 15 */ + background: linear-gradient(rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.05)); + /* Standard syntax */ + height: 5px; +} +.divider { + margin: 0 5px; + color: #cccccc; +} +hr { + border-color: #cccccc; +} +header { + position: fixed; + top: 0; + left: 0; + right: 0; + z-index: 1000; +} +header .navbar { + border-width: 0 0 1px; + border-radius: 0; +} +.navbar-brand { + font-size: inherit; + padding: 0; +} +.navbar-collapse { + margin: 0 -15px; +} +.subnav { + min-height: 40px; +} + +.inheritance h5, .inheritedMembers h5{ + padding-bottom: 5px; + border-bottom: 1px solid #ccc; +} + +article h1, article h2, article h3, article h4{ + margin-top: 25px; +} + +article h4{ + border-bottom: 1px solid #ccc; +} + +article span.small.pull-right{ + margin-top: 20px; +} + +article section { + margin-left: 1em; +} + +/*.expand-all { + padding: 10px 0; +}*/ +.breadcrumb { + margin: 0; + padding: 10px 0; + background-color: inherit; + white-space: nowrap; +} +.breadcrumb > li + li:before { + content: "\00a0/"; +} +#autocollapse.collapsed .navbar-header { + float: none; +} +#autocollapse.collapsed .navbar-toggle { + display: block; +} +#autocollapse.collapsed .navbar-collapse { + border-top: 1px solid transparent; + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1); +} +#autocollapse.collapsed .navbar-collapse.collapse { + display: none !important; +} +#autocollapse.collapsed .navbar-nav { + float: none !important; + margin: 7.5px -15px; +} +#autocollapse.collapsed .navbar-nav > li { + float: none; +} +#autocollapse.collapsed .navbar-nav > li > a { + padding-top: 10px; + padding-bottom: 10px; +} +#autocollapse.collapsed .collapse.in, +#autocollapse.collapsed .collapsing { + display: block !important; +} +#autocollapse.collapsed .collapse.in .navbar-right, +#autocollapse.collapsed .collapsing .navbar-right { + float: none !important; +} +#autocollapse .form-group { + width: 100%; +} +#autocollapse .form-control { + width: 100%; +} +#autocollapse .navbar-header { + margin-left: 0; + margin-right: 0; +} +#autocollapse .navbar-brand { + margin-left: 0; +} +.collapse.in, +.collapsing { + text-align: center; +} +.collapsing .navbar-form { + margin: 0 auto; + max-width: 400px; + padding: 10px 15px; + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); +} +.collapsed .collapse.in .navbar-form { + margin: 0 auto; + max-width: 400px; + padding: 10px 15px; + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); +} +.navbar .navbar-nav { + display: inline-block; +} +.docs-search { + background: white; + vertical-align: middle; +} +.docs-search > .search-query { + font-size: 14px; + border: 0; + width: 120%; + color: #555; +} +.docs-search > .search-query:focus { + outline: 0; +} +.search-results-frame { + clear: both; + display: table; + width: 100%; +} +.search-results.ng-hide { + display: none; +} +.search-results-container { + padding-bottom: 1em; + border-top: 1px solid #111; + background: rgba(25, 25, 25, 0.5); +} +.search-results-container .search-results-group { + padding-top: 50px !important; + padding: 10px; +} +.search-results-group-heading { + font-family: "Open Sans"; + padding-left: 10px; + color: white; +} +.search-close { + position: absolute; + left: 50%; + margin-left: -100px; + color: white; + text-align: center; + padding: 5px; + background: #333; + border-top-right-radius: 5px; + border-top-left-radius: 5px; + width: 200px; + box-shadow: 0 0 10px #111; +} +#search { + display: none; +} + +/* Search results display*/ +#search-results { + max-width: 960px !important; + margin-top: 120px; + margin-bottom: 115px; + margin-left: auto; + margin-right: auto; + line-height: 1.8; + display: none; +} + +#search-results>.search-list { + text-align: center; + font-size: 2.5rem; + margin-bottom: 50px; +} + +#search-results p { + text-align: center; +} + +#search-results p .index-loading { + animation: index-loading 1.5s infinite linear; + -webkit-animation: index-loading 1.5s infinite linear; + -o-animation: index-loading 1.5s infinite linear; + font-size: 2.5rem; +} + +@keyframes index-loading { + from { transform: scale(1) rotate(0deg);} + to { transform: scale(1) rotate(360deg);} +} + +@-webkit-keyframes index-loading { + from { -webkit-transform: rotate(0deg);} + to { -webkit-transform: rotate(360deg);} +} + +@-o-keyframes index-loading { + from { -o-transform: rotate(0deg);} + to { -o-transform: rotate(360deg);} +} + +#search-results .sr-items { + font-size: 24px; +} + +.sr-item { + margin-bottom: 25px; +} + +.sr-item>.item-href { + font-size: 14px; + color: #093; +} + +.sr-item>.item-brief { + font-size: 13px; +} + +.pagination>li>a { + color: #47A7A0 +} + +.pagination>.active>a { + background-color: #47A7A0; + border-color: #47A7A0; +} + +.fixed_header { + position: fixed; + width: 100%; + padding-bottom: 10px; + padding-top: 10px; + margin: 0px; + top: 0; + z-index: 9999; + left: 0; +} + +.fixed_header+.toc{ + margin-top: 50px; + margin-left: 0; +} + +.sidenav, .fixed_header, .toc { + background-color: #f1f1f1; +} + +.sidetoc { + position: fixed; + width: 260px; + top: 150px; + bottom: 0; + overflow-x: hidden; + overflow-y: auto; + background-color: #f1f1f1; + border-left: 1px solid #e7e7e7; + border-right: 1px solid #e7e7e7; + z-index: 1; +} + +.sidetoc.shiftup { + bottom: 70px; +} + +body .toc{ + background-color: #f1f1f1; + overflow-x: hidden; +} + +.sidetoggle.ng-hide { + display: block !important; +} +.sidetoc-expand > .caret { + margin-left: 0px; + margin-top: -2px; +} +.sidetoc-expand > .caret-side { + border-left: 4px solid; + border-top: 4px solid transparent; + border-bottom: 4px solid transparent; + margin-left: 4px; + margin-top: -4px; +} +.sidetoc-heading { + font-weight: 500; +} + +.toc { + margin: 0px 0 0 10px; + padding: 0 10px; +} +.expand-stub { + position: absolute; + left: -10px; +} +.toc .nav > li > a.sidetoc-expand { + position: absolute; + top: 0; + left: 0; +} +.toc .nav > li > a { + color: #666666; + margin-left: 5px; + display: block; + padding: 0; +} +.toc .nav > li > a:hover, +.toc .nav > li > a:focus { + color: #000000; + background: none; + text-decoration: inherit; +} +.toc .nav > li.active > a { + color: #337ab7; +} +.toc .nav > li.active > a:hover, +.toc .nav > li.active > a:focus { + color: #23527c; +} + +.toc .nav > li> .expand-stub { + cursor: pointer; +} + +.toc .nav > li.active > .expand-stub::before, +.toc .nav > li.in > .expand-stub::before, +.toc .nav > li.in.active > .expand-stub::before, +.toc .nav > li.filtered > .expand-stub::before { + content: "-"; +} + +.toc .nav > li > .expand-stub::before, +.toc .nav > li.active > .expand-stub::before { + content: "+"; +} + +.toc .nav > li.filtered > ul, +.toc .nav > li.in > ul { + display: block; +} + +.toc .nav > li > ul { + display: none; +} + +.toc ul{ + font-size: 12px; + margin: 0 0 0 3px; +} + +.toc .level1 > li { + font-weight: bold; + margin-top: 10px; + position: relative; + font-size: 16px; +} +.toc .level2 { + font-weight: normal; + margin: 5px 0 0 15px; + font-size: 14px; +} +.toc-toggle { + display: none; + margin: 0 15px 0px 15px; +} +.sidefilter { + position: fixed; + top: 90px; + width: 260px; + background-color: #f1f1f1; + padding: 15px; + border-left: 1px solid #e7e7e7; + border-right: 1px solid #e7e7e7; + z-index: 1; +} +.toc-filter { + border-radius: 5px; + background: #fff; + color: #666666; + padding: 5px; + position: relative; + margin: 0 5px 0 5px; +} +.toc-filter > input { + border: 0; + color: #666666; + padding-left: 20px; + width: 100%; +} +.toc-filter > input:focus { + outline: 0; +} +.toc-filter > .filter-icon { + position: absolute; + top: 10px; + left: 5px; +} +.article { + margin-top: 120px; + margin-bottom: 115px; +} + +#_content>a{ + margin-top: 105px; +} + +.article.grid-right { + margin-left: 280px; +} + +.inheritance hr { + margin-top: 5px; + margin-bottom: 5px; +} +.article img { + max-width: 100%; +} +.sideaffix { + margin-top: 50px; + font-size: 12px; + max-height: 100%; + overflow: hidden; + top: 100px; + bottom: 10px; + position: fixed; +} +.sideaffix.shiftup { + bottom: 70px; +} +.affix { + position: relative; + height: 100%; +} +.sideaffix > div.contribution { + margin-bottom: 20px; +} +.sideaffix > div.contribution > ul > li > a.contribution-link { + padding: 6px 10px; + font-weight: bold; + font-size: 14px; +} +.sideaffix > div.contribution > ul > li > a.contribution-link:hover { + background-color: #ffffff; +} +.sideaffix ul.nav > li > a:focus { + background: none; +} +.affix h5 { + font-weight: bold; + text-transform: uppercase; + padding-left: 10px; + font-size: 12px; +} +.affix > ul.level1 { + overflow: hidden; + padding-bottom: 10px; + height: calc(100% - 100px); + margin-right: -20px; +} +.affix ul > li > a:before { + color: #cccccc; + position: absolute; +} +.affix ul > li > a:hover { + background: none; + color: #666666; +} +.affix ul > li.active > a, +.affix ul > li.active > a:before { + color: #337ab7; +} +.affix ul > li > a { + padding: 5px 12px; + color: #666666; +} +.affix > ul > li.active:last-child { + margin-bottom: 50px; +} +.affix > ul > li > a:before { + content: "|"; + font-size: 16px; + top: 1px; + left: 0; +} +.affix > ul > li.active > a, +.affix > ul > li.active > a:before { + color: #337ab7; + font-weight: bold; +} +.affix ul ul > li > a { + padding: 2px 15px; +} +.affix ul ul > li > a:before { + content: ">"; + font-size: 14px; + top: -1px; + left: 5px; +} +.affix ul > li > a:before, +.affix ul ul { + display: none; +} +.affix ul > li.active > ul, +.affix ul > li.active > a:before, +.affix ul > li > a:hover:before { + display: block; + white-space: nowrap; +} +.codewrapper { + position: relative; +} +.trydiv { + height: 0px; +} +.tryspan { + position: absolute; + top: 0px; + right: 0px; + border-style: solid; + border-radius: 0px 4px; + box-sizing: border-box; + border-width: 1px; + border-color: #cccccc; + text-align: center; + padding: 2px 8px; + background-color: white; + font-size: 12px; + cursor: pointer; + z-index: 100; + display: none; + color: #767676; +} +.tryspan:hover { + background-color: #3b8bd0; + color: white; + border-color: #3b8bd0; +} +.codewrapper:hover .tryspan { + display: block; +} +.sample-response .response-content{ + max-height: 200px; +} +footer { + position: absolute; + left: 0; + right: 0; + bottom: 0; + z-index: 1000; +} +.footer { + border-top: 1px solid #e7e7e7; + background-color: #f8f8f8; + padding: 15px 0; +} +@media (min-width: 768px) { + #sidetoggle.collapse { + display: block; + } + .topnav .navbar-nav { + float: none; + white-space: nowrap; + } + .topnav .navbar-nav > li { + float: none; + display: inline-block; + } +} +@media only screen and (max-width: 768px) { + #mobile-indicator { + display: block; + } + /* TOC display for responsive */ + .article { + margin-top: 30px !important; + } + header { + position: static; + } + .topnav { + text-align: center; + } + .sidenav { + padding: 15px 0; + margin-left: -15px; + margin-right: -15px; + } + .sidefilter { + position: static; + width: auto; + float: none; + border: none; + } + .sidetoc { + position: static; + width: auto; + float: none; + padding-bottom: 0px; + border: none; + } + .toc .nav > li, .toc .nav > li >a { + display: inline-block; + } + .toc li:after { + margin-left: -3px; + margin-right: 5px; + content: ", "; + color: #666666; + } + .toc .level1 > li { + display: block; + } + + .toc .level1 > li:after { + display: none; + } + .article.grid-right { + margin-left: 0; + } + .grad-top, + .grad-bottom { + display: none; + } + .toc-toggle { + display: block; + } + .sidetoggle.ng-hide { + display: none !important; + } + /*.expand-all { + display: none; + }*/ + .sideaffix { + display: none; + } + .mobile-hide { + display: none; + } + .breadcrumb { + white-space: inherit; + } + + /* workaround for #hashtag url is no longer needed*/ + h1:before, + h2:before, + h3:before, + h4:before { + content: ''; + display: none; + } +} + +/* For toc iframe */ +@media (max-width: 260px) { + .toc .level2 > li { + display: block; + } + + .toc .level2 > li:after { + display: none; + } +} + +/* For code snippet line highlight */ +pre > code .line-highlight { + background-color: #ffffcc; +} + +/* Alerts */ +.alert h5 { + text-transform: uppercase; + font-weight: bold; + margin-top: 0; +} + +.alert h5:before { + position:relative; + top:1px; + display:inline-block; + font-family:'Glyphicons Halflings'; + line-height:1; + -webkit-font-smoothing:antialiased; + -moz-osx-font-smoothing:grayscale; + margin-right: 5px; + font-weight: normal; +} + +.alert-info h5:before { + content:"\e086" +} + +.alert-warning h5:before { + content:"\e127" +} + +.alert-danger h5:before { + content:"\e107" +} + +/* For Embedded Video */ +div.embeddedvideo { + padding-top: 56.25%; + position: relative; + width: 100%; +} + +div.embeddedvideo iframe { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + width: 100%; + height: 100%; +} + +/* For printer */ +@media print{ + .article.grid-right { + margin-top: 0px; + margin-left: 0px; + } + .sideaffix { + display: none; + } + .mobile-hide { + display: none; + } + .footer { + display: none; + } +} + +/* For tabbed content */ + +.tabGroup { + margin-top: 1rem; } + .tabGroup ul[role="tablist"] { + margin: 0; + padding: 0; + list-style: none; } + .tabGroup ul[role="tablist"] > li { + list-style: none; + display: inline-block; } + .tabGroup a[role="tab"] { + color: #6e6e6e; + box-sizing: border-box; + display: inline-block; + padding: 5px 7.5px; + text-decoration: none; + border-bottom: 2px solid #fff; } + .tabGroup a[role="tab"]:hover, .tabGroup a[role="tab"]:focus, .tabGroup a[role="tab"][aria-selected="true"] { + border-bottom: 2px solid #0050C5; } + .tabGroup a[role="tab"][aria-selected="true"] { + color: #222; } + .tabGroup a[role="tab"]:hover, .tabGroup a[role="tab"]:focus { + color: #0050C5; } + .tabGroup a[role="tab"]:focus { + outline: 1px solid #0050C5; + outline-offset: -1px; } + @media (min-width: 768px) { + .tabGroup a[role="tab"] { + padding: 5px 15px; } } + .tabGroup section[role="tabpanel"] { + border: 1px solid #e0e0e0; + padding: 15px; + margin: 0; + overflow: hidden; } + .tabGroup section[role="tabpanel"] > .codeHeader, + .tabGroup section[role="tabpanel"] > pre { + margin-left: -16px; + margin-right: -16px; } + .tabGroup section[role="tabpanel"] > :first-child { + margin-top: 0; } + .tabGroup section[role="tabpanel"] > pre:last-child { + display: block; + margin-bottom: -16px; } + +.mainContainer[dir='rtl'] main ul[role="tablist"] { + margin: 0; } diff --git a/docs/styles/docfx.js b/docs/styles/docfx.js new file mode 100644 index 000000000..8fa50483a --- /dev/null +++ b/docs/styles/docfx.js @@ -0,0 +1,1143 @@ +// Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See LICENSE file in the project root for full license information. +$(function () { + var active = 'active'; + var expanded = 'in'; + var collapsed = 'collapsed'; + var filtered = 'filtered'; + var show = 'show'; + var hide = 'hide'; + var util = new utility(); + + workAroundFixedHeaderForAnchors(); + highlight(); + enableSearch(); + + renderTables(); + renderAlerts(); + renderLinks(); + renderNavbar(); + renderSidebar(); + renderAffix(); + renderFooter(); + renderLogo(); + + breakText(); + renderTabs(); + + window.refresh = function (article) { + // Update markup result + if (typeof article == 'undefined' || typeof article.content == 'undefined') + console.error("Null Argument"); + $("article.content").html(article.content); + + highlight(); + renderTables(); + renderAlerts(); + renderAffix(); + renderTabs(); + } + + // Add this event listener when needed + // window.addEventListener('content-update', contentUpdate); + + function breakText() { + $(".xref").addClass("text-break"); + var texts = $(".text-break"); + texts.each(function () { + $(this).breakWord(); + }); + } + + // Styling for tables in conceptual documents using Bootstrap. + // See http://getbootstrap.com/css/#tables + function renderTables() { + $('table').addClass('table table-bordered table-striped table-condensed').wrap('
'); + } + + // Styling for alerts. + function renderAlerts() { + $('.NOTE, .TIP').addClass('alert alert-info'); + $('.WARNING').addClass('alert alert-warning'); + $('.IMPORTANT, .CAUTION').addClass('alert alert-danger'); + } + + // Enable anchors for headings. + (function () { + anchors.options = { + placement: 'left', + visible: 'touch' + }; + anchors.add('article h2:not(.no-anchor), article h3:not(.no-anchor), article h4:not(.no-anchor)'); + })(); + + // Open links to different host in a new window. + function renderLinks() { + if ($("meta[property='docfx:newtab']").attr("content") === "true") { + $(document.links).filter(function () { + return this.hostname !== window.location.hostname; + }).attr('target', '_blank'); + } + } + + // Enable highlight.js + function highlight() { + $('pre code').each(function (i, block) { + hljs.highlightBlock(block); + }); + $('pre code[highlight-lines]').each(function (i, block) { + if (block.innerHTML === "") return; + var lines = block.innerHTML.split('\n'); + + queryString = block.getAttribute('highlight-lines'); + if (!queryString) return; + + var ranges = queryString.split(','); + for (var j = 0, range; range = ranges[j++];) { + var found = range.match(/^(\d+)\-(\d+)?$/); + if (found) { + // consider region as `{startlinenumber}-{endlinenumber}`, in which {endlinenumber} is optional + var start = +found[1]; + var end = +found[2]; + if (isNaN(end) || end > lines.length) { + end = lines.length; + } + } else { + // consider region as a sigine line number + if (isNaN(range)) continue; + var start = +range; + var end = start; + } + if (start <= 0 || end <= 0 || start > end || start > lines.length) { + // skip current region if invalid + continue; + } + lines[start - 1] = '' + lines[start - 1]; + lines[end - 1] = lines[end - 1] + ''; + } + + block.innerHTML = lines.join('\n'); + }); + } + + // Support full-text-search + function enableSearch() { + var query; + var relHref = $("meta[property='docfx\\:rel']").attr("content"); + if (typeof relHref === 'undefined') { + return; + } + try { + var worker = new Worker(relHref + 'styles/search-worker.js'); + if (!worker && !window.worker) { + localSearch(); + } else { + webWorkerSearch(); + } + + renderSearchBox(); + highlightKeywords(); + addSearchEvent(); + } catch (e) { + console.error(e); + } + + //Adjust the position of search box in navbar + function renderSearchBox() { + autoCollapse(); + $(window).on('resize', autoCollapse); + $(document).on('click', '.navbar-collapse.in', function (e) { + if ($(e.target).is('a')) { + $(this).collapse('hide'); + } + }); + + function autoCollapse() { + var navbar = $('#autocollapse'); + if (navbar.height() === null) { + setTimeout(autoCollapse, 300); + } + navbar.removeClass(collapsed); + if (navbar.height() > 60) { + navbar.addClass(collapsed); + } + } + } + + // Search factory + function localSearch() { + console.log("using local search"); + var lunrIndex = lunr(function () { + this.ref('href'); + this.field('title', { boost: 50 }); + this.field('keywords', { boost: 20 }); + }); + lunr.tokenizer.seperator = /[\s\-\.]+/; + var searchData = {}; + var searchDataRequest = new XMLHttpRequest(); + + var indexPath = relHref + "index.json"; + if (indexPath) { + searchDataRequest.open('GET', indexPath); + searchDataRequest.onload = function () { + if (this.status != 200) { + return; + } + searchData = JSON.parse(this.responseText); + for (var prop in searchData) { + if (searchData.hasOwnProperty(prop)) { + lunrIndex.add(searchData[prop]); + } + } + } + searchDataRequest.send(); + } + + $("body").bind("queryReady", function () { + var hits = lunrIndex.search(query); + var results = []; + hits.forEach(function (hit) { + var item = searchData[hit.ref]; + results.push({ 'href': item.href, 'title': item.title, 'keywords': item.keywords }); + }); + handleSearchResults(results); + }); + } + + function webWorkerSearch() { + console.log("using Web Worker"); + var indexReady = $.Deferred(); + + worker.onmessage = function (oEvent) { + switch (oEvent.data.e) { + case 'index-ready': + indexReady.resolve(); + break; + case 'query-ready': + var hits = oEvent.data.d; + handleSearchResults(hits); + break; + } + } + + indexReady.promise().done(function () { + $("body").bind("queryReady", function () { + worker.postMessage({ q: query }); + }); + if (query && (query.length >= 3)) { + worker.postMessage({ q: query }); + } + }); + } + + // Highlight the searching keywords + function highlightKeywords() { + var q = url('?q'); + if (q !== null) { + var keywords = q.split("%20"); + keywords.forEach(function (keyword) { + if (keyword !== "") { + $('.data-searchable *').mark(keyword); + $('article *').mark(keyword); + } + }); + } + } + + function addSearchEvent() { + $('body').bind("searchEvent", function () { + $('#search-query').keypress(function (e) { + return e.which !== 13; + }); + + $('#search-query').keyup(function () { + query = $(this).val(); + if (query.length < 3) { + flipContents("show"); + } else { + flipContents("hide"); + $("body").trigger("queryReady"); + $('#search-results>.search-list').text('Search Results for "' + query + '"'); + } + }).off("keydown"); + }); + } + + function flipContents(action) { + if (action === "show") { + $('.hide-when-search').show(); + $('#search-results').hide(); + } else { + $('.hide-when-search').hide(); + $('#search-results').show(); + } + } + + function relativeUrlToAbsoluteUrl(currentUrl, relativeUrl) { + var currentItems = currentUrl.split(/\/+/); + var relativeItems = relativeUrl.split(/\/+/); + var depth = currentItems.length - 1; + var items = []; + for (var i = 0; i < relativeItems.length; i++) { + if (relativeItems[i] === '..') { + depth--; + } else if (relativeItems[i] !== '.') { + items.push(relativeItems[i]); + } + } + return currentItems.slice(0, depth).concat(items).join('/'); + } + + function extractContentBrief(content) { + var briefOffset = 512; + var words = query.split(/\s+/g); + var queryIndex = content.indexOf(words[0]); + var briefContent; + if (queryIndex > briefOffset) { + return "..." + content.slice(queryIndex - briefOffset, queryIndex + briefOffset) + "..."; + } else if (queryIndex <= briefOffset) { + return content.slice(0, queryIndex + briefOffset) + "..."; + } + } + + function handleSearchResults(hits) { + var numPerPage = 10; + $('#pagination').empty(); + $('#pagination').removeData("twbs-pagination"); + if (hits.length === 0) { + $('#search-results>.sr-items').html('

No results found

'); + } else { + $('#pagination').twbsPagination({ + totalPages: Math.ceil(hits.length / numPerPage), + visiblePages: 5, + onPageClick: function (event, page) { + var start = (page - 1) * numPerPage; + var curHits = hits.slice(start, start + numPerPage); + $('#search-results>.sr-items').empty().append( + curHits.map(function (hit) { + var currentUrl = window.location.href; + var itemRawHref = relativeUrlToAbsoluteUrl(currentUrl, relHref + hit.href); + var itemHref = relHref + hit.href + "?q=" + query; + var itemTitle = hit.title; + var itemBrief = extractContentBrief(hit.keywords); + + var itemNode = $('
').attr('class', 'sr-item'); + var itemTitleNode = $('
').attr('class', 'item-title').append($('').attr('href', itemHref).attr("target", "_blank").text(itemTitle)); + var itemHrefNode = $('
').attr('class', 'item-href').text(itemRawHref); + var itemBriefNode = $('
').attr('class', 'item-brief').text(itemBrief); + itemNode.append(itemTitleNode).append(itemHrefNode).append(itemBriefNode); + return itemNode; + }) + ); + query.split(/\s+/).forEach(function (word) { + if (word !== '') { + $('#search-results>.sr-items *').mark(word); + } + }); + } + }); + } + } + }; + + // Update href in navbar + function renderNavbar() { + var navbar = $('#navbar ul')[0]; + if (typeof (navbar) === 'undefined') { + loadNavbar(); + } else { + $('#navbar ul a.active').parents('li').addClass(active); + renderBreadcrumb(); + showSearch(); + } + + function showSearch() { + if ($('#search-results').length !== 0) { + $('#search').show(); + $('body').trigger("searchEvent"); + } + } + + function loadNavbar() { + var navbarPath = $("meta[property='docfx\\:navrel']").attr("content"); + if (!navbarPath) { + return; + } + navbarPath = navbarPath.replace(/\\/g, '/'); + var tocPath = $("meta[property='docfx\\:tocrel']").attr("content") || ''; + if (tocPath) tocPath = tocPath.replace(/\\/g, '/'); + $.get(navbarPath, function (data) { + $(data).find("#toc>ul").appendTo("#navbar"); + showSearch(); + var index = navbarPath.lastIndexOf('/'); + var navrel = ''; + if (index > -1) { + navrel = navbarPath.substr(0, index + 1); + } + $('#navbar>ul').addClass('navbar-nav'); + var currentAbsPath = util.getAbsolutePath(window.location.pathname); + // set active item + $('#navbar').find('a[href]').each(function (i, e) { + var href = $(e).attr("href"); + if (util.isRelativePath(href)) { + href = navrel + href; + $(e).attr("href", href); + + var isActive = false; + var originalHref = e.name; + if (originalHref) { + originalHref = navrel + originalHref; + if (util.getDirectory(util.getAbsolutePath(originalHref)) === util.getDirectory(util.getAbsolutePath(tocPath))) { + isActive = true; + } + } else { + if (util.getAbsolutePath(href) === currentAbsPath) { + var dropdown = $(e).attr('data-toggle') == "dropdown" + if (!dropdown) { + isActive = true; + } + } + } + if (isActive) { + $(e).addClass(active); + } + } + }); + renderNavbar(); + }); + } + } + + function renderSidebar() { + var sidetoc = $('#sidetoggle .sidetoc')[0]; + if (typeof (sidetoc) === 'undefined') { + loadToc(); + } else { + registerTocEvents(); + if ($('footer').is(':visible')) { + $('.sidetoc').addClass('shiftup'); + } + + // Scroll to active item + var top = 0; + $('#toc a.active').parents('li').each(function (i, e) { + $(e).addClass(active).addClass(expanded); + $(e).children('a').addClass(active); + top += $(e).position().top; + }) + $('.sidetoc').scrollTop(top - 50); + + if ($('footer').is(':visible')) { + $('.sidetoc').addClass('shiftup'); + } + + renderBreadcrumb(); + } + + function registerTocEvents() { + $('.toc .nav > li > .expand-stub').click(function (e) { + $(e.target).parent().toggleClass(expanded); + }); + $('.toc .nav > li > .expand-stub + a:not([href])').click(function (e) { + $(e.target).parent().toggleClass(expanded); + }); + $('#toc_filter_input').on('input', function (e) { + var val = this.value; + if (val === '') { + // Clear 'filtered' class + $('#toc li').removeClass(filtered).removeClass(hide); + return; + } + + // Get leaf nodes + $('#toc li>a').filter(function (i, e) { + return $(e).siblings().length === 0 + }).each(function (i, anchor) { + var text = $(anchor).attr('title'); + var parent = $(anchor).parent(); + var parentNodes = parent.parents('ul>li'); + for (var i = 0; i < parentNodes.length; i++) { + var parentText = $(parentNodes[i]).children('a').attr('title'); + if (parentText) text = parentText + '.' + text; + }; + if (filterNavItem(text, val)) { + parent.addClass(show); + parent.removeClass(hide); + } else { + parent.addClass(hide); + parent.removeClass(show); + } + }); + $('#toc li>a').filter(function (i, e) { + return $(e).siblings().length > 0 + }).each(function (i, anchor) { + var parent = $(anchor).parent(); + if (parent.find('li.show').length > 0) { + parent.addClass(show); + parent.addClass(filtered); + parent.removeClass(hide); + } else { + parent.addClass(hide); + parent.removeClass(show); + parent.removeClass(filtered); + } + }) + + function filterNavItem(name, text) { + if (!text) return true; + if (name && name.toLowerCase().indexOf(text.toLowerCase()) > -1) return true; + return false; + } + }); + } + + function loadToc() { + var tocPath = $("meta[property='docfx\\:tocrel']").attr("content"); + if (!tocPath) { + return; + } + tocPath = tocPath.replace(/\\/g, '/'); + $('#sidetoc').load(tocPath + " #sidetoggle > div", function () { + var index = tocPath.lastIndexOf('/'); + var tocrel = ''; + if (index > -1) { + tocrel = tocPath.substr(0, index + 1); + } + var currentHref = util.getAbsolutePath(window.location.pathname); + $('#sidetoc').find('a[href]').each(function (i, e) { + var href = $(e).attr("href"); + if (util.isRelativePath(href)) { + href = tocrel + href; + $(e).attr("href", href); + } + + if (util.getAbsolutePath(e.href) === currentHref) { + $(e).addClass(active); + } + + $(e).breakWord(); + }); + + renderSidebar(); + }); + } + } + + function renderBreadcrumb() { + var breadcrumb = []; + $('#navbar a.active').each(function (i, e) { + breadcrumb.push({ + href: e.href, + name: e.innerHTML + }); + }) + $('#toc a.active').each(function (i, e) { + breadcrumb.push({ + href: e.href, + name: e.innerHTML + }); + }) + + var html = util.formList(breadcrumb, 'breadcrumb'); + $('#breadcrumb').html(html); + } + + //Setup Affix + function renderAffix() { + var hierarchy = getHierarchy(); + if (hierarchy && hierarchy.length > 0) { + var html = '
In This Article
' + html += util.formList(hierarchy, ['nav', 'bs-docs-sidenav']); + $("#affix").empty().append(html); + if ($('footer').is(':visible')) { + $(".sideaffix").css("bottom", "70px"); + } + $('#affix a').click(function(e) { + var scrollspy = $('[data-spy="scroll"]').data()['bs.scrollspy']; + var target = e.target.hash; + if (scrollspy && target) { + scrollspy.activate(target); + } + }); + } + + function getHierarchy() { + // supported headers are h1, h2, h3, and h4 + var $headers = $($.map(['h1', 'h2', 'h3', 'h4'], function (h) { return ".article article " + h; }).join(", ")); + + // a stack of hierarchy items that are currently being built + var stack = []; + $headers.each(function (i, e) { + if (!e.id) { + return; + } + + var item = { + name: htmlEncode($(e).text()), + href: "#" + e.id, + items: [] + }; + + if (!stack.length) { + stack.push({ type: e.tagName, siblings: [item] }); + return; + } + + var frame = stack[stack.length - 1]; + if (e.tagName === frame.type) { + frame.siblings.push(item); + } else if (e.tagName[1] > frame.type[1]) { + // we are looking at a child of the last element of frame.siblings. + // push a frame onto the stack. After we've finished building this item's children, + // we'll attach it as a child of the last element + stack.push({ type: e.tagName, siblings: [item] }); + } else { // e.tagName[1] < frame.type[1] + // we are looking at a sibling of an ancestor of the current item. + // pop frames from the stack, building items as we go, until we reach the correct level at which to attach this item. + while (e.tagName[1] < stack[stack.length - 1].type[1]) { + buildParent(); + } + if (e.tagName === stack[stack.length - 1].type) { + stack[stack.length - 1].siblings.push(item); + } else { + stack.push({ type: e.tagName, siblings: [item] }); + } + } + }); + while (stack.length > 1) { + buildParent(); + } + + function buildParent() { + var childrenToAttach = stack.pop(); + var parentFrame = stack[stack.length - 1]; + var parent = parentFrame.siblings[parentFrame.siblings.length - 1]; + $.each(childrenToAttach.siblings, function (i, child) { + parent.items.push(child); + }); + } + if (stack.length > 0) { + + var topLevel = stack.pop().siblings; + if (topLevel.length === 1) { // if there's only one topmost header, dump it + return topLevel[0].items; + } + return topLevel; + } + return undefined; + } + + function htmlEncode(str) { + if (!str) return str; + return str + .replace(/&/g, '&') + .replace(/"/g, '"') + .replace(/'/g, ''') + .replace(//g, '>'); + } + + function htmlDecode(value) { + if (!str) return str; + return value + .replace(/"/g, '"') + .replace(/'/g, "'") + .replace(/</g, '<') + .replace(/>/g, '>') + .replace(/&/g, '&'); + } + + function cssEscape(str) { + // see: http://stackoverflow.com/questions/2786538/need-to-escape-a-special-character-in-a-jquery-selector-string#answer-2837646 + if (!str) return str; + return str + .replace(/[!"#$%&'()*+,.\/:;<=>?@[\\\]^`{|}~]/g, "\\$&"); + } + } + + // Show footer + function renderFooter() { + initFooter(); + $(window).on("scroll", showFooterCore); + + function initFooter() { + if (needFooter()) { + shiftUpBottomCss(); + $("footer").show(); + } else { + resetBottomCss(); + $("footer").hide(); + } + } + + function showFooterCore() { + if (needFooter()) { + shiftUpBottomCss(); + $("footer").fadeIn(); + } else { + resetBottomCss(); + $("footer").fadeOut(); + } + } + + function needFooter() { + var scrollHeight = $(document).height(); + var scrollPosition = $(window).height() + $(window).scrollTop(); + return (scrollHeight - scrollPosition) < 1; + } + + function resetBottomCss() { + $(".sidetoc").removeClass("shiftup"); + $(".sideaffix").removeClass("shiftup"); + } + + function shiftUpBottomCss() { + $(".sidetoc").addClass("shiftup"); + $(".sideaffix").addClass("shiftup"); + } + } + + function renderLogo() { + // For LOGO SVG + // Replace SVG with inline SVG + // http://stackoverflow.com/questions/11978995/how-to-change-color-of-svg-image-using-css-jquery-svg-image-replacement + jQuery('img.svg').each(function () { + var $img = jQuery(this); + var imgID = $img.attr('id'); + var imgClass = $img.attr('class'); + var imgURL = $img.attr('src'); + + jQuery.get(imgURL, function (data) { + // Get the SVG tag, ignore the rest + var $svg = jQuery(data).find('svg'); + + // Add replaced image's ID to the new SVG + if (typeof imgID !== 'undefined') { + $svg = $svg.attr('id', imgID); + } + // Add replaced image's classes to the new SVG + if (typeof imgClass !== 'undefined') { + $svg = $svg.attr('class', imgClass + ' replaced-svg'); + } + + // Remove any invalid XML tags as per http://validator.w3.org + $svg = $svg.removeAttr('xmlns:a'); + + // Replace image with new SVG + $img.replaceWith($svg); + + }, 'xml'); + }); + } + + function renderTabs() { + var contentAttrs = { + id: 'data-bi-id', + name: 'data-bi-name', + type: 'data-bi-type' + }; + + var Tab = (function () { + function Tab(li, a, section) { + this.li = li; + this.a = a; + this.section = section; + } + Object.defineProperty(Tab.prototype, "tabIds", { + get: function () { return this.a.getAttribute('data-tab').split(' '); }, + enumerable: true, + configurable: true + }); + Object.defineProperty(Tab.prototype, "condition", { + get: function () { return this.a.getAttribute('data-condition'); }, + enumerable: true, + configurable: true + }); + Object.defineProperty(Tab.prototype, "visible", { + get: function () { return !this.li.hasAttribute('hidden'); }, + set: function (value) { + if (value) { + this.li.removeAttribute('hidden'); + this.li.removeAttribute('aria-hidden'); + } + else { + this.li.setAttribute('hidden', 'hidden'); + this.li.setAttribute('aria-hidden', 'true'); + } + }, + enumerable: true, + configurable: true + }); + Object.defineProperty(Tab.prototype, "selected", { + get: function () { return !this.section.hasAttribute('hidden'); }, + set: function (value) { + if (value) { + this.a.setAttribute('aria-selected', 'true'); + this.a.tabIndex = 0; + this.section.removeAttribute('hidden'); + this.section.removeAttribute('aria-hidden'); + } + else { + this.a.setAttribute('aria-selected', 'false'); + this.a.tabIndex = -1; + this.section.setAttribute('hidden', 'hidden'); + this.section.setAttribute('aria-hidden', 'true'); + } + }, + enumerable: true, + configurable: true + }); + Tab.prototype.focus = function () { + this.a.focus(); + }; + return Tab; + }()); + + initTabs(document.body); + + function initTabs(container) { + var queryStringTabs = readTabsQueryStringParam(); + var elements = container.querySelectorAll('.tabGroup'); + var state = { groups: [], selectedTabs: [] }; + for (var i = 0; i < elements.length; i++) { + var group = initTabGroup(elements.item(i)); + if (!group.independent) { + updateVisibilityAndSelection(group, state); + state.groups.push(group); + } + } + container.addEventListener('click', function (event) { return handleClick(event, state); }); + if (state.groups.length === 0) { + return state; + } + selectTabs(queryStringTabs, container); + updateTabsQueryStringParam(state); + notifyContentUpdated(); + return state; + } + + function initTabGroup(element) { + var group = { + independent: element.hasAttribute('data-tab-group-independent'), + tabs: [] + }; + var li = element.firstElementChild.firstElementChild; + while (li) { + var a = li.firstElementChild; + a.setAttribute(contentAttrs.name, 'tab'); + var dataTab = a.getAttribute('data-tab').replace(/\+/g, ' '); + a.setAttribute('data-tab', dataTab); + var section = element.querySelector("[id=\"" + a.getAttribute('aria-controls') + "\"]"); + var tab = new Tab(li, a, section); + group.tabs.push(tab); + li = li.nextElementSibling; + } + element.setAttribute(contentAttrs.name, 'tab-group'); + element.tabGroup = group; + return group; + } + + function updateVisibilityAndSelection(group, state) { + var anySelected = false; + var firstVisibleTab; + for (var _i = 0, _a = group.tabs; _i < _a.length; _i++) { + var tab = _a[_i]; + tab.visible = tab.condition === null || state.selectedTabs.indexOf(tab.condition) !== -1; + if (tab.visible) { + if (!firstVisibleTab) { + firstVisibleTab = tab; + } + } + tab.selected = tab.visible && arraysIntersect(state.selectedTabs, tab.tabIds); + anySelected = anySelected || tab.selected; + } + if (!anySelected) { + for (var _b = 0, _c = group.tabs; _b < _c.length; _b++) { + var tabIds = _c[_b].tabIds; + for (var _d = 0, tabIds_1 = tabIds; _d < tabIds_1.length; _d++) { + var tabId = tabIds_1[_d]; + var index = state.selectedTabs.indexOf(tabId); + if (index === -1) { + continue; + } + state.selectedTabs.splice(index, 1); + } + } + var tab = firstVisibleTab; + tab.selected = true; + state.selectedTabs.push(tab.tabIds[0]); + } + } + + function getTabInfoFromEvent(event) { + if (!(event.target instanceof HTMLElement)) { + return null; + } + var anchor = event.target.closest('a[data-tab]'); + if (anchor === null) { + return null; + } + var tabIds = anchor.getAttribute('data-tab').split(' '); + var group = anchor.parentElement.parentElement.parentElement.tabGroup; + if (group === undefined) { + return null; + } + return { tabIds: tabIds, group: group, anchor: anchor }; + } + + function handleClick(event, state) { + var info = getTabInfoFromEvent(event); + if (info === null) { + return; + } + event.preventDefault(); + info.anchor.href = 'javascript:'; + setTimeout(function () { return info.anchor.href = '#' + info.anchor.getAttribute('aria-controls'); }); + var tabIds = info.tabIds, group = info.group; + var originalTop = info.anchor.getBoundingClientRect().top; + if (group.independent) { + for (var _i = 0, _a = group.tabs; _i < _a.length; _i++) { + var tab = _a[_i]; + tab.selected = arraysIntersect(tab.tabIds, tabIds); + } + } + else { + if (arraysIntersect(state.selectedTabs, tabIds)) { + return; + } + var previousTabId = group.tabs.filter(function (t) { return t.selected; })[0].tabIds[0]; + state.selectedTabs.splice(state.selectedTabs.indexOf(previousTabId), 1, tabIds[0]); + for (var _b = 0, _c = state.groups; _b < _c.length; _b++) { + var group_1 = _c[_b]; + updateVisibilityAndSelection(group_1, state); + } + updateTabsQueryStringParam(state); + } + notifyContentUpdated(); + var top = info.anchor.getBoundingClientRect().top; + if (top !== originalTop && event instanceof MouseEvent) { + window.scrollTo(0, window.pageYOffset + top - originalTop); + } + } + + function selectTabs(tabIds) { + for (var _i = 0, tabIds_1 = tabIds; _i < tabIds_1.length; _i++) { + var tabId = tabIds_1[_i]; + var a = document.querySelector(".tabGroup > ul > li > a[data-tab=\"" + tabId + "\"]:not([hidden])"); + if (a === null) { + return; + } + a.dispatchEvent(new CustomEvent('click', { bubbles: true })); + } + } + + function readTabsQueryStringParam() { + var qs = parseQueryString(); + var t = qs.tabs; + if (t === undefined || t === '') { + return []; + } + return t.split(','); + } + + function updateTabsQueryStringParam(state) { + var qs = parseQueryString(); + qs.tabs = state.selectedTabs.join(); + var url = location.protocol + "//" + location.host + location.pathname + "?" + toQueryString(qs) + location.hash; + if (location.href === url) { + return; + } + history.replaceState({}, document.title, url); + } + + function toQueryString(args) { + var parts = []; + for (var name_1 in args) { + if (args.hasOwnProperty(name_1) && args[name_1] !== '' && args[name_1] !== null && args[name_1] !== undefined) { + parts.push(encodeURIComponent(name_1) + '=' + encodeURIComponent(args[name_1])); + } + } + return parts.join('&'); + } + + function parseQueryString(queryString) { + var match; + var pl = /\+/g; + var search = /([^&=]+)=?([^&]*)/g; + var decode = function (s) { return decodeURIComponent(s.replace(pl, ' ')); }; + if (queryString === undefined) { + queryString = ''; + } + queryString = queryString.substring(1); + var urlParams = {}; + while (match = search.exec(queryString)) { + urlParams[decode(match[1])] = decode(match[2]); + } + return urlParams; + } + + function arraysIntersect(a, b) { + for (var _i = 0, a_1 = a; _i < a_1.length; _i++) { + var itemA = a_1[_i]; + for (var _a = 0, b_1 = b; _a < b_1.length; _a++) { + var itemB = b_1[_a]; + if (itemA === itemB) { + return true; + } + } + } + return false; + } + + function notifyContentUpdated() { + // Dispatch this event when needed + // window.dispatchEvent(new CustomEvent('content-update')); + } + } + + function utility() { + this.getAbsolutePath = getAbsolutePath; + this.isRelativePath = isRelativePath; + this.isAbsolutePath = isAbsolutePath; + this.getDirectory = getDirectory; + this.formList = formList; + + function getAbsolutePath(href) { + // Use anchor to normalize href + var anchor = $('
')[0]; + // Ignore protocal, remove search and query + return anchor.host + anchor.pathname; + } + + function isRelativePath(href) { + if (href === undefined || href === '' || href[0] === '/') { + return false; + } + return !isAbsolutePath(href); + } + + function isAbsolutePath(href) { + return (/^(?:[a-z]+:)?\/\//i).test(href); + } + + function getDirectory(href) { + if (!href) return ''; + var index = href.lastIndexOf('/'); + if (index == -1) return ''; + if (index > -1) { + return href.substr(0, index); + } + } + + function formList(item, classes) { + var level = 1; + var model = { + items: item + }; + var cls = [].concat(classes).join(" "); + return getList(model, cls); + + function getList(model, cls) { + if (!model || !model.items) return null; + var l = model.items.length; + if (l === 0) return null; + var html = '
    '; + level++; + for (var i = 0; i < l; i++) { + var item = model.items[i]; + var href = item.href; + var name = item.name; + if (!name) continue; + html += href ? '
  • ' + name + '' : '
  • ' + name; + html += getList(item, cls) || ''; + html += '
  • '; + } + html += '
'; + return html; + } + } + + /** + * Add into long word. + * @param {String} text - The word to break. It should be in plain text without HTML tags. + */ + function breakPlainText(text) { + if (!text) return text; + return text.replace(/([a-z])([A-Z])|(\.)(\w)/g, '$1$3$2$4') + } + + /** + * Add into long word. The jQuery element should contain no html tags. + * If the jQuery element contains tags, this function will not change the element. + */ + $.fn.breakWord = function () { + if (this.html() == this.text()) { + this.html(function (index, text) { + return breakPlainText(text); + }) + } + return this; + } + } + + // adjusted from https://stackoverflow.com/a/13067009/1523776 + function workAroundFixedHeaderForAnchors() { + var HISTORY_SUPPORT = !!(history && history.pushState); + var ANCHOR_REGEX = /^#[^ ]+$/; + + function getFixedOffset() { + return $('header').first().height(); + } + + /** + * If the provided href is an anchor which resolves to an element on the + * page, scroll to it. + * @param {String} href + * @return {Boolean} - Was the href an anchor. + */ + function scrollIfAnchor(href, pushToHistory) { + var match, rect, anchorOffset; + + if (!ANCHOR_REGEX.test(href)) { + return false; + } + + match = document.getElementById(href.slice(1)); + + if (match) { + rect = match.getBoundingClientRect(); + anchorOffset = window.pageYOffset + rect.top - getFixedOffset(); + window.scrollTo(window.pageXOffset, anchorOffset); + + // Add the state to history as-per normal anchor links + if (HISTORY_SUPPORT && pushToHistory) { + history.pushState({}, document.title, location.pathname + href); + } + } + + return !!match; + } + + /** + * Attempt to scroll to the current location's hash. + */ + function scrollToCurrent() { + scrollIfAnchor(window.location.hash); + } + + /** + * If the click event's target was an anchor, fix the scroll position. + */ + function delegateAnchors(e) { + var elem = e.target; + + if (scrollIfAnchor(elem.getAttribute('href'), true)) { + e.preventDefault(); + } + } + + $(window).on('hashchange', scrollToCurrent); + // Exclude tabbed content case + $('a:not([data-tab])').click(delegateAnchors); + scrollToCurrent(); + } +}); diff --git a/docs/styles/docfx.vendor.css b/docs/styles/docfx.vendor.css new file mode 100644 index 000000000..91bb610c8 --- /dev/null +++ b/docs/styles/docfx.vendor.css @@ -0,0 +1,1464 @@ +/*! + * Bootstrap v3.3.7 (http://getbootstrap.com) + * Copyright 2011-2016 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + */ +/*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */ +.label,sub,sup{vertical-align:baseline} +hr,img{border:0} +body,figure{margin:0} +.btn-group>.btn-group,.btn-toolbar .btn,.btn-toolbar .btn-group,.btn-toolbar .input-group,.col-xs-1,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9,.dropdown-menu{float:left} +.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse,.pre-scrollable{max-height:340px} +html{font-family:sans-serif;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%} +article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block} +audio,canvas,progress,video{display:inline-block;vertical-align:baseline} +audio:not([controls]){display:none;height:0} +[hidden],template{display:none} +a{background-color:transparent} +a:active,a:hover{outline:0} +b,optgroup,strong{font-weight:700} +dfn{font-style:italic} +h1{margin:.67em 0} +mark{color:#000;background:#ff0} +sub,sup{position:relative;font-size:75%;line-height:0} +sup{top:-.5em} +sub{bottom:-.25em} +img{vertical-align:middle} +svg:not(:root){overflow:hidden} +hr{height:0;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box} +pre,textarea{overflow:auto} +code,kbd,pre,samp{font-size:1em} +button,input,optgroup,select,textarea{margin:0;font:inherit;color:inherit} +.glyphicon,address{font-style:normal} +button{overflow:visible} +button,select{text-transform:none} +button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer} +button[disabled],html input[disabled]{cursor:default} +button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0} +input[type=checkbox],input[type=radio]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:0} +input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button{height:auto} +input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none} +table{border-spacing:0;border-collapse:collapse} +td,th{padding:0} +/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */ +@media print{blockquote,img,pre,tr{page-break-inside:avoid} +*,:after,:before{color:#000!important;text-shadow:none!important;background:0 0!important;-webkit-box-shadow:none!important;box-shadow:none!important} +a,a:visited{text-decoration:underline} +a[href]:after{content:" (" attr(href) ")"} +abbr[title]:after{content:" (" attr(title) ")"} +a[href^="javascript:"]:after,a[href^="#"]:after{content:""} +blockquote,pre{border:1px solid #999} +thead{display:table-header-group} +img{max-width:100%!important} +h2,h3,p{orphans:3;widows:3} +h2,h3{page-break-after:avoid} +.navbar{display:none} +.btn>.caret,.dropup>.btn>.caret{border-top-color:#000!important} +.label{border:1px solid #000} +.table{border-collapse:collapse!important} +.table td,.table th{background-color:#fff!important} +.table-bordered td,.table-bordered th{border:1px solid #ddd!important} +} +.dropdown-menu,.modal-content{-webkit-background-clip:padding-box} +.btn,.btn-danger.active,.btn-danger:active,.btn-default.active,.btn-default:active,.btn-info.active,.btn-info:active,.btn-primary.active,.btn-primary:active,.btn-warning.active,.btn-warning:active,.btn.active,.btn:active,.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover,.form-control,.navbar-toggle,.open>.dropdown-toggle.btn-danger,.open>.dropdown-toggle.btn-default,.open>.dropdown-toggle.btn-info,.open>.dropdown-toggle.btn-primary,.open>.dropdown-toggle.btn-warning{background-image:none} +.img-thumbnail,body{background-color:#fff} +@font-face{font-family:'Glyphicons Halflings';src:url(../fonts/glyphicons-halflings-regular.eot);src:url(../fonts/glyphicons-halflings-regular.eot?#iefix) format('embedded-opentype'),url(../fonts/glyphicons-halflings-regular.woff2) format('woff2'),url(../fonts/glyphicons-halflings-regular.woff) format('woff'),url(../fonts/glyphicons-halflings-regular.ttf) format('truetype'),url(../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular) format('svg')} +.glyphicon{position:relative;top:1px;display:inline-block;font-family:'Glyphicons Halflings';font-weight:400;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale} +.glyphicon-asterisk:before{content:"\002a"} +.glyphicon-plus:before{content:"\002b"} +.glyphicon-eur:before,.glyphicon-euro:before{content:"\20ac"} +.glyphicon-minus:before{content:"\2212"} +.glyphicon-cloud:before{content:"\2601"} +.glyphicon-envelope:before{content:"\2709"} +.glyphicon-pencil:before{content:"\270f"} +.glyphicon-glass:before{content:"\e001"} +.glyphicon-music:before{content:"\e002"} +.glyphicon-search:before{content:"\e003"} +.glyphicon-heart:before{content:"\e005"} +.glyphicon-star:before{content:"\e006"} +.glyphicon-star-empty:before{content:"\e007"} +.glyphicon-user:before{content:"\e008"} +.glyphicon-film:before{content:"\e009"} +.glyphicon-th-large:before{content:"\e010"} +.glyphicon-th:before{content:"\e011"} +.glyphicon-th-list:before{content:"\e012"} +.glyphicon-ok:before{content:"\e013"} +.glyphicon-remove:before{content:"\e014"} +.glyphicon-zoom-in:before{content:"\e015"} +.glyphicon-zoom-out:before{content:"\e016"} +.glyphicon-off:before{content:"\e017"} +.glyphicon-signal:before{content:"\e018"} +.glyphicon-cog:before{content:"\e019"} +.glyphicon-trash:before{content:"\e020"} +.glyphicon-home:before{content:"\e021"} +.glyphicon-file:before{content:"\e022"} +.glyphicon-time:before{content:"\e023"} +.glyphicon-road:before{content:"\e024"} +.glyphicon-download-alt:before{content:"\e025"} +.glyphicon-download:before{content:"\e026"} +.glyphicon-upload:before{content:"\e027"} +.glyphicon-inbox:before{content:"\e028"} +.glyphicon-play-circle:before{content:"\e029"} +.glyphicon-repeat:before{content:"\e030"} +.glyphicon-refresh:before{content:"\e031"} +.glyphicon-list-alt:before{content:"\e032"} +.glyphicon-lock:before{content:"\e033"} +.glyphicon-flag:before{content:"\e034"} +.glyphicon-headphones:before{content:"\e035"} +.glyphicon-volume-off:before{content:"\e036"} +.glyphicon-volume-down:before{content:"\e037"} +.glyphicon-volume-up:before{content:"\e038"} +.glyphicon-qrcode:before{content:"\e039"} +.glyphicon-barcode:before{content:"\e040"} +.glyphicon-tag:before{content:"\e041"} +.glyphicon-tags:before{content:"\e042"} +.glyphicon-book:before{content:"\e043"} +.glyphicon-bookmark:before{content:"\e044"} +.glyphicon-print:before{content:"\e045"} +.glyphicon-camera:before{content:"\e046"} +.glyphicon-font:before{content:"\e047"} +.glyphicon-bold:before{content:"\e048"} +.glyphicon-italic:before{content:"\e049"} +.glyphicon-text-height:before{content:"\e050"} +.glyphicon-text-width:before{content:"\e051"} +.glyphicon-align-left:before{content:"\e052"} +.glyphicon-align-center:before{content:"\e053"} +.glyphicon-align-right:before{content:"\e054"} +.glyphicon-align-justify:before{content:"\e055"} +.glyphicon-list:before{content:"\e056"} +.glyphicon-indent-left:before{content:"\e057"} +.glyphicon-indent-right:before{content:"\e058"} +.glyphicon-facetime-video:before{content:"\e059"} +.glyphicon-picture:before{content:"\e060"} +.glyphicon-map-marker:before{content:"\e062"} +.glyphicon-adjust:before{content:"\e063"} +.glyphicon-tint:before{content:"\e064"} +.glyphicon-edit:before{content:"\e065"} +.glyphicon-share:before{content:"\e066"} +.glyphicon-check:before{content:"\e067"} +.glyphicon-move:before{content:"\e068"} +.glyphicon-step-backward:before{content:"\e069"} +.glyphicon-fast-backward:before{content:"\e070"} +.glyphicon-backward:before{content:"\e071"} +.glyphicon-play:before{content:"\e072"} +.glyphicon-pause:before{content:"\e073"} +.glyphicon-stop:before{content:"\e074"} +.glyphicon-forward:before{content:"\e075"} +.glyphicon-fast-forward:before{content:"\e076"} +.glyphicon-step-forward:before{content:"\e077"} +.glyphicon-eject:before{content:"\e078"} +.glyphicon-chevron-left:before{content:"\e079"} +.glyphicon-chevron-right:before{content:"\e080"} +.glyphicon-plus-sign:before{content:"\e081"} +.glyphicon-minus-sign:before{content:"\e082"} +.glyphicon-remove-sign:before{content:"\e083"} +.glyphicon-ok-sign:before{content:"\e084"} +.glyphicon-question-sign:before{content:"\e085"} +.glyphicon-info-sign:before{content:"\e086"} +.glyphicon-screenshot:before{content:"\e087"} +.glyphicon-remove-circle:before{content:"\e088"} +.glyphicon-ok-circle:before{content:"\e089"} +.glyphicon-ban-circle:before{content:"\e090"} +.glyphicon-arrow-left:before{content:"\e091"} +.glyphicon-arrow-right:before{content:"\e092"} +.glyphicon-arrow-up:before{content:"\e093"} +.glyphicon-arrow-down:before{content:"\e094"} +.glyphicon-share-alt:before{content:"\e095"} +.glyphicon-resize-full:before{content:"\e096"} +.glyphicon-resize-small:before{content:"\e097"} +.glyphicon-exclamation-sign:before{content:"\e101"} +.glyphicon-gift:before{content:"\e102"} +.glyphicon-leaf:before{content:"\e103"} +.glyphicon-fire:before{content:"\e104"} +.glyphicon-eye-open:before{content:"\e105"} +.glyphicon-eye-close:before{content:"\e106"} +.glyphicon-warning-sign:before{content:"\e107"} +.glyphicon-plane:before{content:"\e108"} +.glyphicon-calendar:before{content:"\e109"} +.glyphicon-random:before{content:"\e110"} +.glyphicon-comment:before{content:"\e111"} +.glyphicon-magnet:before{content:"\e112"} +.glyphicon-chevron-up:before{content:"\e113"} +.glyphicon-chevron-down:before{content:"\e114"} +.glyphicon-retweet:before{content:"\e115"} +.glyphicon-shopping-cart:before{content:"\e116"} +.glyphicon-folder-close:before{content:"\e117"} +.glyphicon-folder-open:before{content:"\e118"} +.glyphicon-resize-vertical:before{content:"\e119"} +.glyphicon-resize-horizontal:before{content:"\e120"} +.glyphicon-hdd:before{content:"\e121"} +.glyphicon-bullhorn:before{content:"\e122"} +.glyphicon-bell:before{content:"\e123"} +.glyphicon-certificate:before{content:"\e124"} +.glyphicon-thumbs-up:before{content:"\e125"} +.glyphicon-thumbs-down:before{content:"\e126"} +.glyphicon-hand-right:before{content:"\e127"} +.glyphicon-hand-left:before{content:"\e128"} +.glyphicon-hand-up:before{content:"\e129"} +.glyphicon-hand-down:before{content:"\e130"} +.glyphicon-circle-arrow-right:before{content:"\e131"} +.glyphicon-circle-arrow-left:before{content:"\e132"} +.glyphicon-circle-arrow-up:before{content:"\e133"} +.glyphicon-circle-arrow-down:before{content:"\e134"} +.glyphicon-globe:before{content:"\e135"} +.glyphicon-wrench:before{content:"\e136"} +.glyphicon-tasks:before{content:"\e137"} +.glyphicon-filter:before{content:"\e138"} +.glyphicon-briefcase:before{content:"\e139"} +.glyphicon-fullscreen:before{content:"\e140"} +.glyphicon-dashboard:before{content:"\e141"} +.glyphicon-paperclip:before{content:"\e142"} +.glyphicon-heart-empty:before{content:"\e143"} +.glyphicon-link:before{content:"\e144"} +.glyphicon-phone:before{content:"\e145"} +.glyphicon-pushpin:before{content:"\e146"} +.glyphicon-usd:before{content:"\e148"} +.glyphicon-gbp:before{content:"\e149"} +.glyphicon-sort:before{content:"\e150"} +.glyphicon-sort-by-alphabet:before{content:"\e151"} +.glyphicon-sort-by-alphabet-alt:before{content:"\e152"} +.glyphicon-sort-by-order:before{content:"\e153"} +.glyphicon-sort-by-order-alt:before{content:"\e154"} +.glyphicon-sort-by-attributes:before{content:"\e155"} +.glyphicon-sort-by-attributes-alt:before{content:"\e156"} +.glyphicon-unchecked:before{content:"\e157"} +.glyphicon-expand:before{content:"\e158"} +.glyphicon-collapse-down:before{content:"\e159"} +.glyphicon-collapse-up:before{content:"\e160"} +.glyphicon-log-in:before{content:"\e161"} +.glyphicon-flash:before{content:"\e162"} +.glyphicon-log-out:before{content:"\e163"} +.glyphicon-new-window:before{content:"\e164"} +.glyphicon-record:before{content:"\e165"} +.glyphicon-save:before{content:"\e166"} +.glyphicon-open:before{content:"\e167"} +.glyphicon-saved:before{content:"\e168"} +.glyphicon-import:before{content:"\e169"} +.glyphicon-export:before{content:"\e170"} +.glyphicon-send:before{content:"\e171"} +.glyphicon-floppy-disk:before{content:"\e172"} +.glyphicon-floppy-saved:before{content:"\e173"} +.glyphicon-floppy-remove:before{content:"\e174"} +.glyphicon-floppy-save:before{content:"\e175"} +.glyphicon-floppy-open:before{content:"\e176"} +.glyphicon-credit-card:before{content:"\e177"} +.glyphicon-transfer:before{content:"\e178"} +.glyphicon-cutlery:before{content:"\e179"} +.glyphicon-header:before{content:"\e180"} +.glyphicon-compressed:before{content:"\e181"} +.glyphicon-earphone:before{content:"\e182"} +.glyphicon-phone-alt:before{content:"\e183"} +.glyphicon-tower:before{content:"\e184"} +.glyphicon-stats:before{content:"\e185"} +.glyphicon-sd-video:before{content:"\e186"} +.glyphicon-hd-video:before{content:"\e187"} +.glyphicon-subtitles:before{content:"\e188"} +.glyphicon-sound-stereo:before{content:"\e189"} +.glyphicon-sound-dolby:before{content:"\e190"} +.glyphicon-sound-5-1:before{content:"\e191"} +.glyphicon-sound-6-1:before{content:"\e192"} +.glyphicon-sound-7-1:before{content:"\e193"} +.glyphicon-copyright-mark:before{content:"\e194"} +.glyphicon-registration-mark:before{content:"\e195"} +.glyphicon-cloud-download:before{content:"\e197"} +.glyphicon-cloud-upload:before{content:"\e198"} +.glyphicon-tree-conifer:before{content:"\e199"} +.glyphicon-tree-deciduous:before{content:"\e200"} +.glyphicon-cd:before{content:"\e201"} +.glyphicon-save-file:before{content:"\e202"} +.glyphicon-open-file:before{content:"\e203"} +.glyphicon-level-up:before{content:"\e204"} +.glyphicon-copy:before{content:"\e205"} +.glyphicon-paste:before{content:"\e206"} +.glyphicon-alert:before{content:"\e209"} +.glyphicon-equalizer:before{content:"\e210"} +.glyphicon-king:before{content:"\e211"} +.glyphicon-queen:before{content:"\e212"} +.glyphicon-pawn:before{content:"\e213"} +.glyphicon-bishop:before{content:"\e214"} +.glyphicon-knight:before{content:"\e215"} +.glyphicon-baby-formula:before{content:"\e216"} +.glyphicon-tent:before{content:"\26fa"} +.glyphicon-blackboard:before{content:"\e218"} +.glyphicon-bed:before{content:"\e219"} +.glyphicon-apple:before{content:"\f8ff"} +.glyphicon-erase:before{content:"\e221"} +.glyphicon-hourglass:before{content:"\231b"} +.glyphicon-lamp:before{content:"\e223"} +.glyphicon-duplicate:before{content:"\e224"} +.glyphicon-piggy-bank:before{content:"\e225"} +.glyphicon-scissors:before{content:"\e226"} +.glyphicon-bitcoin:before,.glyphicon-btc:before,.glyphicon-xbt:before{content:"\e227"} +.glyphicon-jpy:before,.glyphicon-yen:before{content:"\00a5"} +.glyphicon-rub:before,.glyphicon-ruble:before{content:"\20bd"} +.glyphicon-scale:before{content:"\e230"} +.glyphicon-ice-lolly:before{content:"\e231"} +.glyphicon-ice-lolly-tasted:before{content:"\e232"} +.glyphicon-education:before{content:"\e233"} +.glyphicon-option-horizontal:before{content:"\e234"} +.glyphicon-option-vertical:before{content:"\e235"} +.glyphicon-menu-hamburger:before{content:"\e236"} +.glyphicon-modal-window:before{content:"\e237"} +.glyphicon-oil:before{content:"\e238"} +.glyphicon-grain:before{content:"\e239"} +.glyphicon-sunglasses:before{content:"\e240"} +.glyphicon-text-size:before{content:"\e241"} +.glyphicon-text-color:before{content:"\e242"} +.glyphicon-text-background:before{content:"\e243"} +.glyphicon-object-align-top:before{content:"\e244"} +.glyphicon-object-align-bottom:before{content:"\e245"} +.glyphicon-object-align-horizontal:before{content:"\e246"} +.glyphicon-object-align-left:before{content:"\e247"} +.glyphicon-object-align-vertical:before{content:"\e248"} +.glyphicon-object-align-right:before{content:"\e249"} +.glyphicon-triangle-right:before{content:"\e250"} +.glyphicon-triangle-left:before{content:"\e251"} +.glyphicon-triangle-bottom:before{content:"\e252"} +.glyphicon-triangle-top:before{content:"\e253"} +.glyphicon-console:before{content:"\e254"} +.glyphicon-superscript:before{content:"\e255"} +.glyphicon-subscript:before{content:"\e256"} +.glyphicon-menu-left:before{content:"\e257"} +.glyphicon-menu-right:before{content:"\e258"} +.glyphicon-menu-down:before{content:"\e259"} +.glyphicon-menu-up:before{content:"\e260"} +*,:after,:before{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box} +html{font-size:10px;-webkit-tap-highlight-color:transparent} +body{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:1.42857143;color:#333} +button,input,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit} +a{color:#337ab7;text-decoration:none} +a:focus,a:hover{color:#23527c;text-decoration:underline} +a:focus{outline:-webkit-focus-ring-color auto 5px;outline-offset:-2px} +.carousel-inner>.item>a>img,.carousel-inner>.item>img,.img-responsive,.thumbnail a>img,.thumbnail>img{display:block;max-width:100%;height:auto} +.img-rounded{border-radius:6px} +.img-thumbnail{display:inline-block;max-width:100%;height:auto;padding:4px;line-height:1.42857143;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out} +.img-circle{border-radius:50%} +hr{margin-top:20px;margin-bottom:20px;border-top:1px solid #eee} +.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0} +.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto} +[role=button]{cursor:pointer} +.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{font-family:inherit;font-weight:500;line-height:1.1;color:inherit} +.h1 .small,.h1 small,.h2 .small,.h2 small,.h3 .small,.h3 small,.h4 .small,.h4 small,.h5 .small,.h5 small,.h6 .small,.h6 small,h1 .small,h1 small,h2 .small,h2 small,h3 .small,h3 small,h4 .small,h4 small,h5 .small,h5 small,h6 .small,h6 small{font-weight:400;line-height:1;color:#777} +.h1,.h2,.h3,h1,h2,h3{margin-top:20px;margin-bottom:10px} +.h1 .small,.h1 small,.h2 .small,.h2 small,.h3 .small,.h3 small,h1 .small,h1 small,h2 .small,h2 small,h3 .small,h3 small{font-size:65%} +.h4,.h5,.h6,h4,h5,h6{margin-top:10px;margin-bottom:10px} +.h4 .small,.h4 small,.h5 .small,.h5 small,.h6 .small,.h6 small,h4 .small,h4 small,h5 .small,h5 small,h6 .small,h6 small{font-size:75%} +.h1,h1{font-size:36px} +.h2,h2{font-size:30px} +.h3,h3{font-size:24px} +.h4,h4{font-size:18px} +.h5,h5{font-size:14px} +.h6,h6{font-size:12px} +p{margin:0 0 10px} +.lead{margin-bottom:20px;font-size:16px;font-weight:300;line-height:1.4} +dt,kbd kbd,label{font-weight:700} +address,blockquote .small,blockquote footer,blockquote small,dd,dt,pre{line-height:1.42857143} +@media (min-width:768px){.lead{font-size:21px} +} +.small,small{font-size:85%} +.mark,mark{padding:.2em;background-color:#fcf8e3} +.list-inline,.list-unstyled{padding-left:0;list-style:none} +.text-left{text-align:left} +.text-right{text-align:right} +.text-center{text-align:center} +.text-justify{text-align:justify} +.text-nowrap{white-space:nowrap} +.text-lowercase{text-transform:lowercase} +.text-uppercase{text-transform:uppercase} +.text-capitalize{text-transform:capitalize} +.text-muted{color:#777} +.text-primary{color:#337ab7} +a.text-primary:focus,a.text-primary:hover{color:#286090} +.text-success{color:#3c763d} +a.text-success:focus,a.text-success:hover{color:#2b542c} +.text-info{color:#31708f} +a.text-info:focus,a.text-info:hover{color:#245269} +.text-warning{color:#8a6d3b} +a.text-warning:focus,a.text-warning:hover{color:#66512c} +.text-danger{color:#a94442} +a.text-danger:focus,a.text-danger:hover{color:#843534} +.bg-primary{color:#fff;background-color:#337ab7} +a.bg-primary:focus,a.bg-primary:hover{background-color:#286090} +.bg-success{background-color:#dff0d8} +a.bg-success:focus,a.bg-success:hover{background-color:#c1e2b3} +.bg-info{background-color:#d9edf7} +a.bg-info:focus,a.bg-info:hover{background-color:#afd9ee} +.bg-warning{background-color:#fcf8e3} +a.bg-warning:focus,a.bg-warning:hover{background-color:#f7ecb5} +.bg-danger{background-color:#f2dede} +a.bg-danger:focus,a.bg-danger:hover{background-color:#e4b9b9} +pre code,table{background-color:transparent} +.page-header{padding-bottom:9px;margin:40px 0 20px;border-bottom:1px solid #eee} +dl,ol,ul{margin-top:0} +blockquote ol:last-child,blockquote p:last-child,blockquote ul:last-child,ol ol,ol ul,ul ol,ul ul{margin-bottom:0} +address,dl{margin-bottom:20px} +ol,ul{margin-bottom:10px} +.list-inline{margin-left:-5px} +.list-inline>li{display:inline-block;padding-right:5px;padding-left:5px} +dd{margin-left:0} +@media (min-width:768px){.dl-horizontal dt{float:left;width:160px;overflow:hidden;clear:left;text-align:right;text-overflow:ellipsis;white-space:nowrap} +.dl-horizontal dd{margin-left:180px} +.container{width:750px} +} +abbr[data-original-title],abbr[title]{cursor:help;border-bottom:1px dotted #777} +.initialism{font-size:90%;text-transform:uppercase} +blockquote{padding:10px 20px;margin:0 0 20px;font-size:17.5px;border-left:5px solid #eee} +blockquote .small,blockquote footer,blockquote small{display:block;font-size:80%;color:#777} +legend,pre{display:block;color:#333} +blockquote .small:before,blockquote footer:before,blockquote small:before{content:'\2014 \00A0'} +.blockquote-reverse,blockquote.pull-right{padding-right:15px;padding-left:0;text-align:right;border-right:5px solid #eee;border-left:0} +code,kbd{padding:2px 4px;font-size:90%} +caption,th{text-align:left} +.blockquote-reverse .small:before,.blockquote-reverse footer:before,.blockquote-reverse small:before,blockquote.pull-right .small:before,blockquote.pull-right footer:before,blockquote.pull-right small:before{content:''} +.blockquote-reverse .small:after,.blockquote-reverse footer:after,.blockquote-reverse small:after,blockquote.pull-right .small:after,blockquote.pull-right footer:after,blockquote.pull-right small:after{content:'\00A0 \2014'} +code,kbd,pre,samp{font-family:Menlo,Monaco,Consolas,"Courier New",monospace} +code{color:#c7254e;background-color:#f9f2f4;border-radius:4px} +kbd{color:#fff;background-color:#333;border-radius:3px;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.25);box-shadow:inset 0 -1px 0 rgba(0,0,0,.25)} +kbd kbd{padding:0;font-size:100%;-webkit-box-shadow:none;box-shadow:none} +pre{padding:9.5px;margin:0 0 10px;font-size:13px;word-break:break-all;word-wrap:break-word;background-color:#f5f5f5;border:1px solid #ccc;border-radius:4px} +.container,.container-fluid{margin-right:auto;margin-left:auto} +pre code{padding:0;font-size:inherit;color:inherit;white-space:pre-wrap;border-radius:0} +.container,.container-fluid{padding-right:15px;padding-left:15px} +.pre-scrollable{overflow-y:scroll} +@media (min-width:992px){.container{width:970px} +} +@media (min-width:1200px){.container{width:1170px} +} +.row{margin-right:-15px;margin-left:-15px} +.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-xs-1,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9{position:relative;min-height:1px;padding-right:15px;padding-left:15px} +.col-xs-12{width:100%} +.col-xs-11{width:91.66666667%} +.col-xs-10{width:83.33333333%} +.col-xs-9{width:75%} +.col-xs-8{width:66.66666667%} +.col-xs-7{width:58.33333333%} +.col-xs-6{width:50%} +.col-xs-5{width:41.66666667%} +.col-xs-4{width:33.33333333%} +.col-xs-3{width:25%} +.col-xs-2{width:16.66666667%} +.col-xs-1{width:8.33333333%} +.col-xs-pull-12{right:100%} +.col-xs-pull-11{right:91.66666667%} +.col-xs-pull-10{right:83.33333333%} +.col-xs-pull-9{right:75%} +.col-xs-pull-8{right:66.66666667%} +.col-xs-pull-7{right:58.33333333%} +.col-xs-pull-6{right:50%} +.col-xs-pull-5{right:41.66666667%} +.col-xs-pull-4{right:33.33333333%} +.col-xs-pull-3{right:25%} +.col-xs-pull-2{right:16.66666667%} +.col-xs-pull-1{right:8.33333333%} +.col-xs-pull-0{right:auto} +.col-xs-push-12{left:100%} +.col-xs-push-11{left:91.66666667%} +.col-xs-push-10{left:83.33333333%} +.col-xs-push-9{left:75%} +.col-xs-push-8{left:66.66666667%} +.col-xs-push-7{left:58.33333333%} +.col-xs-push-6{left:50%} +.col-xs-push-5{left:41.66666667%} +.col-xs-push-4{left:33.33333333%} +.col-xs-push-3{left:25%} +.col-xs-push-2{left:16.66666667%} +.col-xs-push-1{left:8.33333333%} +.col-xs-push-0{left:auto} +.col-xs-offset-12{margin-left:100%} +.col-xs-offset-11{margin-left:91.66666667%} +.col-xs-offset-10{margin-left:83.33333333%} +.col-xs-offset-9{margin-left:75%} +.col-xs-offset-8{margin-left:66.66666667%} +.col-xs-offset-7{margin-left:58.33333333%} +.col-xs-offset-6{margin-left:50%} +.col-xs-offset-5{margin-left:41.66666667%} +.col-xs-offset-4{margin-left:33.33333333%} +.col-xs-offset-3{margin-left:25%} +.col-xs-offset-2{margin-left:16.66666667%} +.col-xs-offset-1{margin-left:8.33333333%} +.col-xs-offset-0{margin-left:0} +@media (min-width:768px){.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9{float:left} +.col-sm-12{width:100%} +.col-sm-11{width:91.66666667%} +.col-sm-10{width:83.33333333%} +.col-sm-9{width:75%} +.col-sm-8{width:66.66666667%} +.col-sm-7{width:58.33333333%} +.col-sm-6{width:50%} +.col-sm-5{width:41.66666667%} +.col-sm-4{width:33.33333333%} +.col-sm-3{width:25%} +.col-sm-2{width:16.66666667%} +.col-sm-1{width:8.33333333%} +.col-sm-pull-12{right:100%} +.col-sm-pull-11{right:91.66666667%} +.col-sm-pull-10{right:83.33333333%} +.col-sm-pull-9{right:75%} +.col-sm-pull-8{right:66.66666667%} +.col-sm-pull-7{right:58.33333333%} +.col-sm-pull-6{right:50%} +.col-sm-pull-5{right:41.66666667%} +.col-sm-pull-4{right:33.33333333%} +.col-sm-pull-3{right:25%} +.col-sm-pull-2{right:16.66666667%} +.col-sm-pull-1{right:8.33333333%} +.col-sm-pull-0{right:auto} +.col-sm-push-12{left:100%} +.col-sm-push-11{left:91.66666667%} +.col-sm-push-10{left:83.33333333%} +.col-sm-push-9{left:75%} +.col-sm-push-8{left:66.66666667%} +.col-sm-push-7{left:58.33333333%} +.col-sm-push-6{left:50%} +.col-sm-push-5{left:41.66666667%} +.col-sm-push-4{left:33.33333333%} +.col-sm-push-3{left:25%} +.col-sm-push-2{left:16.66666667%} +.col-sm-push-1{left:8.33333333%} +.col-sm-push-0{left:auto} +.col-sm-offset-12{margin-left:100%} +.col-sm-offset-11{margin-left:91.66666667%} +.col-sm-offset-10{margin-left:83.33333333%} +.col-sm-offset-9{margin-left:75%} +.col-sm-offset-8{margin-left:66.66666667%} +.col-sm-offset-7{margin-left:58.33333333%} +.col-sm-offset-6{margin-left:50%} +.col-sm-offset-5{margin-left:41.66666667%} +.col-sm-offset-4{margin-left:33.33333333%} +.col-sm-offset-3{margin-left:25%} +.col-sm-offset-2{margin-left:16.66666667%} +.col-sm-offset-1{margin-left:8.33333333%} +.col-sm-offset-0{margin-left:0} +} +@media (min-width:992px){.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9{float:left} +.col-md-12{width:100%} +.col-md-11{width:91.66666667%} +.col-md-10{width:83.33333333%} +.col-md-9{width:75%} +.col-md-8{width:66.66666667%} +.col-md-7{width:58.33333333%} +.col-md-6{width:50%} +.col-md-5{width:41.66666667%} +.col-md-4{width:33.33333333%} +.col-md-3{width:25%} +.col-md-2{width:16.66666667%} +.col-md-1{width:8.33333333%} +.col-md-pull-12{right:100%} +.col-md-pull-11{right:91.66666667%} +.col-md-pull-10{right:83.33333333%} +.col-md-pull-9{right:75%} +.col-md-pull-8{right:66.66666667%} +.col-md-pull-7{right:58.33333333%} +.col-md-pull-6{right:50%} +.col-md-pull-5{right:41.66666667%} +.col-md-pull-4{right:33.33333333%} +.col-md-pull-3{right:25%} +.col-md-pull-2{right:16.66666667%} +.col-md-pull-1{right:8.33333333%} +.col-md-pull-0{right:auto} +.col-md-push-12{left:100%} +.col-md-push-11{left:91.66666667%} +.col-md-push-10{left:83.33333333%} +.col-md-push-9{left:75%} +.col-md-push-8{left:66.66666667%} +.col-md-push-7{left:58.33333333%} +.col-md-push-6{left:50%} +.col-md-push-5{left:41.66666667%} +.col-md-push-4{left:33.33333333%} +.col-md-push-3{left:25%} +.col-md-push-2{left:16.66666667%} +.col-md-push-1{left:8.33333333%} +.col-md-push-0{left:auto} +.col-md-offset-12{margin-left:100%} +.col-md-offset-11{margin-left:91.66666667%} +.col-md-offset-10{margin-left:83.33333333%} +.col-md-offset-9{margin-left:75%} +.col-md-offset-8{margin-left:66.66666667%} +.col-md-offset-7{margin-left:58.33333333%} +.col-md-offset-6{margin-left:50%} +.col-md-offset-5{margin-left:41.66666667%} +.col-md-offset-4{margin-left:33.33333333%} +.col-md-offset-3{margin-left:25%} +.col-md-offset-2{margin-left:16.66666667%} +.col-md-offset-1{margin-left:8.33333333%} +.col-md-offset-0{margin-left:0} +} +@media (min-width:1200px){.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9{float:left} +.col-lg-12{width:100%} +.col-lg-11{width:91.66666667%} +.col-lg-10{width:83.33333333%} +.col-lg-9{width:75%} +.col-lg-8{width:66.66666667%} +.col-lg-7{width:58.33333333%} +.col-lg-6{width:50%} +.col-lg-5{width:41.66666667%} +.col-lg-4{width:33.33333333%} +.col-lg-3{width:25%} +.col-lg-2{width:16.66666667%} +.col-lg-1{width:8.33333333%} +.col-lg-pull-12{right:100%} +.col-lg-pull-11{right:91.66666667%} +.col-lg-pull-10{right:83.33333333%} +.col-lg-pull-9{right:75%} +.col-lg-pull-8{right:66.66666667%} +.col-lg-pull-7{right:58.33333333%} +.col-lg-pull-6{right:50%} +.col-lg-pull-5{right:41.66666667%} +.col-lg-pull-4{right:33.33333333%} +.col-lg-pull-3{right:25%} +.col-lg-pull-2{right:16.66666667%} +.col-lg-pull-1{right:8.33333333%} +.col-lg-pull-0{right:auto} +.col-lg-push-12{left:100%} +.col-lg-push-11{left:91.66666667%} +.col-lg-push-10{left:83.33333333%} +.col-lg-push-9{left:75%} +.col-lg-push-8{left:66.66666667%} +.col-lg-push-7{left:58.33333333%} +.col-lg-push-6{left:50%} +.col-lg-push-5{left:41.66666667%} +.col-lg-push-4{left:33.33333333%} +.col-lg-push-3{left:25%} +.col-lg-push-2{left:16.66666667%} +.col-lg-push-1{left:8.33333333%} +.col-lg-push-0{left:auto} +.col-lg-offset-12{margin-left:100%} +.col-lg-offset-11{margin-left:91.66666667%} +.col-lg-offset-10{margin-left:83.33333333%} +.col-lg-offset-9{margin-left:75%} +.col-lg-offset-8{margin-left:66.66666667%} +.col-lg-offset-7{margin-left:58.33333333%} +.col-lg-offset-6{margin-left:50%} +.col-lg-offset-5{margin-left:41.66666667%} +.col-lg-offset-4{margin-left:33.33333333%} +.col-lg-offset-3{margin-left:25%} +.col-lg-offset-2{margin-left:16.66666667%} +.col-lg-offset-1{margin-left:8.33333333%} +.col-lg-offset-0{margin-left:0} +} +caption{padding-top:8px;padding-bottom:8px;color:#777} +.table{width:100%;max-width:100%;margin-bottom:20px} +.table>tbody>tr>td,.table>tbody>tr>th,.table>tfoot>tr>td,.table>tfoot>tr>th,.table>thead>tr>td,.table>thead>tr>th{padding:8px;line-height:1.42857143;vertical-align:top;border-top:1px solid #ddd} +.table>thead>tr>th{vertical-align:bottom;border-bottom:2px solid #ddd} +.table>caption+thead>tr:first-child>td,.table>caption+thead>tr:first-child>th,.table>colgroup+thead>tr:first-child>td,.table>colgroup+thead>tr:first-child>th,.table>thead:first-child>tr:first-child>td,.table>thead:first-child>tr:first-child>th{border-top:0} +.table>tbody+tbody{border-top:2px solid #ddd} +.table .table{background-color:#fff} +.table-condensed>tbody>tr>td,.table-condensed>tbody>tr>th,.table-condensed>tfoot>tr>td,.table-condensed>tfoot>tr>th,.table-condensed>thead>tr>td,.table-condensed>thead>tr>th{padding:5px} +.table-bordered,.table-bordered>tbody>tr>td,.table-bordered>tbody>tr>th,.table-bordered>tfoot>tr>td,.table-bordered>tfoot>tr>th,.table-bordered>thead>tr>td,.table-bordered>thead>tr>th{border:1px solid #ddd} +.table-bordered>thead>tr>td,.table-bordered>thead>tr>th{border-bottom-width:2px} +.table-striped>tbody>tr:nth-of-type(odd){background-color:#f9f9f9} +.table-hover>tbody>tr:hover,.table>tbody>tr.active>td,.table>tbody>tr.active>th,.table>tbody>tr>td.active,.table>tbody>tr>th.active,.table>tfoot>tr.active>td,.table>tfoot>tr.active>th,.table>tfoot>tr>td.active,.table>tfoot>tr>th.active,.table>thead>tr.active>td,.table>thead>tr.active>th,.table>thead>tr>td.active,.table>thead>tr>th.active{background-color:#f5f5f5} +table col[class*=col-]{position:static;display:table-column;float:none} +table td[class*=col-],table th[class*=col-]{position:static;display:table-cell;float:none} +.table-hover>tbody>tr.active:hover>td,.table-hover>tbody>tr.active:hover>th,.table-hover>tbody>tr:hover>.active,.table-hover>tbody>tr>td.active:hover,.table-hover>tbody>tr>th.active:hover{background-color:#e8e8e8} +.table>tbody>tr.success>td,.table>tbody>tr.success>th,.table>tbody>tr>td.success,.table>tbody>tr>th.success,.table>tfoot>tr.success>td,.table>tfoot>tr.success>th,.table>tfoot>tr>td.success,.table>tfoot>tr>th.success,.table>thead>tr.success>td,.table>thead>tr.success>th,.table>thead>tr>td.success,.table>thead>tr>th.success{background-color:#dff0d8} +.table-hover>tbody>tr.success:hover>td,.table-hover>tbody>tr.success:hover>th,.table-hover>tbody>tr:hover>.success,.table-hover>tbody>tr>td.success:hover,.table-hover>tbody>tr>th.success:hover{background-color:#d0e9c6} +.table>tbody>tr.info>td,.table>tbody>tr.info>th,.table>tbody>tr>td.info,.table>tbody>tr>th.info,.table>tfoot>tr.info>td,.table>tfoot>tr.info>th,.table>tfoot>tr>td.info,.table>tfoot>tr>th.info,.table>thead>tr.info>td,.table>thead>tr.info>th,.table>thead>tr>td.info,.table>thead>tr>th.info{background-color:#d9edf7} +.table-hover>tbody>tr.info:hover>td,.table-hover>tbody>tr.info:hover>th,.table-hover>tbody>tr:hover>.info,.table-hover>tbody>tr>td.info:hover,.table-hover>tbody>tr>th.info:hover{background-color:#c4e3f3} +.table>tbody>tr.warning>td,.table>tbody>tr.warning>th,.table>tbody>tr>td.warning,.table>tbody>tr>th.warning,.table>tfoot>tr.warning>td,.table>tfoot>tr.warning>th,.table>tfoot>tr>td.warning,.table>tfoot>tr>th.warning,.table>thead>tr.warning>td,.table>thead>tr.warning>th,.table>thead>tr>td.warning,.table>thead>tr>th.warning{background-color:#fcf8e3} +.table-hover>tbody>tr.warning:hover>td,.table-hover>tbody>tr.warning:hover>th,.table-hover>tbody>tr:hover>.warning,.table-hover>tbody>tr>td.warning:hover,.table-hover>tbody>tr>th.warning:hover{background-color:#faf2cc} +.table>tbody>tr.danger>td,.table>tbody>tr.danger>th,.table>tbody>tr>td.danger,.table>tbody>tr>th.danger,.table>tfoot>tr.danger>td,.table>tfoot>tr.danger>th,.table>tfoot>tr>td.danger,.table>tfoot>tr>th.danger,.table>thead>tr.danger>td,.table>thead>tr.danger>th,.table>thead>tr>td.danger,.table>thead>tr>th.danger{background-color:#f2dede} +.table-hover>tbody>tr.danger:hover>td,.table-hover>tbody>tr.danger:hover>th,.table-hover>tbody>tr:hover>.danger,.table-hover>tbody>tr>td.danger:hover,.table-hover>tbody>tr>th.danger:hover{background-color:#ebcccc} +.table-responsive{min-height:.01%;overflow-x:auto} +@media screen and (max-width:767px){.table-responsive{width:100%;margin-bottom:15px;overflow-y:hidden;-ms-overflow-style:-ms-autohiding-scrollbar;border:1px solid #ddd} +.table-responsive>.table{margin-bottom:0} +.table-responsive>.table>tbody>tr>td,.table-responsive>.table>tbody>tr>th,.table-responsive>.table>tfoot>tr>td,.table-responsive>.table>tfoot>tr>th,.table-responsive>.table>thead>tr>td,.table-responsive>.table>thead>tr>th{white-space:nowrap} +.table-responsive>.table-bordered{border:0} +.table-responsive>.table-bordered>tbody>tr>td:first-child,.table-responsive>.table-bordered>tbody>tr>th:first-child,.table-responsive>.table-bordered>tfoot>tr>td:first-child,.table-responsive>.table-bordered>tfoot>tr>th:first-child,.table-responsive>.table-bordered>thead>tr>td:first-child,.table-responsive>.table-bordered>thead>tr>th:first-child{border-left:0} +.table-responsive>.table-bordered>tbody>tr>td:last-child,.table-responsive>.table-bordered>tbody>tr>th:last-child,.table-responsive>.table-bordered>tfoot>tr>td:last-child,.table-responsive>.table-bordered>tfoot>tr>th:last-child,.table-responsive>.table-bordered>thead>tr>td:last-child,.table-responsive>.table-bordered>thead>tr>th:last-child{border-right:0} +.table-responsive>.table-bordered>tbody>tr:last-child>td,.table-responsive>.table-bordered>tbody>tr:last-child>th,.table-responsive>.table-bordered>tfoot>tr:last-child>td,.table-responsive>.table-bordered>tfoot>tr:last-child>th{border-bottom:0} +} +fieldset,legend{padding:0;border:0} +fieldset{min-width:0;margin:0} +legend{width:100%;margin-bottom:20px;font-size:21px;line-height:inherit;border-bottom:1px solid #e5e5e5} +label{display:inline-block;max-width:100%;margin-bottom:5px} +input[type=search]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;-webkit-appearance:none} +input[type=checkbox],input[type=radio]{margin:4px 0 0;margin-top:1px\9;line-height:normal} +.form-control,output{font-size:14px;line-height:1.42857143;color:#555;display:block} +input[type=file]{display:block} +input[type=range]{display:block;width:100%} +select[multiple],select[size]{height:auto} +input[type=file]:focus,input[type=checkbox]:focus,input[type=radio]:focus{outline:-webkit-focus-ring-color auto 5px;outline-offset:-2px} +output{padding-top:7px} +.form-control{width:100%;height:34px;padding:6px 12px;background-color:#fff;border:1px solid #ccc;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075);-webkit-transition:border-color ease-in-out .15s,-webkit-box-shadow ease-in-out .15s;-o-transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s} +.form-control:focus{border-color:#66afe9;outline:0;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6);box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6)} +.form-control::-moz-placeholder{color:#999;opacity:1} +.form-control:-ms-input-placeholder{color:#999} +.form-control::-webkit-input-placeholder{color:#999} +.has-success .checkbox,.has-success .checkbox-inline,.has-success .control-label,.has-success .form-control-feedback,.has-success .help-block,.has-success .radio,.has-success .radio-inline,.has-success.checkbox label,.has-success.checkbox-inline label,.has-success.radio label,.has-success.radio-inline label{color:#3c763d} +.form-control::-ms-expand{background-color:transparent;border:0} +.form-control[disabled],.form-control[readonly],fieldset[disabled] .form-control{background-color:#eee;opacity:1} +.form-control[disabled],fieldset[disabled] .form-control{cursor:not-allowed} +textarea.form-control{height:auto} +@media screen and (-webkit-min-device-pixel-ratio:0){input[type=date].form-control,input[type=time].form-control,input[type=datetime-local].form-control,input[type=month].form-control{line-height:34px} +.input-group-sm input[type=date],.input-group-sm input[type=time],.input-group-sm input[type=datetime-local],.input-group-sm input[type=month],input[type=date].input-sm,input[type=time].input-sm,input[type=datetime-local].input-sm,input[type=month].input-sm{line-height:30px} +.input-group-lg input[type=date],.input-group-lg input[type=time],.input-group-lg input[type=datetime-local],.input-group-lg input[type=month],input[type=date].input-lg,input[type=time].input-lg,input[type=datetime-local].input-lg,input[type=month].input-lg{line-height:46px} +} +.form-group{margin-bottom:15px} +.checkbox,.radio{position:relative;display:block;margin-top:10px;margin-bottom:10px} +.checkbox label,.radio label{min-height:20px;padding-left:20px;margin-bottom:0;font-weight:400;cursor:pointer} +.checkbox input[type=checkbox],.checkbox-inline input[type=checkbox],.radio input[type=radio],.radio-inline input[type=radio]{position:absolute;margin-top:4px\9;margin-left:-20px} +.checkbox+.checkbox,.radio+.radio{margin-top:-5px} +.checkbox-inline,.radio-inline{position:relative;display:inline-block;padding-left:20px;margin-bottom:0;font-weight:400;vertical-align:middle;cursor:pointer} +.checkbox-inline+.checkbox-inline,.radio-inline+.radio-inline{margin-top:0;margin-left:10px} +.checkbox-inline.disabled,.checkbox.disabled label,.radio-inline.disabled,.radio.disabled label,fieldset[disabled] .checkbox label,fieldset[disabled] .checkbox-inline,fieldset[disabled] .radio label,fieldset[disabled] .radio-inline,fieldset[disabled] input[type=checkbox],fieldset[disabled] input[type=radio],input[type=checkbox].disabled,input[type=checkbox][disabled],input[type=radio].disabled,input[type=radio][disabled]{cursor:not-allowed} +.form-control-static{min-height:34px;padding-top:7px;padding-bottom:7px;margin-bottom:0} +.form-control-static.input-lg,.form-control-static.input-sm{padding-right:0;padding-left:0} +.form-group-sm .form-control,.input-sm{padding:5px 10px;border-radius:3px;font-size:12px} +.input-sm{height:30px;line-height:1.5} +select.input-sm{height:30px;line-height:30px} +select[multiple].input-sm,textarea.input-sm{height:auto} +.form-group-sm .form-control{height:30px;line-height:1.5} +.form-group-lg .form-control,.input-lg{border-radius:6px;padding:10px 16px;font-size:18px} +.form-group-sm select.form-control{height:30px;line-height:30px} +.form-group-sm select[multiple].form-control,.form-group-sm textarea.form-control{height:auto} +.form-group-sm .form-control-static{height:30px;min-height:32px;padding:6px 10px;font-size:12px;line-height:1.5} +.input-lg{height:46px;line-height:1.3333333} +select.input-lg{height:46px;line-height:46px} +select[multiple].input-lg,textarea.input-lg{height:auto} +.form-group-lg .form-control{height:46px;line-height:1.3333333} +.form-group-lg select.form-control{height:46px;line-height:46px} +.form-group-lg select[multiple].form-control,.form-group-lg textarea.form-control{height:auto} +.form-group-lg .form-control-static{height:46px;min-height:38px;padding:11px 16px;font-size:18px;line-height:1.3333333} +.has-feedback{position:relative} +.has-feedback .form-control{padding-right:42.5px} +.form-control-feedback{position:absolute;top:0;right:0;z-index:2;display:block;width:34px;height:34px;line-height:34px;text-align:center;pointer-events:none} +.collapsing,.dropdown,.dropup{position:relative} +.form-group-lg .form-control+.form-control-feedback,.input-group-lg+.form-control-feedback,.input-lg+.form-control-feedback{width:46px;height:46px;line-height:46px} +.form-group-sm .form-control+.form-control-feedback,.input-group-sm+.form-control-feedback,.input-sm+.form-control-feedback{width:30px;height:30px;line-height:30px} +.has-success .form-control{border-color:#3c763d;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)} +.has-success .form-control:focus{border-color:#2b542c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168} +.has-success .input-group-addon{color:#3c763d;background-color:#dff0d8;border-color:#3c763d} +.has-warning .checkbox,.has-warning .checkbox-inline,.has-warning .control-label,.has-warning .form-control-feedback,.has-warning .help-block,.has-warning .radio,.has-warning .radio-inline,.has-warning.checkbox label,.has-warning.checkbox-inline label,.has-warning.radio label,.has-warning.radio-inline label{color:#8a6d3b} +.has-warning .form-control{border-color:#8a6d3b;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)} +.has-warning .form-control:focus{border-color:#66512c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b} +.has-warning .input-group-addon{color:#8a6d3b;background-color:#fcf8e3;border-color:#8a6d3b} +.has-error .checkbox,.has-error .checkbox-inline,.has-error .control-label,.has-error .form-control-feedback,.has-error .help-block,.has-error .radio,.has-error .radio-inline,.has-error.checkbox label,.has-error.checkbox-inline label,.has-error.radio label,.has-error.radio-inline label{color:#a94442} +.has-error .form-control{border-color:#a94442;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)} +.has-error .form-control:focus{border-color:#843534;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483} +.has-error .input-group-addon{color:#a94442;background-color:#f2dede;border-color:#a94442} +.has-feedback label~.form-control-feedback{top:25px} +.has-feedback label.sr-only~.form-control-feedback{top:0} +.help-block{display:block;margin-top:5px;margin-bottom:10px;color:#737373} +@media (min-width:768px){.form-inline .form-control-static,.form-inline .form-group{display:inline-block} +.form-inline .control-label,.form-inline .form-group{margin-bottom:0;vertical-align:middle} +.form-inline .form-control{display:inline-block;width:auto;vertical-align:middle} +.form-inline .input-group{display:inline-table;vertical-align:middle} +.form-inline .input-group .form-control,.form-inline .input-group .input-group-addon,.form-inline .input-group .input-group-btn{width:auto} +.form-inline .input-group>.form-control{width:100%} +.form-inline .checkbox,.form-inline .radio{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle} +.form-inline .checkbox label,.form-inline .radio label{padding-left:0} +.form-inline .checkbox input[type=checkbox],.form-inline .radio input[type=radio]{position:relative;margin-left:0} +.form-inline .has-feedback .form-control-feedback{top:0} +.form-horizontal .control-label{padding-top:7px;margin-bottom:0;text-align:right} +} +.form-horizontal .checkbox,.form-horizontal .checkbox-inline,.form-horizontal .radio,.form-horizontal .radio-inline{padding-top:7px;margin-top:0;margin-bottom:0} +.form-horizontal .checkbox,.form-horizontal .radio{min-height:27px} +.form-horizontal .form-group{margin-right:-15px;margin-left:-15px} +.form-horizontal .has-feedback .form-control-feedback{right:15px} +@media (min-width:768px){.form-horizontal .form-group-lg .control-label{padding-top:11px;font-size:18px} +.form-horizontal .form-group-sm .control-label{padding-top:6px;font-size:12px} +} +.btn{display:inline-block;padding:6px 12px;margin-bottom:0;font-size:14px;font-weight:400;line-height:1.42857143;text-align:center;white-space:nowrap;vertical-align:middle;-ms-touch-action:manipulation;touch-action:manipulation;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;border:1px solid transparent;border-radius:4px} +.btn.active.focus,.btn.active:focus,.btn.focus,.btn:active.focus,.btn:active:focus,.btn:focus{outline:-webkit-focus-ring-color auto 5px;outline-offset:-2px} +.btn.focus,.btn:focus,.btn:hover{color:#333;text-decoration:none} +.btn.active,.btn:active{outline:0;-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)} +.btn.disabled,.btn[disabled],fieldset[disabled] .btn{cursor:not-allowed;filter:alpha(opacity=65);-webkit-box-shadow:none;box-shadow:none;opacity:.65} +a.btn.disabled,fieldset[disabled] a.btn{pointer-events:none} +.btn-default{color:#333;background-color:#fff;border-color:#ccc} +.btn-default.focus,.btn-default:focus{color:#333;background-color:#e6e6e6;border-color:#8c8c8c} +.btn-default.active,.btn-default:active,.btn-default:hover,.open>.dropdown-toggle.btn-default{color:#333;background-color:#e6e6e6;border-color:#adadad} +.btn-default.active.focus,.btn-default.active:focus,.btn-default.active:hover,.btn-default:active.focus,.btn-default:active:focus,.btn-default:active:hover,.open>.dropdown-toggle.btn-default.focus,.open>.dropdown-toggle.btn-default:focus,.open>.dropdown-toggle.btn-default:hover{color:#333;background-color:#d4d4d4;border-color:#8c8c8c} +.btn-default.disabled.focus,.btn-default.disabled:focus,.btn-default.disabled:hover,.btn-default[disabled].focus,.btn-default[disabled]:focus,.btn-default[disabled]:hover,fieldset[disabled] .btn-default.focus,fieldset[disabled] .btn-default:focus,fieldset[disabled] .btn-default:hover{background-color:#fff;border-color:#ccc} +.btn-default .badge{color:#fff;background-color:#333} +.btn-primary{color:#fff;background-color:#337ab7;border-color:#2e6da4} +.btn-primary.focus,.btn-primary:focus{color:#fff;background-color:#286090;border-color:#122b40} +.btn-primary.active,.btn-primary:active,.btn-primary:hover,.open>.dropdown-toggle.btn-primary{color:#fff;background-color:#286090;border-color:#204d74} +.btn-primary.active.focus,.btn-primary.active:focus,.btn-primary.active:hover,.btn-primary:active.focus,.btn-primary:active:focus,.btn-primary:active:hover,.open>.dropdown-toggle.btn-primary.focus,.open>.dropdown-toggle.btn-primary:focus,.open>.dropdown-toggle.btn-primary:hover{color:#fff;background-color:#204d74;border-color:#122b40} +.btn-primary.disabled.focus,.btn-primary.disabled:focus,.btn-primary.disabled:hover,.btn-primary[disabled].focus,.btn-primary[disabled]:focus,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary.focus,fieldset[disabled] .btn-primary:focus,fieldset[disabled] .btn-primary:hover{background-color:#337ab7;border-color:#2e6da4} +.btn-primary .badge{color:#337ab7;background-color:#fff} +.btn-success{color:#fff;background-color:#5cb85c;border-color:#4cae4c} +.btn-success.focus,.btn-success:focus{color:#fff;background-color:#449d44;border-color:#255625} +.btn-success.active,.btn-success:active,.btn-success:hover,.open>.dropdown-toggle.btn-success{color:#fff;background-color:#449d44;border-color:#398439} +.btn-success.active.focus,.btn-success.active:focus,.btn-success.active:hover,.btn-success:active.focus,.btn-success:active:focus,.btn-success:active:hover,.open>.dropdown-toggle.btn-success.focus,.open>.dropdown-toggle.btn-success:focus,.open>.dropdown-toggle.btn-success:hover{color:#fff;background-color:#398439;border-color:#255625} +.btn-success.active,.btn-success:active,.open>.dropdown-toggle.btn-success{background-image:none} +.btn-success.disabled.focus,.btn-success.disabled:focus,.btn-success.disabled:hover,.btn-success[disabled].focus,.btn-success[disabled]:focus,.btn-success[disabled]:hover,fieldset[disabled] .btn-success.focus,fieldset[disabled] .btn-success:focus,fieldset[disabled] .btn-success:hover{background-color:#5cb85c;border-color:#4cae4c} +.btn-success .badge{color:#5cb85c;background-color:#fff} +.btn-info{color:#fff;background-color:#5bc0de;border-color:#46b8da} +.btn-info.focus,.btn-info:focus{color:#fff;background-color:#31b0d5;border-color:#1b6d85} +.btn-info.active,.btn-info:active,.btn-info:hover,.open>.dropdown-toggle.btn-info{color:#fff;background-color:#31b0d5;border-color:#269abc} +.btn-info.active.focus,.btn-info.active:focus,.btn-info.active:hover,.btn-info:active.focus,.btn-info:active:focus,.btn-info:active:hover,.open>.dropdown-toggle.btn-info.focus,.open>.dropdown-toggle.btn-info:focus,.open>.dropdown-toggle.btn-info:hover{color:#fff;background-color:#269abc;border-color:#1b6d85} +.btn-info.disabled.focus,.btn-info.disabled:focus,.btn-info.disabled:hover,.btn-info[disabled].focus,.btn-info[disabled]:focus,.btn-info[disabled]:hover,fieldset[disabled] .btn-info.focus,fieldset[disabled] .btn-info:focus,fieldset[disabled] .btn-info:hover{background-color:#5bc0de;border-color:#46b8da} +.btn-info .badge{color:#5bc0de;background-color:#fff} +.btn-warning{color:#fff;background-color:#f0ad4e;border-color:#eea236} +.btn-warning.focus,.btn-warning:focus{color:#fff;background-color:#ec971f;border-color:#985f0d} +.btn-warning.active,.btn-warning:active,.btn-warning:hover,.open>.dropdown-toggle.btn-warning{color:#fff;background-color:#ec971f;border-color:#d58512} +.btn-warning.active.focus,.btn-warning.active:focus,.btn-warning.active:hover,.btn-warning:active.focus,.btn-warning:active:focus,.btn-warning:active:hover,.open>.dropdown-toggle.btn-warning.focus,.open>.dropdown-toggle.btn-warning:focus,.open>.dropdown-toggle.btn-warning:hover{color:#fff;background-color:#d58512;border-color:#985f0d} +.btn-warning.disabled.focus,.btn-warning.disabled:focus,.btn-warning.disabled:hover,.btn-warning[disabled].focus,.btn-warning[disabled]:focus,.btn-warning[disabled]:hover,fieldset[disabled] .btn-warning.focus,fieldset[disabled] .btn-warning:focus,fieldset[disabled] .btn-warning:hover{background-color:#f0ad4e;border-color:#eea236} +.btn-warning .badge{color:#f0ad4e;background-color:#fff} +.btn-danger{color:#fff;background-color:#d9534f;border-color:#d43f3a} +.btn-danger.focus,.btn-danger:focus{color:#fff;background-color:#c9302c;border-color:#761c19} +.btn-danger.active,.btn-danger:active,.btn-danger:hover,.open>.dropdown-toggle.btn-danger{color:#fff;background-color:#c9302c;border-color:#ac2925} +.btn-danger.active.focus,.btn-danger.active:focus,.btn-danger.active:hover,.btn-danger:active.focus,.btn-danger:active:focus,.btn-danger:active:hover,.open>.dropdown-toggle.btn-danger.focus,.open>.dropdown-toggle.btn-danger:focus,.open>.dropdown-toggle.btn-danger:hover{color:#fff;background-color:#ac2925;border-color:#761c19} +.btn-danger.disabled.focus,.btn-danger.disabled:focus,.btn-danger.disabled:hover,.btn-danger[disabled].focus,.btn-danger[disabled]:focus,.btn-danger[disabled]:hover,fieldset[disabled] .btn-danger.focus,fieldset[disabled] .btn-danger:focus,fieldset[disabled] .btn-danger:hover{background-color:#d9534f;border-color:#d43f3a} +.btn-danger .badge{color:#d9534f;background-color:#fff} +.btn-link{font-weight:400;color:#337ab7;border-radius:0} +.btn-link,.btn-link.active,.btn-link:active,.btn-link[disabled],fieldset[disabled] .btn-link{background-color:transparent;-webkit-box-shadow:none;box-shadow:none} +.btn-link,.btn-link:active,.btn-link:focus,.btn-link:hover{border-color:transparent} +.btn-link:focus,.btn-link:hover{color:#23527c;text-decoration:underline;background-color:transparent} +.btn-link[disabled]:focus,.btn-link[disabled]:hover,fieldset[disabled] .btn-link:focus,fieldset[disabled] .btn-link:hover{color:#777;text-decoration:none} +.btn-group-lg>.btn,.btn-lg{padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px} +.btn-group-sm>.btn,.btn-sm{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px} +.btn-group-xs>.btn,.btn-xs{padding:1px 5px;font-size:12px;line-height:1.5;border-radius:3px} +.btn-block{display:block;width:100%} +.btn-block+.btn-block{margin-top:5px} +input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn-block{width:100%} +.fade{opacity:0;-webkit-transition:opacity .15s linear;-o-transition:opacity .15s linear;transition:opacity .15s linear} +.fade.in{opacity:1} +.collapse{display:none} +.collapse.in{display:block} +tr.collapse.in{display:table-row} +tbody.collapse.in{display:table-row-group} +.collapsing{height:0;overflow:hidden;-webkit-transition-timing-function:ease;-o-transition-timing-function:ease;transition-timing-function:ease;-webkit-transition-duration:.35s;-o-transition-duration:.35s;transition-duration:.35s;-webkit-transition-property:height,visibility;-o-transition-property:height,visibility;transition-property:height,visibility} +.caret{display:inline-block;width:0;height:0;margin-left:2px;vertical-align:middle;border-top:4px dashed;border-top:4px solid\9;border-right:4px solid transparent;border-left:4px solid transparent} +.dropdown-toggle:focus{outline:0} +.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;min-width:160px;padding:5px 0;margin:2px 0 0;font-size:14px;text-align:left;list-style:none;background-color:#fff;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,.15);border-radius:4px;-webkit-box-shadow:0 6px 12px rgba(0,0,0,.175);box-shadow:0 6px 12px rgba(0,0,0,.175)} +.dropdown-menu-right,.dropdown-menu.pull-right{right:0;left:auto} +.dropdown-header,.dropdown-menu>li>a{display:block;padding:3px 20px;line-height:1.42857143;white-space:nowrap} +.btn-group>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group>.btn-group:first-child:not(:last-child)>.dropdown-toggle,.btn-group>.btn:first-child:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0} +.btn-group>.btn-group:last-child:not(:first-child)>.btn:first-child,.btn-group>.btn:last-child:not(:first-child),.btn-group>.dropdown-toggle:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0} +.btn-group-vertical>.btn:not(:first-child):not(:last-child),.btn-group>.btn-group:not(:first-child):not(:last-child)>.btn,.btn-group>.btn:not(:first-child):not(:last-child):not(.dropdown-toggle){border-radius:0} +.dropdown-menu .divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5} +.dropdown-menu>li>a{clear:both;font-weight:400;color:#333} +.dropdown-menu>li>a:focus,.dropdown-menu>li>a:hover{color:#262626;text-decoration:none;background-color:#f5f5f5} +.dropdown-menu>.active>a,.dropdown-menu>.active>a:focus,.dropdown-menu>.active>a:hover{color:#fff;text-decoration:none;background-color:#337ab7;outline:0} +.dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover{color:#777} +.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover{text-decoration:none;cursor:not-allowed;background-color:transparent;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)} +.open>.dropdown-menu{display:block} +.open>a{outline:0} +.dropdown-menu-left{right:auto;left:0} +.dropdown-header{font-size:12px;color:#777} +.dropdown-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:990} +.nav-justified>.dropdown .dropdown-menu,.nav-tabs.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto} +.pull-right>.dropdown-menu{right:0;left:auto} +.dropup .caret,.navbar-fixed-bottom .dropdown .caret{content:"";border-top:0;border-bottom:4px dashed;border-bottom:4px solid\9} +.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:2px} +@media (min-width:768px){.navbar-right .dropdown-menu{right:0;left:auto} +.navbar-right .dropdown-menu-left{right:auto;left:0} +} +.btn-group,.btn-group-vertical{position:relative;display:inline-block;vertical-align:middle} +.btn-group-vertical>.btn,.btn-group>.btn{position:relative;float:left} +.btn-group-vertical>.btn.active,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn:focus,.btn-group-vertical>.btn:hover,.btn-group>.btn.active,.btn-group>.btn:active,.btn-group>.btn:focus,.btn-group>.btn:hover{z-index:2} +.btn-group .btn+.btn,.btn-group .btn+.btn-group,.btn-group .btn-group+.btn,.btn-group .btn-group+.btn-group{margin-left:-1px} +.btn-toolbar{margin-left:-5px} +.btn-toolbar>.btn,.btn-toolbar>.btn-group,.btn-toolbar>.input-group{margin-left:5px} +.btn .caret,.btn-group>.btn:first-child{margin-left:0} +.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0} +.btn-group>.btn+.dropdown-toggle{padding-right:8px;padding-left:8px} +.btn-group>.btn-lg+.dropdown-toggle{padding-right:12px;padding-left:12px} +.btn-group.open .dropdown-toggle{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)} +.btn-group.open .dropdown-toggle.btn-link{-webkit-box-shadow:none;box-shadow:none} +.btn-lg .caret{border-width:5px 5px 0} +.dropup .btn-lg .caret{border-width:0 5px 5px} +.btn-group-vertical>.btn,.btn-group-vertical>.btn-group,.btn-group-vertical>.btn-group>.btn{display:block;float:none;width:100%;max-width:100%} +.btn-group-vertical>.btn-group>.btn{float:none} +.btn-group-vertical>.btn+.btn,.btn-group-vertical>.btn+.btn-group,.btn-group-vertical>.btn-group+.btn,.btn-group-vertical>.btn-group+.btn-group{margin-top:-1px;margin-left:0} +.btn-group-vertical>.btn:first-child:not(:last-child){border-radius:4px 4px 0 0} +.btn-group-vertical>.btn:last-child:not(:first-child){border-radius:0 0 4px 4px} +.btn-group-vertical>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0} +.btn-group-vertical>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group-vertical>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-bottom-right-radius:0;border-bottom-left-radius:0} +.btn-group-vertical>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-left-radius:0;border-top-right-radius:0} +.btn-group-justified{display:table;width:100%;table-layout:fixed;border-collapse:separate} +.btn-group-justified>.btn,.btn-group-justified>.btn-group{display:table-cell;float:none;width:1%} +.btn-group-justified>.btn-group .btn{width:100%} +.btn-group-justified>.btn-group .dropdown-menu{left:auto} +[data-toggle=buttons]>.btn input[type=checkbox],[data-toggle=buttons]>.btn input[type=radio],[data-toggle=buttons]>.btn-group>.btn input[type=checkbox],[data-toggle=buttons]>.btn-group>.btn input[type=radio]{position:absolute;clip:rect(0,0,0,0);pointer-events:none} +.input-group{position:relative;display:table;border-collapse:separate} +.input-group[class*=col-]{float:none;padding-right:0;padding-left:0} +.input-group .form-control{position:relative;z-index:2;float:left;width:100%;margin-bottom:0} +.input-group .form-control:focus{z-index:3} +.input-group-lg>.form-control,.input-group-lg>.input-group-addon,.input-group-lg>.input-group-btn>.btn{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px} +select.input-group-lg>.form-control,select.input-group-lg>.input-group-addon,select.input-group-lg>.input-group-btn>.btn{height:46px;line-height:46px} +select[multiple].input-group-lg>.form-control,select[multiple].input-group-lg>.input-group-addon,select[multiple].input-group-lg>.input-group-btn>.btn,textarea.input-group-lg>.form-control,textarea.input-group-lg>.input-group-addon,textarea.input-group-lg>.input-group-btn>.btn{height:auto} +.input-group-sm>.form-control,.input-group-sm>.input-group-addon,.input-group-sm>.input-group-btn>.btn{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px} +select.input-group-sm>.form-control,select.input-group-sm>.input-group-addon,select.input-group-sm>.input-group-btn>.btn{height:30px;line-height:30px} +select[multiple].input-group-sm>.form-control,select[multiple].input-group-sm>.input-group-addon,select[multiple].input-group-sm>.input-group-btn>.btn,textarea.input-group-sm>.form-control,textarea.input-group-sm>.input-group-addon,textarea.input-group-sm>.input-group-btn>.btn{height:auto} +.input-group .form-control,.input-group-addon,.input-group-btn{display:table-cell} +.nav>li,.nav>li>a{display:block;position:relative} +.input-group .form-control:not(:first-child):not(:last-child),.input-group-addon:not(:first-child):not(:last-child),.input-group-btn:not(:first-child):not(:last-child){border-radius:0} +.input-group-addon,.input-group-btn{width:1%;white-space:nowrap;vertical-align:middle} +.input-group-addon{padding:6px 12px;font-size:14px;font-weight:400;line-height:1;color:#555;text-align:center;background-color:#eee;border:1px solid #ccc;border-radius:4px} +.input-group-addon.input-sm{padding:5px 10px;font-size:12px;border-radius:3px} +.input-group-addon.input-lg{padding:10px 16px;font-size:18px;border-radius:6px} +.input-group-addon input[type=checkbox],.input-group-addon input[type=radio]{margin-top:0} +.input-group .form-control:first-child,.input-group-addon:first-child,.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group>.btn,.input-group-btn:first-child>.dropdown-toggle,.input-group-btn:last-child>.btn-group:not(:last-child)>.btn,.input-group-btn:last-child>.btn:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0} +.input-group-addon:first-child{border-right:0} +.input-group .form-control:last-child,.input-group-addon:last-child,.input-group-btn:first-child>.btn-group:not(:first-child)>.btn,.input-group-btn:first-child>.btn:not(:first-child),.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group>.btn,.input-group-btn:last-child>.dropdown-toggle{border-top-left-radius:0;border-bottom-left-radius:0} +.input-group-addon:last-child{border-left:0} +.input-group-btn{position:relative;font-size:0;white-space:nowrap} +.input-group-btn>.btn{position:relative} +.input-group-btn>.btn+.btn{margin-left:-1px} +.input-group-btn>.btn:active,.input-group-btn>.btn:focus,.input-group-btn>.btn:hover{z-index:2} +.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group{margin-right:-1px} +.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group{z-index:2;margin-left:-1px} +.nav{padding-left:0;margin-bottom:0;list-style:none} +.nav>li>a{padding:10px 15px} +.nav>li>a:focus,.nav>li>a:hover{text-decoration:none;background-color:#eee} +.nav>li.disabled>a{color:#777} +.nav>li.disabled>a:focus,.nav>li.disabled>a:hover{color:#777;text-decoration:none;cursor:not-allowed;background-color:transparent} +.nav .open>a,.nav .open>a:focus,.nav .open>a:hover{background-color:#eee;border-color:#337ab7} +.nav .nav-divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5} +.nav>li>a>img{max-width:none} +.nav-tabs{border-bottom:1px solid #ddd} +.nav-tabs>li{float:left;margin-bottom:-1px} +.nav-tabs>li>a{margin-right:2px;line-height:1.42857143;border:1px solid transparent;border-radius:4px 4px 0 0} +.nav-tabs>li>a:hover{border-color:#eee #eee #ddd} +.nav-tabs>li.active>a,.nav-tabs>li.active>a:focus,.nav-tabs>li.active>a:hover{color:#555;cursor:default;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent} +.nav-tabs.nav-justified{width:100%;border-bottom:0} +.nav-tabs.nav-justified>li{float:none} +.nav-tabs.nav-justified>li>a{margin-bottom:5px;text-align:center;margin-right:0;border-radius:4px} +.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:focus,.nav-tabs.nav-justified>.active>a:hover{border:1px solid #ddd} +@media (min-width:768px){.nav-tabs.nav-justified>li{display:table-cell;width:1%} +.nav-tabs.nav-justified>li>a{margin-bottom:0;border-bottom:1px solid #ddd;border-radius:4px 4px 0 0} +.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:focus,.nav-tabs.nav-justified>.active>a:hover{border-bottom-color:#fff} +} +.nav-pills>li{float:left} +.nav-justified>li,.nav-stacked>li{float:none} +.nav-pills>li>a{border-radius:4px} +.nav-pills>li+li{margin-left:2px} +.nav-pills>li.active>a,.nav-pills>li.active>a:focus,.nav-pills>li.active>a:hover{color:#fff;background-color:#337ab7} +.nav-stacked>li+li{margin-top:2px;margin-left:0} +.nav-justified{width:100%} +.nav-justified>li>a{margin-bottom:5px;text-align:center} +.nav-tabs-justified{border-bottom:0} +.nav-tabs-justified>li>a{margin-right:0;border-radius:4px} +.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:focus,.nav-tabs-justified>.active>a:hover{border:1px solid #ddd} +@media (min-width:768px){.nav-justified>li{display:table-cell;width:1%} +.nav-justified>li>a{margin-bottom:0} +.nav-tabs-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0} +.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:focus,.nav-tabs-justified>.active>a:hover{border-bottom-color:#fff} +} +.tab-content>.tab-pane{display:none} +.tab-content>.active{display:block} +.nav-tabs .dropdown-menu{margin-top:-1px;border-top-left-radius:0;border-top-right-radius:0} +.navbar{position:relative;min-height:50px;margin-bottom:20px;border:1px solid transparent} +.navbar-collapse{padding-right:15px;padding-left:15px;overflow-x:visible;-webkit-overflow-scrolling:touch;border-top:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1)} +.navbar-collapse.in{overflow-y:auto} +@media (min-width:768px){.navbar{border-radius:4px} +.navbar-header{float:left} +.navbar-collapse{width:auto;border-top:0;-webkit-box-shadow:none;box-shadow:none} +.navbar-collapse.collapse{display:block!important;height:auto!important;padding-bottom:0;overflow:visible!important} +.navbar-collapse.in{overflow-y:visible} +.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse,.navbar-static-top .navbar-collapse{padding-right:0;padding-left:0} +} +.embed-responsive,.modal,.modal-open,.progress{overflow:hidden} +@media (max-device-width:480px) and (orientation:landscape){.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse{max-height:200px} +} +.container-fluid>.navbar-collapse,.container-fluid>.navbar-header,.container>.navbar-collapse,.container>.navbar-header{margin-right:-15px;margin-left:-15px} +.navbar-static-top{z-index:1000;border-width:0 0 1px} +.navbar-fixed-bottom,.navbar-fixed-top{position:fixed;right:0;left:0;z-index:1030} +.navbar-fixed-top{top:0;border-width:0 0 1px} +.navbar-fixed-bottom{bottom:0;margin-bottom:0;border-width:1px 0 0} +.navbar-brand{float:left;height:50px;padding:15px;font-size:18px;line-height:20px} +.navbar-brand:focus,.navbar-brand:hover{text-decoration:none} +.navbar-brand>img{display:block} +@media (min-width:768px){.container-fluid>.navbar-collapse,.container-fluid>.navbar-header,.container>.navbar-collapse,.container>.navbar-header{margin-right:0;margin-left:0} +.navbar-fixed-bottom,.navbar-fixed-top,.navbar-static-top{border-radius:0} +.navbar>.container .navbar-brand,.navbar>.container-fluid .navbar-brand{margin-left:-15px} +} +.navbar-toggle{position:relative;float:right;padding:9px 10px;margin-top:8px;margin-right:15px;margin-bottom:8px;background-color:transparent;border:1px solid transparent;border-radius:4px} +.navbar-toggle:focus{outline:0} +.navbar-toggle .icon-bar{display:block;width:22px;height:2px;border-radius:1px} +.navbar-toggle .icon-bar+.icon-bar{margin-top:4px} +.navbar-nav{margin:7.5px -15px} +.navbar-nav>li>a{padding-top:10px;padding-bottom:10px;line-height:20px} +@media (max-width:767px){.navbar-nav .open .dropdown-menu{position:static;float:none;width:auto;margin-top:0;background-color:transparent;border:0;-webkit-box-shadow:none;box-shadow:none} +.navbar-nav .open .dropdown-menu .dropdown-header,.navbar-nav .open .dropdown-menu>li>a{padding:5px 15px 5px 25px} +.navbar-nav .open .dropdown-menu>li>a{line-height:20px} +.navbar-nav .open .dropdown-menu>li>a:focus,.navbar-nav .open .dropdown-menu>li>a:hover{background-image:none} +} +.progress-bar-striped,.progress-striped .progress-bar,.progress-striped .progress-bar-success{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)} +@media (min-width:768px){.navbar-toggle{display:none} +.navbar-nav{float:left;margin:0} +.navbar-nav>li{float:left} +.navbar-nav>li>a{padding-top:15px;padding-bottom:15px} +} +.navbar-form{padding:10px 15px;border-top:1px solid transparent;border-bottom:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1);margin:8px -15px} +@media (min-width:768px){.navbar-form .form-control-static,.navbar-form .form-group{display:inline-block} +.navbar-form .control-label,.navbar-form .form-group{margin-bottom:0;vertical-align:middle} +.navbar-form .form-control{display:inline-block;width:auto;vertical-align:middle} +.navbar-form .input-group{display:inline-table;vertical-align:middle} +.navbar-form .input-group .form-control,.navbar-form .input-group .input-group-addon,.navbar-form .input-group .input-group-btn{width:auto} +.navbar-form .input-group>.form-control{width:100%} +.navbar-form .checkbox,.navbar-form .radio{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle} +.navbar-form .checkbox label,.navbar-form .radio label{padding-left:0} +.navbar-form .checkbox input[type=checkbox],.navbar-form .radio input[type=radio]{position:relative;margin-left:0} +.navbar-form .has-feedback .form-control-feedback{top:0} +.navbar-form{width:auto;padding-top:0;padding-bottom:0;margin-right:0;margin-left:0;border:0;-webkit-box-shadow:none;box-shadow:none} +} +.breadcrumb>li,.pagination{display:inline-block} +.btn .badge,.btn .label{top:-1px;position:relative} +@media (max-width:767px){.navbar-form .form-group{margin-bottom:5px} +.navbar-form .form-group:last-child{margin-bottom:0} +} +.navbar-nav>li>.dropdown-menu{margin-top:0;border-top-left-radius:0;border-top-right-radius:0} +.navbar-fixed-bottom .navbar-nav>li>.dropdown-menu{margin-bottom:0;border-radius:4px 4px 0 0} +.navbar-btn{margin-top:8px;margin-bottom:8px} +.navbar-btn.btn-sm{margin-top:10px;margin-bottom:10px} +.navbar-btn.btn-xs{margin-top:14px;margin-bottom:14px} +.navbar-text{margin-top:15px;margin-bottom:15px} +@media (min-width:768px){.navbar-text{float:left;margin-right:15px;margin-left:15px} +.navbar-left{float:left!important} +.navbar-right{float:right!important;margin-right:-15px} +.navbar-right~.navbar-right{margin-right:0} +} +.navbar-default{background-color:#f8f8f8;border-color:#e7e7e7} +.navbar-default .navbar-brand{color:#777} +.navbar-default .navbar-brand:focus,.navbar-default .navbar-brand:hover{color:#5e5e5e;background-color:transparent} +.navbar-default .navbar-nav>li>a,.navbar-default .navbar-text{color:#777} +.navbar-default .navbar-nav>li>a:focus,.navbar-default .navbar-nav>li>a:hover{color:#333;background-color:transparent} +.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.active>a:focus,.navbar-default .navbar-nav>.active>a:hover{color:#555;background-color:#e7e7e7} +.navbar-default .navbar-nav>.disabled>a,.navbar-default .navbar-nav>.disabled>a:focus,.navbar-default .navbar-nav>.disabled>a:hover{color:#ccc;background-color:transparent} +.navbar-default .navbar-toggle{border-color:#ddd} +.navbar-default .navbar-toggle:focus,.navbar-default .navbar-toggle:hover{background-color:#ddd} +.navbar-default .navbar-toggle .icon-bar{background-color:#888} +.navbar-default .navbar-collapse,.navbar-default .navbar-form{border-color:#e7e7e7} +.navbar-default .navbar-nav>.open>a,.navbar-default .navbar-nav>.open>a:focus,.navbar-default .navbar-nav>.open>a:hover{color:#555;background-color:#e7e7e7} +@media (max-width:767px){.navbar-default .navbar-nav .open .dropdown-menu>li>a{color:#777} +.navbar-default .navbar-nav .open .dropdown-menu>li>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>li>a:hover{color:#333;background-color:transparent} +.navbar-default .navbar-nav .open .dropdown-menu>.active>a,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:hover{color:#555;background-color:#e7e7e7} +.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:hover{color:#ccc;background-color:transparent} +} +.navbar-default .navbar-link{color:#777} +.navbar-default .navbar-link:hover{color:#333} +.navbar-default .btn-link{color:#777} +.navbar-default .btn-link:focus,.navbar-default .btn-link:hover{color:#333} +.navbar-default .btn-link[disabled]:focus,.navbar-default .btn-link[disabled]:hover,fieldset[disabled] .navbar-default .btn-link:focus,fieldset[disabled] .navbar-default .btn-link:hover{color:#ccc} +.navbar-inverse{background-color:#222;border-color:#080808} +.navbar-inverse .navbar-brand{color:#9d9d9d} +.navbar-inverse .navbar-brand:focus,.navbar-inverse .navbar-brand:hover{color:#fff;background-color:transparent} +.navbar-inverse .navbar-nav>li>a,.navbar-inverse .navbar-text{color:#9d9d9d} +.navbar-inverse .navbar-nav>li>a:focus,.navbar-inverse .navbar-nav>li>a:hover{color:#fff;background-color:transparent} +.navbar-inverse .navbar-nav>.active>a,.navbar-inverse .navbar-nav>.active>a:focus,.navbar-inverse .navbar-nav>.active>a:hover{color:#fff;background-color:#080808} +.navbar-inverse .navbar-nav>.disabled>a,.navbar-inverse .navbar-nav>.disabled>a:focus,.navbar-inverse .navbar-nav>.disabled>a:hover{color:#444;background-color:transparent} +.navbar-inverse .navbar-toggle{border-color:#333} +.navbar-inverse .navbar-toggle:focus,.navbar-inverse .navbar-toggle:hover{background-color:#333} +.navbar-inverse .navbar-toggle .icon-bar{background-color:#fff} +.navbar-inverse .navbar-collapse,.navbar-inverse .navbar-form{border-color:#101010} +.navbar-inverse .navbar-nav>.open>a,.navbar-inverse .navbar-nav>.open>a:focus,.navbar-inverse .navbar-nav>.open>a:hover{color:#fff;background-color:#080808} +@media (max-width:767px){.navbar-inverse .navbar-nav .open .dropdown-menu>.dropdown-header{border-color:#080808} +.navbar-inverse .navbar-nav .open .dropdown-menu .divider{background-color:#080808} +.navbar-inverse .navbar-nav .open .dropdown-menu>li>a{color:#9d9d9d} +.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:hover{color:#fff;background-color:transparent} +.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:hover{color:#fff;background-color:#080808} +.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:hover{color:#444;background-color:transparent} +} +.navbar-inverse .navbar-link{color:#9d9d9d} +.navbar-inverse .navbar-link:hover{color:#fff} +.navbar-inverse .btn-link{color:#9d9d9d} +.navbar-inverse .btn-link:focus,.navbar-inverse .btn-link:hover{color:#fff} +.navbar-inverse .btn-link[disabled]:focus,.navbar-inverse .btn-link[disabled]:hover,fieldset[disabled] .navbar-inverse .btn-link:focus,fieldset[disabled] .navbar-inverse .btn-link:hover{color:#444} +.breadcrumb{padding:8px 15px;margin-bottom:20px;list-style:none;background-color:#f5f5f5;border-radius:4px} +.breadcrumb>li+li:before{padding:0 5px;color:#ccc;content:"/\00a0"} +.breadcrumb>.active{color:#777} +.pagination{padding-left:0;margin:20px 0;border-radius:4px} +.pager li,.pagination>li{display:inline} +.pagination>li>a,.pagination>li>span{position:relative;float:left;padding:6px 12px;margin-left:-1px;line-height:1.42857143;color:#337ab7;text-decoration:none;background-color:#fff;border:1px solid #ddd} +.pagination>li:first-child>a,.pagination>li:first-child>span{margin-left:0;border-top-left-radius:4px;border-bottom-left-radius:4px} +.pagination>li:last-child>a,.pagination>li:last-child>span{border-top-right-radius:4px;border-bottom-right-radius:4px} +.pagination>li>a:focus,.pagination>li>a:hover,.pagination>li>span:focus,.pagination>li>span:hover{z-index:2;color:#23527c;background-color:#eee;border-color:#ddd} +.pagination>.active>a,.pagination>.active>a:focus,.pagination>.active>a:hover,.pagination>.active>span,.pagination>.active>span:focus,.pagination>.active>span:hover{z-index:3;color:#fff;cursor:default;background-color:#337ab7;border-color:#337ab7} +.pagination>.disabled>a,.pagination>.disabled>a:focus,.pagination>.disabled>a:hover,.pagination>.disabled>span,.pagination>.disabled>span:focus,.pagination>.disabled>span:hover{color:#777;cursor:not-allowed;background-color:#fff;border-color:#ddd} +.pagination-lg>li>a,.pagination-lg>li>span{padding:10px 16px;font-size:18px;line-height:1.3333333} +.pagination-lg>li:first-child>a,.pagination-lg>li:first-child>span{border-top-left-radius:6px;border-bottom-left-radius:6px} +.pagination-lg>li:last-child>a,.pagination-lg>li:last-child>span{border-top-right-radius:6px;border-bottom-right-radius:6px} +.pagination-sm>li>a,.pagination-sm>li>span{padding:5px 10px;font-size:12px;line-height:1.5} +.badge,.label{font-weight:700;line-height:1;white-space:nowrap;text-align:center} +.pagination-sm>li:first-child>a,.pagination-sm>li:first-child>span{border-top-left-radius:3px;border-bottom-left-radius:3px} +.pagination-sm>li:last-child>a,.pagination-sm>li:last-child>span{border-top-right-radius:3px;border-bottom-right-radius:3px} +.pager{padding-left:0;margin:20px 0;text-align:center;list-style:none} +.pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;border-radius:15px} +.pager li>a:focus,.pager li>a:hover{text-decoration:none;background-color:#eee} +.pager .next>a,.pager .next>span{float:right} +.pager .previous>a,.pager .previous>span{float:left} +.pager .disabled>a,.pager .disabled>a:focus,.pager .disabled>a:hover,.pager .disabled>span{color:#777;cursor:not-allowed;background-color:#fff} +a.badge:focus,a.badge:hover,a.label:focus,a.label:hover{color:#fff;cursor:pointer;text-decoration:none} +.label{display:inline;padding:.2em .6em .3em;font-size:75%;color:#fff;border-radius:.25em} +.label:empty{display:none} +.label-default{background-color:#777} +.label-default[href]:focus,.label-default[href]:hover{background-color:#5e5e5e} +.label-primary{background-color:#337ab7} +.label-primary[href]:focus,.label-primary[href]:hover{background-color:#286090} +.label-success{background-color:#5cb85c} +.label-success[href]:focus,.label-success[href]:hover{background-color:#449d44} +.label-info{background-color:#5bc0de} +.label-info[href]:focus,.label-info[href]:hover{background-color:#31b0d5} +.label-warning{background-color:#f0ad4e} +.label-warning[href]:focus,.label-warning[href]:hover{background-color:#ec971f} +.label-danger{background-color:#d9534f} +.label-danger[href]:focus,.label-danger[href]:hover{background-color:#c9302c} +.badge{display:inline-block;min-width:10px;padding:3px 7px;font-size:12px;color:#fff;vertical-align:middle;background-color:#777;border-radius:10px} +.badge:empty{display:none} +.media-object,.thumbnail{display:block} +.btn-group-xs>.btn .badge,.btn-xs .badge{top:0;padding:1px 5px} +.list-group-item.active>.badge,.nav-pills>.active>a>.badge{color:#337ab7;background-color:#fff} +.jumbotron,.jumbotron .h1,.jumbotron h1{color:inherit} +.list-group-item>.badge{float:right} +.list-group-item>.badge+.badge{margin-right:5px} +.nav-pills>li>a>.badge{margin-left:3px} +.jumbotron{padding-top:30px;padding-bottom:30px;margin-bottom:30px;background-color:#eee} +.jumbotron p{margin-bottom:15px;font-size:21px;font-weight:200} +.alert,.thumbnail{margin-bottom:20px} +.alert .alert-link,.close{font-weight:700} +.jumbotron>hr{border-top-color:#d5d5d5} +.container .jumbotron,.container-fluid .jumbotron{padding-right:15px;padding-left:15px;border-radius:6px} +.jumbotron .container{max-width:100%} +@media screen and (min-width:768px){.jumbotron{padding-top:48px;padding-bottom:48px} +.container .jumbotron,.container-fluid .jumbotron{padding-right:60px;padding-left:60px} +.jumbotron .h1,.jumbotron h1{font-size:63px} +} +.thumbnail{padding:4px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:border .2s ease-in-out;-o-transition:border .2s ease-in-out;transition:border .2s ease-in-out} +.thumbnail a>img,.thumbnail>img{margin-right:auto;margin-left:auto} +a.thumbnail.active,a.thumbnail:focus,a.thumbnail:hover{border-color:#337ab7} +.thumbnail .caption{padding:9px;color:#333} +.alert{padding:15px;border:1px solid transparent;border-radius:4px} +.alert h4{margin-top:0;color:inherit} +.alert>p,.alert>ul{margin-bottom:0} +.alert>p+p{margin-top:5px} +.alert-dismissable,.alert-dismissible{padding-right:35px} +.alert-dismissable .close,.alert-dismissible .close{position:relative;top:-2px;right:-21px;color:inherit} +.modal,.modal-backdrop{top:0;right:0;bottom:0;left:0} +.alert-success{color:#3c763d;background-color:#dff0d8;border-color:#d6e9c6} +.alert-success hr{border-top-color:#c9e2b3} +.alert-success .alert-link{color:#2b542c} +.alert-info{color:#31708f;background-color:#d9edf7;border-color:#bce8f1} +.alert-info hr{border-top-color:#a6e1ec} +.alert-info .alert-link{color:#245269} +.alert-warning{color:#8a6d3b;background-color:#fcf8e3;border-color:#faebcc} +.alert-warning hr{border-top-color:#f7e1b5} +.alert-warning .alert-link{color:#66512c} +.alert-danger{color:#a94442;background-color:#f2dede;border-color:#ebccd1} +.alert-danger hr{border-top-color:#e4b9c0} +.alert-danger .alert-link{color:#843534} +@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0} +to{background-position:0 0} +} +@-o-keyframes progress-bar-stripes{from{background-position:40px 0} +to{background-position:0 0} +} +@keyframes progress-bar-stripes{from{background-position:40px 0} +to{background-position:0 0} +} +.progress{height:20px;margin-bottom:20px;background-color:#f5f5f5;border-radius:4px;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,.1);box-shadow:inset 0 1px 2px rgba(0,0,0,.1)} +.progress-bar{float:left;width:0;height:100%;font-size:12px;line-height:20px;color:#fff;text-align:center;background-color:#337ab7;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);-webkit-transition:width .6s ease;-o-transition:width .6s ease;transition:width .6s ease} +.progress-bar-striped,.progress-striped .progress-bar{background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);-webkit-background-size:40px 40px;background-size:40px 40px} +.progress-bar.active,.progress.active .progress-bar{-webkit-animation:progress-bar-stripes 2s linear infinite;-o-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite} +.progress-bar-success{background-color:#5cb85c} +.progress-striped .progress-bar-success{background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)} +.progress-striped .progress-bar-info,.progress-striped .progress-bar-warning{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)} +.progress-bar-info{background-color:#5bc0de} +.progress-striped .progress-bar-info{background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)} +.progress-bar-warning{background-color:#f0ad4e} +.progress-striped .progress-bar-warning{background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)} +.progress-bar-danger{background-color:#d9534f} +.progress-striped .progress-bar-danger{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)} +.media{margin-top:15px} +.media:first-child{margin-top:0} +.media,.media-body{overflow:hidden;zoom:1} +.media-body{width:10000px} +.media-object.img-thumbnail{max-width:none} +.media-right,.media>.pull-right{padding-left:10px} +.media-left,.media>.pull-left{padding-right:10px} +.media-body,.media-left,.media-right{display:table-cell;vertical-align:top} +.media-middle{vertical-align:middle} +.media-bottom{vertical-align:bottom} +.media-heading{margin-top:0;margin-bottom:5px} +.media-list{padding-left:0;list-style:none} +.list-group{padding-left:0;margin-bottom:20px} +.list-group-item{position:relative;display:block;padding:10px 15px;margin-bottom:-1px;background-color:#fff;border:1px solid #ddd} +.list-group-item:first-child{border-top-left-radius:4px;border-top-right-radius:4px} +.list-group-item:last-child{margin-bottom:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px} +a.list-group-item,button.list-group-item{color:#555} +a.list-group-item .list-group-item-heading,button.list-group-item .list-group-item-heading{color:#333} +a.list-group-item:focus,a.list-group-item:hover,button.list-group-item:focus,button.list-group-item:hover{color:#555;text-decoration:none;background-color:#f5f5f5} +button.list-group-item{width:100%;text-align:left} +.list-group-item.disabled,.list-group-item.disabled:focus,.list-group-item.disabled:hover{color:#777;cursor:not-allowed;background-color:#eee} +.list-group-item.disabled .list-group-item-heading,.list-group-item.disabled:focus .list-group-item-heading,.list-group-item.disabled:hover .list-group-item-heading{color:inherit} +.list-group-item.disabled .list-group-item-text,.list-group-item.disabled:focus .list-group-item-text,.list-group-item.disabled:hover .list-group-item-text{color:#777} +.list-group-item.active,.list-group-item.active:focus,.list-group-item.active:hover{z-index:2;color:#fff;background-color:#337ab7;border-color:#337ab7} +.list-group-item.active .list-group-item-heading,.list-group-item.active .list-group-item-heading>.small,.list-group-item.active .list-group-item-heading>small,.list-group-item.active:focus .list-group-item-heading,.list-group-item.active:focus .list-group-item-heading>.small,.list-group-item.active:focus .list-group-item-heading>small,.list-group-item.active:hover .list-group-item-heading,.list-group-item.active:hover .list-group-item-heading>.small,.list-group-item.active:hover .list-group-item-heading>small{color:inherit} +.list-group-item.active .list-group-item-text,.list-group-item.active:focus .list-group-item-text,.list-group-item.active:hover .list-group-item-text{color:#c7ddef} +.list-group-item-success{color:#3c763d;background-color:#dff0d8} +a.list-group-item-success,button.list-group-item-success{color:#3c763d} +a.list-group-item-success .list-group-item-heading,button.list-group-item-success .list-group-item-heading{color:inherit} +a.list-group-item-success:focus,a.list-group-item-success:hover,button.list-group-item-success:focus,button.list-group-item-success:hover{color:#3c763d;background-color:#d0e9c6} +a.list-group-item-success.active,a.list-group-item-success.active:focus,a.list-group-item-success.active:hover,button.list-group-item-success.active,button.list-group-item-success.active:focus,button.list-group-item-success.active:hover{color:#fff;background-color:#3c763d;border-color:#3c763d} +.list-group-item-info{color:#31708f;background-color:#d9edf7} +a.list-group-item-info,button.list-group-item-info{color:#31708f} +a.list-group-item-info .list-group-item-heading,button.list-group-item-info .list-group-item-heading{color:inherit} +a.list-group-item-info:focus,a.list-group-item-info:hover,button.list-group-item-info:focus,button.list-group-item-info:hover{color:#31708f;background-color:#c4e3f3} +a.list-group-item-info.active,a.list-group-item-info.active:focus,a.list-group-item-info.active:hover,button.list-group-item-info.active,button.list-group-item-info.active:focus,button.list-group-item-info.active:hover{color:#fff;background-color:#31708f;border-color:#31708f} +.list-group-item-warning{color:#8a6d3b;background-color:#fcf8e3} +a.list-group-item-warning,button.list-group-item-warning{color:#8a6d3b} +a.list-group-item-warning .list-group-item-heading,button.list-group-item-warning .list-group-item-heading{color:inherit} +a.list-group-item-warning:focus,a.list-group-item-warning:hover,button.list-group-item-warning:focus,button.list-group-item-warning:hover{color:#8a6d3b;background-color:#faf2cc} +a.list-group-item-warning.active,a.list-group-item-warning.active:focus,a.list-group-item-warning.active:hover,button.list-group-item-warning.active,button.list-group-item-warning.active:focus,button.list-group-item-warning.active:hover{color:#fff;background-color:#8a6d3b;border-color:#8a6d3b} +.list-group-item-danger{color:#a94442;background-color:#f2dede} +a.list-group-item-danger,button.list-group-item-danger{color:#a94442} +a.list-group-item-danger .list-group-item-heading,button.list-group-item-danger .list-group-item-heading{color:inherit} +a.list-group-item-danger:focus,a.list-group-item-danger:hover,button.list-group-item-danger:focus,button.list-group-item-danger:hover{color:#a94442;background-color:#ebcccc} +a.list-group-item-danger.active,a.list-group-item-danger.active:focus,a.list-group-item-danger.active:hover,button.list-group-item-danger.active,button.list-group-item-danger.active:focus,button.list-group-item-danger.active:hover{color:#fff;background-color:#a94442;border-color:#a94442} +.panel-heading>.dropdown .dropdown-toggle,.panel-title,.panel-title>.small,.panel-title>.small>a,.panel-title>a,.panel-title>small,.panel-title>small>a{color:inherit} +.list-group-item-heading{margin-top:0;margin-bottom:5px} +.list-group-item-text{margin-bottom:0;line-height:1.3} +.panel{margin-bottom:20px;background-color:#fff;border:1px solid transparent;border-radius:4px;-webkit-box-shadow:0 1px 1px rgba(0,0,0,.05);box-shadow:0 1px 1px rgba(0,0,0,.05)} +.panel-title,.panel>.list-group,.panel>.panel-collapse>.list-group,.panel>.panel-collapse>.table,.panel>.table,.panel>.table-responsive>.table{margin-bottom:0} +.panel-body{padding:15px} +.panel-heading{padding:10px 15px;border-bottom:1px solid transparent;border-top-left-radius:3px;border-top-right-radius:3px} +.panel-title{margin-top:0;font-size:16px} +.panel-footer{padding:10px 15px;background-color:#f5f5f5;border-top:1px solid #ddd;border-bottom-right-radius:3px;border-bottom-left-radius:3px} +.panel>.list-group .list-group-item,.panel>.panel-collapse>.list-group .list-group-item{border-width:1px 0;border-radius:0} +.panel-group .panel-heading,.panel>.table-bordered>tbody>tr:first-child>td,.panel>.table-bordered>tbody>tr:first-child>th,.panel>.table-bordered>tbody>tr:last-child>td,.panel>.table-bordered>tbody>tr:last-child>th,.panel>.table-bordered>tfoot>tr:last-child>td,.panel>.table-bordered>tfoot>tr:last-child>th,.panel>.table-bordered>thead>tr:first-child>td,.panel>.table-bordered>thead>tr:first-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>th,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>td,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>th,.panel>.table-responsive>.table-bordered>thead>tr:first-child>td,.panel>.table-responsive>.table-bordered>thead>tr:first-child>th{border-bottom:0} +.panel>.list-group:first-child .list-group-item:first-child,.panel>.panel-collapse>.list-group:first-child .list-group-item:first-child{border-top:0;border-top-left-radius:3px;border-top-right-radius:3px} +.panel>.list-group:last-child .list-group-item:last-child,.panel>.panel-collapse>.list-group:last-child .list-group-item:last-child{border-bottom:0;border-bottom-right-radius:3px;border-bottom-left-radius:3px} +.panel>.panel-heading+.panel-collapse>.list-group .list-group-item:first-child{border-top-left-radius:0;border-top-right-radius:0} +.list-group+.panel-footer,.panel-heading+.list-group .list-group-item:first-child{border-top-width:0} +.panel>.panel-collapse>.table caption,.panel>.table caption,.panel>.table-responsive>.table caption{padding-right:15px;padding-left:15px} +.panel>.table-responsive:first-child>.table:first-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child,.panel>.table:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child,.panel>.table:first-child>thead:first-child>tr:first-child{border-top-left-radius:3px;border-top-right-radius:3px} +.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table:first-child>thead:first-child>tr:first-child th:first-child{border-top-left-radius:3px} +.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:last-child,.panel>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table:first-child>thead:first-child>tr:first-child th:last-child{border-top-right-radius:3px} +.panel>.table-responsive:last-child>.table:last-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child,.panel>.table:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child{border-bottom-right-radius:3px;border-bottom-left-radius:3px} +.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:first-child{border-bottom-left-radius:3px} +.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:last-child{border-bottom-right-radius:3px} +.panel>.panel-body+.table,.panel>.panel-body+.table-responsive,.panel>.table+.panel-body,.panel>.table-responsive+.panel-body{border-top:1px solid #ddd} +.panel>.table>tbody:first-child>tr:first-child td,.panel>.table>tbody:first-child>tr:first-child th{border-top:0} +.panel>.table-bordered,.panel>.table-responsive>.table-bordered{border:0} +.panel>.table-bordered>tbody>tr>td:first-child,.panel>.table-bordered>tbody>tr>th:first-child,.panel>.table-bordered>tfoot>tr>td:first-child,.panel>.table-bordered>tfoot>tr>th:first-child,.panel>.table-bordered>thead>tr>td:first-child,.panel>.table-bordered>thead>tr>th:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:first-child,.panel>.table-responsive>.table-bordered>thead>tr>td:first-child,.panel>.table-responsive>.table-bordered>thead>tr>th:first-child{border-left:0} +.panel>.table-bordered>tbody>tr>td:last-child,.panel>.table-bordered>tbody>tr>th:last-child,.panel>.table-bordered>tfoot>tr>td:last-child,.panel>.table-bordered>tfoot>tr>th:last-child,.panel>.table-bordered>thead>tr>td:last-child,.panel>.table-bordered>thead>tr>th:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:last-child,.panel>.table-responsive>.table-bordered>thead>tr>td:last-child,.panel>.table-responsive>.table-bordered>thead>tr>th:last-child{border-right:0} +.panel>.table-responsive{margin-bottom:0;border:0} +.panel-group{margin-bottom:20px} +.panel-group .panel{margin-bottom:0;border-radius:4px} +.panel-group .panel+.panel{margin-top:5px} +.panel-group .panel-heading+.panel-collapse>.list-group,.panel-group .panel-heading+.panel-collapse>.panel-body{border-top:1px solid #ddd} +.panel-group .panel-footer{border-top:0} +.panel-group .panel-footer+.panel-collapse .panel-body{border-bottom:1px solid #ddd} +.panel-default{border-color:#ddd} +.panel-default>.panel-heading{color:#333;background-color:#f5f5f5;border-color:#ddd} +.panel-default>.panel-heading+.panel-collapse>.panel-body{border-top-color:#ddd} +.panel-default>.panel-heading .badge{color:#f5f5f5;background-color:#333} +.panel-default>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#ddd} +.panel-primary{border-color:#337ab7} +.panel-primary>.panel-heading{color:#fff;background-color:#337ab7;border-color:#337ab7} +.panel-primary>.panel-heading+.panel-collapse>.panel-body{border-top-color:#337ab7} +.panel-primary>.panel-heading .badge{color:#337ab7;background-color:#fff} +.panel-primary>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#337ab7} +.panel-success{border-color:#d6e9c6} +.panel-success>.panel-heading{color:#3c763d;background-color:#dff0d8;border-color:#d6e9c6} +.panel-success>.panel-heading+.panel-collapse>.panel-body{border-top-color:#d6e9c6} +.panel-success>.panel-heading .badge{color:#dff0d8;background-color:#3c763d} +.panel-success>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#d6e9c6} +.panel-info{border-color:#bce8f1} +.panel-info>.panel-heading{color:#31708f;background-color:#d9edf7;border-color:#bce8f1} +.panel-info>.panel-heading+.panel-collapse>.panel-body{border-top-color:#bce8f1} +.panel-info>.panel-heading .badge{color:#d9edf7;background-color:#31708f} +.panel-info>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#bce8f1} +.panel-warning{border-color:#faebcc} +.panel-warning>.panel-heading{color:#8a6d3b;background-color:#fcf8e3;border-color:#faebcc} +.panel-warning>.panel-heading+.panel-collapse>.panel-body{border-top-color:#faebcc} +.panel-warning>.panel-heading .badge{color:#fcf8e3;background-color:#8a6d3b} +.panel-warning>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#faebcc} +.panel-danger{border-color:#ebccd1} +.panel-danger>.panel-heading{color:#a94442;background-color:#f2dede;border-color:#ebccd1} +.panel-danger>.panel-heading+.panel-collapse>.panel-body{border-top-color:#ebccd1} +.panel-danger>.panel-heading .badge{color:#f2dede;background-color:#a94442} +.panel-danger>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#ebccd1} +.embed-responsive{position:relative;display:block;height:0;padding:0} +.embed-responsive .embed-responsive-item,.embed-responsive embed,.embed-responsive iframe,.embed-responsive object,.embed-responsive video{position:absolute;top:0;bottom:0;left:0;width:100%;height:100%;border:0} +.embed-responsive-16by9{padding-bottom:56.25%} +.embed-responsive-4by3{padding-bottom:75%} +.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.05);box-shadow:inset 0 1px 1px rgba(0,0,0,.05)} +.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,.15)} +.well-lg{padding:24px;border-radius:6px} +.well-sm{padding:9px;border-radius:3px} +.close{float:right;font-size:21px;line-height:1;color:#000;text-shadow:0 1px 0 #fff;filter:alpha(opacity=20);opacity:.2} +.popover,.tooltip{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-style:normal;font-weight:400;line-height:1.42857143;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;word-wrap:normal;white-space:normal;line-break:auto;text-decoration:none} +.close:focus,.close:hover{color:#000;text-decoration:none;cursor:pointer;filter:alpha(opacity=50);opacity:.5} +button.close{-webkit-appearance:none;padding:0;cursor:pointer;background:0 0;border:0} +.modal{position:fixed;z-index:1050;display:none;-webkit-overflow-scrolling:touch;outline:0} +.modal.fade .modal-dialog{-webkit-transition:-webkit-transform .3s ease-out;-o-transition:-o-transform .3s ease-out;transition:transform .3s ease-out;-webkit-transform:translate(0,-25%);-ms-transform:translate(0,-25%);-o-transform:translate(0,-25%);transform:translate(0,-25%)} +.modal.in .modal-dialog{-webkit-transform:translate(0,0);-ms-transform:translate(0,0);-o-transform:translate(0,0);transform:translate(0,0)} +.modal-open .modal{overflow-x:hidden;overflow-y:auto} +.modal-dialog{position:relative;width:auto;margin:10px} +.modal-content{position:relative;background-color:#fff;background-clip:padding-box;border:1px solid #999;border:1px solid rgba(0,0,0,.2);border-radius:6px;outline:0;-webkit-box-shadow:0 3px 9px rgba(0,0,0,.5);box-shadow:0 3px 9px rgba(0,0,0,.5)} +.modal-backdrop{position:fixed;z-index:1040;background-color:#000} +.modal-backdrop.fade{filter:alpha(opacity=0);opacity:0} +.modal-backdrop.in{filter:alpha(opacity=50);opacity:.5} +.modal-header{padding:15px;border-bottom:1px solid #e5e5e5} +.modal-header .close{margin-top:-2px} +.modal-title{margin:0;line-height:1.42857143} +.modal-body{position:relative;padding:15px} +.modal-footer{padding:15px;text-align:right;border-top:1px solid #e5e5e5} +.modal-footer .btn+.btn{margin-bottom:0;margin-left:5px} +.modal-footer .btn-group .btn+.btn{margin-left:-1px} +.modal-footer .btn-block+.btn-block{margin-left:0} +.modal-scrollbar-measure{position:absolute;top:-9999px;width:50px;height:50px;overflow:scroll} +@media (min-width:768px){.modal-dialog{width:600px;margin:30px auto} +.modal-content{-webkit-box-shadow:0 5px 15px rgba(0,0,0,.5);box-shadow:0 5px 15px rgba(0,0,0,.5)} +.modal-sm{width:300px} +} +@media (min-width:992px){.modal-lg{width:900px} +} +.tooltip{position:absolute;z-index:1070;display:block;font-size:12px;text-align:left;text-align:start;filter:alpha(opacity=0);opacity:0} +.tooltip.in{filter:alpha(opacity=90);opacity:.9} +.tooltip.top{padding:5px 0;margin-top:-3px} +.tooltip.right{padding:0 5px;margin-left:3px} +.tooltip.bottom{padding:5px 0;margin-top:3px} +.tooltip.left{padding:0 5px;margin-left:-3px} +.tooltip-inner{max-width:200px;padding:3px 8px;color:#fff;text-align:center;background-color:#000;border-radius:4px} +.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid} +.tooltip.top .tooltip-arrow,.tooltip.top-left .tooltip-arrow,.tooltip.top-right .tooltip-arrow{bottom:0;border-width:5px 5px 0;border-top-color:#000} +.tooltip.top .tooltip-arrow{left:50%;margin-left:-5px} +.tooltip.top-left .tooltip-arrow{right:5px;margin-bottom:-5px} +.tooltip.top-right .tooltip-arrow{left:5px;margin-bottom:-5px} +.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-width:5px 5px 5px 0;border-right-color:#000} +.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-width:5px 0 5px 5px;border-left-color:#000} +.tooltip.bottom .tooltip-arrow,.tooltip.bottom-left .tooltip-arrow,.tooltip.bottom-right .tooltip-arrow{border-width:0 5px 5px;border-bottom-color:#000;top:0} +.tooltip.bottom .tooltip-arrow{left:50%;margin-left:-5px} +.tooltip.bottom-left .tooltip-arrow{right:5px;margin-top:-5px} +.tooltip.bottom-right .tooltip-arrow{left:5px;margin-top:-5px} +.popover{position:absolute;top:0;left:0;z-index:1060;display:none;max-width:276px;padding:1px;font-size:14px;text-align:left;text-align:start;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,.2);border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,.2);box-shadow:0 5px 10px rgba(0,0,0,.2)} +.carousel-caption,.carousel-control{color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6)} +.popover.top{margin-top:-10px} +.popover.right{margin-left:10px} +.popover.bottom{margin-top:10px} +.popover.left{margin-left:-10px} +.popover-title{padding:8px 14px;margin:0;font-size:14px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-radius:5px 5px 0 0} +.popover-content{padding:9px 14px} +.popover>.arrow,.popover>.arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid} +.carousel,.carousel-inner{position:relative} +.popover>.arrow{border-width:11px} +.popover>.arrow:after{content:"";border-width:10px} +.popover.top>.arrow{bottom:-11px;left:50%;margin-left:-11px;border-top-color:#999;border-top-color:rgba(0,0,0,.25);border-bottom-width:0} +.popover.top>.arrow:after{bottom:1px;margin-left:-10px;content:" ";border-top-color:#fff;border-bottom-width:0} +.popover.left>.arrow:after,.popover.right>.arrow:after{bottom:-10px;content:" "} +.popover.right>.arrow{top:50%;left:-11px;margin-top:-11px;border-right-color:#999;border-right-color:rgba(0,0,0,.25);border-left-width:0} +.popover.right>.arrow:after{left:1px;border-right-color:#fff;border-left-width:0} +.popover.bottom>.arrow{top:-11px;left:50%;margin-left:-11px;border-top-width:0;border-bottom-color:#999;border-bottom-color:rgba(0,0,0,.25)} +.popover.bottom>.arrow:after{top:1px;margin-left:-10px;content:" ";border-top-width:0;border-bottom-color:#fff} +.popover.left>.arrow{top:50%;right:-11px;margin-top:-11px;border-right-width:0;border-left-color:#999;border-left-color:rgba(0,0,0,.25)} +.popover.left>.arrow:after{right:1px;border-right-width:0;border-left-color:#fff} +.carousel-inner{width:100%;overflow:hidden} +.carousel-inner>.item{position:relative;display:none;-webkit-transition:.6s ease-in-out left;-o-transition:.6s ease-in-out left;transition:.6s ease-in-out left} +.carousel-inner>.item>a>img,.carousel-inner>.item>img{line-height:1} +@media all and (transform-3d),(-webkit-transform-3d){.carousel-inner>.item{-webkit-transition:-webkit-transform .6s ease-in-out;-o-transition:-o-transform .6s ease-in-out;transition:transform .6s ease-in-out;-webkit-backface-visibility:hidden;backface-visibility:hidden;-webkit-perspective:1000px;perspective:1000px} +.carousel-inner>.item.active.right,.carousel-inner>.item.next{left:0;-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)} +.carousel-inner>.item.active.left,.carousel-inner>.item.prev{left:0;-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)} +.carousel-inner>.item.active,.carousel-inner>.item.next.left,.carousel-inner>.item.prev.right{left:0;-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)} +} +.carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block} +.carousel-inner>.active{left:0} +.carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%} +.carousel-inner>.next{left:100%} +.carousel-inner>.prev{left:-100%} +.carousel-inner>.next.left,.carousel-inner>.prev.right{left:0} +.carousel-inner>.active.left{left:-100%} +.carousel-inner>.active.right{left:100%} +.carousel-control{position:absolute;top:0;bottom:0;left:0;width:15%;font-size:20px;background-color:rgba(0,0,0,0);filter:alpha(opacity=50);opacity:.5} +.carousel-control.left{background-image:-webkit-linear-gradient(left,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);background-image:-o-linear-gradient(left,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);background-image:-webkit-gradient(linear,left top,right top,from(rgba(0,0,0,.5)),to(rgba(0,0,0,.0001)));background-image:linear-gradient(to right,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1);background-repeat:repeat-x} +.carousel-control.right{right:0;left:auto;background-image:-webkit-linear-gradient(left,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);background-image:-o-linear-gradient(left,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);background-image:-webkit-gradient(linear,left top,right top,from(rgba(0,0,0,.0001)),to(rgba(0,0,0,.5)));background-image:linear-gradient(to right,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1);background-repeat:repeat-x} +.carousel-control:focus,.carousel-control:hover{color:#fff;text-decoration:none;filter:alpha(opacity=90);outline:0;opacity:.9} +.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next,.carousel-control .icon-prev{position:absolute;top:50%;z-index:5;display:inline-block;margin-top:-10px} +.carousel-control .glyphicon-chevron-left,.carousel-control .icon-prev{left:50%;margin-left:-10px} +.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next{right:50%;margin-right:-10px} +.carousel-control .icon-next,.carousel-control .icon-prev{width:20px;height:20px;font-family:serif;line-height:1} +.carousel-control .icon-prev:before{content:'\2039'} +.carousel-control .icon-next:before{content:'\203a'} +.carousel-indicators{position:absolute;bottom:10px;left:50%;z-index:15;width:60%;padding-left:0;margin-left:-30%;text-align:center;list-style:none} +.carousel-indicators li{display:inline-block;width:10px;height:10px;margin:1px;text-indent:-999px;cursor:pointer;background-color:#000\9;background-color:rgba(0,0,0,0);border:1px solid #fff;border-radius:10px} +.carousel-indicators .active{width:12px;height:12px;margin:0;background-color:#fff} +.carousel-caption{position:absolute;right:15%;bottom:20px;left:15%;z-index:10;padding-top:20px;padding-bottom:20px} +.carousel-caption .btn,.text-hide{text-shadow:none} +@media screen and (min-width:768px){.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next,.carousel-control .icon-prev{width:30px;height:30px;margin-top:-10px;font-size:30px} +.carousel-control .glyphicon-chevron-left,.carousel-control .icon-prev{margin-left:-10px} +.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next{margin-right:-10px} +.carousel-caption{right:20%;left:20%;padding-bottom:30px} +.carousel-indicators{bottom:20px} +} +.btn-group-vertical>.btn-group:after,.btn-group-vertical>.btn-group:before,.btn-toolbar:after,.btn-toolbar:before,.clearfix:after,.clearfix:before,.container-fluid:after,.container-fluid:before,.container:after,.container:before,.dl-horizontal dd:after,.dl-horizontal dd:before,.form-horizontal .form-group:after,.form-horizontal .form-group:before,.modal-footer:after,.modal-footer:before,.modal-header:after,.modal-header:before,.nav:after,.nav:before,.navbar-collapse:after,.navbar-collapse:before,.navbar-header:after,.navbar-header:before,.navbar:after,.navbar:before,.pager:after,.pager:before,.panel-body:after,.panel-body:before,.row:after,.row:before{display:table;content:" "} +.btn-group-vertical>.btn-group:after,.btn-toolbar:after,.clearfix:after,.container-fluid:after,.container:after,.dl-horizontal dd:after,.form-horizontal .form-group:after,.modal-footer:after,.modal-header:after,.nav:after,.navbar-collapse:after,.navbar-header:after,.navbar:after,.pager:after,.panel-body:after,.row:after{clear:both} +.center-block{display:block;margin-right:auto;margin-left:auto} +.pull-right{float:right!important} +.pull-left{float:left!important} +.hide{display:none!important} +.show{display:block!important} +.hidden,.visible-lg,.visible-lg-block,.visible-lg-inline,.visible-lg-inline-block,.visible-md,.visible-md-block,.visible-md-inline,.visible-md-inline-block,.visible-sm,.visible-sm-block,.visible-sm-inline,.visible-sm-inline-block,.visible-xs,.visible-xs-block,.visible-xs-inline,.visible-xs-inline-block{display:none!important} +.invisible{visibility:hidden} +.text-hide{font:0/0 a;color:transparent;background-color:transparent;border:0} +.affix{position:fixed} +@-ms-viewport{width:device-width} +@media (max-width:767px){.visible-xs{display:block!important} +table.visible-xs{display:table!important} +tr.visible-xs{display:table-row!important} +td.visible-xs,th.visible-xs{display:table-cell!important} +.visible-xs-block{display:block!important} +.visible-xs-inline{display:inline!important} +.visible-xs-inline-block{display:inline-block!important} +} +@media (min-width:768px) and (max-width:991px){.visible-sm{display:block!important} +table.visible-sm{display:table!important} +tr.visible-sm{display:table-row!important} +td.visible-sm,th.visible-sm{display:table-cell!important} +.visible-sm-block{display:block!important} +.visible-sm-inline{display:inline!important} +.visible-sm-inline-block{display:inline-block!important} +} +@media (min-width:992px) and (max-width:1199px){.visible-md{display:block!important} +table.visible-md{display:table!important} +tr.visible-md{display:table-row!important} +td.visible-md,th.visible-md{display:table-cell!important} +.visible-md-block{display:block!important} +.visible-md-inline{display:inline!important} +.visible-md-inline-block{display:inline-block!important} +} +@media (min-width:1200px){.visible-lg{display:block!important} +table.visible-lg{display:table!important} +tr.visible-lg{display:table-row!important} +td.visible-lg,th.visible-lg{display:table-cell!important} +.visible-lg-block{display:block!important} +.visible-lg-inline{display:inline!important} +.visible-lg-inline-block{display:inline-block!important} +.hidden-lg{display:none!important} +} +@media (max-width:767px){.hidden-xs{display:none!important} +} +@media (min-width:768px) and (max-width:991px){.hidden-sm{display:none!important} +} +@media (min-width:992px) and (max-width:1199px){.hidden-md{display:none!important} +} +.visible-print{display:none!important} +@media print{.visible-print{display:block!important} +table.visible-print{display:table!important} +tr.visible-print{display:table-row!important} +td.visible-print,th.visible-print{display:table-cell!important} +} +.visible-print-block{display:none!important} +@media print{.visible-print-block{display:block!important} +} +.visible-print-inline{display:none!important} +@media print{.visible-print-inline{display:inline!important} +} +.visible-print-inline-block{display:none!important} +@media print{.visible-print-inline-block{display:inline-block!important} +.hidden-print{display:none!important} +} +.hljs{display:block;background:#fff;padding:.5em;color:#333;overflow-x:auto} +.hljs-comment,.hljs-meta{color:#969896} +.hljs-emphasis,.hljs-quote,.hljs-string,.hljs-strong,.hljs-template-variable,.hljs-variable{color:#df5000} +.hljs-keyword,.hljs-selector-tag,.hljs-type{color:#a71d5d} +.hljs-attribute,.hljs-bullet,.hljs-literal,.hljs-symbol{color:#0086b3} +.hljs-name,.hljs-section{color:#63a35c} +.hljs-tag{color:#333} +.hljs-attr,.hljs-selector-attr,.hljs-selector-class,.hljs-selector-id,.hljs-selector-pseudo,.hljs-title{color:#795da3} +.hljs-addition{color:#55a532;background-color:#eaffea} +.hljs-deletion{color:#bd2c00;background-color:#ffecec} +.hljs-link{text-decoration:underline} \ No newline at end of file diff --git a/docs/styles/docfx.vendor.js b/docs/styles/docfx.vendor.js new file mode 100644 index 000000000..ff662c6de --- /dev/null +++ b/docs/styles/docfx.vendor.js @@ -0,0 +1,55 @@ +/*! jQuery v2.1.4 | (c) 2005, 2015 jQuery Foundation, Inc. | jquery.org/license */ +!function(a,b){"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){var c=[],d=c.slice,e=c.concat,f=c.push,g=c.indexOf,h={},i=h.toString,j=h.hasOwnProperty,k={},l=a.document,m="2.1.4",n=function(a,b){return new n.fn.init(a,b)},o=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,p=/^-ms-/,q=/-([\da-z])/gi,r=function(a,b){return b.toUpperCase()};n.fn=n.prototype={jquery:m,constructor:n,selector:"",length:0,toArray:function(){return d.call(this)},get:function(a){return null!=a?0>a?this[a+this.length]:this[a]:d.call(this)},pushStack:function(a){var b=n.merge(this.constructor(),a);return b.prevObject=this,b.context=this.context,b},each:function(a,b){return n.each(this,a,b)},map:function(a){return this.pushStack(n.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(d.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(0>a?b:0);return this.pushStack(c>=0&&b>c?[this[c]]:[])},end:function(){return this.prevObject||this.constructor(null)},push:f,sort:c.sort,splice:c.splice},n.extend=n.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for("boolean"==typeof g&&(j=g,g=arguments[h]||{},h++),"object"==typeof g||n.isFunction(g)||(g={}),h===i&&(g=this,h--);i>h;h++)if(null!=(a=arguments[h]))for(b in a)c=g[b],d=a[b],g!==d&&(j&&d&&(n.isPlainObject(d)||(e=n.isArray(d)))?(e?(e=!1,f=c&&n.isArray(c)?c:[]):f=c&&n.isPlainObject(c)?c:{},g[b]=n.extend(j,f,d)):void 0!==d&&(g[b]=d));return g},n.extend({expando:"jQuery"+(m+Math.random()).replace(/\D/g,""),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return"function"===n.type(a)},isArray:Array.isArray,isWindow:function(a){return null!=a&&a===a.window},isNumeric:function(a){return!n.isArray(a)&&a-parseFloat(a)+1>=0},isPlainObject:function(a){return"object"!==n.type(a)||a.nodeType||n.isWindow(a)?!1:a.constructor&&!j.call(a.constructor.prototype,"isPrototypeOf")?!1:!0},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},type:function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?h[i.call(a)]||"object":typeof a},globalEval:function(a){var b,c=eval;a=n.trim(a),a&&(1===a.indexOf("use strict")?(b=l.createElement("script"),b.text=a,l.head.appendChild(b).parentNode.removeChild(b)):c(a))},camelCase:function(a){return a.replace(p,"ms-").replace(q,r)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,b,c){var d,e=0,f=a.length,g=s(a);if(c){if(g){for(;f>e;e++)if(d=b.apply(a[e],c),d===!1)break}else for(e in a)if(d=b.apply(a[e],c),d===!1)break}else if(g){for(;f>e;e++)if(d=b.call(a[e],e,a[e]),d===!1)break}else for(e in a)if(d=b.call(a[e],e,a[e]),d===!1)break;return a},trim:function(a){return null==a?"":(a+"").replace(o,"")},makeArray:function(a,b){var c=b||[];return null!=a&&(s(Object(a))?n.merge(c,"string"==typeof a?[a]:a):f.call(c,a)),c},inArray:function(a,b,c){return null==b?-1:g.call(b,a,c)},merge:function(a,b){for(var c=+b.length,d=0,e=a.length;c>d;d++)a[e++]=b[d];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;g>f;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,f=0,g=a.length,h=s(a),i=[];if(h)for(;g>f;f++)d=b(a[f],f,c),null!=d&&i.push(d);else for(f in a)d=b(a[f],f,c),null!=d&&i.push(d);return e.apply([],i)},guid:1,proxy:function(a,b){var c,e,f;return"string"==typeof b&&(c=a[b],b=a,a=c),n.isFunction(a)?(e=d.call(arguments,2),f=function(){return a.apply(b||this,e.concat(d.call(arguments)))},f.guid=a.guid=a.guid||n.guid++,f):void 0},now:Date.now,support:k}),n.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(a,b){h["[object "+b+"]"]=b.toLowerCase()});function s(a){var b="length"in a&&a.length,c=n.type(a);return"function"===c||n.isWindow(a)?!1:1===a.nodeType&&b?!0:"array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a}var t=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u="sizzle"+1*new Date,v=a.document,w=0,x=0,y=ha(),z=ha(),A=ha(),B=function(a,b){return a===b&&(l=!0),0},C=1<<31,D={}.hasOwnProperty,E=[],F=E.pop,G=E.push,H=E.push,I=E.slice,J=function(a,b){for(var c=0,d=a.length;d>c;c++)if(a[c]===b)return c;return-1},K="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",L="[\\x20\\t\\r\\n\\f]",M="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",N=M.replace("w","w#"),O="\\["+L+"*("+M+")(?:"+L+"*([*^$|!~]?=)"+L+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+N+"))|)"+L+"*\\]",P=":("+M+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+O+")*)|.*)\\)|)",Q=new RegExp(L+"+","g"),R=new RegExp("^"+L+"+|((?:^|[^\\\\])(?:\\\\.)*)"+L+"+$","g"),S=new RegExp("^"+L+"*,"+L+"*"),T=new RegExp("^"+L+"*([>+~]|"+L+")"+L+"*"),U=new RegExp("="+L+"*([^\\]'\"]*?)"+L+"*\\]","g"),V=new RegExp(P),W=new RegExp("^"+N+"$"),X={ID:new RegExp("^#("+M+")"),CLASS:new RegExp("^\\.("+M+")"),TAG:new RegExp("^("+M.replace("w","w*")+")"),ATTR:new RegExp("^"+O),PSEUDO:new RegExp("^"+P),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+L+"*(even|odd|(([+-]|)(\\d*)n|)"+L+"*(?:([+-]|)"+L+"*(\\d+)|))"+L+"*\\)|)","i"),bool:new RegExp("^(?:"+K+")$","i"),needsContext:new RegExp("^"+L+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+L+"*((?:-\\d)?\\d*)"+L+"*\\)|)(?=[^-]|$)","i")},Y=/^(?:input|select|textarea|button)$/i,Z=/^h\d$/i,$=/^[^{]+\{\s*\[native \w/,_=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,aa=/[+~]/,ba=/'|\\/g,ca=new RegExp("\\\\([\\da-f]{1,6}"+L+"?|("+L+")|.)","ig"),da=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:0>d?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)},ea=function(){m()};try{H.apply(E=I.call(v.childNodes),v.childNodes),E[v.childNodes.length].nodeType}catch(fa){H={apply:E.length?function(a,b){G.apply(a,I.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function ga(a,b,d,e){var f,h,j,k,l,o,r,s,w,x;if((b?b.ownerDocument||b:v)!==n&&m(b),b=b||n,d=d||[],k=b.nodeType,"string"!=typeof a||!a||1!==k&&9!==k&&11!==k)return d;if(!e&&p){if(11!==k&&(f=_.exec(a)))if(j=f[1]){if(9===k){if(h=b.getElementById(j),!h||!h.parentNode)return d;if(h.id===j)return d.push(h),d}else if(b.ownerDocument&&(h=b.ownerDocument.getElementById(j))&&t(b,h)&&h.id===j)return d.push(h),d}else{if(f[2])return H.apply(d,b.getElementsByTagName(a)),d;if((j=f[3])&&c.getElementsByClassName)return H.apply(d,b.getElementsByClassName(j)),d}if(c.qsa&&(!q||!q.test(a))){if(s=r=u,w=b,x=1!==k&&a,1===k&&"object"!==b.nodeName.toLowerCase()){o=g(a),(r=b.getAttribute("id"))?s=r.replace(ba,"\\$&"):b.setAttribute("id",s),s="[id='"+s+"'] ",l=o.length;while(l--)o[l]=s+ra(o[l]);w=aa.test(a)&&pa(b.parentNode)||b,x=o.join(",")}if(x)try{return H.apply(d,w.querySelectorAll(x)),d}catch(y){}finally{r||b.removeAttribute("id")}}}return i(a.replace(R,"$1"),b,d,e)}function ha(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function ia(a){return a[u]=!0,a}function ja(a){var b=n.createElement("div");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function ka(a,b){var c=a.split("|"),e=a.length;while(e--)d.attrHandle[c[e]]=b}function la(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&(~b.sourceIndex||C)-(~a.sourceIndex||C);if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function ma(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function na(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function oa(a){return ia(function(b){return b=+b,ia(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function pa(a){return a&&"undefined"!=typeof a.getElementsByTagName&&a}c=ga.support={},f=ga.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?"HTML"!==b.nodeName:!1},m=ga.setDocument=function(a){var b,e,g=a?a.ownerDocument||a:v;return g!==n&&9===g.nodeType&&g.documentElement?(n=g,o=g.documentElement,e=g.defaultView,e&&e!==e.top&&(e.addEventListener?e.addEventListener("unload",ea,!1):e.attachEvent&&e.attachEvent("onunload",ea)),p=!f(g),c.attributes=ja(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=ja(function(a){return a.appendChild(g.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=$.test(g.getElementsByClassName),c.getById=ja(function(a){return o.appendChild(a).id=u,!g.getElementsByName||!g.getElementsByName(u).length}),c.getById?(d.find.ID=function(a,b){if("undefined"!=typeof b.getElementById&&p){var c=b.getElementById(a);return c&&c.parentNode?[c]:[]}},d.filter.ID=function(a){var b=a.replace(ca,da);return function(a){return a.getAttribute("id")===b}}):(delete d.find.ID,d.filter.ID=function(a){var b=a.replace(ca,da);return function(a){var c="undefined"!=typeof a.getAttributeNode&&a.getAttributeNode("id");return c&&c.value===b}}),d.find.TAG=c.getElementsByTagName?function(a,b){return"undefined"!=typeof b.getElementsByTagName?b.getElementsByTagName(a):c.qsa?b.querySelectorAll(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){return p?b.getElementsByClassName(a):void 0},r=[],q=[],(c.qsa=$.test(g.querySelectorAll))&&(ja(function(a){o.appendChild(a).innerHTML="",a.querySelectorAll("[msallowcapture^='']").length&&q.push("[*^$]="+L+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||q.push("\\["+L+"*(?:value|"+K+")"),a.querySelectorAll("[id~="+u+"-]").length||q.push("~="),a.querySelectorAll(":checked").length||q.push(":checked"),a.querySelectorAll("a#"+u+"+*").length||q.push(".#.+[+~]")}),ja(function(a){var b=g.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&q.push("name"+L+"*[*^$|!~]?="),a.querySelectorAll(":enabled").length||q.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),q.push(",.*:")})),(c.matchesSelector=$.test(s=o.matches||o.webkitMatchesSelector||o.mozMatchesSelector||o.oMatchesSelector||o.msMatchesSelector))&&ja(function(a){c.disconnectedMatch=s.call(a,"div"),s.call(a,"[s!='']:x"),r.push("!=",P)}),q=q.length&&new RegExp(q.join("|")),r=r.length&&new RegExp(r.join("|")),b=$.test(o.compareDocumentPosition),t=b||$.test(o.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},B=b?function(a,b){if(a===b)return l=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===g||a.ownerDocument===v&&t(v,a)?-1:b===g||b.ownerDocument===v&&t(v,b)?1:k?J(k,a)-J(k,b):0:4&d?-1:1)}:function(a,b){if(a===b)return l=!0,0;var c,d=0,e=a.parentNode,f=b.parentNode,h=[a],i=[b];if(!e||!f)return a===g?-1:b===g?1:e?-1:f?1:k?J(k,a)-J(k,b):0;if(e===f)return la(a,b);c=a;while(c=c.parentNode)h.unshift(c);c=b;while(c=c.parentNode)i.unshift(c);while(h[d]===i[d])d++;return d?la(h[d],i[d]):h[d]===v?-1:i[d]===v?1:0},g):n},ga.matches=function(a,b){return ga(a,null,null,b)},ga.matchesSelector=function(a,b){if((a.ownerDocument||a)!==n&&m(a),b=b.replace(U,"='$1']"),!(!c.matchesSelector||!p||r&&r.test(b)||q&&q.test(b)))try{var d=s.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return ga(b,n,null,[a]).length>0},ga.contains=function(a,b){return(a.ownerDocument||a)!==n&&m(a),t(a,b)},ga.attr=function(a,b){(a.ownerDocument||a)!==n&&m(a);var e=d.attrHandle[b.toLowerCase()],f=e&&D.call(d.attrHandle,b.toLowerCase())?e(a,b,!p):void 0;return void 0!==f?f:c.attributes||!p?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},ga.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},ga.uniqueSort=function(a){var b,d=[],e=0,f=0;if(l=!c.detectDuplicates,k=!c.sortStable&&a.slice(0),a.sort(B),l){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return k=null,a},e=ga.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=ga.selectors={cacheLength:50,createPseudo:ia,match:X,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(ca,da),a[3]=(a[3]||a[4]||a[5]||"").replace(ca,da),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||ga.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&ga.error(a[0]),a},PSEUDO:function(a){var b,c=!a[6]&&a[2];return X.CHILD.test(a[0])?null:(a[3]?a[2]=a[4]||a[5]||"":c&&V.test(c)&&(b=g(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(ca,da).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=y[a+" "];return b||(b=new RegExp("(^|"+L+")"+a+"("+L+"|$)"))&&y(a,function(a){return b.test("string"==typeof a.className&&a.className||"undefined"!=typeof a.getAttribute&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=ga.attr(d,a);return null==e?"!="===b:b?(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e.replace(Q," ")+" ").indexOf(c)>-1:"|="===b?e===c||e.slice(0,c.length+1)===c+"-":!1):!0}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),s=!i&&!h;if(q){if(f){while(p){l=b;while(l=l[p])if(h?l.nodeName.toLowerCase()===r:1===l.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&s){k=q[u]||(q[u]={}),j=k[a]||[],n=j[0]===w&&j[1],m=j[0]===w&&j[2],l=n&&q.childNodes[n];while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if(1===l.nodeType&&++m&&l===b){k[a]=[w,n,m];break}}else if(s&&(j=(b[u]||(b[u]={}))[a])&&j[0]===w)m=j[1];else while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if((h?l.nodeName.toLowerCase()===r:1===l.nodeType)&&++m&&(s&&((l[u]||(l[u]={}))[a]=[w,m]),l===b))break;return m-=e,m===d||m%d===0&&m/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||ga.error("unsupported pseudo: "+a);return e[u]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?ia(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=J(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:ia(function(a){var b=[],c=[],d=h(a.replace(R,"$1"));return d[u]?ia(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),b[0]=null,!c.pop()}}),has:ia(function(a){return function(b){return ga(a,b).length>0}}),contains:ia(function(a){return a=a.replace(ca,da),function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:ia(function(a){return W.test(a||"")||ga.error("unsupported lang: "+a),a=a.replace(ca,da).toLowerCase(),function(b){var c;do if(c=p?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===o},focus:function(a){return a===n.activeElement&&(!n.hasFocus||n.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return Z.test(a.nodeName)},input:function(a){return Y.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:oa(function(){return[0]}),last:oa(function(a,b){return[b-1]}),eq:oa(function(a,b,c){return[0>c?c+b:c]}),even:oa(function(a,b){for(var c=0;b>c;c+=2)a.push(c);return a}),odd:oa(function(a,b){for(var c=1;b>c;c+=2)a.push(c);return a}),lt:oa(function(a,b,c){for(var d=0>c?c+b:c;--d>=0;)a.push(d);return a}),gt:oa(function(a,b,c){for(var d=0>c?c+b:c;++db;b++)d+=a[b].value;return d}function sa(a,b,c){var d=b.dir,e=c&&"parentNode"===d,f=x++;return b.first?function(b,c,f){while(b=b[d])if(1===b.nodeType||e)return a(b,c,f)}:function(b,c,g){var h,i,j=[w,f];if(g){while(b=b[d])if((1===b.nodeType||e)&&a(b,c,g))return!0}else while(b=b[d])if(1===b.nodeType||e){if(i=b[u]||(b[u]={}),(h=i[d])&&h[0]===w&&h[1]===f)return j[2]=h[2];if(i[d]=j,j[2]=a(b,c,g))return!0}}}function ta(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function ua(a,b,c){for(var d=0,e=b.length;e>d;d++)ga(a,b[d],c);return c}function va(a,b,c,d,e){for(var f,g=[],h=0,i=a.length,j=null!=b;i>h;h++)(f=a[h])&&(!c||c(f,d,e))&&(g.push(f),j&&b.push(h));return g}function wa(a,b,c,d,e,f){return d&&!d[u]&&(d=wa(d)),e&&!e[u]&&(e=wa(e,f)),ia(function(f,g,h,i){var j,k,l,m=[],n=[],o=g.length,p=f||ua(b||"*",h.nodeType?[h]:h,[]),q=!a||!f&&b?p:va(p,m,a,h,i),r=c?e||(f?a:o||d)?[]:g:q;if(c&&c(q,r,h,i),d){j=va(r,n),d(j,[],h,i),k=j.length;while(k--)(l=j[k])&&(r[n[k]]=!(q[n[k]]=l))}if(f){if(e||a){if(e){j=[],k=r.length;while(k--)(l=r[k])&&j.push(q[k]=l);e(null,r=[],j,i)}k=r.length;while(k--)(l=r[k])&&(j=e?J(f,l):m[k])>-1&&(f[j]=!(g[j]=l))}}else r=va(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):H.apply(g,r)})}function xa(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],h=g||d.relative[" "],i=g?1:0,k=sa(function(a){return a===b},h,!0),l=sa(function(a){return J(b,a)>-1},h,!0),m=[function(a,c,d){var e=!g&&(d||c!==j)||((b=c).nodeType?k(a,c,d):l(a,c,d));return b=null,e}];f>i;i++)if(c=d.relative[a[i].type])m=[sa(ta(m),c)];else{if(c=d.filter[a[i].type].apply(null,a[i].matches),c[u]){for(e=++i;f>e;e++)if(d.relative[a[e].type])break;return wa(i>1&&ta(m),i>1&&ra(a.slice(0,i-1).concat({value:" "===a[i-2].type?"*":""})).replace(R,"$1"),c,e>i&&xa(a.slice(i,e)),f>e&&xa(a=a.slice(e)),f>e&&ra(a))}m.push(c)}return ta(m)}function ya(a,b){var c=b.length>0,e=a.length>0,f=function(f,g,h,i,k){var l,m,o,p=0,q="0",r=f&&[],s=[],t=j,u=f||e&&d.find.TAG("*",k),v=w+=null==t?1:Math.random()||.1,x=u.length;for(k&&(j=g!==n&&g);q!==x&&null!=(l=u[q]);q++){if(e&&l){m=0;while(o=a[m++])if(o(l,g,h)){i.push(l);break}k&&(w=v)}c&&((l=!o&&l)&&p--,f&&r.push(l))}if(p+=q,c&&q!==p){m=0;while(o=b[m++])o(r,s,g,h);if(f){if(p>0)while(q--)r[q]||s[q]||(s[q]=F.call(i));s=va(s)}H.apply(i,s),k&&!f&&s.length>0&&p+b.length>1&&ga.uniqueSort(i)}return k&&(w=v,j=t),r};return c?ia(f):f}return h=ga.compile=function(a,b){var c,d=[],e=[],f=A[a+" "];if(!f){b||(b=g(a)),c=b.length;while(c--)f=xa(b[c]),f[u]?d.push(f):e.push(f);f=A(a,ya(e,d)),f.selector=a}return f},i=ga.select=function(a,b,e,f){var i,j,k,l,m,n="function"==typeof a&&a,o=!f&&g(a=n.selector||a);if(e=e||[],1===o.length){if(j=o[0]=o[0].slice(0),j.length>2&&"ID"===(k=j[0]).type&&c.getById&&9===b.nodeType&&p&&d.relative[j[1].type]){if(b=(d.find.ID(k.matches[0].replace(ca,da),b)||[])[0],!b)return e;n&&(b=b.parentNode),a=a.slice(j.shift().value.length)}i=X.needsContext.test(a)?0:j.length;while(i--){if(k=j[i],d.relative[l=k.type])break;if((m=d.find[l])&&(f=m(k.matches[0].replace(ca,da),aa.test(j[0].type)&&pa(b.parentNode)||b))){if(j.splice(i,1),a=f.length&&ra(j),!a)return H.apply(e,f),e;break}}}return(n||h(a,o))(f,b,!p,e,aa.test(a)&&pa(b.parentNode)||b),e},c.sortStable=u.split("").sort(B).join("")===u,c.detectDuplicates=!!l,m(),c.sortDetached=ja(function(a){return 1&a.compareDocumentPosition(n.createElement("div"))}),ja(function(a){return a.innerHTML="","#"===a.firstChild.getAttribute("href")})||ka("type|href|height|width",function(a,b,c){return c?void 0:a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&ja(function(a){return a.innerHTML="",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||ka("value",function(a,b,c){return c||"input"!==a.nodeName.toLowerCase()?void 0:a.defaultValue}),ja(function(a){return null==a.getAttribute("disabled")})||ka(K,function(a,b,c){var d;return c?void 0:a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),ga}(a);n.find=t,n.expr=t.selectors,n.expr[":"]=n.expr.pseudos,n.unique=t.uniqueSort,n.text=t.getText,n.isXMLDoc=t.isXML,n.contains=t.contains;var u=n.expr.match.needsContext,v=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,w=/^.[^:#\[\.,]*$/;function x(a,b,c){if(n.isFunction(b))return n.grep(a,function(a,d){return!!b.call(a,d,a)!==c});if(b.nodeType)return n.grep(a,function(a){return a===b!==c});if("string"==typeof b){if(w.test(b))return n.filter(b,a,c);b=n.filter(b,a)}return n.grep(a,function(a){return g.call(b,a)>=0!==c})}n.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?n.find.matchesSelector(d,a)?[d]:[]:n.find.matches(a,n.grep(b,function(a){return 1===a.nodeType}))},n.fn.extend({find:function(a){var b,c=this.length,d=[],e=this;if("string"!=typeof a)return this.pushStack(n(a).filter(function(){for(b=0;c>b;b++)if(n.contains(e[b],this))return!0}));for(b=0;c>b;b++)n.find(a,e[b],d);return d=this.pushStack(c>1?n.unique(d):d),d.selector=this.selector?this.selector+" "+a:a,d},filter:function(a){return this.pushStack(x(this,a||[],!1))},not:function(a){return this.pushStack(x(this,a||[],!0))},is:function(a){return!!x(this,"string"==typeof a&&u.test(a)?n(a):a||[],!1).length}});var y,z=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,A=n.fn.init=function(a,b){var c,d;if(!a)return this;if("string"==typeof a){if(c="<"===a[0]&&">"===a[a.length-1]&&a.length>=3?[null,a,null]:z.exec(a),!c||!c[1]&&b)return!b||b.jquery?(b||y).find(a):this.constructor(b).find(a);if(c[1]){if(b=b instanceof n?b[0]:b,n.merge(this,n.parseHTML(c[1],b&&b.nodeType?b.ownerDocument||b:l,!0)),v.test(c[1])&&n.isPlainObject(b))for(c in b)n.isFunction(this[c])?this[c](b[c]):this.attr(c,b[c]);return this}return d=l.getElementById(c[2]),d&&d.parentNode&&(this.length=1,this[0]=d),this.context=l,this.selector=a,this}return a.nodeType?(this.context=this[0]=a,this.length=1,this):n.isFunction(a)?"undefined"!=typeof y.ready?y.ready(a):a(n):(void 0!==a.selector&&(this.selector=a.selector,this.context=a.context),n.makeArray(a,this))};A.prototype=n.fn,y=n(l);var B=/^(?:parents|prev(?:Until|All))/,C={children:!0,contents:!0,next:!0,prev:!0};n.extend({dir:function(a,b,c){var d=[],e=void 0!==c;while((a=a[b])&&9!==a.nodeType)if(1===a.nodeType){if(e&&n(a).is(c))break;d.push(a)}return d},sibling:function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c}}),n.fn.extend({has:function(a){var b=n(a,this),c=b.length;return this.filter(function(){for(var a=0;c>a;a++)if(n.contains(this,b[a]))return!0})},closest:function(a,b){for(var c,d=0,e=this.length,f=[],g=u.test(a)||"string"!=typeof a?n(a,b||this.context):0;e>d;d++)for(c=this[d];c&&c!==b;c=c.parentNode)if(c.nodeType<11&&(g?g.index(c)>-1:1===c.nodeType&&n.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?n.unique(f):f)},index:function(a){return a?"string"==typeof a?g.call(n(a),this[0]):g.call(this,a.jquery?a[0]:a):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(n.unique(n.merge(this.get(),n(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function D(a,b){while((a=a[b])&&1!==a.nodeType);return a}n.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return n.dir(a,"parentNode")},parentsUntil:function(a,b,c){return n.dir(a,"parentNode",c)},next:function(a){return D(a,"nextSibling")},prev:function(a){return D(a,"previousSibling")},nextAll:function(a){return n.dir(a,"nextSibling")},prevAll:function(a){return n.dir(a,"previousSibling")},nextUntil:function(a,b,c){return n.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return n.dir(a,"previousSibling",c)},siblings:function(a){return n.sibling((a.parentNode||{}).firstChild,a)},children:function(a){return n.sibling(a.firstChild)},contents:function(a){return a.contentDocument||n.merge([],a.childNodes)}},function(a,b){n.fn[a]=function(c,d){var e=n.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=n.filter(d,e)),this.length>1&&(C[a]||n.unique(e),B.test(a)&&e.reverse()),this.pushStack(e)}});var E=/\S+/g,F={};function G(a){var b=F[a]={};return n.each(a.match(E)||[],function(a,c){b[c]=!0}),b}n.Callbacks=function(a){a="string"==typeof a?F[a]||G(a):n.extend({},a);var b,c,d,e,f,g,h=[],i=!a.once&&[],j=function(l){for(b=a.memory&&l,c=!0,g=e||0,e=0,f=h.length,d=!0;h&&f>g;g++)if(h[g].apply(l[0],l[1])===!1&&a.stopOnFalse){b=!1;break}d=!1,h&&(i?i.length&&j(i.shift()):b?h=[]:k.disable())},k={add:function(){if(h){var c=h.length;!function g(b){n.each(b,function(b,c){var d=n.type(c);"function"===d?a.unique&&k.has(c)||h.push(c):c&&c.length&&"string"!==d&&g(c)})}(arguments),d?f=h.length:b&&(e=c,j(b))}return this},remove:function(){return h&&n.each(arguments,function(a,b){var c;while((c=n.inArray(b,h,c))>-1)h.splice(c,1),d&&(f>=c&&f--,g>=c&&g--)}),this},has:function(a){return a?n.inArray(a,h)>-1:!(!h||!h.length)},empty:function(){return h=[],f=0,this},disable:function(){return h=i=b=void 0,this},disabled:function(){return!h},lock:function(){return i=void 0,b||k.disable(),this},locked:function(){return!i},fireWith:function(a,b){return!h||c&&!i||(b=b||[],b=[a,b.slice?b.slice():b],d?i.push(b):j(b)),this},fire:function(){return k.fireWith(this,arguments),this},fired:function(){return!!c}};return k},n.extend({Deferred:function(a){var b=[["resolve","done",n.Callbacks("once memory"),"resolved"],["reject","fail",n.Callbacks("once memory"),"rejected"],["notify","progress",n.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return n.Deferred(function(c){n.each(b,function(b,f){var g=n.isFunction(a[b])&&a[b];e[f[1]](function(){var a=g&&g.apply(this,arguments);a&&n.isFunction(a.promise)?a.promise().done(c.resolve).fail(c.reject).progress(c.notify):c[f[0]+"With"](this===d?c.promise():this,g?[a]:arguments)})}),a=null}).promise()},promise:function(a){return null!=a?n.extend(a,d):d}},e={};return d.pipe=d.then,n.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[1^a][2].disable,b[2][2].lock),e[f[0]]=function(){return e[f[0]+"With"](this===e?d:this,arguments),this},e[f[0]+"With"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b=0,c=d.call(arguments),e=c.length,f=1!==e||a&&n.isFunction(a.promise)?e:0,g=1===f?a:n.Deferred(),h=function(a,b,c){return function(e){b[a]=this,c[a]=arguments.length>1?d.call(arguments):e,c===i?g.notifyWith(b,c):--f||g.resolveWith(b,c)}},i,j,k;if(e>1)for(i=new Array(e),j=new Array(e),k=new Array(e);e>b;b++)c[b]&&n.isFunction(c[b].promise)?c[b].promise().done(h(b,k,c)).fail(g.reject).progress(h(b,j,i)):--f;return f||g.resolveWith(k,c),g.promise()}});var H;n.fn.ready=function(a){return n.ready.promise().done(a),this},n.extend({isReady:!1,readyWait:1,holdReady:function(a){a?n.readyWait++:n.ready(!0)},ready:function(a){(a===!0?--n.readyWait:n.isReady)||(n.isReady=!0,a!==!0&&--n.readyWait>0||(H.resolveWith(l,[n]),n.fn.triggerHandler&&(n(l).triggerHandler("ready"),n(l).off("ready"))))}});function I(){l.removeEventListener("DOMContentLoaded",I,!1),a.removeEventListener("load",I,!1),n.ready()}n.ready.promise=function(b){return H||(H=n.Deferred(),"complete"===l.readyState?setTimeout(n.ready):(l.addEventListener("DOMContentLoaded",I,!1),a.addEventListener("load",I,!1))),H.promise(b)},n.ready.promise();var J=n.access=function(a,b,c,d,e,f,g){var h=0,i=a.length,j=null==c;if("object"===n.type(c)){e=!0;for(h in c)n.access(a,b,h,c[h],!0,f,g)}else if(void 0!==d&&(e=!0,n.isFunction(d)||(g=!0),j&&(g?(b.call(a,d),b=null):(j=b,b=function(a,b,c){return j.call(n(a),c)})),b))for(;i>h;h++)b(a[h],c,g?d:d.call(a[h],h,b(a[h],c)));return e?a:j?b.call(a):i?b(a[0],c):f};n.acceptData=function(a){return 1===a.nodeType||9===a.nodeType||!+a.nodeType};function K(){Object.defineProperty(this.cache={},0,{get:function(){return{}}}),this.expando=n.expando+K.uid++}K.uid=1,K.accepts=n.acceptData,K.prototype={key:function(a){if(!K.accepts(a))return 0;var b={},c=a[this.expando];if(!c){c=K.uid++;try{b[this.expando]={value:c},Object.defineProperties(a,b)}catch(d){b[this.expando]=c,n.extend(a,b)}}return this.cache[c]||(this.cache[c]={}),c},set:function(a,b,c){var d,e=this.key(a),f=this.cache[e];if("string"==typeof b)f[b]=c;else if(n.isEmptyObject(f))n.extend(this.cache[e],b);else for(d in b)f[d]=b[d];return f},get:function(a,b){var c=this.cache[this.key(a)];return void 0===b?c:c[b]},access:function(a,b,c){var d;return void 0===b||b&&"string"==typeof b&&void 0===c?(d=this.get(a,b),void 0!==d?d:this.get(a,n.camelCase(b))):(this.set(a,b,c),void 0!==c?c:b)},remove:function(a,b){var c,d,e,f=this.key(a),g=this.cache[f];if(void 0===b)this.cache[f]={};else{n.isArray(b)?d=b.concat(b.map(n.camelCase)):(e=n.camelCase(b),b in g?d=[b,e]:(d=e,d=d in g?[d]:d.match(E)||[])),c=d.length;while(c--)delete g[d[c]]}},hasData:function(a){return!n.isEmptyObject(this.cache[a[this.expando]]||{})},discard:function(a){a[this.expando]&&delete this.cache[a[this.expando]]}};var L=new K,M=new K,N=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,O=/([A-Z])/g;function P(a,b,c){var d;if(void 0===c&&1===a.nodeType)if(d="data-"+b.replace(O,"-$1").toLowerCase(),c=a.getAttribute(d),"string"==typeof c){try{c="true"===c?!0:"false"===c?!1:"null"===c?null:+c+""===c?+c:N.test(c)?n.parseJSON(c):c}catch(e){}M.set(a,b,c)}else c=void 0;return c}n.extend({hasData:function(a){return M.hasData(a)||L.hasData(a)},data:function(a,b,c){ +return M.access(a,b,c)},removeData:function(a,b){M.remove(a,b)},_data:function(a,b,c){return L.access(a,b,c)},_removeData:function(a,b){L.remove(a,b)}}),n.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=M.get(f),1===f.nodeType&&!L.get(f,"hasDataAttrs"))){c=g.length;while(c--)g[c]&&(d=g[c].name,0===d.indexOf("data-")&&(d=n.camelCase(d.slice(5)),P(f,d,e[d])));L.set(f,"hasDataAttrs",!0)}return e}return"object"==typeof a?this.each(function(){M.set(this,a)}):J(this,function(b){var c,d=n.camelCase(a);if(f&&void 0===b){if(c=M.get(f,a),void 0!==c)return c;if(c=M.get(f,d),void 0!==c)return c;if(c=P(f,d,void 0),void 0!==c)return c}else this.each(function(){var c=M.get(this,d);M.set(this,d,b),-1!==a.indexOf("-")&&void 0!==c&&M.set(this,a,b)})},null,b,arguments.length>1,null,!0)},removeData:function(a){return this.each(function(){M.remove(this,a)})}}),n.extend({queue:function(a,b,c){var d;return a?(b=(b||"fx")+"queue",d=L.get(a,b),c&&(!d||n.isArray(c)?d=L.access(a,b,n.makeArray(c)):d.push(c)),d||[]):void 0},dequeue:function(a,b){b=b||"fx";var c=n.queue(a,b),d=c.length,e=c.shift(),f=n._queueHooks(a,b),g=function(){n.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return L.get(a,c)||L.access(a,c,{empty:n.Callbacks("once memory").add(function(){L.remove(a,[b+"queue",c])})})}}),n.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.lengthx",k.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue}();var U="undefined";k.focusinBubbles="onfocusin"in a;var V=/^key/,W=/^(?:mouse|pointer|contextmenu)|click/,X=/^(?:focusinfocus|focusoutblur)$/,Y=/^([^.]*)(?:\.(.+)|)$/;function Z(){return!0}function $(){return!1}function _(){try{return l.activeElement}catch(a){}}n.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=L.get(a);if(r){c.handler&&(f=c,c=f.handler,e=f.selector),c.guid||(c.guid=n.guid++),(i=r.events)||(i=r.events={}),(g=r.handle)||(g=r.handle=function(b){return typeof n!==U&&n.event.triggered!==b.type?n.event.dispatch.apply(a,arguments):void 0}),b=(b||"").match(E)||[""],j=b.length;while(j--)h=Y.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o&&(l=n.event.special[o]||{},o=(e?l.delegateType:l.bindType)||o,l=n.event.special[o]||{},k=n.extend({type:o,origType:q,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&n.expr.match.needsContext.test(e),namespace:p.join(".")},f),(m=i[o])||(m=i[o]=[],m.delegateCount=0,l.setup&&l.setup.call(a,d,p,g)!==!1||a.addEventListener&&a.addEventListener(o,g,!1)),l.add&&(l.add.call(a,k),k.handler.guid||(k.handler.guid=c.guid)),e?m.splice(m.delegateCount++,0,k):m.push(k),n.event.global[o]=!0)}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=L.hasData(a)&&L.get(a);if(r&&(i=r.events)){b=(b||"").match(E)||[""],j=b.length;while(j--)if(h=Y.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o){l=n.event.special[o]||{},o=(d?l.delegateType:l.bindType)||o,m=i[o]||[],h=h[2]&&new RegExp("(^|\\.)"+p.join("\\.(?:.*\\.|)")+"(\\.|$)"),g=f=m.length;while(f--)k=m[f],!e&&q!==k.origType||c&&c.guid!==k.guid||h&&!h.test(k.namespace)||d&&d!==k.selector&&("**"!==d||!k.selector)||(m.splice(f,1),k.selector&&m.delegateCount--,l.remove&&l.remove.call(a,k));g&&!m.length&&(l.teardown&&l.teardown.call(a,p,r.handle)!==!1||n.removeEvent(a,o,r.handle),delete i[o])}else for(o in i)n.event.remove(a,o+b[j],c,d,!0);n.isEmptyObject(i)&&(delete r.handle,L.remove(a,"events"))}},trigger:function(b,c,d,e){var f,g,h,i,k,m,o,p=[d||l],q=j.call(b,"type")?b.type:b,r=j.call(b,"namespace")?b.namespace.split("."):[];if(g=h=d=d||l,3!==d.nodeType&&8!==d.nodeType&&!X.test(q+n.event.triggered)&&(q.indexOf(".")>=0&&(r=q.split("."),q=r.shift(),r.sort()),k=q.indexOf(":")<0&&"on"+q,b=b[n.expando]?b:new n.Event(q,"object"==typeof b&&b),b.isTrigger=e?2:3,b.namespace=r.join("."),b.namespace_re=b.namespace?new RegExp("(^|\\.)"+r.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,b.result=void 0,b.target||(b.target=d),c=null==c?[b]:n.makeArray(c,[b]),o=n.event.special[q]||{},e||!o.trigger||o.trigger.apply(d,c)!==!1)){if(!e&&!o.noBubble&&!n.isWindow(d)){for(i=o.delegateType||q,X.test(i+q)||(g=g.parentNode);g;g=g.parentNode)p.push(g),h=g;h===(d.ownerDocument||l)&&p.push(h.defaultView||h.parentWindow||a)}f=0;while((g=p[f++])&&!b.isPropagationStopped())b.type=f>1?i:o.bindType||q,m=(L.get(g,"events")||{})[b.type]&&L.get(g,"handle"),m&&m.apply(g,c),m=k&&g[k],m&&m.apply&&n.acceptData(g)&&(b.result=m.apply(g,c),b.result===!1&&b.preventDefault());return b.type=q,e||b.isDefaultPrevented()||o._default&&o._default.apply(p.pop(),c)!==!1||!n.acceptData(d)||k&&n.isFunction(d[q])&&!n.isWindow(d)&&(h=d[k],h&&(d[k]=null),n.event.triggered=q,d[q](),n.event.triggered=void 0,h&&(d[k]=h)),b.result}},dispatch:function(a){a=n.event.fix(a);var b,c,e,f,g,h=[],i=d.call(arguments),j=(L.get(this,"events")||{})[a.type]||[],k=n.event.special[a.type]||{};if(i[0]=a,a.delegateTarget=this,!k.preDispatch||k.preDispatch.call(this,a)!==!1){h=n.event.handlers.call(this,a,j),b=0;while((f=h[b++])&&!a.isPropagationStopped()){a.currentTarget=f.elem,c=0;while((g=f.handlers[c++])&&!a.isImmediatePropagationStopped())(!a.namespace_re||a.namespace_re.test(g.namespace))&&(a.handleObj=g,a.data=g.data,e=((n.event.special[g.origType]||{}).handle||g.handler).apply(f.elem,i),void 0!==e&&(a.result=e)===!1&&(a.preventDefault(),a.stopPropagation()))}return k.postDispatch&&k.postDispatch.call(this,a),a.result}},handlers:function(a,b){var c,d,e,f,g=[],h=b.delegateCount,i=a.target;if(h&&i.nodeType&&(!a.button||"click"!==a.type))for(;i!==this;i=i.parentNode||this)if(i.disabled!==!0||"click"!==a.type){for(d=[],c=0;h>c;c++)f=b[c],e=f.selector+" ",void 0===d[e]&&(d[e]=f.needsContext?n(e,this).index(i)>=0:n.find(e,this,null,[i]).length),d[e]&&d.push(f);d.length&&g.push({elem:i,handlers:d})}return h]*)\/>/gi,ba=/<([\w:]+)/,ca=/<|&#?\w+;/,da=/<(?:script|style|link)/i,ea=/checked\s*(?:[^=]|=\s*.checked.)/i,fa=/^$|\/(?:java|ecma)script/i,ga=/^true\/(.*)/,ha=/^\s*\s*$/g,ia={option:[1,""],thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};ia.optgroup=ia.option,ia.tbody=ia.tfoot=ia.colgroup=ia.caption=ia.thead,ia.th=ia.td;function ja(a,b){return n.nodeName(a,"table")&&n.nodeName(11!==b.nodeType?b:b.firstChild,"tr")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function ka(a){return a.type=(null!==a.getAttribute("type"))+"/"+a.type,a}function la(a){var b=ga.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function ma(a,b){for(var c=0,d=a.length;d>c;c++)L.set(a[c],"globalEval",!b||L.get(b[c],"globalEval"))}function na(a,b){var c,d,e,f,g,h,i,j;if(1===b.nodeType){if(L.hasData(a)&&(f=L.access(a),g=L.set(b,f),j=f.events)){delete g.handle,g.events={};for(e in j)for(c=0,d=j[e].length;d>c;c++)n.event.add(b,e,j[e][c])}M.hasData(a)&&(h=M.access(a),i=n.extend({},h),M.set(b,i))}}function oa(a,b){var c=a.getElementsByTagName?a.getElementsByTagName(b||"*"):a.querySelectorAll?a.querySelectorAll(b||"*"):[];return void 0===b||b&&n.nodeName(a,b)?n.merge([a],c):c}function pa(a,b){var c=b.nodeName.toLowerCase();"input"===c&&T.test(a.type)?b.checked=a.checked:("input"===c||"textarea"===c)&&(b.defaultValue=a.defaultValue)}n.extend({clone:function(a,b,c){var d,e,f,g,h=a.cloneNode(!0),i=n.contains(a.ownerDocument,a);if(!(k.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||n.isXMLDoc(a)))for(g=oa(h),f=oa(a),d=0,e=f.length;e>d;d++)pa(f[d],g[d]);if(b)if(c)for(f=f||oa(a),g=g||oa(h),d=0,e=f.length;e>d;d++)na(f[d],g[d]);else na(a,h);return g=oa(h,"script"),g.length>0&&ma(g,!i&&oa(a,"script")),h},buildFragment:function(a,b,c,d){for(var e,f,g,h,i,j,k=b.createDocumentFragment(),l=[],m=0,o=a.length;o>m;m++)if(e=a[m],e||0===e)if("object"===n.type(e))n.merge(l,e.nodeType?[e]:e);else if(ca.test(e)){f=f||k.appendChild(b.createElement("div")),g=(ba.exec(e)||["",""])[1].toLowerCase(),h=ia[g]||ia._default,f.innerHTML=h[1]+e.replace(aa,"<$1>")+h[2],j=h[0];while(j--)f=f.lastChild;n.merge(l,f.childNodes),f=k.firstChild,f.textContent=""}else l.push(b.createTextNode(e));k.textContent="",m=0;while(e=l[m++])if((!d||-1===n.inArray(e,d))&&(i=n.contains(e.ownerDocument,e),f=oa(k.appendChild(e),"script"),i&&ma(f),c)){j=0;while(e=f[j++])fa.test(e.type||"")&&c.push(e)}return k},cleanData:function(a){for(var b,c,d,e,f=n.event.special,g=0;void 0!==(c=a[g]);g++){if(n.acceptData(c)&&(e=c[L.expando],e&&(b=L.cache[e]))){if(b.events)for(d in b.events)f[d]?n.event.remove(c,d):n.removeEvent(c,d,b.handle);L.cache[e]&&delete L.cache[e]}delete M.cache[c[M.expando]]}}}),n.fn.extend({text:function(a){return J(this,function(a){return void 0===a?n.text(this):this.empty().each(function(){(1===this.nodeType||11===this.nodeType||9===this.nodeType)&&(this.textContent=a)})},null,a,arguments.length)},append:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=ja(this,a);b.appendChild(a)}})},prepend:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=ja(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},remove:function(a,b){for(var c,d=a?n.filter(a,this):this,e=0;null!=(c=d[e]);e++)b||1!==c.nodeType||n.cleanData(oa(c)),c.parentNode&&(b&&n.contains(c.ownerDocument,c)&&ma(oa(c,"script")),c.parentNode.removeChild(c));return this},empty:function(){for(var a,b=0;null!=(a=this[b]);b++)1===a.nodeType&&(n.cleanData(oa(a,!1)),a.textContent="");return this},clone:function(a,b){return a=null==a?!1:a,b=null==b?a:b,this.map(function(){return n.clone(this,a,b)})},html:function(a){return J(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a&&1===b.nodeType)return b.innerHTML;if("string"==typeof a&&!da.test(a)&&!ia[(ba.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(aa,"<$1>");try{for(;d>c;c++)b=this[c]||{},1===b.nodeType&&(n.cleanData(oa(b,!1)),b.innerHTML=a);b=0}catch(e){}}b&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(){var a=arguments[0];return this.domManip(arguments,function(b){a=this.parentNode,n.cleanData(oa(this)),a&&a.replaceChild(b,this)}),a&&(a.length||a.nodeType)?this:this.remove()},detach:function(a){return this.remove(a,!0)},domManip:function(a,b){a=e.apply([],a);var c,d,f,g,h,i,j=0,l=this.length,m=this,o=l-1,p=a[0],q=n.isFunction(p);if(q||l>1&&"string"==typeof p&&!k.checkClone&&ea.test(p))return this.each(function(c){var d=m.eq(c);q&&(a[0]=p.call(this,c,d.html())),d.domManip(a,b)});if(l&&(c=n.buildFragment(a,this[0].ownerDocument,!1,this),d=c.firstChild,1===c.childNodes.length&&(c=d),d)){for(f=n.map(oa(c,"script"),ka),g=f.length;l>j;j++)h=c,j!==o&&(h=n.clone(h,!0,!0),g&&n.merge(f,oa(h,"script"))),b.call(this[j],h,j);if(g)for(i=f[f.length-1].ownerDocument,n.map(f,la),j=0;g>j;j++)h=f[j],fa.test(h.type||"")&&!L.access(h,"globalEval")&&n.contains(i,h)&&(h.src?n._evalUrl&&n._evalUrl(h.src):n.globalEval(h.textContent.replace(ha,"")))}return this}}),n.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){n.fn[a]=function(a){for(var c,d=[],e=n(a),g=e.length-1,h=0;g>=h;h++)c=h===g?this:this.clone(!0),n(e[h])[b](c),f.apply(d,c.get());return this.pushStack(d)}});var qa,ra={};function sa(b,c){var d,e=n(c.createElement(b)).appendTo(c.body),f=a.getDefaultComputedStyle&&(d=a.getDefaultComputedStyle(e[0]))?d.display:n.css(e[0],"display");return e.detach(),f}function ta(a){var b=l,c=ra[a];return c||(c=sa(a,b),"none"!==c&&c||(qa=(qa||n("