diff --git a/Build.bat b/Build.bat
index 7f9b4c60c443f5e9922556a5b6beae9a071e64a8..ffd86e39cd8f0405f1f77589d4155be42b5b036c 100644
--- a/Build.bat
+++ b/Build.bat
@@ -6,7 +6,7 @@ cd src
 Msbuild Jackett.sln /t:Clean,Build /p:Configuration=Release /verbosity:minimal
 cd ..
 
-xcopy src\Jackett.Console\bin\Release Build.windows\  /e /y
+xcopy src\Jackett.Console\bin\Release build.windows\  /e /y
 copy /Y src\Jackett.Service\bin\Release\JackettService.exe build.windows\JackettService.exe
 copy /Y src\Jackett.Service\bin\Release\JackettService.exe.config build.windows\JackettService.exe.config
 copy /Y src\Jackett.Tray\bin\Release\JackettTray.exe build.windows\JackettTray.exe
@@ -20,7 +20,7 @@ Msbuild Jackett.sln /t:Clean
 call "C:\Program Files (x86)\Mono\bin\xbuild.bat"  Jackett.sln /t:Build /p:Configuration=Release /verbosity:minimal
 cd ..
 
-xcopy src\Jackett.Console\bin\Release Build.mono\  /e /y
+xcopy src\Jackett.Console\bin\Release build.mono\  /e /y
 copy /Y src\Jackett.Service\bin\Release\JackettService.exe build.mono\JackettService.exe
 copy /Y src\Jackett.Service\bin\Release\JackettService.exe.config build.mono\JackettService.exe.config
 copy /Y src\Jackett.Tray\bin\Release\JackettTray.exe build.mono\JackettTray.exe
diff --git a/Installer.iss b/Installer.iss
index 9a3dc63868f8ea067d7b4f8f1a35922957e82dd3..f5b51eb7dd6e19f91956aa8b42c55579a43bd199 100644
--- a/Installer.iss
+++ b/Installer.iss
@@ -2,7 +2,7 @@
 ; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!
 
 #define MyAppName "Jackett"
-#define MyAppVersion "0.5"
+#define MyAppVersion GetFileVersion("build.windows/Jackett.dll")
 #define MyAppPublisher "Jackett  Inc."
 #define MyAppURL "https://github.com/zone117x/Jackett"
 #define MyAppExeName "JackettTray.exe"
@@ -36,8 +36,8 @@ Name: "windowsService"; Description: "Install as a Windows Service"
 Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked
 
 [Files]
-Source: "Build.windows\JackettTray.exe"; DestDir: "{app}"; Flags: ignoreversion
-Source: "Build.windows\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs
+Source: "build.windows\JackettTray.exe"; DestDir: "{app}"; Flags: ignoreversion
+Source: "build.windows\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs
 ; NOTE: Don't use "Flags: ignoreversion" on any shared system files
 
 [Icons]
diff --git a/README.md b/README.md
index 7470729cabee1798e6484638630e6612fba362ec..ae49055d287ee8ee620168808c7c7feb5e2ebefa 100644
--- a/README.md
+++ b/README.md
@@ -23,6 +23,7 @@ Download in the [Releases page](https://github.com/zone117x/Jackett/releases)
  * [BeyondHD](https://beyondhd.me/)
  * [BIT-HDTV](https://www.bit-hdtv.com)
  * [BitMeTV](http://www.bitmetv.org/)
+ * [Demonoid](http://www.demonoid.pw/)
  * [FrenchTorrentDb](http://www.frenchtorrentdb.com/)
  * [Freshon](https://freshon.tv/)
  * [HD-Space](https://hd-space.org/)
@@ -32,6 +33,7 @@ Download in the [Releases page](https://github.com/zone117x/Jackett/releases)
  * [MoreThan.tv](https://morethan.tv/)
  * [pretome](https://pretome.info)
  * [PrivateHD](https://privatehd.to/)
+ * [RuTor](http://rutor.org/)
  * [SceneAccess](https://sceneaccess.eu/login)
  * [SceneTime](https://www.scenetime.com/)
  * [ShowRSS](https://showrss.info/)
@@ -89,4 +91,4 @@ Use the github issues pages or talk to us directly at: [irc.freenode.net#jackett
 
 ### Screenshots
 
-![screenshot](http://i.imgur.com/t1sVva6.png "screenshot")
\ No newline at end of file
+![screenshot](http://i.imgur.com/t1sVva6.png "screenshot")
diff --git a/src/CurlSharp/CurlSharp.csproj b/src/CurlSharp/CurlSharp.csproj
index de7a139ac4d131c3e8dc09602baf044d1ab94d99..a5676d902c236d946d2bbdf689f29d7030bcec30 100644
--- a/src/CurlSharp/CurlSharp.csproj
+++ b/src/CurlSharp/CurlSharp.csproj
@@ -18,7 +18,7 @@
     <DebugType>full</DebugType>
     <Optimize>false</Optimize>
     <OutputPath>bin\Debug</OutputPath>
-    <DefineConstants>DEBUG;LINUX</DefineConstants>
+    <DefineConstants>DEBUG</DefineConstants>
     <WarningLevel>4</WarningLevel>
     <ConsolePause>false</ConsolePause>
     <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
@@ -31,7 +31,8 @@
     <WarningLevel>4</WarningLevel>
     <ConsolePause>false</ConsolePause>
     <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
-    <DefineConstants>LINUX</DefineConstants>
+    <DefineConstants>
+    </DefineConstants>
     <Prefer32Bit>false</Prefer32Bit>
   </PropertyGroup>
   <ItemGroup>
diff --git a/src/Jackett.Console/ConsoleOptions.cs b/src/Jackett.Console/ConsoleOptions.cs
index cefa8d94fedd177a804bedd7474534ce4b3070da..8ad9bd000df464b479e8cf7d81b83d05048ab75b 100644
--- a/src/Jackett.Console/ConsoleOptions.cs
+++ b/src/Jackett.Console/ConsoleOptions.cs
@@ -33,8 +33,11 @@ namespace Jackett.Console
         [Option('k', "Stop", HelpText = "Stop the Jacket Windows service (Must be admin)")]
         public bool StopService { get; set; }
 
-        [Option('x', "ListenPublic", HelpText = "Listen publicly [true/false]")]
-        public bool? ListenPublic { get; set; }
+        [Option('x',  "ListenPublic",  HelpText = "Listen publicly")]
+        public bool ListenPublic { get; set; }
+
+        [Option('z', "ListenPrivate", HelpText = "Only allow local access")]
+        public bool ListenPrivate { get; set; }
 
         [Option('h', "Help",  HelpText = "Show Help")]
         public bool ShowHelp { get; set; }
@@ -48,7 +51,10 @@ namespace Jackett.Console
         [Option('m', "MigrateSettings", HelpText = "Migrate settings manually (Must be admin on Windows)")]
         public bool MigrateSettings { get; set; }
 
-        [Option('f', "SSLFix", HelpText = "Linux Libcurl NSS Missing ECC Ciphers workaround (Use if you can't access some trackers) [true/false].")]
+        [Option('f', "SSLFix", HelpText = "[true/false] Linux Libcurl NSS Missing ECC Ciphers workaround (Use if you can't access some trackers) .")]
         public bool? SSLFix { get; set; }
+
+        [ParserState]
+        public IParserState LastParserState { get; set; }
     }
 }
diff --git a/src/Jackett.Console/Jackett.Console.csproj b/src/Jackett.Console/Jackett.Console.csproj
index 11b25b22394dbc96175859f0e7e15f58e89f0c5c..d47be62640efef46c990cc42dcd5fd32c86ef654 100644
--- a/src/Jackett.Console/Jackett.Console.csproj
+++ b/src/Jackett.Console/Jackett.Console.csproj
@@ -1,5 +1,5 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
   <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
   <PropertyGroup>
     <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
diff --git a/src/Jackett.Console/Program.cs b/src/Jackett.Console/Program.cs
index 90c49c6b584415e9f5b3bfabd4758b1749538d51..f83d4ed14f29fdab51ee572c1fc2561e56c6e849 100644
--- a/src/Jackett.Console/Program.cs
+++ b/src/Jackett.Console/Program.cs
@@ -26,22 +26,43 @@ namespace JackettConsole
                 var options = new ConsoleOptions();
                 if (!Parser.Default.ParseArguments(args, options) || options.ShowHelp == true)
                 {
-                    var text = HelpText.AutoBuild(options, (HelpText current) => HelpText.DefaultParsingErrorsHandler(options, current));
-                    text.Copyright = " ";
-                    text.Heading = "Jackett v" + Engine.ConfigService.GetVersion() + " options:";
-                    Console.WriteLine(text);
-                    Environment.ExitCode = 1;
-                    return;
+                    if (options.LastParserState != null && options.LastParserState.Errors.Count > 0)
+                    {
+                        var help = new HelpText();
+                        var errors = help.RenderParsingErrorsText(options, 2); // indent with two spaces
+                        Console.WriteLine("Jackett v" + Engine.ConfigService.GetVersion());
+                        Console.WriteLine("Switch error: " + errors);
+                        Console.WriteLine("See --help for further details on switches.");
+                        Environment.ExitCode = 1;
+                        return;
+                    }
+                    else
+                    {
+
+                        var text = HelpText.AutoBuild(options, (HelpText current) => HelpText.DefaultParsingErrorsHandler(options, current));
+                        text.Copyright = " ";
+                        text.Heading = "Jackett v" + Engine.ConfigService.GetVersion() + " options:";
+                        Console.WriteLine(text);
+                        Environment.ExitCode = 1;
+                        return;
+                    }
                 }
                 else
                 {
+
+                    if (options.ListenPublic && options.ListenPrivate)
+                    {
+                        Console.WriteLine("You can only use listen private OR listen publicly.");
+                        Environment.ExitCode = 1;
+                        return;
+                    }
                     /*  ======     Options    =====  */
 
                     // SSL Fix
                     Startup.DoSSLFix = options.SSLFix;
 
                     // Use curl
-                    if (options.Client!=null)
+                    if (options.Client != null)
                         Startup.ClientOverride = options.Client.ToLowerInvariant();
 
                     // Logging
@@ -126,12 +147,12 @@ namespace JackettConsole
                     /*  ======     Overrides    =====  */
 
                     // Override listen public
-                    if(options.ListenPublic.HasValue)
+                    if (options.ListenPublic || options.ListenPrivate)
                     {
                         if (Engine.Server.Config.AllowExternal != options.ListenPublic)
                         {
                             Engine.Logger.Info("Overriding external access to " + options.ListenPublic);
-                            Engine.Server.Config.AllowExternal = options.ListenPublic.Value;
+                            Engine.Server.Config.AllowExternal = options.ListenPublic;
                             if (System.Environment.OSVersion.Platform != PlatformID.Unix)
                             {
                                 if (ServerUtil.IsUserAdministrator())
@@ -151,7 +172,7 @@ namespace JackettConsole
                     }
 
                     // Override port
-                    if(options.Port != 0)
+                    if (options.Port != 0)
                     {
                         if (Engine.Server.Config.Port != options.Port)
                         {
diff --git a/src/Jackett.Distribution/Program.cs b/src/Jackett.Distribution/Program.cs
index af4a4a507a556016c5af79dd6c7f518ba9b68176..0305c4c5af8e1697c81c1cf18f0ce901905fa916 100644
--- a/src/Jackett.Distribution/Program.cs
+++ b/src/Jackett.Distribution/Program.cs
@@ -15,7 +15,9 @@ namespace Jackett.Distribution
     {
         static readonly string repoOwner = "zone117x";
         static readonly string repoName = "Jackett";
-        static readonly string buildZipFile = "JackettBuild.zip";
+        static readonly string jackettLibPath = Path.Combine("build.windows", "Jackett.dll");
+        static readonly string buildZipFileWindows = "JackettBuildWindows.zip";
+        static readonly string buildZipFileMono = "JackettBuildMono.zip";
         static readonly string installFile = Path.Combine("Output", "setup.exe");
 
         static GitHubClient github;
@@ -32,22 +34,25 @@ namespace Jackett.Distribution
             github.Credentials = new Credentials(token);
 
             localVersion = GetJackettVersion();
-            var latestReleaseVersion = LatestGithubRelease().Result;
+            /*var latestReleaseVersion = LatestGithubRelease().Result;
             if (localVersion <= latestReleaseVersion)
             {
                 Console.WriteLine("Latest Github release is {0}, will not upload local version {1}", latestReleaseVersion, localVersion);
                 return;
-            }
+            }*/
+
+            Console.WriteLine("Zipping release build for Windows " + localVersion);
+            ZippingReleaseBuildWindows();
 
-            Console.WriteLine("Zipping release build " + localVersion);
-            ZippingReleaseBuild();
+            Console.WriteLine("Zipping release build for Mono " + localVersion);
+            ZippingReleaseBuildMono();
 
             UploadRelease().Wait();
         }
 
         static Version GetJackettVersion()
         {
-            var assemblyVersion = AssemblyName.GetAssemblyName(Path.Combine("Build", "Jackett.dll")).Version;
+            var assemblyVersion = AssemblyName.GetAssemblyName(jackettLibPath).Version;
             return new Version(assemblyVersion.Major, assemblyVersion.Minor, assemblyVersion.Build);
         }
 
@@ -59,11 +64,18 @@ namespace Jackett.Distribution
             return version;
         }
 
-        static void ZippingReleaseBuild()
+        static void ZippingReleaseBuildWindows()
+        {
+            if (File.Exists(buildZipFileWindows))
+                File.Delete(buildZipFileWindows);
+            ZipFile.CreateFromDirectory("build.windows", buildZipFileWindows);
+        }
+
+        static void ZippingReleaseBuildMono()
         {
-            if (File.Exists(buildZipFile))
-                File.Delete(buildZipFile);
-            ZipFile.CreateFromDirectory("Build", buildZipFile);
+            if (File.Exists(buildZipFileMono))
+                File.Delete(buildZipFileMono);
+            ZipFile.CreateFromDirectory("build.mono", buildZipFileMono);
         }
 
         static async Task UploadRelease()
@@ -93,23 +105,23 @@ namespace Jackett.Distribution
 
             var releaseResult = await github.Release.Create(repoOwner, repoName, newRelease);
 
+            Console.WriteLine("Uploading Windows build");
+            await UploadFileToGithub(releaseResult, buildZipFileWindows, string.Format("Jackett.Windows.v{0}.zip", localVersion), "application/zip");
+            Console.WriteLine("Uploading Mono build");
+            await UploadFileToGithub(releaseResult, buildZipFileMono, string.Format("Jackett.Mono.v{0}.zip", localVersion), "application/zip");
+            Console.WriteLine("Uploading Windows installer");
+            await UploadFileToGithub(releaseResult, installFile, string.Format("Jackett.v{0}.Windows.Installer.exe", localVersion), "application/octet-stream");
+        }
 
-            var buildZipAsset = new ReleaseAssetUpload()
-            {
-                FileName = string.Format("Jackett.v{0}.zip", localVersion),
-                ContentType = "application/zip",
-                RawData = File.OpenRead(buildZipFile)
-            };
-            var buildZipAssetResult = await github.Release.UploadAsset(releaseResult, buildZipAsset);
-
-            var installFileAsset = new ReleaseAssetUpload()
+        static Task UploadFileToGithub(Release githubRelease, string filePath, string filePublishName, string contentType)
+        {
+            var buildZipAssetWindows = new ReleaseAssetUpload()
             {
-                FileName = string.Format("Jackett.v{0}.Windows.Installer.exe", localVersion),
-                ContentType = "application/octet-stream",
-                RawData = File.OpenRead(installFile)
+                FileName = filePublishName,
+                ContentType = contentType,
+                RawData = File.OpenRead(filePath)
             };
-            var installFileAssetResult = await github.Release.UploadAsset(releaseResult, installFileAsset);
-
+            return github.Release.UploadAsset(githubRelease, buildZipAssetWindows);
         }
     }
 }
diff --git a/src/Jackett.Test/Jackett.Test.csproj b/src/Jackett.Test/Jackett.Test.csproj
index 234f876d19d19caed14485c9d1f557f1c5b40b1c..1f07527e68b3a79af7c3da234eaf8daab95be605 100644
--- a/src/Jackett.Test/Jackett.Test.csproj
+++ b/src/Jackett.Test/Jackett.Test.csproj
@@ -54,6 +54,10 @@
       <HintPath>..\packages\Autofac.WebApi2.Owin.3.2.0\lib\net45\Autofac.Integration.WebApi.Owin.dll</HintPath>
       <Private>True</Private>
     </Reference>
+    <Reference Include="AutoMapper, Version=4.0.4.0, Culture=neutral, PublicKeyToken=be96cd2c38ef1005, processorArchitecture=MSIL">
+      <HintPath>..\packages\AutoMapper.4.0.4\lib\net45\AutoMapper.dll</HintPath>
+      <Private>True</Private>
+    </Reference>
     <Reference Include="CsQuery, Version=1.3.3.249, Culture=neutral, processorArchitecture=MSIL">
       <HintPath>..\packages\CsQuery.1.3.4\lib\net40\CsQuery.dll</HintPath>
       <Private>True</Private>
@@ -70,6 +74,7 @@
       <HintPath>..\packages\Microsoft.AspNet.Identity.Core.2.2.1\lib\net45\Microsoft.AspNet.Identity.Core.dll</HintPath>
       <Private>True</Private>
     </Reference>
+    <Reference Include="Microsoft.CSharp" />
     <Reference Include="Microsoft.Owin, Version=3.0.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
       <HintPath>..\packages\Microsoft.Owin.3.0.1\lib\net45\Microsoft.Owin.dll</HintPath>
       <Private>True</Private>
@@ -155,6 +160,7 @@
   <ItemGroup>
     <Compile Include="Indexers\BakaBTTests.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="Services\ProtectionServiceTests.cs" />
     <Compile Include="TestBase.cs" />
     <Compile Include="TestIIndexerManagerServiceHelper.cs" />
     <Compile Include="TestUtil.cs" />
@@ -162,7 +168,9 @@
     <Compile Include="Util\ServerUtilTests.cs" />
   </ItemGroup>
   <ItemGroup>
-    <None Include="app.config" />
+    <None Include="app.config">
+      <SubType>Designer</SubType>
+    </None>
     <None Include="packages.config" />
   </ItemGroup>
   <ItemGroup>
diff --git a/src/Jackett.Test/Services/ProtectionServiceTests.cs b/src/Jackett.Test/Services/ProtectionServiceTests.cs
new file mode 100644
index 0000000000000000000000000000000000000000..e8fb274d5ee8ca6bad1bde5d513d4e82e6ba1e2b
--- /dev/null
+++ b/src/Jackett.Test/Services/ProtectionServiceTests.cs
@@ -0,0 +1,30 @@
+using Jackett.Services;
+using NUnit.Framework;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Autofac;
+
+namespace JackettTest.Services
+{
+    [TestFixture]
+    class ProtectionServiceTests :  TestBase
+    {
+
+        [Test]
+        public void Should_be_able_to_encrypt_and_decrypt()
+        {
+            var ss = TestUtil.Container.Resolve<IServerService>();
+            ss.Config.InstanceId = "12345678";
+            var ps = TestUtil.Container.Resolve<IProtectionService>();
+            var input = "test123";
+            var protectedInput = ps.Protect(input);
+            var output = ps.UnProtect(protectedInput);
+
+            Assert.AreEqual(output, input);
+            Assert.AreNotEqual(input, protectedInput);
+        }
+    }
+}
diff --git a/src/Jackett.Test/app.config b/src/Jackett.Test/app.config
index eda8c8545ee4aead9709d3c7ea5285a5762afd7d..c88a03853b9238f911cfa6cde83a00f060051c02 100644
--- a/src/Jackett.Test/app.config
+++ b/src/Jackett.Test/app.config
@@ -22,6 +22,10 @@
         <assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
         <bindingRedirect oldVersion="0.0.0.0-7.0.0.0" newVersion="7.0.0.0" />
       </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="AutoMapper" publicKeyToken="be96cd2c38ef1005" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-4.0.4.0" newVersion="4.0.4.0" />
+      </dependentAssembly>
     </assemblyBinding>
   </runtime>
 <startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" /></startup></configuration>
diff --git a/src/Jackett.Test/packages.config b/src/Jackett.Test/packages.config
index 3813a8d524c979069f10fb74c974c2e9c21f16d4..b1b8148591f7c027c69541db645b498d26e95c37 100644
--- a/src/Jackett.Test/packages.config
+++ b/src/Jackett.Test/packages.config
@@ -4,6 +4,7 @@
   <package id="Autofac.Owin" version="3.1.0" targetFramework="net45" />
   <package id="Autofac.WebApi2" version="3.4.0" targetFramework="net45" />
   <package id="Autofac.WebApi2.Owin" version="3.2.0" targetFramework="net45" />
+  <package id="AutoMapper" version="4.0.4" targetFramework="net45" />
   <package id="CsQuery" version="1.3.4" targetFramework="net45" />
   <package id="FluentAssertions" version="3.4.1" targetFramework="net45" />
   <package id="Microsoft.AspNet.Identity.Core" version="2.2.1" targetFramework="net45" />
diff --git a/src/Jackett/AuthenticationException.cs b/src/Jackett/AuthenticationException.cs
new file mode 100644
index 0000000000000000000000000000000000000000..e6a387a7d13ada509d9e6837b8286a294cc25ab4
--- /dev/null
+++ b/src/Jackett/AuthenticationException.cs
@@ -0,0 +1,12 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Jackett
+{
+    class AuthenticationException : Exception
+    {
+    }
+}
diff --git a/src/Jackett/Content/custom.css b/src/Jackett/Content/custom.css
index e4b2279a9d9bece81b688c34de9d9b741e996000..a98776d3523e50656e72d730b1162d20e1736ca5 100644
--- a/src/Jackett/Content/custom.css
+++ b/src/Jackett/Content/custom.css
@@ -223,4 +223,38 @@ hr {
 
 .indexer-caps table {
     border-bottom:   1px solid #ddd;
+}
+
+.jackettlogWarn {
+    background-color: #FFFF8E !important;
+}
+
+.jackettlogError {
+    background-color: #FF6060 !important;
+}
+
+.jackettdownloaded {
+    color: blueviolet;
+}
+
+.jacketdownloadlocal {
+    padding-left: 10px;
+}
+
+.downloadcolumn {
+    text-align:center;
+}
+
+pre {
+    display: block;
+    padding: 3px;
+    margin: 0 0 0px;
+    font-size: 13px;
+    line-height: 1.42857143;
+    color: #333;
+    word-break: break-all;
+    word-wrap: break-word;
+    background-color: transparent;
+    border: 0px;
+    border-radius: 0px;
 }
\ No newline at end of file
diff --git a/src/Jackett/Content/custom.js b/src/Jackett/Content/custom.js
index 5aca89c2bf15d79adfb5dca1a9b53272c11d2eb3..5aec604fe1e2b661617e836f4f3d629457249153 100644
--- a/src/Jackett/Content/custom.js
+++ b/src/Jackett/Content/custom.js
@@ -1,16 +1,40 @@
 $(document).ready(function () {
     $.ajaxSetup({ cache: false });
-    HandlebarsIntl.registerWith(Handlebars);
     reloadIndexers();
     loadJackettSettings();
+
+    window.jackettIsLocal = window.location.hostname === 'localhost' ||
+                 window.location.hostname === '127.0.0.1';
+
+    $('body').on('click', '.downloadlink', function (e, b) {
+        $(e.target).addClass('jackettdownloaded');
+    });
+
+
+    $('body').on('click', '.jacketdownloadserver', function (event) {
+        var href = $(event.target).parent().attr('href');
+        var jqxhr = $.get(href, function (data) {
+            if (data.result == "error") {
+                doNotify("Error: " + data.error, "danger", "glyphicon glyphicon-alert");
+                return;
+            } else {
+                doNotify("Downloaded sent to the blackhole successfully.", "success", "glyphicon glyphicon-ok");
+            }
+        }).fail(function () {
+            doNotify("Request to Jackett server failed", "danger", "glyphicon glyphicon-alert");
+        });
+        event.preventDefault();
+        return false;
+    });
+
 });
 
 function loadJackettSettings() {
     getJackettConfig(function (data) {
-
         $("#api-key-input").val(data.config.api_key);
         $("#app-version").html(data.app_version);
         $("#jackett-port").val(data.config.port);
+        $("#jackett-savedir").val(data.config.blackholedir);
         $("#jackett-allowext").attr('checked', data.config.external);
         var password = data.config.password;
         $("#jackett-adminpwd").val(password);
@@ -34,12 +58,14 @@ $("#jackett-show-releases").click(function () {
                    {
                        "targets": 0,
                        "visible": false,
-                       "searchable": false
+                       "searchable": false,
+                       "type": 'date'
                    },
                    {
                        "targets": 1,
                        "visible": false,
-                       "searchable": false
+                       "searchable": false,
+                       "type": 'date'
                    },
                    {
                        "targets": 2,
@@ -53,7 +79,31 @@ $("#jackett-show-releases").click(function () {
                        "searchable": false,
                        "iDataSort": 1
                    }
-                ]
+                ],
+                initComplete: function () {
+                    var count = 0;
+                    this.api().columns().every(function () {
+                        count++;
+                        if (count === 5 || count === 7) {
+                            var column = this;
+                            var select = $('<select><option value=""></option></select>')
+                                .appendTo($(column.footer()).empty())
+                                .on('change', function () {
+                                    var val = $.fn.dataTable.util.escapeRegex(
+                                        $(this).val()
+                                    );
+
+                                    column
+                                        .search(val ? '^' + val + '$' : '', true, false)
+                                        .draw();
+                                });
+
+                            column.data().unique().sort().each(function (d, j) {
+                                select.append('<option value="' + d + '">' + d + '</option>')
+                            });
+                        }
+                    });
+                }
             });
         $("#modals").append(releaseDialog);
         releaseDialog.modal("show");
@@ -64,16 +114,34 @@ $("#jackett-show-releases").click(function () {
 });
 
 
+$("#view-jackett-logs").click(function () {
+    var jqxhr = $.get("/admin/GetLogs", function (data) {
+        var releaseTemplate = Handlebars.compile($("#jackett-logs").html());
+        var item = { logs: data };
+        var releaseDialog = $(releaseTemplate(item));
+        $("#modals").append(releaseDialog);
+        releaseDialog.modal("show");
+
+    }).fail(function () {
+        doNotify("Request to Jackett server failed", "danger", "glyphicon glyphicon-alert");
+    });
+});
+
+
 $("#change-jackett-port").click(function () {
     var jackett_port = $("#jackett-port").val();
     var jackett_external = $("#jackett-allowext").is(':checked');
-    var jsonObject = { port: jackett_port, external: jackett_external };
-    var jqxhr = $.post("/admin/set_port", JSON.stringify(jsonObject), function (data) {
+    var jsonObject = {
+        port: jackett_port,
+        external: jackett_external,
+        blackholedir: $("#jackett-savedir").val()
+    };
+    var jqxhr = $.post("/admin/set_config", JSON.stringify(jsonObject), function (data) {
         if (data.result == "error") {
             doNotify("Error: " + data.error, "danger", "glyphicon glyphicon-alert");
             return;
         } else {
-            doNotify("The port has been changed. Redirecting you to the new port.", "success", "glyphicon glyphicon-ok");
+            doNotify("Redirecting you to complete configuration update..", "success", "glyphicon glyphicon-ok");
             window.setTimeout(function () {
                 url = window.location.href;
                 if (data.external) {
@@ -132,19 +200,19 @@ function reloadIndexers() {
 }
 
 function displayIndexers(items) {
-    var indexerTemplate = Handlebars.compile($("#templates > .configured-indexer")[0].outerHTML);
-    var unconfiguredIndexerTemplate = Handlebars.compile($("#templates > .unconfigured-indexer")[0].outerHTML);
+    var indexerTemplate = Handlebars.compile($("#configured-indexer").html());
+    var unconfiguredIndexerTemplate = Handlebars.compile($("#unconfigured-indexer").html());
     for (var i = 0; i < items.length; i++) {
         var item = items[i];
         item.torznab_host = resolveUrl("/torznab/" + item.id);
-        item.potato_host = resolveUrl("/potato/" + item.id);  
+        item.potato_host = resolveUrl("/potato/" + item.id);
         if (item.configured)
             $('#indexers').append(indexerTemplate(item));
         else
             $('#unconfigured-indexers').append($(unconfiguredIndexerTemplate(item)));
     }
 
-    var addIndexerButton = $("#templates > .add-indexer")[0].outerHTML;
+    var addIndexerButton = $('#add-indexer').html();
     $('#indexers').append(addIndexerButton);
 
     $('#indexers').fadeIn();
@@ -228,12 +296,38 @@ function populateConfigItems(configForm, config) {
     }
     var $formItemContainer = configForm.find(".config-setup-form");
     $formItemContainer.empty();
-    var setupItemTemplate = Handlebars.compile($("#templates > .setup-item")[0].outerHTML);
+
+    $('.jackettrecaptcha').remove();
+
+    var hasReacaptcha = false;
+    var captchaItem = null;
     for (var i = 0; i < config.length; i++) {
-        var item = config[i];
-        var setupValueTemplate = Handlebars.compile($("#templates > .setup-item-" + item.type)[0].outerHTML);
-        item.value_element = setupValueTemplate(item);
-        $formItemContainer.append(setupItemTemplate(item));
+        if (config[i].type === 'recaptcha') {
+            hasReacaptcha = true;
+            captchaItem = config[i];
+        }
+    }
+
+    var setupItemTemplate = Handlebars.compile($("#setup-item").html());
+    if (hasReacaptcha && !window.jackettIsLocal) {
+        var setupValueTemplate = Handlebars.compile($("#setup-item-nonlocalrecaptcha").html());
+        captchaItem.value_element = setupValueTemplate(captchaItem);
+        var template = setupItemTemplate(captchaItem);
+        $formItemContainer.append(template);
+    } else {
+
+        for (var i = 0; i < config.length; i++) {
+            var item = config[i];
+            var setupValueTemplate = Handlebars.compile($("#setup-item-" + item.type).html());
+            item.value_element = setupValueTemplate(item);
+            var template = setupItemTemplate(item);
+            $formItemContainer.append(template);
+            if (item.type === 'recaptcha') {
+                grecaptcha.render($('.jackettrecaptcha')[0], {
+                    'sitekey': item.sitekey
+                });
+            }
+        }
     }
 }
 
@@ -246,22 +340,31 @@ function newConfigModal(title, config, caps) {
 }
 
 function getConfigModalJson(configForm) {
-    var configJson = {};
+    var configJson = [];
     configForm.find(".config-setup-form").children().each(function (i, el) {
         $el = $(el);
         var type = $el.data("type");
         var id = $el.data("id");
+        var itemEntry = { id: id };
         switch (type) {
             case "hiddendata":
-                configJson[id] = $el.find(".setup-item-hiddendata input").val();
+                itemEntry.value = $el.find(".setup-item-hiddendata input").val();
                 break;
             case "inputstring":
-                configJson[id] = $el.find(".setup-item-inputstring input").val();
+                itemEntry.value = $el.find(".setup-item-inputstring input").val();
                 break;
             case "inputbool":
-                configJson[id] = $el.find(".setup-item-inputbool input").is(":checked");
+                itemEntry.value = $el.find(".setup-item-inputbool input").is(":checked");
+                break;
+            case "recaptcha":
+                if (window.jackettIsLocal) {
+                    itemEntry.value = $('.g-recaptcha-response').val();
+                } else {
+                    itemEntry.cookie = $el.find(".setup-item-recaptcha input").val();
+                }
                 break;
         }
+        configJson.push(itemEntry)
     });
     return configJson;
 }
@@ -275,7 +378,7 @@ function populateSetupForm(indexerId, name, config, caps) {
 
         var originalBtnText = $goButton.html();
         $goButton.prop('disabled', true);
-        $goButton.html($('#templates > .spinner')[0].outerHTML);
+        $goButton.html($('#spinner').html());
 
         var jqxhr = $.post("/admin/configure_indexer", JSON.stringify(data), function (data) {
             if (data.result == "error") {
diff --git a/src/Jackett/Content/handlebars-intl.min.js b/src/Jackett/Content/handlebars-intl.min.js
deleted file mode 100644
index c77fa711816fa23cf4808650a3857e0b8cc6f979..0000000000000000000000000000000000000000
--- a/src/Jackett/Content/handlebars-intl.min.js
+++ /dev/null
@@ -1,2 +0,0 @@
-(function(){"use strict";function a(a){var b,c,d,e,f=Array.prototype.slice.call(arguments,1);for(b=0,c=f.length;c>b;b+=1)if(d=f[b])for(e in d)p.call(d,e)&&(a[e]=d[e]);return a}function b(a,b,c){this.locales=a,this.formats=b,this.pluralFn=c}function c(a){this.id=a}function d(a,b,c,d,e){this.id=a,this.useOrdinal=b,this.offset=c,this.options=d,this.pluralFn=e}function e(a,b,c,d){this.id=a,this.offset=b,this.numberFormat=c,this.string=d}function f(a,b){this.id=a,this.options=b}function g(a,b,c){var d="string"==typeof a?g.__parse(a):a;if(!d||"messageFormatPattern"!==d.type)throw new TypeError("A message must be provided as a String or AST.");c=this._mergeFormats(g.formats,c),r(this,"_locale",{value:this._resolveLocale(b)});var e=this._findPluralRuleFunction(this._locale),f=this._compilePattern(d,b,c,e),h=this;this.format=function(a){return h._format(f,a)}}function h(a){return 400*a/146097}function i(a,b){b=b||{},G(a)&&(a=a.concat()),D(this,"_locale",{value:this._resolveLocale(a)}),D(this,"_options",{value:{style:this._resolveStyle(b.style),units:this._isValidUnits(b.units)&&b.units}}),D(this,"_locales",{value:a}),D(this,"_fields",{value:this._findFields(this._locale)}),D(this,"_messages",{value:E(null)});var c=this;this.format=function(a,b){return c._format(a,b)}}function j(a){var b=Q(null);return function(){var c=Array.prototype.slice.call(arguments),d=k(c),e=d&&b[d];return e||(e=Q(a.prototype),a.apply(e,c),d&&(b[d]=e)),e}}function k(a){if("undefined"!=typeof JSON){var b,c,d,e=[];for(b=0,c=a.length;c>b;b+=1)d=a[b],e.push(d&&"object"==typeof d?l(d):d);return JSON.stringify(e)}}function l(a){var b,c,d,e,f=[],g=[];for(b in a)a.hasOwnProperty(b)&&g.push(b);var h=g.sort();for(c=0,d=h.length;d>c;c+=1)b=h[c],e={},e[b]=a[b],f[c]=e;return f}function m(a){var b,c,d,e,f=Array.prototype.slice.call(arguments,1);for(b=0,c=f.length;c>b;b+=1)if(d=f[b])for(e in d)d.hasOwnProperty(e)&&(a[e]=d[e]);return a}function n(a){function b(a,b){return function(){return"undefined"!=typeof console&&"function"==typeof console.warn&&console.warn("{{"+a+"}} is deprecated, use: {{"+b.name+"}}"),b.apply(this,arguments)}}function c(a){if(!a.fn)throw new Error("{{#intl}} must be invoked as a block helper");var b=p(a.data),c=m({},b.intl,a.hash);return b.intl=c,a.fn(this,{data:b})}function d(a,b){var c,d,e,f=b.data&&b.data.intl,g=a.split(".");try{for(e=0,d=g.length;d>e;e++)c=f=f[g[e]]}finally{if(void 0===c)throw new ReferenceError("Could not find Intl object: "+a)}return c}function e(a,b,c){a=new Date(a),k(a,"A date or timestamp must be provided to {{formatDate}}"),c||(c=b,b=null);var d=c.data.intl&&c.data.intl.locales,e=n("date",b,c);return T(d,e).format(a)}function f(a,b,c){a=new Date(a),k(a,"A date or timestamp must be provided to {{formatTime}}"),c||(c=b,b=null);var d=c.data.intl&&c.data.intl.locales,e=n("time",b,c);return T(d,e).format(a)}function g(a,b,c){a=new Date(a),k(a,"A date or timestamp must be provided to {{formatRelative}}"),c||(c=b,b=null);var d=c.data.intl&&c.data.intl.locales,e=n("relative",b,c),f=c.hash.now;return delete e.now,V(d,e).format(a,{now:f})}function h(a,b,c){l(a,"A number must be provided to {{formatNumber}}"),c||(c=b,b=null);var d=c.data.intl&&c.data.intl.locales,e=n("number",b,c);return S(d,e).format(a)}function i(a,b){b||(b=a,a=null);var c=b.hash;if(!a&&"string"!=typeof a&&!c.intlName)throw new ReferenceError("{{formatMessage}} must be provided a message or intlName");var e=b.data.intl||{},f=e.locales,g=e.formats;return!a&&c.intlName&&(a=d(c.intlName,b)),"function"==typeof a?a(c):("string"==typeof a&&(a=U(a,f,g)),a.format(c))}function j(){var a,b,c=[].slice.call(arguments).pop(),d=c.hash;for(a in d)d.hasOwnProperty(a)&&(b=d[a],"string"==typeof b&&(d[a]=q(b)));return new o(String(i.apply(this,arguments)))}function k(a,b){if(!isFinite(a))throw new TypeError(b)}function l(a,b){if("number"!=typeof a)throw new TypeError(b)}function n(a,b,c){var e,f=c.hash;return b?("string"==typeof b&&(e=d("formats."+a+"."+b,c)),e=m({},e,f)):e=f,e}var o=a.SafeString,p=a.createFrame,q=a.Utils.escapeExpression,r={intl:c,intlGet:d,formatDate:e,formatTime:f,formatRelative:g,formatNumber:h,formatMessage:i,formatHTMLMessage:j,intlDate:b("intlDate",e),intlTime:b("intlTime",f),intlNumber:b("intlNumber",h),intlMessage:b("intlMessage",i),intlHTMLMessage:b("intlHTMLMessage",j)};for(var s in r)r.hasOwnProperty(s)&&a.registerHelper(s,r[s])}function o(a){x.__addLocaleData(a),M.__addLocaleData(a)}var p=Object.prototype.hasOwnProperty,q=function(){try{return!!Object.defineProperty({},"a",{})}catch(a){return!1}}(),r=(!q&&!Object.prototype.__defineGetter__,q?Object.defineProperty:function(a,b,c){"get"in c&&a.__defineGetter__?a.__defineGetter__(b,c.get):(!p.call(a,b)||"value"in c)&&(a[b]=c.value)}),s=Object.create||function(a,b){function c(){}var d,e;c.prototype=a,d=new c;for(e in b)p.call(b,e)&&r(d,e,b[e]);return d},t=b;b.prototype.compile=function(a){return this.pluralStack=[],this.currentPlural=null,this.pluralNumberFormat=null,this.compileMessage(a)},b.prototype.compileMessage=function(a){if(!a||"messageFormatPattern"!==a.type)throw new Error('Message AST is not of type: "messageFormatPattern"');var b,c,d,e=a.elements,f=[];for(b=0,c=e.length;c>b;b+=1)switch(d=e[b],d.type){case"messageTextElement":f.push(this.compileMessageText(d));break;case"argumentElement":f.push(this.compileArgument(d));break;default:throw new Error("Message element does not have a valid type")}return f},b.prototype.compileMessageText=function(a){return this.currentPlural&&/(^|[^\\])#/g.test(a.value)?(this.pluralNumberFormat||(this.pluralNumberFormat=new Intl.NumberFormat(this.locales)),new e(this.currentPlural.id,this.currentPlural.format.offset,this.pluralNumberFormat,a.value)):a.value.replace(/\\#/g,"#")},b.prototype.compileArgument=function(a){var b=a.format;if(!b)return new c(a.id);var e,g=this.formats,h=this.locales,i=this.pluralFn;switch(b.type){case"numberFormat":return e=g.number[b.style],{id:a.id,format:new Intl.NumberFormat(h,e).format};case"dateFormat":return e=g.date[b.style],{id:a.id,format:new Intl.DateTimeFormat(h,e).format};case"timeFormat":return e=g.time[b.style],{id:a.id,format:new Intl.DateTimeFormat(h,e).format};case"pluralFormat":return e=this.compileOptions(a),new d(a.id,b.ordinal,b.offset,e,i);case"selectFormat":return e=this.compileOptions(a),new f(a.id,e);default:throw new Error("Message element does not have a valid format type")}},b.prototype.compileOptions=function(a){var b=a.format,c=b.options,d={};this.pluralStack.push(this.currentPlural),this.currentPlural="pluralFormat"===b.type?a:null;var e,f,g;for(e=0,f=c.length;f>e;e+=1)g=c[e],d[g.selector]=this.compileMessage(g.value);return this.currentPlural=this.pluralStack.pop(),d},c.prototype.format=function(a){return a?"string"==typeof a?a:String(a):""},d.prototype.getOption=function(a){var b=this.options,c=b["="+a]||b[this.pluralFn(a-this.offset,this.useOrdinal)];return c||b.other},e.prototype.format=function(a){var b=this.numberFormat.format(a-this.offset);return this.string.replace(/(^|[^\\])#/g,"$1"+b).replace(/\\#/g,"#")},f.prototype.getOption=function(a){var b=this.options;return b[a]||b.other};var u=function(){function a(a,b){function c(){this.constructor=a}c.prototype=b.prototype,a.prototype=new c}function b(a,b,c,d,e,f){this.message=a,this.expected=b,this.found=c,this.offset=d,this.line=e,this.column=f,this.name="SyntaxError"}function c(a){function c(b){function c(b,c,d){var e,f;for(e=c;d>e;e++)f=a.charAt(e),"\n"===f?(b.seenCR||b.line++,b.column=1,b.seenCR=!1):"\r"===f||"\u2028"===f||"\u2029"===f?(b.line++,b.column=1,b.seenCR=!0):(b.column++,b.seenCR=!1)}return Ua!==b&&(Ua>b&&(Ua=0,Va={line:1,column:1,seenCR:!1}),c(Va,Ua,b),Ua=b),Va}function d(a){Wa>Sa||(Sa>Wa&&(Wa=Sa,Xa=[]),Xa.push(a))}function e(d,e,f){function g(a){var b=1;for(a.sort(function(a,b){return a.description<b.description?-1:a.description>b.description?1:0});b<a.length;)a[b-1]===a[b]?a.splice(b,1):b++}function h(a,b){function c(a){function b(a){return a.charCodeAt(0).toString(16).toUpperCase()}return a.replace(/\\/g,"\\\\").replace(/"/g,'\\"').replace(/\x08/g,"\\b").replace(/\t/g,"\\t").replace(/\n/g,"\\n").replace(/\f/g,"\\f").replace(/\r/g,"\\r").replace(/[\x00-\x07\x0B\x0E\x0F]/g,function(a){return"\\x0"+b(a)}).replace(/[\x10-\x1F\x80-\xFF]/g,function(a){return"\\x"+b(a)}).replace(/[\u0180-\u0FFF]/g,function(a){return"\\u0"+b(a)}).replace(/[\u1080-\uFFFF]/g,function(a){return"\\u"+b(a)})}var d,e,f,g=new Array(a.length);for(f=0;f<a.length;f++)g[f]=a[f].description;return d=a.length>1?g.slice(0,-1).join(", ")+" or "+g[a.length-1]:g[0],e=b?'"'+c(b)+'"':"end of input","Expected "+d+" but "+e+" found."}var i=c(f),j=f<a.length?a.charAt(f):null;return null!==e&&g(e),new b(null!==d?d:h(e,j),e,j,f,i.line,i.column)}function f(){var a;return a=g()}function g(){var a,b,c;for(a=Sa,b=[],c=h();c!==E;)b.push(c),c=h();return b!==E&&(Ta=a,b=H(b)),a=b}function h(){var a;return a=j(),a===E&&(a=l()),a}function i(){var b,c,d,e,f,g;if(b=Sa,c=[],d=Sa,e=w(),e!==E?(f=B(),f!==E?(g=w(),g!==E?(e=[e,f,g],d=e):(Sa=d,d=I)):(Sa=d,d=I)):(Sa=d,d=I),d!==E)for(;d!==E;)c.push(d),d=Sa,e=w(),e!==E?(f=B(),f!==E?(g=w(),g!==E?(e=[e,f,g],d=e):(Sa=d,d=I)):(Sa=d,d=I)):(Sa=d,d=I);else c=I;return c!==E&&(Ta=b,c=J(c)),b=c,b===E&&(b=Sa,c=v(),c!==E&&(c=a.substring(b,Sa)),b=c),b}function j(){var a,b;return a=Sa,b=i(),b!==E&&(Ta=a,b=K(b)),a=b}function k(){var b,c,e;if(b=z(),b===E){if(b=Sa,c=[],L.test(a.charAt(Sa))?(e=a.charAt(Sa),Sa++):(e=E,0===Ya&&d(M)),e!==E)for(;e!==E;)c.push(e),L.test(a.charAt(Sa))?(e=a.charAt(Sa),Sa++):(e=E,0===Ya&&d(M));else c=I;c!==E&&(c=a.substring(b,Sa)),b=c}return b}function l(){var b,c,e,f,g,h,i,j,l;return b=Sa,123===a.charCodeAt(Sa)?(c=N,Sa++):(c=E,0===Ya&&d(O)),c!==E?(e=w(),e!==E?(f=k(),f!==E?(g=w(),g!==E?(h=Sa,44===a.charCodeAt(Sa)?(i=Q,Sa++):(i=E,0===Ya&&d(R)),i!==E?(j=w(),j!==E?(l=m(),l!==E?(i=[i,j,l],h=i):(Sa=h,h=I)):(Sa=h,h=I)):(Sa=h,h=I),h===E&&(h=P),h!==E?(i=w(),i!==E?(125===a.charCodeAt(Sa)?(j=S,Sa++):(j=E,0===Ya&&d(T)),j!==E?(Ta=b,c=U(f,h),b=c):(Sa=b,b=I)):(Sa=b,b=I)):(Sa=b,b=I)):(Sa=b,b=I)):(Sa=b,b=I)):(Sa=b,b=I)):(Sa=b,b=I),b}function m(){var a;return a=n(),a===E&&(a=o(),a===E&&(a=p(),a===E&&(a=q()))),a}function n(){var b,c,e,f,g,h,i;return b=Sa,a.substr(Sa,6)===V?(c=V,Sa+=6):(c=E,0===Ya&&d(W)),c===E&&(a.substr(Sa,4)===X?(c=X,Sa+=4):(c=E,0===Ya&&d(Y)),c===E&&(a.substr(Sa,4)===Z?(c=Z,Sa+=4):(c=E,0===Ya&&d($)))),c!==E?(e=w(),e!==E?(f=Sa,44===a.charCodeAt(Sa)?(g=Q,Sa++):(g=E,0===Ya&&d(R)),g!==E?(h=w(),h!==E?(i=B(),i!==E?(g=[g,h,i],f=g):(Sa=f,f=I)):(Sa=f,f=I)):(Sa=f,f=I),f===E&&(f=P),f!==E?(Ta=b,c=_(c,f),b=c):(Sa=b,b=I)):(Sa=b,b=I)):(Sa=b,b=I),b}function o(){var b,c,e,f,g,h;return b=Sa,a.substr(Sa,6)===aa?(c=aa,Sa+=6):(c=E,0===Ya&&d(ba)),c!==E?(e=w(),e!==E?(44===a.charCodeAt(Sa)?(f=Q,Sa++):(f=E,0===Ya&&d(R)),f!==E?(g=w(),g!==E?(h=u(),h!==E?(Ta=b,c=ca(h),b=c):(Sa=b,b=I)):(Sa=b,b=I)):(Sa=b,b=I)):(Sa=b,b=I)):(Sa=b,b=I),b}function p(){var b,c,e,f,g,h;return b=Sa,a.substr(Sa,13)===da?(c=da,Sa+=13):(c=E,0===Ya&&d(ea)),c!==E?(e=w(),e!==E?(44===a.charCodeAt(Sa)?(f=Q,Sa++):(f=E,0===Ya&&d(R)),f!==E?(g=w(),g!==E?(h=u(),h!==E?(Ta=b,c=fa(h),b=c):(Sa=b,b=I)):(Sa=b,b=I)):(Sa=b,b=I)):(Sa=b,b=I)):(Sa=b,b=I),b}function q(){var b,c,e,f,g,h,i;if(b=Sa,a.substr(Sa,6)===ga?(c=ga,Sa+=6):(c=E,0===Ya&&d(ha)),c!==E)if(e=w(),e!==E)if(44===a.charCodeAt(Sa)?(f=Q,Sa++):(f=E,0===Ya&&d(R)),f!==E)if(g=w(),g!==E){if(h=[],i=s(),i!==E)for(;i!==E;)h.push(i),i=s();else h=I;h!==E?(Ta=b,c=ia(h),b=c):(Sa=b,b=I)}else Sa=b,b=I;else Sa=b,b=I;else Sa=b,b=I;else Sa=b,b=I;return b}function r(){var b,c,e,f;return b=Sa,c=Sa,61===a.charCodeAt(Sa)?(e=ja,Sa++):(e=E,0===Ya&&d(ka)),e!==E?(f=z(),f!==E?(e=[e,f],c=e):(Sa=c,c=I)):(Sa=c,c=I),c!==E&&(c=a.substring(b,Sa)),b=c,b===E&&(b=B()),b}function s(){var b,c,e,f,h,i,j,k,l;return b=Sa,c=w(),c!==E?(e=r(),e!==E?(f=w(),f!==E?(123===a.charCodeAt(Sa)?(h=N,Sa++):(h=E,0===Ya&&d(O)),h!==E?(i=w(),i!==E?(j=g(),j!==E?(k=w(),k!==E?(125===a.charCodeAt(Sa)?(l=S,Sa++):(l=E,0===Ya&&d(T)),l!==E?(Ta=b,c=la(e,j),b=c):(Sa=b,b=I)):(Sa=b,b=I)):(Sa=b,b=I)):(Sa=b,b=I)):(Sa=b,b=I)):(Sa=b,b=I)):(Sa=b,b=I)):(Sa=b,b=I),b}function t(){var b,c,e,f;return b=Sa,a.substr(Sa,7)===ma?(c=ma,Sa+=7):(c=E,0===Ya&&d(na)),c!==E?(e=w(),e!==E?(f=z(),f!==E?(Ta=b,c=oa(f),b=c):(Sa=b,b=I)):(Sa=b,b=I)):(Sa=b,b=I),b}function u(){var a,b,c,d,e;if(a=Sa,b=t(),b===E&&(b=P),b!==E)if(c=w(),c!==E){if(d=[],e=s(),e!==E)for(;e!==E;)d.push(e),e=s();else d=I;d!==E?(Ta=a,b=pa(b,d),a=b):(Sa=a,a=I)}else Sa=a,a=I;else Sa=a,a=I;return a}function v(){var b,c;if(Ya++,b=[],ra.test(a.charAt(Sa))?(c=a.charAt(Sa),Sa++):(c=E,0===Ya&&d(sa)),c!==E)for(;c!==E;)b.push(c),ra.test(a.charAt(Sa))?(c=a.charAt(Sa),Sa++):(c=E,0===Ya&&d(sa));else b=I;return Ya--,b===E&&(c=E,0===Ya&&d(qa)),b}function w(){var b,c,e;for(Ya++,b=Sa,c=[],e=v();e!==E;)c.push(e),e=v();return c!==E&&(c=a.substring(b,Sa)),b=c,Ya--,b===E&&(c=E,0===Ya&&d(ta)),b}function x(){var b;return ua.test(a.charAt(Sa))?(b=a.charAt(Sa),Sa++):(b=E,0===Ya&&d(va)),b}function y(){var b;return wa.test(a.charAt(Sa))?(b=a.charAt(Sa),Sa++):(b=E,0===Ya&&d(xa)),b}function z(){var b,c,e,f,g,h;if(b=Sa,48===a.charCodeAt(Sa)?(c=ya,Sa++):(c=E,0===Ya&&d(za)),c===E){if(c=Sa,e=Sa,Aa.test(a.charAt(Sa))?(f=a.charAt(Sa),Sa++):(f=E,0===Ya&&d(Ba)),f!==E){for(g=[],h=x();h!==E;)g.push(h),h=x();g!==E?(f=[f,g],e=f):(Sa=e,e=I)}else Sa=e,e=I;e!==E&&(e=a.substring(c,Sa)),c=e}return c!==E&&(Ta=b,c=Ca(c)),b=c}function A(){var b,c,e,f,g,h,i,j;return Da.test(a.charAt(Sa))?(b=a.charAt(Sa),Sa++):(b=E,0===Ya&&d(Ea)),b===E&&(b=Sa,a.substr(Sa,2)===Fa?(c=Fa,Sa+=2):(c=E,0===Ya&&d(Ga)),c!==E&&(Ta=b,c=Ha()),b=c,b===E&&(b=Sa,a.substr(Sa,2)===Ia?(c=Ia,Sa+=2):(c=E,0===Ya&&d(Ja)),c!==E&&(Ta=b,c=Ka()),b=c,b===E&&(b=Sa,a.substr(Sa,2)===La?(c=La,Sa+=2):(c=E,0===Ya&&d(Ma)),c!==E&&(Ta=b,c=Na()),b=c,b===E&&(b=Sa,a.substr(Sa,2)===Oa?(c=Oa,Sa+=2):(c=E,0===Ya&&d(Pa)),c!==E?(e=Sa,f=Sa,g=y(),g!==E?(h=y(),h!==E?(i=y(),i!==E?(j=y(),j!==E?(g=[g,h,i,j],f=g):(Sa=f,f=I)):(Sa=f,f=I)):(Sa=f,f=I)):(Sa=f,f=I),f!==E&&(f=a.substring(e,Sa)),e=f,e!==E?(Ta=b,c=Qa(e),b=c):(Sa=b,b=I)):(Sa=b,b=I))))),b}function B(){var a,b,c;if(a=Sa,b=[],c=A(),c!==E)for(;c!==E;)b.push(c),c=A();else b=I;return b!==E&&(Ta=a,b=Ra(b)),a=b}var C,D=arguments.length>1?arguments[1]:{},E={},F={start:f},G=f,H=function(a){return{type:"messageFormatPattern",elements:a}},I=E,J=function(a){var b,c,d,e,f,g="";for(b=0,d=a.length;d>b;b+=1)for(e=a[b],c=0,f=e.length;f>c;c+=1)g+=e[c];return g},K=function(a){return{type:"messageTextElement",value:a}},L=/^[^ \t\n\r,.+={}#]/,M={type:"class",value:"[^ \\t\\n\\r,.+={}#]",description:"[^ \\t\\n\\r,.+={}#]"},N="{",O={type:"literal",value:"{",description:'"{"'},P=null,Q=",",R={type:"literal",value:",",description:'","'},S="}",T={type:"literal",value:"}",description:'"}"'},U=function(a,b){return{type:"argumentElement",id:a,format:b&&b[2]}},V="number",W={type:"literal",value:"number",description:'"number"'},X="date",Y={type:"literal",value:"date",description:'"date"'},Z="time",$={type:"literal",value:"time",description:'"time"'},_=function(a,b){return{type:a+"Format",style:b&&b[2]}},aa="plural",ba={type:"literal",value:"plural",description:'"plural"'},ca=function(a){return{type:a.type,ordinal:!1,offset:a.offset||0,options:a.options}},da="selectordinal",ea={type:"literal",value:"selectordinal",description:'"selectordinal"'},fa=function(a){return{type:a.type,ordinal:!0,offset:a.offset||0,options:a.options}},ga="select",ha={type:"literal",value:"select",description:'"select"'},ia=function(a){return{type:"selectFormat",options:a}},ja="=",ka={type:"literal",value:"=",description:'"="'},la=function(a,b){return{type:"optionalFormatPattern",selector:a,value:b}},ma="offset:",na={type:"literal",value:"offset:",description:'"offset:"'},oa=function(a){return a},pa=function(a,b){return{type:"pluralFormat",offset:a,options:b}},qa={type:"other",description:"whitespace"},ra=/^[ \t\n\r]/,sa={type:"class",value:"[ \\t\\n\\r]",description:"[ \\t\\n\\r]"},ta={type:"other",description:"optionalWhitespace"},ua=/^[0-9]/,va={type:"class",value:"[0-9]",description:"[0-9]"},wa=/^[0-9a-f]/i,xa={type:"class",value:"[0-9a-f]i",description:"[0-9a-f]i"},ya="0",za={type:"literal",value:"0",description:'"0"'},Aa=/^[1-9]/,Ba={type:"class",value:"[1-9]",description:"[1-9]"},Ca=function(a){return parseInt(a,10)},Da=/^[^{}\\\0-\x1F \t\n\r]/,Ea={type:"class",value:"[^{}\\\\\\0-\\x1F \\t\\n\\r]",description:"[^{}\\\\\\0-\\x1F \\t\\n\\r]"},Fa="\\#",Ga={type:"literal",value:"\\#",description:'"\\\\#"'},Ha=function(){return"\\#"},Ia="\\{",Ja={type:"literal",value:"\\{",description:'"\\\\{"'},Ka=function(){return"{"},La="\\}",Ma={type:"literal",value:"\\}",description:'"\\\\}"'},Na=function(){return"}"},Oa="\\u",Pa={type:"literal",value:"\\u",description:'"\\\\u"'},Qa=function(a){return String.fromCharCode(parseInt(a,16))},Ra=function(a){return a.join("")},Sa=0,Ta=0,Ua=0,Va={line:1,column:1,seenCR:!1},Wa=0,Xa=[],Ya=0;if("startRule"in D){if(!(D.startRule in F))throw new Error("Can't start parsing from rule \""+D.startRule+'".');G=F[D.startRule]}if(C=G(),C!==E&&Sa===a.length)return C;throw C!==E&&Sa<a.length&&d({type:"end",description:"end of input"}),e(null,Xa,Wa)}return a(b,Error),{SyntaxError:b,parse:c}}(),v=g;r(g,"formats",{enumerable:!0,value:{number:{currency:{style:"currency"},percent:{style:"percent"}},date:{"short":{month:"numeric",day:"numeric",year:"2-digit"},medium:{month:"short",day:"numeric",year:"numeric"},"long":{month:"long",day:"numeric",year:"numeric"},full:{weekday:"long",month:"long",day:"numeric",year:"numeric"}},time:{"short":{hour:"numeric",minute:"numeric"},medium:{hour:"numeric",minute:"numeric",second:"numeric"},"long":{hour:"numeric",minute:"numeric",second:"numeric",timeZoneName:"short"},full:{hour:"numeric",minute:"numeric",second:"numeric",timeZoneName:"short"}}}}),r(g,"__localeData__",{value:s(null)}),r(g,"__addLocaleData",{value:function(a){if(!a||!a.locale)throw new Error("Locale data provided to IntlMessageFormat is missing a `locale` property");g.__localeData__[a.locale.toLowerCase()]=a}}),r(g,"__parse",{value:u.parse}),r(g,"defaultLocale",{enumerable:!0,writable:!0,value:void 0}),g.prototype.resolvedOptions=function(){return{locale:this._locale}},g.prototype._compilePattern=function(a,b,c,d){var e=new t(b,c,d);return e.compile(a)},g.prototype._findPluralRuleFunction=function(a){for(var b=g.__localeData__,c=b[a.toLowerCase()];c;){if(c.pluralRuleFunction)return c.pluralRuleFunction;c=c.parentLocale&&b[c.parentLocale.toLowerCase()]}throw new Error("Locale data added to IntlMessageFormat is missing a `pluralRuleFunction` for :"+a)},g.prototype._format=function(a,b){var c,d,e,f,g,h="";for(c=0,d=a.length;d>c;c+=1)if(e=a[c],"string"!=typeof e){if(f=e.id,!b||!p.call(b,f))throw new Error("A value must be provided for: "+f);g=b[f],h+=e.options?this._format(e.getOption(g),b):e.format(g)}else h+=e;return h},g.prototype._mergeFormats=function(b,c){var d,e,f={};for(d in b)p.call(b,d)&&(f[d]=e=s(b[d]),c&&p.call(c,d)&&a(e,c[d]));return f},g.prototype._resolveLocale=function(a){"string"==typeof a&&(a=[a]),a=(a||[]).concat(g.defaultLocale);var b,c,d,e,f=g.__localeData__;for(b=0,c=a.length;c>b;b+=1)for(d=a[b].toLowerCase().split("-");d.length;){if(e=f[d.join("-")])return e.locale;d.pop()}var h=a.pop();throw new Error("No locale data has been added to IntlMessageFormat for: "+a.join(", ")+", or the default locale: "+h)};var w={locale:"en",pluralRuleFunction:function(a,b){var c=String(a).split("."),d=!c[1],e=Number(c[0])==a,f=e&&c[0].slice(-1),g=e&&c[0].slice(-2);return b?1==f&&11!=g?"one":2==f&&12!=g?"two":3==f&&13!=g?"few":"other":1==a&&d?"one":"other"}};v.__addLocaleData(w),v.defaultLocale="en";var x=v,y=Math.round,z=function(a,b){a=+a,b=+b;var c=y(b-a),d=y(c/1e3),e=y(d/60),f=y(e/60),g=y(f/24),i=y(g/7),j=h(g),k=y(12*j),l=y(j);return{millisecond:c,second:d,minute:e,hour:f,day:g,week:i,month:k,year:l}},A=Object.prototype.hasOwnProperty,B=Object.prototype.toString,C=function(){try{return!!Object.defineProperty({},"a",{})}catch(a){return!1}}(),D=(!C&&!Object.prototype.__defineGetter__,C?Object.defineProperty:function(a,b,c){"get"in c&&a.__defineGetter__?a.__defineGetter__(b,c.get):(!A.call(a,b)||"value"in c)&&(a[b]=c.value)}),E=Object.create||function(a,b){function c(){}var d,e;c.prototype=a,d=new c;for(e in b)A.call(b,e)&&D(d,e,b[e]);return d},F=Array.prototype.indexOf||function(a,b){var c=this;if(!c.length)return-1;for(var d=b||0,e=c.length;e>d;d++)if(c[d]===a)return d;return-1},G=Array.isArray||function(a){return"[object Array]"===B.call(a)},H=Date.now||function(){return(new Date).getTime()},I=i,J=["second","minute","hour","day","month","year"],K=["best fit","numeric"];D(i,"__localeData__",{value:E(null)}),D(i,"__addLocaleData",{value:function(a){if(!a||!a.locale)throw new Error("Locale data provided to IntlRelativeFormat is missing a `locale` property value");i.__localeData__[a.locale.toLowerCase()]=a,x.__addLocaleData(a)}}),D(i,"defaultLocale",{enumerable:!0,writable:!0,value:void 0}),D(i,"thresholds",{enumerable:!0,value:{second:45,minute:45,hour:22,day:26,month:11}}),i.prototype.resolvedOptions=function(){return{locale:this._locale,style:this._options.style,units:this._options.units}},i.prototype._compileMessage=function(a){var b,c=this._locales,d=(this._locale,this._fields[a]),e=d.relativeTime,f="",g="";for(b in e.future)e.future.hasOwnProperty(b)&&(f+=" "+b+" {"+e.future[b].replace("{0}","#")+"}");for(b in e.past)e.past.hasOwnProperty(b)&&(g+=" "+b+" {"+e.past[b].replace("{0}","#")+"}");var h="{when, select, future {{0, plural, "+f+"}}past {{0, plural, "+g+"}}}";return new x(h,c)},i.prototype._getMessage=function(a){var b=this._messages;return b[a]||(b[a]=this._compileMessage(a)),b[a]},i.prototype._getRelativeUnits=function(a,b){var c=this._fields[b];return c.relative?c.relative[a]:void 0},i.prototype._findFields=function(a){for(var b=i.__localeData__,c=b[a.toLowerCase()];c;){if(c.fields)return c.fields;c=c.parentLocale&&b[c.parentLocale.toLowerCase()]}throw new Error("Locale data added to IntlRelativeFormat is missing `fields` for :"+a)},i.prototype._format=function(a,b){var c=b&&void 0!==b.now?b.now:H();if(void 0===a&&(a=c),!isFinite(c))throw new RangeError("The `now` option provided to IntlRelativeFormat#format() is not in valid range.");if(!isFinite(a))throw new RangeError("The date value provided to IntlRelativeFormat#format() is not in valid range.");var d=z(c,a),e=this._options.units||this._selectUnits(d),f=d[e];if("numeric"!==this._options.style){var g=this._getRelativeUnits(f,e);if(g)return g}return this._getMessage(e).format({0:Math.abs(f),when:0>f?"past":"future"})},i.prototype._isValidUnits=function(a){if(!a||F.call(J,a)>=0)return!0;if("string"==typeof a){var b=/s$/.test(a)&&a.substr(0,a.length-1);if(b&&F.call(J,b)>=0)throw new Error('"'+a+'" is not a valid IntlRelativeFormat `units` value, did you mean: '+b)}throw new Error('"'+a+'" is not a valid IntlRelativeFormat `units` value, it must be one of: "'+J.join('", "')+'"')},i.prototype._resolveLocale=function(a){"string"==typeof a&&(a=[a]),a=(a||[]).concat(i.defaultLocale);var b,c,d,e,f=i.__localeData__;for(b=0,c=a.length;c>b;b+=1)for(d=a[b].toLowerCase().split("-");d.length;){if(e=f[d.join("-")])return e.locale;d.pop()}var g=a.pop();throw new Error("No locale data has been added to IntlRelativeFormat for: "+a.join(", ")+", or the default locale: "+g)},i.prototype._resolveStyle=function(a){if(!a)return K[0];if(F.call(K,a)>=0)return a;throw new Error('"'+a+'" is not a valid IntlRelativeFormat `style` value, it must be one of: "'+K.join('", "')+'"')},i.prototype._selectUnits=function(a){var b,c,d;for(b=0,c=J.length;c>b&&(d=J[b],!(Math.abs(a[d])<i.thresholds[d]));b+=1);return d};var L={locale:"en",pluralRuleFunction:function(a,b){var c=String(a).split("."),d=!c[1],e=Number(c[0])==a,f=e&&c[0].slice(-1),g=e&&c[0].slice(-2);return b?1==f&&11!=g?"one":2==f&&12!=g?"two":3==f&&13!=g?"few":"other":1==a&&d?"one":"other"},fields:{year:{displayName:"Year",relative:{0:"this year",1:"next year","-1":"last year"},relativeTime:{future:{one:"in {0} year",other:"in {0} years"},past:{one:"{0} year ago",other:"{0} years ago"}}},month:{displayName:"Month",relative:{0:"this month",1:"next month","-1":"last month"},relativeTime:{future:{one:"in {0} month",other:"in {0} months"},past:{one:"{0} month ago",other:"{0} months ago"}}},day:{displayName:"Day",relative:{0:"today",1:"tomorrow","-1":"yesterday"},relativeTime:{future:{one:"in {0} day",other:"in {0} days"},past:{one:"{0} day ago",other:"{0} days ago"}}},hour:{displayName:"Hour",relativeTime:{future:{one:"in {0} hour",other:"in {0} hours"},past:{one:"{0} hour ago",other:"{0} hours ago"}}},minute:{displayName:"Minute",relativeTime:{future:{one:"in {0} minute",other:"in {0} minutes"},past:{one:"{0} minute ago",other:"{0} minutes ago"}}},second:{displayName:"Second",relative:{0:"now"},relativeTime:{future:{one:"in {0} second",other:"in {0} seconds"},past:{one:"{0} second ago",other:"{0} seconds ago"}}}}};I.__addLocaleData(L),I.defaultLocale="en";var M=I,N=Object.prototype.hasOwnProperty,O=function(){try{return!!Object.defineProperty({},"a",{})}catch(a){return!1}}(),P=(!O&&!Object.prototype.__defineGetter__,O?Object.defineProperty:function(a,b,c){"get"in c&&a.__defineGetter__?a.__defineGetter__(b,c.get):(!N.call(a,b)||"value"in c)&&(a[b]=c.value)}),Q=Object.create||function(a,b){function c(){}var d,e;c.prototype=a,d=new c;for(e in b)N.call(b,e)&&P(d,e,b[e]);return d},R=j,S=R(Intl.NumberFormat),T=R(Intl.DateTimeFormat),U=R(x),V=R(M),W={locale:"en",pluralRuleFunction:function(a,b){var c=String(a).split("."),d=!c[1],e=Number(c[0])==a,f=e&&c[0].slice(-1),g=e&&c[0].slice(-2);return b?1==f&&11!=g?"one":2==f&&12!=g?"two":3==f&&13!=g?"few":"other":1==a&&d?"one":"other"},fields:{year:{displayName:"Year",relative:{0:"this year",1:"next year","-1":"last year"},relativeTime:{future:{one:"in {0} year",other:"in {0} years"},past:{one:"{0} year ago",other:"{0} years ago"}}},month:{displayName:"Month",relative:{0:"this month",1:"next month","-1":"last month"},relativeTime:{future:{one:"in {0} month",other:"in {0} months"},past:{one:"{0} month ago",other:"{0} months ago"}}},day:{displayName:"Day",relative:{0:"today",1:"tomorrow","-1":"yesterday"},relativeTime:{future:{one:"in {0} day",other:"in {0} days"},past:{one:"{0} day ago",other:"{0} days ago"}}},hour:{displayName:"Hour",relativeTime:{future:{one:"in {0} hour",other:"in {0} hours"},past:{one:"{0} hour ago",other:"{0} hours ago"}}},minute:{displayName:"Minute",relativeTime:{future:{one:"in {0} minute",other:"in {0} minutes"},past:{one:"{0} minute ago",other:"{0} minutes ago"}}},second:{displayName:"Second",relative:{0:"now"},relativeTime:{future:{one:"in {0} second",other:"in {0} seconds"},past:{one:"{0} second ago",other:"{0} seconds ago"}}}}};o(W);var X={registerWith:n,__addLocaleData:o};this.HandlebarsIntl=X}).call(this);
-//# sourceMappingURL=handlebars-intl.min.js.map
\ No newline at end of file
diff --git a/src/Jackett/Content/handlebars.js b/src/Jackett/Content/handlebars.js
deleted file mode 100644
index 2a5cf0df71ba11235a9477d54a51d0a298a74efd..0000000000000000000000000000000000000000
--- a/src/Jackett/Content/handlebars.js
+++ /dev/null
@@ -1,4131 +0,0 @@
-/*!
-
- handlebars v3.0.3
-
-Copyright (C) 2011-2014 by Yehuda Katz
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
-
-@license
-*/
-(function webpackUniversalModuleDefinition(root, factory) {
-	if(typeof exports === 'object' && typeof module === 'object')
-		module.exports = factory();
-	else if(typeof define === 'function' && define.amd)
-		define(factory);
-	else if(typeof exports === 'object')
-		exports["Handlebars"] = factory();
-	else
-		root["Handlebars"] = factory();
-})(this, function() {
-return /******/ (function(modules) { // webpackBootstrap
-/******/ 	// The module cache
-/******/ 	var installedModules = {};
-
-/******/ 	// The require function
-/******/ 	function __webpack_require__(moduleId) {
-
-/******/ 		// Check if module is in cache
-/******/ 		if(installedModules[moduleId])
-/******/ 			return installedModules[moduleId].exports;
-
-/******/ 		// Create a new module (and put it into the cache)
-/******/ 		var module = installedModules[moduleId] = {
-/******/ 			exports: {},
-/******/ 			id: moduleId,
-/******/ 			loaded: false
-/******/ 		};
-
-/******/ 		// Execute the module function
-/******/ 		modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
-
-/******/ 		// Flag the module as loaded
-/******/ 		module.loaded = true;
-
-/******/ 		// Return the exports of the module
-/******/ 		return module.exports;
-/******/ 	}
-
-
-/******/ 	// expose the modules object (__webpack_modules__)
-/******/ 	__webpack_require__.m = modules;
-
-/******/ 	// expose the module cache
-/******/ 	__webpack_require__.c = installedModules;
-
-/******/ 	// __webpack_public_path__
-/******/ 	__webpack_require__.p = "";
-
-/******/ 	// Load entry module and return exports
-/******/ 	return __webpack_require__(0);
-/******/ })
-/************************************************************************/
-/******/ ([
-/* 0 */
-/***/ function(module, exports, __webpack_require__) {
-
-	'use strict';
-
-	var _interopRequireDefault = __webpack_require__(8)['default'];
-
-	exports.__esModule = true;
-
-	var _runtime = __webpack_require__(1);
-
-	var _runtime2 = _interopRequireDefault(_runtime);
-
-	// Compiler imports
-
-	var _AST = __webpack_require__(2);
-
-	var _AST2 = _interopRequireDefault(_AST);
-
-	var _Parser$parse = __webpack_require__(3);
-
-	var _Compiler$compile$precompile = __webpack_require__(4);
-
-	var _JavaScriptCompiler = __webpack_require__(5);
-
-	var _JavaScriptCompiler2 = _interopRequireDefault(_JavaScriptCompiler);
-
-	var _Visitor = __webpack_require__(6);
-
-	var _Visitor2 = _interopRequireDefault(_Visitor);
-
-	var _noConflict = __webpack_require__(7);
-
-	var _noConflict2 = _interopRequireDefault(_noConflict);
-
-	var _create = _runtime2['default'].create;
-	function create() {
-	  var hb = _create();
-
-	  hb.compile = function (input, options) {
-	    return _Compiler$compile$precompile.compile(input, options, hb);
-	  };
-	  hb.precompile = function (input, options) {
-	    return _Compiler$compile$precompile.precompile(input, options, hb);
-	  };
-
-	  hb.AST = _AST2['default'];
-	  hb.Compiler = _Compiler$compile$precompile.Compiler;
-	  hb.JavaScriptCompiler = _JavaScriptCompiler2['default'];
-	  hb.Parser = _Parser$parse.parser;
-	  hb.parse = _Parser$parse.parse;
-
-	  return hb;
-	}
-
-	var inst = create();
-	inst.create = create;
-
-	_noConflict2['default'](inst);
-
-	inst.Visitor = _Visitor2['default'];
-
-	inst['default'] = inst;
-
-	exports['default'] = inst;
-	module.exports = exports['default'];
-
-/***/ },
-/* 1 */
-/***/ function(module, exports, __webpack_require__) {
-
-	'use strict';
-
-	var _interopRequireWildcard = __webpack_require__(9)['default'];
-
-	var _interopRequireDefault = __webpack_require__(8)['default'];
-
-	exports.__esModule = true;
-
-	var _import = __webpack_require__(10);
-
-	var base = _interopRequireWildcard(_import);
-
-	// Each of these augment the Handlebars object. No need to setup here.
-	// (This is done to easily share code between commonjs and browse envs)
-
-	var _SafeString = __webpack_require__(11);
-
-	var _SafeString2 = _interopRequireDefault(_SafeString);
-
-	var _Exception = __webpack_require__(12);
-
-	var _Exception2 = _interopRequireDefault(_Exception);
-
-	var _import2 = __webpack_require__(13);
-
-	var Utils = _interopRequireWildcard(_import2);
-
-	var _import3 = __webpack_require__(14);
-
-	var runtime = _interopRequireWildcard(_import3);
-
-	var _noConflict = __webpack_require__(7);
-
-	var _noConflict2 = _interopRequireDefault(_noConflict);
-
-	// For compatibility and usage outside of module systems, make the Handlebars object a namespace
-	function create() {
-	  var hb = new base.HandlebarsEnvironment();
-
-	  Utils.extend(hb, base);
-	  hb.SafeString = _SafeString2['default'];
-	  hb.Exception = _Exception2['default'];
-	  hb.Utils = Utils;
-	  hb.escapeExpression = Utils.escapeExpression;
-
-	  hb.VM = runtime;
-	  hb.template = function (spec) {
-	    return runtime.template(spec, hb);
-	  };
-
-	  return hb;
-	}
-
-	var inst = create();
-	inst.create = create;
-
-	_noConflict2['default'](inst);
-
-	inst['default'] = inst;
-
-	exports['default'] = inst;
-	module.exports = exports['default'];
-
-/***/ },
-/* 2 */
-/***/ function(module, exports, __webpack_require__) {
-
-	'use strict';
-
-	exports.__esModule = true;
-	var AST = {
-	  Program: function Program(statements, blockParams, strip, locInfo) {
-	    this.loc = locInfo;
-	    this.type = 'Program';
-	    this.body = statements;
-
-	    this.blockParams = blockParams;
-	    this.strip = strip;
-	  },
-
-	  MustacheStatement: function MustacheStatement(path, params, hash, escaped, strip, locInfo) {
-	    this.loc = locInfo;
-	    this.type = 'MustacheStatement';
-
-	    this.path = path;
-	    this.params = params || [];
-	    this.hash = hash;
-	    this.escaped = escaped;
-
-	    this.strip = strip;
-	  },
-
-	  BlockStatement: function BlockStatement(path, params, hash, program, inverse, openStrip, inverseStrip, closeStrip, locInfo) {
-	    this.loc = locInfo;
-	    this.type = 'BlockStatement';
-
-	    this.path = path;
-	    this.params = params || [];
-	    this.hash = hash;
-	    this.program = program;
-	    this.inverse = inverse;
-
-	    this.openStrip = openStrip;
-	    this.inverseStrip = inverseStrip;
-	    this.closeStrip = closeStrip;
-	  },
-
-	  PartialStatement: function PartialStatement(name, params, hash, strip, locInfo) {
-	    this.loc = locInfo;
-	    this.type = 'PartialStatement';
-
-	    this.name = name;
-	    this.params = params || [];
-	    this.hash = hash;
-
-	    this.indent = '';
-	    this.strip = strip;
-	  },
-
-	  ContentStatement: function ContentStatement(string, locInfo) {
-	    this.loc = locInfo;
-	    this.type = 'ContentStatement';
-	    this.original = this.value = string;
-	  },
-
-	  CommentStatement: function CommentStatement(comment, strip, locInfo) {
-	    this.loc = locInfo;
-	    this.type = 'CommentStatement';
-	    this.value = comment;
-
-	    this.strip = strip;
-	  },
-
-	  SubExpression: function SubExpression(path, params, hash, locInfo) {
-	    this.loc = locInfo;
-
-	    this.type = 'SubExpression';
-	    this.path = path;
-	    this.params = params || [];
-	    this.hash = hash;
-	  },
-
-	  PathExpression: function PathExpression(data, depth, parts, original, locInfo) {
-	    this.loc = locInfo;
-	    this.type = 'PathExpression';
-
-	    this.data = data;
-	    this.original = original;
-	    this.parts = parts;
-	    this.depth = depth;
-	  },
-
-	  StringLiteral: function StringLiteral(string, locInfo) {
-	    this.loc = locInfo;
-	    this.type = 'StringLiteral';
-	    this.original = this.value = string;
-	  },
-
-	  NumberLiteral: function NumberLiteral(number, locInfo) {
-	    this.loc = locInfo;
-	    this.type = 'NumberLiteral';
-	    this.original = this.value = Number(number);
-	  },
-
-	  BooleanLiteral: function BooleanLiteral(bool, locInfo) {
-	    this.loc = locInfo;
-	    this.type = 'BooleanLiteral';
-	    this.original = this.value = bool === 'true';
-	  },
-
-	  UndefinedLiteral: function UndefinedLiteral(locInfo) {
-	    this.loc = locInfo;
-	    this.type = 'UndefinedLiteral';
-	    this.original = this.value = undefined;
-	  },
-
-	  NullLiteral: function NullLiteral(locInfo) {
-	    this.loc = locInfo;
-	    this.type = 'NullLiteral';
-	    this.original = this.value = null;
-	  },
-
-	  Hash: function Hash(pairs, locInfo) {
-	    this.loc = locInfo;
-	    this.type = 'Hash';
-	    this.pairs = pairs;
-	  },
-	  HashPair: function HashPair(key, value, locInfo) {
-	    this.loc = locInfo;
-	    this.type = 'HashPair';
-	    this.key = key;
-	    this.value = value;
-	  },
-
-	  // Public API used to evaluate derived attributes regarding AST nodes
-	  helpers: {
-	    // a mustache is definitely a helper if:
-	    // * it is an eligible helper, and
-	    // * it has at least one parameter or hash segment
-	    helperExpression: function helperExpression(node) {
-	      return !!(node.type === 'SubExpression' || node.params.length || node.hash);
-	    },
-
-	    scopedId: function scopedId(path) {
-	      return /^\.|this\b/.test(path.original);
-	    },
-
-	    // an ID is simple if it only has one part, and that part is not
-	    // `..` or `this`.
-	    simpleId: function simpleId(path) {
-	      return path.parts.length === 1 && !AST.helpers.scopedId(path) && !path.depth;
-	    }
-	  }
-	};
-
-	// Must be exported as an object rather than the root of the module as the jison lexer
-	// must modify the object to operate properly.
-	exports['default'] = AST;
-	module.exports = exports['default'];
-
-/***/ },
-/* 3 */
-/***/ function(module, exports, __webpack_require__) {
-
-	'use strict';
-
-	var _interopRequireDefault = __webpack_require__(8)['default'];
-
-	var _interopRequireWildcard = __webpack_require__(9)['default'];
-
-	exports.__esModule = true;
-	exports.parse = parse;
-
-	var _parser = __webpack_require__(15);
-
-	var _parser2 = _interopRequireDefault(_parser);
-
-	var _AST = __webpack_require__(2);
-
-	var _AST2 = _interopRequireDefault(_AST);
-
-	var _WhitespaceControl = __webpack_require__(16);
-
-	var _WhitespaceControl2 = _interopRequireDefault(_WhitespaceControl);
-
-	var _import = __webpack_require__(17);
-
-	var Helpers = _interopRequireWildcard(_import);
-
-	var _extend = __webpack_require__(13);
-
-	exports.parser = _parser2['default'];
-
-	var yy = {};
-	_extend.extend(yy, Helpers, _AST2['default']);
-
-	function parse(input, options) {
-	  // Just return if an already-compiled AST was passed in.
-	  if (input.type === 'Program') {
-	    return input;
-	  }
-
-	  _parser2['default'].yy = yy;
-
-	  // Altering the shared object here, but this is ok as parser is a sync operation
-	  yy.locInfo = function (locInfo) {
-	    return new yy.SourceLocation(options && options.srcName, locInfo);
-	  };
-
-	  var strip = new _WhitespaceControl2['default']();
-	  return strip.accept(_parser2['default'].parse(input));
-	}
-
-/***/ },
-/* 4 */
-/***/ function(module, exports, __webpack_require__) {
-
-	'use strict';
-
-	var _interopRequireDefault = __webpack_require__(8)['default'];
-
-	exports.__esModule = true;
-	exports.Compiler = Compiler;
-	exports.precompile = precompile;
-	exports.compile = compile;
-
-	var _Exception = __webpack_require__(12);
-
-	var _Exception2 = _interopRequireDefault(_Exception);
-
-	var _isArray$indexOf = __webpack_require__(13);
-
-	var _AST = __webpack_require__(2);
-
-	var _AST2 = _interopRequireDefault(_AST);
-
-	var slice = [].slice;
-
-	function Compiler() {}
-
-	// the foundHelper register will disambiguate helper lookup from finding a
-	// function in a context. This is necessary for mustache compatibility, which
-	// requires that context functions in blocks are evaluated by blockHelperMissing,
-	// and then proceed as if the resulting value was provided to blockHelperMissing.
-
-	Compiler.prototype = {
-	  compiler: Compiler,
-
-	  equals: function equals(other) {
-	    var len = this.opcodes.length;
-	    if (other.opcodes.length !== len) {
-	      return false;
-	    }
-
-	    for (var i = 0; i < len; i++) {
-	      var opcode = this.opcodes[i],
-	          otherOpcode = other.opcodes[i];
-	      if (opcode.opcode !== otherOpcode.opcode || !argEquals(opcode.args, otherOpcode.args)) {
-	        return false;
-	      }
-	    }
-
-	    // We know that length is the same between the two arrays because they are directly tied
-	    // to the opcode behavior above.
-	    len = this.children.length;
-	    for (var i = 0; i < len; i++) {
-	      if (!this.children[i].equals(other.children[i])) {
-	        return false;
-	      }
-	    }
-
-	    return true;
-	  },
-
-	  guid: 0,
-
-	  compile: function compile(program, options) {
-	    this.sourceNode = [];
-	    this.opcodes = [];
-	    this.children = [];
-	    this.options = options;
-	    this.stringParams = options.stringParams;
-	    this.trackIds = options.trackIds;
-
-	    options.blockParams = options.blockParams || [];
-
-	    // These changes will propagate to the other compiler components
-	    var knownHelpers = options.knownHelpers;
-	    options.knownHelpers = {
-	      helperMissing: true,
-	      blockHelperMissing: true,
-	      each: true,
-	      'if': true,
-	      unless: true,
-	      'with': true,
-	      log: true,
-	      lookup: true
-	    };
-	    if (knownHelpers) {
-	      for (var _name in knownHelpers) {
-	        if (_name in knownHelpers) {
-	          options.knownHelpers[_name] = knownHelpers[_name];
-	        }
-	      }
-	    }
-
-	    return this.accept(program);
-	  },
-
-	  compileProgram: function compileProgram(program) {
-	    var childCompiler = new this.compiler(),
-	        // eslint-disable-line new-cap
-	    result = childCompiler.compile(program, this.options),
-	        guid = this.guid++;
-
-	    this.usePartial = this.usePartial || result.usePartial;
-
-	    this.children[guid] = result;
-	    this.useDepths = this.useDepths || result.useDepths;
-
-	    return guid;
-	  },
-
-	  accept: function accept(node) {
-	    this.sourceNode.unshift(node);
-	    var ret = this[node.type](node);
-	    this.sourceNode.shift();
-	    return ret;
-	  },
-
-	  Program: function Program(program) {
-	    this.options.blockParams.unshift(program.blockParams);
-
-	    var body = program.body,
-	        bodyLength = body.length;
-	    for (var i = 0; i < bodyLength; i++) {
-	      this.accept(body[i]);
-	    }
-
-	    this.options.blockParams.shift();
-
-	    this.isSimple = bodyLength === 1;
-	    this.blockParams = program.blockParams ? program.blockParams.length : 0;
-
-	    return this;
-	  },
-
-	  BlockStatement: function BlockStatement(block) {
-	    transformLiteralToPath(block);
-
-	    var program = block.program,
-	        inverse = block.inverse;
-
-	    program = program && this.compileProgram(program);
-	    inverse = inverse && this.compileProgram(inverse);
-
-	    var type = this.classifySexpr(block);
-
-	    if (type === 'helper') {
-	      this.helperSexpr(block, program, inverse);
-	    } else if (type === 'simple') {
-	      this.simpleSexpr(block);
-
-	      // now that the simple mustache is resolved, we need to
-	      // evaluate it by executing `blockHelperMissing`
-	      this.opcode('pushProgram', program);
-	      this.opcode('pushProgram', inverse);
-	      this.opcode('emptyHash');
-	      this.opcode('blockValue', block.path.original);
-	    } else {
-	      this.ambiguousSexpr(block, program, inverse);
-
-	      // now that the simple mustache is resolved, we need to
-	      // evaluate it by executing `blockHelperMissing`
-	      this.opcode('pushProgram', program);
-	      this.opcode('pushProgram', inverse);
-	      this.opcode('emptyHash');
-	      this.opcode('ambiguousBlockValue');
-	    }
-
-	    this.opcode('append');
-	  },
-
-	  PartialStatement: function PartialStatement(partial) {
-	    this.usePartial = true;
-
-	    var params = partial.params;
-	    if (params.length > 1) {
-	      throw new _Exception2['default']('Unsupported number of partial arguments: ' + params.length, partial);
-	    } else if (!params.length) {
-	      params.push({ type: 'PathExpression', parts: [], depth: 0 });
-	    }
-
-	    var partialName = partial.name.original,
-	        isDynamic = partial.name.type === 'SubExpression';
-	    if (isDynamic) {
-	      this.accept(partial.name);
-	    }
-
-	    this.setupFullMustacheParams(partial, undefined, undefined, true);
-
-	    var indent = partial.indent || '';
-	    if (this.options.preventIndent && indent) {
-	      this.opcode('appendContent', indent);
-	      indent = '';
-	    }
-
-	    this.opcode('invokePartial', isDynamic, partialName, indent);
-	    this.opcode('append');
-	  },
-
-	  MustacheStatement: function MustacheStatement(mustache) {
-	    this.SubExpression(mustache); // eslint-disable-line new-cap
-
-	    if (mustache.escaped && !this.options.noEscape) {
-	      this.opcode('appendEscaped');
-	    } else {
-	      this.opcode('append');
-	    }
-	  },
-
-	  ContentStatement: function ContentStatement(content) {
-	    if (content.value) {
-	      this.opcode('appendContent', content.value);
-	    }
-	  },
-
-	  CommentStatement: function CommentStatement() {},
-
-	  SubExpression: function SubExpression(sexpr) {
-	    transformLiteralToPath(sexpr);
-	    var type = this.classifySexpr(sexpr);
-
-	    if (type === 'simple') {
-	      this.simpleSexpr(sexpr);
-	    } else if (type === 'helper') {
-	      this.helperSexpr(sexpr);
-	    } else {
-	      this.ambiguousSexpr(sexpr);
-	    }
-	  },
-	  ambiguousSexpr: function ambiguousSexpr(sexpr, program, inverse) {
-	    var path = sexpr.path,
-	        name = path.parts[0],
-	        isBlock = program != null || inverse != null;
-
-	    this.opcode('getContext', path.depth);
-
-	    this.opcode('pushProgram', program);
-	    this.opcode('pushProgram', inverse);
-
-	    this.accept(path);
-
-	    this.opcode('invokeAmbiguous', name, isBlock);
-	  },
-
-	  simpleSexpr: function simpleSexpr(sexpr) {
-	    this.accept(sexpr.path);
-	    this.opcode('resolvePossibleLambda');
-	  },
-
-	  helperSexpr: function helperSexpr(sexpr, program, inverse) {
-	    var params = this.setupFullMustacheParams(sexpr, program, inverse),
-	        path = sexpr.path,
-	        name = path.parts[0];
-
-	    if (this.options.knownHelpers[name]) {
-	      this.opcode('invokeKnownHelper', params.length, name);
-	    } else if (this.options.knownHelpersOnly) {
-	      throw new _Exception2['default']('You specified knownHelpersOnly, but used the unknown helper ' + name, sexpr);
-	    } else {
-	      path.falsy = true;
-
-	      this.accept(path);
-	      this.opcode('invokeHelper', params.length, path.original, _AST2['default'].helpers.simpleId(path));
-	    }
-	  },
-
-	  PathExpression: function PathExpression(path) {
-	    this.addDepth(path.depth);
-	    this.opcode('getContext', path.depth);
-
-	    var name = path.parts[0],
-	        scoped = _AST2['default'].helpers.scopedId(path),
-	        blockParamId = !path.depth && !scoped && this.blockParamIndex(name);
-
-	    if (blockParamId) {
-	      this.opcode('lookupBlockParam', blockParamId, path.parts);
-	    } else if (!name) {
-	      // Context reference, i.e. `{{foo .}}` or `{{foo ..}}`
-	      this.opcode('pushContext');
-	    } else if (path.data) {
-	      this.options.data = true;
-	      this.opcode('lookupData', path.depth, path.parts);
-	    } else {
-	      this.opcode('lookupOnContext', path.parts, path.falsy, scoped);
-	    }
-	  },
-
-	  StringLiteral: function StringLiteral(string) {
-	    this.opcode('pushString', string.value);
-	  },
-
-	  NumberLiteral: function NumberLiteral(number) {
-	    this.opcode('pushLiteral', number.value);
-	  },
-
-	  BooleanLiteral: function BooleanLiteral(bool) {
-	    this.opcode('pushLiteral', bool.value);
-	  },
-
-	  UndefinedLiteral: function UndefinedLiteral() {
-	    this.opcode('pushLiteral', 'undefined');
-	  },
-
-	  NullLiteral: function NullLiteral() {
-	    this.opcode('pushLiteral', 'null');
-	  },
-
-	  Hash: function Hash(hash) {
-	    var pairs = hash.pairs,
-	        i = 0,
-	        l = pairs.length;
-
-	    this.opcode('pushHash');
-
-	    for (; i < l; i++) {
-	      this.pushParam(pairs[i].value);
-	    }
-	    while (i--) {
-	      this.opcode('assignToHash', pairs[i].key);
-	    }
-	    this.opcode('popHash');
-	  },
-
-	  // HELPERS
-	  opcode: function opcode(name) {
-	    this.opcodes.push({ opcode: name, args: slice.call(arguments, 1), loc: this.sourceNode[0].loc });
-	  },
-
-	  addDepth: function addDepth(depth) {
-	    if (!depth) {
-	      return;
-	    }
-
-	    this.useDepths = true;
-	  },
-
-	  classifySexpr: function classifySexpr(sexpr) {
-	    var isSimple = _AST2['default'].helpers.simpleId(sexpr.path);
-
-	    var isBlockParam = isSimple && !!this.blockParamIndex(sexpr.path.parts[0]);
-
-	    // a mustache is an eligible helper if:
-	    // * its id is simple (a single part, not `this` or `..`)
-	    var isHelper = !isBlockParam && _AST2['default'].helpers.helperExpression(sexpr);
-
-	    // if a mustache is an eligible helper but not a definite
-	    // helper, it is ambiguous, and will be resolved in a later
-	    // pass or at runtime.
-	    var isEligible = !isBlockParam && (isHelper || isSimple);
-
-	    // if ambiguous, we can possibly resolve the ambiguity now
-	    // An eligible helper is one that does not have a complex path, i.e. `this.foo`, `../foo` etc.
-	    if (isEligible && !isHelper) {
-	      var _name2 = sexpr.path.parts[0],
-	          options = this.options;
-
-	      if (options.knownHelpers[_name2]) {
-	        isHelper = true;
-	      } else if (options.knownHelpersOnly) {
-	        isEligible = false;
-	      }
-	    }
-
-	    if (isHelper) {
-	      return 'helper';
-	    } else if (isEligible) {
-	      return 'ambiguous';
-	    } else {
-	      return 'simple';
-	    }
-	  },
-
-	  pushParams: function pushParams(params) {
-	    for (var i = 0, l = params.length; i < l; i++) {
-	      this.pushParam(params[i]);
-	    }
-	  },
-
-	  pushParam: function pushParam(val) {
-	    var value = val.value != null ? val.value : val.original || '';
-
-	    if (this.stringParams) {
-	      if (value.replace) {
-	        value = value.replace(/^(\.?\.\/)*/g, '').replace(/\//g, '.');
-	      }
-
-	      if (val.depth) {
-	        this.addDepth(val.depth);
-	      }
-	      this.opcode('getContext', val.depth || 0);
-	      this.opcode('pushStringParam', value, val.type);
-
-	      if (val.type === 'SubExpression') {
-	        // SubExpressions get evaluated and passed in
-	        // in string params mode.
-	        this.accept(val);
-	      }
-	    } else {
-	      if (this.trackIds) {
-	        var blockParamIndex = undefined;
-	        if (val.parts && !_AST2['default'].helpers.scopedId(val) && !val.depth) {
-	          blockParamIndex = this.blockParamIndex(val.parts[0]);
-	        }
-	        if (blockParamIndex) {
-	          var blockParamChild = val.parts.slice(1).join('.');
-	          this.opcode('pushId', 'BlockParam', blockParamIndex, blockParamChild);
-	        } else {
-	          value = val.original || value;
-	          if (value.replace) {
-	            value = value.replace(/^\.\//g, '').replace(/^\.$/g, '');
-	          }
-
-	          this.opcode('pushId', val.type, value);
-	        }
-	      }
-	      this.accept(val);
-	    }
-	  },
-
-	  setupFullMustacheParams: function setupFullMustacheParams(sexpr, program, inverse, omitEmpty) {
-	    var params = sexpr.params;
-	    this.pushParams(params);
-
-	    this.opcode('pushProgram', program);
-	    this.opcode('pushProgram', inverse);
-
-	    if (sexpr.hash) {
-	      this.accept(sexpr.hash);
-	    } else {
-	      this.opcode('emptyHash', omitEmpty);
-	    }
-
-	    return params;
-	  },
-
-	  blockParamIndex: function blockParamIndex(name) {
-	    for (var depth = 0, len = this.options.blockParams.length; depth < len; depth++) {
-	      var blockParams = this.options.blockParams[depth],
-	          param = blockParams && _isArray$indexOf.indexOf(blockParams, name);
-	      if (blockParams && param >= 0) {
-	        return [depth, param];
-	      }
-	    }
-	  }
-	};
-
-	function precompile(input, options, env) {
-	  if (input == null || typeof input !== 'string' && input.type !== 'Program') {
-	    throw new _Exception2['default']('You must pass a string or Handlebars AST to Handlebars.precompile. You passed ' + input);
-	  }
-
-	  options = options || {};
-	  if (!('data' in options)) {
-	    options.data = true;
-	  }
-	  if (options.compat) {
-	    options.useDepths = true;
-	  }
-
-	  var ast = env.parse(input, options),
-	      environment = new env.Compiler().compile(ast, options);
-	  return new env.JavaScriptCompiler().compile(environment, options);
-	}
-
-	function compile(input, _x, env) {
-	  var options = arguments[1] === undefined ? {} : arguments[1];
-
-	  if (input == null || typeof input !== 'string' && input.type !== 'Program') {
-	    throw new _Exception2['default']('You must pass a string or Handlebars AST to Handlebars.compile. You passed ' + input);
-	  }
-
-	  if (!('data' in options)) {
-	    options.data = true;
-	  }
-	  if (options.compat) {
-	    options.useDepths = true;
-	  }
-
-	  var compiled = undefined;
-
-	  function compileInput() {
-	    var ast = env.parse(input, options),
-	        environment = new env.Compiler().compile(ast, options),
-	        templateSpec = new env.JavaScriptCompiler().compile(environment, options, undefined, true);
-	    return env.template(templateSpec);
-	  }
-
-	  // Template is only compiled on first use and cached after that point.
-	  function ret(context, execOptions) {
-	    if (!compiled) {
-	      compiled = compileInput();
-	    }
-	    return compiled.call(this, context, execOptions);
-	  }
-	  ret._setup = function (setupOptions) {
-	    if (!compiled) {
-	      compiled = compileInput();
-	    }
-	    return compiled._setup(setupOptions);
-	  };
-	  ret._child = function (i, data, blockParams, depths) {
-	    if (!compiled) {
-	      compiled = compileInput();
-	    }
-	    return compiled._child(i, data, blockParams, depths);
-	  };
-	  return ret;
-	}
-
-	function argEquals(a, b) {
-	  if (a === b) {
-	    return true;
-	  }
-
-	  if (_isArray$indexOf.isArray(a) && _isArray$indexOf.isArray(b) && a.length === b.length) {
-	    for (var i = 0; i < a.length; i++) {
-	      if (!argEquals(a[i], b[i])) {
-	        return false;
-	      }
-	    }
-	    return true;
-	  }
-	}
-
-	function transformLiteralToPath(sexpr) {
-	  if (!sexpr.path.parts) {
-	    var literal = sexpr.path;
-	    // Casting to string here to make false and 0 literal values play nicely with the rest
-	    // of the system.
-	    sexpr.path = new _AST2['default'].PathExpression(false, 0, [literal.original + ''], literal.original + '', literal.loc);
-	  }
-	}
-
-/***/ },
-/* 5 */
-/***/ function(module, exports, __webpack_require__) {
-
-	'use strict';
-
-	var _interopRequireDefault = __webpack_require__(8)['default'];
-
-	exports.__esModule = true;
-
-	var _COMPILER_REVISION$REVISION_CHANGES = __webpack_require__(10);
-
-	var _Exception = __webpack_require__(12);
-
-	var _Exception2 = _interopRequireDefault(_Exception);
-
-	var _isArray = __webpack_require__(13);
-
-	var _CodeGen = __webpack_require__(18);
-
-	var _CodeGen2 = _interopRequireDefault(_CodeGen);
-
-	function Literal(value) {
-	  this.value = value;
-	}
-
-	function JavaScriptCompiler() {}
-
-	JavaScriptCompiler.prototype = {
-	  // PUBLIC API: You can override these methods in a subclass to provide
-	  // alternative compiled forms for name lookup and buffering semantics
-	  nameLookup: function nameLookup(parent, name /* , type*/) {
-	    if (JavaScriptCompiler.isValidJavaScriptVariableName(name)) {
-	      return [parent, '.', name];
-	    } else {
-	      return [parent, '[\'', name, '\']'];
-	    }
-	  },
-	  depthedLookup: function depthedLookup(name) {
-	    return [this.aliasable('this.lookup'), '(depths, "', name, '")'];
-	  },
-
-	  compilerInfo: function compilerInfo() {
-	    var revision = _COMPILER_REVISION$REVISION_CHANGES.COMPILER_REVISION,
-	        versions = _COMPILER_REVISION$REVISION_CHANGES.REVISION_CHANGES[revision];
-	    return [revision, versions];
-	  },
-
-	  appendToBuffer: function appendToBuffer(source, location, explicit) {
-	    // Force a source as this simplifies the merge logic.
-	    if (!_isArray.isArray(source)) {
-	      source = [source];
-	    }
-	    source = this.source.wrap(source, location);
-
-	    if (this.environment.isSimple) {
-	      return ['return ', source, ';'];
-	    } else if (explicit) {
-	      // This is a case where the buffer operation occurs as a child of another
-	      // construct, generally braces. We have to explicitly output these buffer
-	      // operations to ensure that the emitted code goes in the correct location.
-	      return ['buffer += ', source, ';'];
-	    } else {
-	      source.appendToBuffer = true;
-	      return source;
-	    }
-	  },
-
-	  initializeBuffer: function initializeBuffer() {
-	    return this.quotedString('');
-	  },
-	  // END PUBLIC API
-
-	  compile: function compile(environment, options, context, asObject) {
-	    this.environment = environment;
-	    this.options = options;
-	    this.stringParams = this.options.stringParams;
-	    this.trackIds = this.options.trackIds;
-	    this.precompile = !asObject;
-
-	    this.name = this.environment.name;
-	    this.isChild = !!context;
-	    this.context = context || {
-	      programs: [],
-	      environments: []
-	    };
-
-	    this.preamble();
-
-	    this.stackSlot = 0;
-	    this.stackVars = [];
-	    this.aliases = {};
-	    this.registers = { list: [] };
-	    this.hashes = [];
-	    this.compileStack = [];
-	    this.inlineStack = [];
-	    this.blockParams = [];
-
-	    this.compileChildren(environment, options);
-
-	    this.useDepths = this.useDepths || environment.useDepths || this.options.compat;
-	    this.useBlockParams = this.useBlockParams || environment.useBlockParams;
-
-	    var opcodes = environment.opcodes,
-	        opcode = undefined,
-	        firstLoc = undefined,
-	        i = undefined,
-	        l = undefined;
-
-	    for (i = 0, l = opcodes.length; i < l; i++) {
-	      opcode = opcodes[i];
-
-	      this.source.currentLocation = opcode.loc;
-	      firstLoc = firstLoc || opcode.loc;
-	      this[opcode.opcode].apply(this, opcode.args);
-	    }
-
-	    // Flush any trailing content that might be pending.
-	    this.source.currentLocation = firstLoc;
-	    this.pushSource('');
-
-	    /* istanbul ignore next */
-	    if (this.stackSlot || this.inlineStack.length || this.compileStack.length) {
-	      throw new _Exception2['default']('Compile completed with content left on stack');
-	    }
-
-	    var fn = this.createFunctionContext(asObject);
-	    if (!this.isChild) {
-	      var ret = {
-	        compiler: this.compilerInfo(),
-	        main: fn
-	      };
-	      var programs = this.context.programs;
-	      for (i = 0, l = programs.length; i < l; i++) {
-	        if (programs[i]) {
-	          ret[i] = programs[i];
-	        }
-	      }
-
-	      if (this.environment.usePartial) {
-	        ret.usePartial = true;
-	      }
-	      if (this.options.data) {
-	        ret.useData = true;
-	      }
-	      if (this.useDepths) {
-	        ret.useDepths = true;
-	      }
-	      if (this.useBlockParams) {
-	        ret.useBlockParams = true;
-	      }
-	      if (this.options.compat) {
-	        ret.compat = true;
-	      }
-
-	      if (!asObject) {
-	        ret.compiler = JSON.stringify(ret.compiler);
-
-	        this.source.currentLocation = { start: { line: 1, column: 0 } };
-	        ret = this.objectLiteral(ret);
-
-	        if (options.srcName) {
-	          ret = ret.toStringWithSourceMap({ file: options.destName });
-	          ret.map = ret.map && ret.map.toString();
-	        } else {
-	          ret = ret.toString();
-	        }
-	      } else {
-	        ret.compilerOptions = this.options;
-	      }
-
-	      return ret;
-	    } else {
-	      return fn;
-	    }
-	  },
-
-	  preamble: function preamble() {
-	    // track the last context pushed into place to allow skipping the
-	    // getContext opcode when it would be a noop
-	    this.lastContext = 0;
-	    this.source = new _CodeGen2['default'](this.options.srcName);
-	  },
-
-	  createFunctionContext: function createFunctionContext(asObject) {
-	    var varDeclarations = '';
-
-	    var locals = this.stackVars.concat(this.registers.list);
-	    if (locals.length > 0) {
-	      varDeclarations += ', ' + locals.join(', ');
-	    }
-
-	    // Generate minimizer alias mappings
-	    //
-	    // When using true SourceNodes, this will update all references to the given alias
-	    // as the source nodes are reused in situ. For the non-source node compilation mode,
-	    // aliases will not be used, but this case is already being run on the client and
-	    // we aren't concern about minimizing the template size.
-	    var aliasCount = 0;
-	    for (var alias in this.aliases) {
-	      // eslint-disable-line guard-for-in
-	      var node = this.aliases[alias];
-
-	      if (this.aliases.hasOwnProperty(alias) && node.children && node.referenceCount > 1) {
-	        varDeclarations += ', alias' + ++aliasCount + '=' + alias;
-	        node.children[0] = 'alias' + aliasCount;
-	      }
-	    }
-
-	    var params = ['depth0', 'helpers', 'partials', 'data'];
-
-	    if (this.useBlockParams || this.useDepths) {
-	      params.push('blockParams');
-	    }
-	    if (this.useDepths) {
-	      params.push('depths');
-	    }
-
-	    // Perform a second pass over the output to merge content when possible
-	    var source = this.mergeSource(varDeclarations);
-
-	    if (asObject) {
-	      params.push(source);
-
-	      return Function.apply(this, params);
-	    } else {
-	      return this.source.wrap(['function(', params.join(','), ') {\n  ', source, '}']);
-	    }
-	  },
-	  mergeSource: function mergeSource(varDeclarations) {
-	    var isSimple = this.environment.isSimple,
-	        appendOnly = !this.forceBuffer,
-	        appendFirst = undefined,
-	        sourceSeen = undefined,
-	        bufferStart = undefined,
-	        bufferEnd = undefined;
-	    this.source.each(function (line) {
-	      if (line.appendToBuffer) {
-	        if (bufferStart) {
-	          line.prepend('  + ');
-	        } else {
-	          bufferStart = line;
-	        }
-	        bufferEnd = line;
-	      } else {
-	        if (bufferStart) {
-	          if (!sourceSeen) {
-	            appendFirst = true;
-	          } else {
-	            bufferStart.prepend('buffer += ');
-	          }
-	          bufferEnd.add(';');
-	          bufferStart = bufferEnd = undefined;
-	        }
-
-	        sourceSeen = true;
-	        if (!isSimple) {
-	          appendOnly = false;
-	        }
-	      }
-	    });
-
-	    if (appendOnly) {
-	      if (bufferStart) {
-	        bufferStart.prepend('return ');
-	        bufferEnd.add(';');
-	      } else if (!sourceSeen) {
-	        this.source.push('return "";');
-	      }
-	    } else {
-	      varDeclarations += ', buffer = ' + (appendFirst ? '' : this.initializeBuffer());
-
-	      if (bufferStart) {
-	        bufferStart.prepend('return buffer + ');
-	        bufferEnd.add(';');
-	      } else {
-	        this.source.push('return buffer;');
-	      }
-	    }
-
-	    if (varDeclarations) {
-	      this.source.prepend('var ' + varDeclarations.substring(2) + (appendFirst ? '' : ';\n'));
-	    }
-
-	    return this.source.merge();
-	  },
-
-	  // [blockValue]
-	  //
-	  // On stack, before: hash, inverse, program, value
-	  // On stack, after: return value of blockHelperMissing
-	  //
-	  // The purpose of this opcode is to take a block of the form
-	  // `{{#this.foo}}...{{/this.foo}}`, resolve the value of `foo`, and
-	  // replace it on the stack with the result of properly
-	  // invoking blockHelperMissing.
-	  blockValue: function blockValue(name) {
-	    var blockHelperMissing = this.aliasable('helpers.blockHelperMissing'),
-	        params = [this.contextName(0)];
-	    this.setupHelperArgs(name, 0, params);
-
-	    var blockName = this.popStack();
-	    params.splice(1, 0, blockName);
-
-	    this.push(this.source.functionCall(blockHelperMissing, 'call', params));
-	  },
-
-	  // [ambiguousBlockValue]
-	  //
-	  // On stack, before: hash, inverse, program, value
-	  // Compiler value, before: lastHelper=value of last found helper, if any
-	  // On stack, after, if no lastHelper: same as [blockValue]
-	  // On stack, after, if lastHelper: value
-	  ambiguousBlockValue: function ambiguousBlockValue() {
-	    // We're being a bit cheeky and reusing the options value from the prior exec
-	    var blockHelperMissing = this.aliasable('helpers.blockHelperMissing'),
-	        params = [this.contextName(0)];
-	    this.setupHelperArgs('', 0, params, true);
-
-	    this.flushInline();
-
-	    var current = this.topStack();
-	    params.splice(1, 0, current);
-
-	    this.pushSource(['if (!', this.lastHelper, ') { ', current, ' = ', this.source.functionCall(blockHelperMissing, 'call', params), '}']);
-	  },
-
-	  // [appendContent]
-	  //
-	  // On stack, before: ...
-	  // On stack, after: ...
-	  //
-	  // Appends the string value of `content` to the current buffer
-	  appendContent: function appendContent(content) {
-	    if (this.pendingContent) {
-	      content = this.pendingContent + content;
-	    } else {
-	      this.pendingLocation = this.source.currentLocation;
-	    }
-
-	    this.pendingContent = content;
-	  },
-
-	  // [append]
-	  //
-	  // On stack, before: value, ...
-	  // On stack, after: ...
-	  //
-	  // Coerces `value` to a String and appends it to the current buffer.
-	  //
-	  // If `value` is truthy, or 0, it is coerced into a string and appended
-	  // Otherwise, the empty string is appended
-	  append: function append() {
-	    if (this.isInline()) {
-	      this.replaceStack(function (current) {
-	        return [' != null ? ', current, ' : ""'];
-	      });
-
-	      this.pushSource(this.appendToBuffer(this.popStack()));
-	    } else {
-	      var local = this.popStack();
-	      this.pushSource(['if (', local, ' != null) { ', this.appendToBuffer(local, undefined, true), ' }']);
-	      if (this.environment.isSimple) {
-	        this.pushSource(['else { ', this.appendToBuffer('\'\'', undefined, true), ' }']);
-	      }
-	    }
-	  },
-
-	  // [appendEscaped]
-	  //
-	  // On stack, before: value, ...
-	  // On stack, after: ...
-	  //
-	  // Escape `value` and append it to the buffer
-	  appendEscaped: function appendEscaped() {
-	    this.pushSource(this.appendToBuffer([this.aliasable('this.escapeExpression'), '(', this.popStack(), ')']));
-	  },
-
-	  // [getContext]
-	  //
-	  // On stack, before: ...
-	  // On stack, after: ...
-	  // Compiler value, after: lastContext=depth
-	  //
-	  // Set the value of the `lastContext` compiler value to the depth
-	  getContext: function getContext(depth) {
-	    this.lastContext = depth;
-	  },
-
-	  // [pushContext]
-	  //
-	  // On stack, before: ...
-	  // On stack, after: currentContext, ...
-	  //
-	  // Pushes the value of the current context onto the stack.
-	  pushContext: function pushContext() {
-	    this.pushStackLiteral(this.contextName(this.lastContext));
-	  },
-
-	  // [lookupOnContext]
-	  //
-	  // On stack, before: ...
-	  // On stack, after: currentContext[name], ...
-	  //
-	  // Looks up the value of `name` on the current context and pushes
-	  // it onto the stack.
-	  lookupOnContext: function lookupOnContext(parts, falsy, scoped) {
-	    var i = 0;
-
-	    if (!scoped && this.options.compat && !this.lastContext) {
-	      // The depthed query is expected to handle the undefined logic for the root level that
-	      // is implemented below, so we evaluate that directly in compat mode
-	      this.push(this.depthedLookup(parts[i++]));
-	    } else {
-	      this.pushContext();
-	    }
-
-	    this.resolvePath('context', parts, i, falsy);
-	  },
-
-	  // [lookupBlockParam]
-	  //
-	  // On stack, before: ...
-	  // On stack, after: blockParam[name], ...
-	  //
-	  // Looks up the value of `parts` on the given block param and pushes
-	  // it onto the stack.
-	  lookupBlockParam: function lookupBlockParam(blockParamId, parts) {
-	    this.useBlockParams = true;
-
-	    this.push(['blockParams[', blockParamId[0], '][', blockParamId[1], ']']);
-	    this.resolvePath('context', parts, 1);
-	  },
-
-	  // [lookupData]
-	  //
-	  // On stack, before: ...
-	  // On stack, after: data, ...
-	  //
-	  // Push the data lookup operator
-	  lookupData: function lookupData(depth, parts) {
-	    if (!depth) {
-	      this.pushStackLiteral('data');
-	    } else {
-	      this.pushStackLiteral('this.data(data, ' + depth + ')');
-	    }
-
-	    this.resolvePath('data', parts, 0, true);
-	  },
-
-	  resolvePath: function resolvePath(type, parts, i, falsy) {
-	    var _this = this;
-
-	    if (this.options.strict || this.options.assumeObjects) {
-	      this.push(strictLookup(this.options.strict, this, parts, type));
-	      return;
-	    }
-
-	    var len = parts.length;
-	    for (; i < len; i++) {
-	      /*eslint-disable no-loop-func */
-	      this.replaceStack(function (current) {
-	        var lookup = _this.nameLookup(current, parts[i], type);
-	        // We want to ensure that zero and false are handled properly if the context (falsy flag)
-	        // needs to have the special handling for these values.
-	        if (!falsy) {
-	          return [' != null ? ', lookup, ' : ', current];
-	        } else {
-	          // Otherwise we can use generic falsy handling
-	          return [' && ', lookup];
-	        }
-	      });
-	      /*eslint-enable no-loop-func */
-	    }
-	  },
-
-	  // [resolvePossibleLambda]
-	  //
-	  // On stack, before: value, ...
-	  // On stack, after: resolved value, ...
-	  //
-	  // If the `value` is a lambda, replace it on the stack by
-	  // the return value of the lambda
-	  resolvePossibleLambda: function resolvePossibleLambda() {
-	    this.push([this.aliasable('this.lambda'), '(', this.popStack(), ', ', this.contextName(0), ')']);
-	  },
-
-	  // [pushStringParam]
-	  //
-	  // On stack, before: ...
-	  // On stack, after: string, currentContext, ...
-	  //
-	  // This opcode is designed for use in string mode, which
-	  // provides the string value of a parameter along with its
-	  // depth rather than resolving it immediately.
-	  pushStringParam: function pushStringParam(string, type) {
-	    this.pushContext();
-	    this.pushString(type);
-
-	    // If it's a subexpression, the string result
-	    // will be pushed after this opcode.
-	    if (type !== 'SubExpression') {
-	      if (typeof string === 'string') {
-	        this.pushString(string);
-	      } else {
-	        this.pushStackLiteral(string);
-	      }
-	    }
-	  },
-
-	  emptyHash: function emptyHash(omitEmpty) {
-	    if (this.trackIds) {
-	      this.push('{}'); // hashIds
-	    }
-	    if (this.stringParams) {
-	      this.push('{}'); // hashContexts
-	      this.push('{}'); // hashTypes
-	    }
-	    this.pushStackLiteral(omitEmpty ? 'undefined' : '{}');
-	  },
-	  pushHash: function pushHash() {
-	    if (this.hash) {
-	      this.hashes.push(this.hash);
-	    }
-	    this.hash = { values: [], types: [], contexts: [], ids: [] };
-	  },
-	  popHash: function popHash() {
-	    var hash = this.hash;
-	    this.hash = this.hashes.pop();
-
-	    if (this.trackIds) {
-	      this.push(this.objectLiteral(hash.ids));
-	    }
-	    if (this.stringParams) {
-	      this.push(this.objectLiteral(hash.contexts));
-	      this.push(this.objectLiteral(hash.types));
-	    }
-
-	    this.push(this.objectLiteral(hash.values));
-	  },
-
-	  // [pushString]
-	  //
-	  // On stack, before: ...
-	  // On stack, after: quotedString(string), ...
-	  //
-	  // Push a quoted version of `string` onto the stack
-	  pushString: function pushString(string) {
-	    this.pushStackLiteral(this.quotedString(string));
-	  },
-
-	  // [pushLiteral]
-	  //
-	  // On stack, before: ...
-	  // On stack, after: value, ...
-	  //
-	  // Pushes a value onto the stack. This operation prevents
-	  // the compiler from creating a temporary variable to hold
-	  // it.
-	  pushLiteral: function pushLiteral(value) {
-	    this.pushStackLiteral(value);
-	  },
-
-	  // [pushProgram]
-	  //
-	  // On stack, before: ...
-	  // On stack, after: program(guid), ...
-	  //
-	  // Push a program expression onto the stack. This takes
-	  // a compile-time guid and converts it into a runtime-accessible
-	  // expression.
-	  pushProgram: function pushProgram(guid) {
-	    if (guid != null) {
-	      this.pushStackLiteral(this.programExpression(guid));
-	    } else {
-	      this.pushStackLiteral(null);
-	    }
-	  },
-
-	  // [invokeHelper]
-	  //
-	  // On stack, before: hash, inverse, program, params..., ...
-	  // On stack, after: result of helper invocation
-	  //
-	  // Pops off the helper's parameters, invokes the helper,
-	  // and pushes the helper's return value onto the stack.
-	  //
-	  // If the helper is not found, `helperMissing` is called.
-	  invokeHelper: function invokeHelper(paramSize, name, isSimple) {
-	    var nonHelper = this.popStack(),
-	        helper = this.setupHelper(paramSize, name),
-	        simple = isSimple ? [helper.name, ' || '] : '';
-
-	    var lookup = ['('].concat(simple, nonHelper);
-	    if (!this.options.strict) {
-	      lookup.push(' || ', this.aliasable('helpers.helperMissing'));
-	    }
-	    lookup.push(')');
-
-	    this.push(this.source.functionCall(lookup, 'call', helper.callParams));
-	  },
-
-	  // [invokeKnownHelper]
-	  //
-	  // On stack, before: hash, inverse, program, params..., ...
-	  // On stack, after: result of helper invocation
-	  //
-	  // This operation is used when the helper is known to exist,
-	  // so a `helperMissing` fallback is not required.
-	  invokeKnownHelper: function invokeKnownHelper(paramSize, name) {
-	    var helper = this.setupHelper(paramSize, name);
-	    this.push(this.source.functionCall(helper.name, 'call', helper.callParams));
-	  },
-
-	  // [invokeAmbiguous]
-	  //
-	  // On stack, before: hash, inverse, program, params..., ...
-	  // On stack, after: result of disambiguation
-	  //
-	  // This operation is used when an expression like `{{foo}}`
-	  // is provided, but we don't know at compile-time whether it
-	  // is a helper or a path.
-	  //
-	  // This operation emits more code than the other options,
-	  // and can be avoided by passing the `knownHelpers` and
-	  // `knownHelpersOnly` flags at compile-time.
-	  invokeAmbiguous: function invokeAmbiguous(name, helperCall) {
-	    this.useRegister('helper');
-
-	    var nonHelper = this.popStack();
-
-	    this.emptyHash();
-	    var helper = this.setupHelper(0, name, helperCall);
-
-	    var helperName = this.lastHelper = this.nameLookup('helpers', name, 'helper');
-
-	    var lookup = ['(', '(helper = ', helperName, ' || ', nonHelper, ')'];
-	    if (!this.options.strict) {
-	      lookup[0] = '(helper = ';
-	      lookup.push(' != null ? helper : ', this.aliasable('helpers.helperMissing'));
-	    }
-
-	    this.push(['(', lookup, helper.paramsInit ? ['),(', helper.paramsInit] : [], '),', '(typeof helper === ', this.aliasable('"function"'), ' ? ', this.source.functionCall('helper', 'call', helper.callParams), ' : helper))']);
-	  },
-
-	  // [invokePartial]
-	  //
-	  // On stack, before: context, ...
-	  // On stack after: result of partial invocation
-	  //
-	  // This operation pops off a context, invokes a partial with that context,
-	  // and pushes the result of the invocation back.
-	  invokePartial: function invokePartial(isDynamic, name, indent) {
-	    var params = [],
-	        options = this.setupParams(name, 1, params, false);
-
-	    if (isDynamic) {
-	      name = this.popStack();
-	      delete options.name;
-	    }
-
-	    if (indent) {
-	      options.indent = JSON.stringify(indent);
-	    }
-	    options.helpers = 'helpers';
-	    options.partials = 'partials';
-
-	    if (!isDynamic) {
-	      params.unshift(this.nameLookup('partials', name, 'partial'));
-	    } else {
-	      params.unshift(name);
-	    }
-
-	    if (this.options.compat) {
-	      options.depths = 'depths';
-	    }
-	    options = this.objectLiteral(options);
-	    params.push(options);
-
-	    this.push(this.source.functionCall('this.invokePartial', '', params));
-	  },
-
-	  // [assignToHash]
-	  //
-	  // On stack, before: value, ..., hash, ...
-	  // On stack, after: ..., hash, ...
-	  //
-	  // Pops a value off the stack and assigns it to the current hash
-	  assignToHash: function assignToHash(key) {
-	    var value = this.popStack(),
-	        context = undefined,
-	        type = undefined,
-	        id = undefined;
-
-	    if (this.trackIds) {
-	      id = this.popStack();
-	    }
-	    if (this.stringParams) {
-	      type = this.popStack();
-	      context = this.popStack();
-	    }
-
-	    var hash = this.hash;
-	    if (context) {
-	      hash.contexts[key] = context;
-	    }
-	    if (type) {
-	      hash.types[key] = type;
-	    }
-	    if (id) {
-	      hash.ids[key] = id;
-	    }
-	    hash.values[key] = value;
-	  },
-
-	  pushId: function pushId(type, name, child) {
-	    if (type === 'BlockParam') {
-	      this.pushStackLiteral('blockParams[' + name[0] + '].path[' + name[1] + ']' + (child ? ' + ' + JSON.stringify('.' + child) : ''));
-	    } else if (type === 'PathExpression') {
-	      this.pushString(name);
-	    } else if (type === 'SubExpression') {
-	      this.pushStackLiteral('true');
-	    } else {
-	      this.pushStackLiteral('null');
-	    }
-	  },
-
-	  // HELPERS
-
-	  compiler: JavaScriptCompiler,
-
-	  compileChildren: function compileChildren(environment, options) {
-	    var children = environment.children,
-	        child = undefined,
-	        compiler = undefined;
-
-	    for (var i = 0, l = children.length; i < l; i++) {
-	      child = children[i];
-	      compiler = new this.compiler(); // eslint-disable-line new-cap
-
-	      var index = this.matchExistingProgram(child);
-
-	      if (index == null) {
-	        this.context.programs.push(''); // Placeholder to prevent name conflicts for nested children
-	        index = this.context.programs.length;
-	        child.index = index;
-	        child.name = 'program' + index;
-	        this.context.programs[index] = compiler.compile(child, options, this.context, !this.precompile);
-	        this.context.environments[index] = child;
-
-	        this.useDepths = this.useDepths || compiler.useDepths;
-	        this.useBlockParams = this.useBlockParams || compiler.useBlockParams;
-	      } else {
-	        child.index = index;
-	        child.name = 'program' + index;
-
-	        this.useDepths = this.useDepths || child.useDepths;
-	        this.useBlockParams = this.useBlockParams || child.useBlockParams;
-	      }
-	    }
-	  },
-	  matchExistingProgram: function matchExistingProgram(child) {
-	    for (var i = 0, len = this.context.environments.length; i < len; i++) {
-	      var environment = this.context.environments[i];
-	      if (environment && environment.equals(child)) {
-	        return i;
-	      }
-	    }
-	  },
-
-	  programExpression: function programExpression(guid) {
-	    var child = this.environment.children[guid],
-	        programParams = [child.index, 'data', child.blockParams];
-
-	    if (this.useBlockParams || this.useDepths) {
-	      programParams.push('blockParams');
-	    }
-	    if (this.useDepths) {
-	      programParams.push('depths');
-	    }
-
-	    return 'this.program(' + programParams.join(', ') + ')';
-	  },
-
-	  useRegister: function useRegister(name) {
-	    if (!this.registers[name]) {
-	      this.registers[name] = true;
-	      this.registers.list.push(name);
-	    }
-	  },
-
-	  push: function push(expr) {
-	    if (!(expr instanceof Literal)) {
-	      expr = this.source.wrap(expr);
-	    }
-
-	    this.inlineStack.push(expr);
-	    return expr;
-	  },
-
-	  pushStackLiteral: function pushStackLiteral(item) {
-	    this.push(new Literal(item));
-	  },
-
-	  pushSource: function pushSource(source) {
-	    if (this.pendingContent) {
-	      this.source.push(this.appendToBuffer(this.source.quotedString(this.pendingContent), this.pendingLocation));
-	      this.pendingContent = undefined;
-	    }
-
-	    if (source) {
-	      this.source.push(source);
-	    }
-	  },
-
-	  replaceStack: function replaceStack(callback) {
-	    var prefix = ['('],
-	        stack = undefined,
-	        createdStack = undefined,
-	        usedLiteral = undefined;
-
-	    /* istanbul ignore next */
-	    if (!this.isInline()) {
-	      throw new _Exception2['default']('replaceStack on non-inline');
-	    }
-
-	    // We want to merge the inline statement into the replacement statement via ','
-	    var top = this.popStack(true);
-
-	    if (top instanceof Literal) {
-	      // Literals do not need to be inlined
-	      stack = [top.value];
-	      prefix = ['(', stack];
-	      usedLiteral = true;
-	    } else {
-	      // Get or create the current stack name for use by the inline
-	      createdStack = true;
-	      var _name = this.incrStack();
-
-	      prefix = ['((', this.push(_name), ' = ', top, ')'];
-	      stack = this.topStack();
-	    }
-
-	    var item = callback.call(this, stack);
-
-	    if (!usedLiteral) {
-	      this.popStack();
-	    }
-	    if (createdStack) {
-	      this.stackSlot--;
-	    }
-	    this.push(prefix.concat(item, ')'));
-	  },
-
-	  incrStack: function incrStack() {
-	    this.stackSlot++;
-	    if (this.stackSlot > this.stackVars.length) {
-	      this.stackVars.push('stack' + this.stackSlot);
-	    }
-	    return this.topStackName();
-	  },
-	  topStackName: function topStackName() {
-	    return 'stack' + this.stackSlot;
-	  },
-	  flushInline: function flushInline() {
-	    var inlineStack = this.inlineStack;
-	    this.inlineStack = [];
-	    for (var i = 0, len = inlineStack.length; i < len; i++) {
-	      var entry = inlineStack[i];
-	      /* istanbul ignore if */
-	      if (entry instanceof Literal) {
-	        this.compileStack.push(entry);
-	      } else {
-	        var stack = this.incrStack();
-	        this.pushSource([stack, ' = ', entry, ';']);
-	        this.compileStack.push(stack);
-	      }
-	    }
-	  },
-	  isInline: function isInline() {
-	    return this.inlineStack.length;
-	  },
-
-	  popStack: function popStack(wrapped) {
-	    var inline = this.isInline(),
-	        item = (inline ? this.inlineStack : this.compileStack).pop();
-
-	    if (!wrapped && item instanceof Literal) {
-	      return item.value;
-	    } else {
-	      if (!inline) {
-	        /* istanbul ignore next */
-	        if (!this.stackSlot) {
-	          throw new _Exception2['default']('Invalid stack pop');
-	        }
-	        this.stackSlot--;
-	      }
-	      return item;
-	    }
-	  },
-
-	  topStack: function topStack() {
-	    var stack = this.isInline() ? this.inlineStack : this.compileStack,
-	        item = stack[stack.length - 1];
-
-	    /* istanbul ignore if */
-	    if (item instanceof Literal) {
-	      return item.value;
-	    } else {
-	      return item;
-	    }
-	  },
-
-	  contextName: function contextName(context) {
-	    if (this.useDepths && context) {
-	      return 'depths[' + context + ']';
-	    } else {
-	      return 'depth' + context;
-	    }
-	  },
-
-	  quotedString: function quotedString(str) {
-	    return this.source.quotedString(str);
-	  },
-
-	  objectLiteral: function objectLiteral(obj) {
-	    return this.source.objectLiteral(obj);
-	  },
-
-	  aliasable: function aliasable(name) {
-	    var ret = this.aliases[name];
-	    if (ret) {
-	      ret.referenceCount++;
-	      return ret;
-	    }
-
-	    ret = this.aliases[name] = this.source.wrap(name);
-	    ret.aliasable = true;
-	    ret.referenceCount = 1;
-
-	    return ret;
-	  },
-
-	  setupHelper: function setupHelper(paramSize, name, blockHelper) {
-	    var params = [],
-	        paramsInit = this.setupHelperArgs(name, paramSize, params, blockHelper);
-	    var foundHelper = this.nameLookup('helpers', name, 'helper');
-
-	    return {
-	      params: params,
-	      paramsInit: paramsInit,
-	      name: foundHelper,
-	      callParams: [this.contextName(0)].concat(params)
-	    };
-	  },
-
-	  setupParams: function setupParams(helper, paramSize, params) {
-	    var options = {},
-	        contexts = [],
-	        types = [],
-	        ids = [],
-	        param = undefined;
-
-	    options.name = this.quotedString(helper);
-	    options.hash = this.popStack();
-
-	    if (this.trackIds) {
-	      options.hashIds = this.popStack();
-	    }
-	    if (this.stringParams) {
-	      options.hashTypes = this.popStack();
-	      options.hashContexts = this.popStack();
-	    }
-
-	    var inverse = this.popStack(),
-	        program = this.popStack();
-
-	    // Avoid setting fn and inverse if neither are set. This allows
-	    // helpers to do a check for `if (options.fn)`
-	    if (program || inverse) {
-	      options.fn = program || 'this.noop';
-	      options.inverse = inverse || 'this.noop';
-	    }
-
-	    // The parameters go on to the stack in order (making sure that they are evaluated in order)
-	    // so we need to pop them off the stack in reverse order
-	    var i = paramSize;
-	    while (i--) {
-	      param = this.popStack();
-	      params[i] = param;
-
-	      if (this.trackIds) {
-	        ids[i] = this.popStack();
-	      }
-	      if (this.stringParams) {
-	        types[i] = this.popStack();
-	        contexts[i] = this.popStack();
-	      }
-	    }
-
-	    if (this.trackIds) {
-	      options.ids = this.source.generateArray(ids);
-	    }
-	    if (this.stringParams) {
-	      options.types = this.source.generateArray(types);
-	      options.contexts = this.source.generateArray(contexts);
-	    }
-
-	    if (this.options.data) {
-	      options.data = 'data';
-	    }
-	    if (this.useBlockParams) {
-	      options.blockParams = 'blockParams';
-	    }
-	    return options;
-	  },
-
-	  setupHelperArgs: function setupHelperArgs(helper, paramSize, params, useRegister) {
-	    var options = this.setupParams(helper, paramSize, params, true);
-	    options = this.objectLiteral(options);
-	    if (useRegister) {
-	      this.useRegister('options');
-	      params.push('options');
-	      return ['options=', options];
-	    } else {
-	      params.push(options);
-	      return '';
-	    }
-	  }
-	};
-
-	(function () {
-	  var reservedWords = ('break else new var' + ' case finally return void' + ' catch for switch while' + ' continue function this with' + ' default if throw' + ' delete in try' + ' do instanceof typeof' + ' abstract enum int short' + ' boolean export interface static' + ' byte extends long super' + ' char final native synchronized' + ' class float package throws' + ' const goto private transient' + ' debugger implements protected volatile' + ' double import public let yield await' + ' null true false').split(' ');
-
-	  var compilerWords = JavaScriptCompiler.RESERVED_WORDS = {};
-
-	  for (var i = 0, l = reservedWords.length; i < l; i++) {
-	    compilerWords[reservedWords[i]] = true;
-	  }
-	})();
-
-	JavaScriptCompiler.isValidJavaScriptVariableName = function (name) {
-	  return !JavaScriptCompiler.RESERVED_WORDS[name] && /^[a-zA-Z_$][0-9a-zA-Z_$]*$/.test(name);
-	};
-
-	function strictLookup(requireTerminal, compiler, parts, type) {
-	  var stack = compiler.popStack(),
-	      i = 0,
-	      len = parts.length;
-	  if (requireTerminal) {
-	    len--;
-	  }
-
-	  for (; i < len; i++) {
-	    stack = compiler.nameLookup(stack, parts[i], type);
-	  }
-
-	  if (requireTerminal) {
-	    return [compiler.aliasable('this.strict'), '(', stack, ', ', compiler.quotedString(parts[i]), ')'];
-	  } else {
-	    return stack;
-	  }
-	}
-
-	exports['default'] = JavaScriptCompiler;
-	module.exports = exports['default'];
-
-/***/ },
-/* 6 */
-/***/ function(module, exports, __webpack_require__) {
-
-	'use strict';
-
-	var _interopRequireDefault = __webpack_require__(8)['default'];
-
-	exports.__esModule = true;
-
-	var _Exception = __webpack_require__(12);
-
-	var _Exception2 = _interopRequireDefault(_Exception);
-
-	var _AST = __webpack_require__(2);
-
-	var _AST2 = _interopRequireDefault(_AST);
-
-	function Visitor() {
-	  this.parents = [];
-	}
-
-	Visitor.prototype = {
-	  constructor: Visitor,
-	  mutating: false,
-
-	  // Visits a given value. If mutating, will replace the value if necessary.
-	  acceptKey: function acceptKey(node, name) {
-	    var value = this.accept(node[name]);
-	    if (this.mutating) {
-	      // Hacky sanity check:
-	      if (value && (!value.type || !_AST2['default'][value.type])) {
-	        throw new _Exception2['default']('Unexpected node type "' + value.type + '" found when accepting ' + name + ' on ' + node.type);
-	      }
-	      node[name] = value;
-	    }
-	  },
-
-	  // Performs an accept operation with added sanity check to ensure
-	  // required keys are not removed.
-	  acceptRequired: function acceptRequired(node, name) {
-	    this.acceptKey(node, name);
-
-	    if (!node[name]) {
-	      throw new _Exception2['default'](node.type + ' requires ' + name);
-	    }
-	  },
-
-	  // Traverses a given array. If mutating, empty respnses will be removed
-	  // for child elements.
-	  acceptArray: function acceptArray(array) {
-	    for (var i = 0, l = array.length; i < l; i++) {
-	      this.acceptKey(array, i);
-
-	      if (!array[i]) {
-	        array.splice(i, 1);
-	        i--;
-	        l--;
-	      }
-	    }
-	  },
-
-	  accept: function accept(object) {
-	    if (!object) {
-	      return;
-	    }
-
-	    if (this.current) {
-	      this.parents.unshift(this.current);
-	    }
-	    this.current = object;
-
-	    var ret = this[object.type](object);
-
-	    this.current = this.parents.shift();
-
-	    if (!this.mutating || ret) {
-	      return ret;
-	    } else if (ret !== false) {
-	      return object;
-	    }
-	  },
-
-	  Program: function Program(program) {
-	    this.acceptArray(program.body);
-	  },
-
-	  MustacheStatement: function MustacheStatement(mustache) {
-	    this.acceptRequired(mustache, 'path');
-	    this.acceptArray(mustache.params);
-	    this.acceptKey(mustache, 'hash');
-	  },
-
-	  BlockStatement: function BlockStatement(block) {
-	    this.acceptRequired(block, 'path');
-	    this.acceptArray(block.params);
-	    this.acceptKey(block, 'hash');
-
-	    this.acceptKey(block, 'program');
-	    this.acceptKey(block, 'inverse');
-	  },
-
-	  PartialStatement: function PartialStatement(partial) {
-	    this.acceptRequired(partial, 'name');
-	    this.acceptArray(partial.params);
-	    this.acceptKey(partial, 'hash');
-	  },
-
-	  ContentStatement: function ContentStatement() {},
-	  CommentStatement: function CommentStatement() {},
-
-	  SubExpression: function SubExpression(sexpr) {
-	    this.acceptRequired(sexpr, 'path');
-	    this.acceptArray(sexpr.params);
-	    this.acceptKey(sexpr, 'hash');
-	  },
-
-	  PathExpression: function PathExpression() {},
-
-	  StringLiteral: function StringLiteral() {},
-	  NumberLiteral: function NumberLiteral() {},
-	  BooleanLiteral: function BooleanLiteral() {},
-	  UndefinedLiteral: function UndefinedLiteral() {},
-	  NullLiteral: function NullLiteral() {},
-
-	  Hash: function Hash(hash) {
-	    this.acceptArray(hash.pairs);
-	  },
-	  HashPair: function HashPair(pair) {
-	    this.acceptRequired(pair, 'value');
-	  }
-	};
-
-	exports['default'] = Visitor;
-	module.exports = exports['default'];
-	/* content */ /* comment */ /* path */ /* string */ /* number */ /* bool */ /* literal */ /* literal */
-
-/***/ },
-/* 7 */
-/***/ function(module, exports, __webpack_require__) {
-
-	/* WEBPACK VAR INJECTION */(function(global) {'use strict';
-
-	exports.__esModule = true;
-	/*global window */
-
-	exports['default'] = function (Handlebars) {
-	  /* istanbul ignore next */
-	  var root = typeof global !== 'undefined' ? global : window,
-	      $Handlebars = root.Handlebars;
-	  /* istanbul ignore next */
-	  Handlebars.noConflict = function () {
-	    if (root.Handlebars === Handlebars) {
-	      root.Handlebars = $Handlebars;
-	    }
-	  };
-	};
-
-	module.exports = exports['default'];
-	/* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }())))
-
-/***/ },
-/* 8 */
-/***/ function(module, exports, __webpack_require__) {
-
-	"use strict";
-
-	exports["default"] = function (obj) {
-	  return obj && obj.__esModule ? obj : {
-	    "default": obj
-	  };
-	};
-
-	exports.__esModule = true;
-
-/***/ },
-/* 9 */
-/***/ function(module, exports, __webpack_require__) {
-
-	"use strict";
-
-	exports["default"] = function (obj) {
-	  if (obj && obj.__esModule) {
-	    return obj;
-	  } else {
-	    var newObj = {};
-
-	    if (typeof obj === "object" && obj !== null) {
-	      for (var key in obj) {
-	        if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key];
-	      }
-	    }
-
-	    newObj["default"] = obj;
-	    return newObj;
-	  }
-	};
-
-	exports.__esModule = true;
-
-/***/ },
-/* 10 */
-/***/ function(module, exports, __webpack_require__) {
-
-	'use strict';
-
-	var _interopRequireWildcard = __webpack_require__(9)['default'];
-
-	var _interopRequireDefault = __webpack_require__(8)['default'];
-
-	exports.__esModule = true;
-	exports.HandlebarsEnvironment = HandlebarsEnvironment;
-	exports.createFrame = createFrame;
-
-	var _import = __webpack_require__(13);
-
-	var Utils = _interopRequireWildcard(_import);
-
-	var _Exception = __webpack_require__(12);
-
-	var _Exception2 = _interopRequireDefault(_Exception);
-
-	var VERSION = '3.0.1';
-	exports.VERSION = VERSION;
-	var COMPILER_REVISION = 6;
-
-	exports.COMPILER_REVISION = COMPILER_REVISION;
-	var REVISION_CHANGES = {
-	  1: '<= 1.0.rc.2', // 1.0.rc.2 is actually rev2 but doesn't report it
-	  2: '== 1.0.0-rc.3',
-	  3: '== 1.0.0-rc.4',
-	  4: '== 1.x.x',
-	  5: '== 2.0.0-alpha.x',
-	  6: '>= 2.0.0-beta.1'
-	};
-
-	exports.REVISION_CHANGES = REVISION_CHANGES;
-	var isArray = Utils.isArray,
-	    isFunction = Utils.isFunction,
-	    toString = Utils.toString,
-	    objectType = '[object Object]';
-
-	function HandlebarsEnvironment(helpers, partials) {
-	  this.helpers = helpers || {};
-	  this.partials = partials || {};
-
-	  registerDefaultHelpers(this);
-	}
-
-	HandlebarsEnvironment.prototype = {
-	  constructor: HandlebarsEnvironment,
-
-	  logger: logger,
-	  log: log,
-
-	  registerHelper: function registerHelper(name, fn) {
-	    if (toString.call(name) === objectType) {
-	      if (fn) {
-	        throw new _Exception2['default']('Arg not supported with multiple helpers');
-	      }
-	      Utils.extend(this.helpers, name);
-	    } else {
-	      this.helpers[name] = fn;
-	    }
-	  },
-	  unregisterHelper: function unregisterHelper(name) {
-	    delete this.helpers[name];
-	  },
-
-	  registerPartial: function registerPartial(name, partial) {
-	    if (toString.call(name) === objectType) {
-	      Utils.extend(this.partials, name);
-	    } else {
-	      if (typeof partial === 'undefined') {
-	        throw new _Exception2['default']('Attempting to register a partial as undefined');
-	      }
-	      this.partials[name] = partial;
-	    }
-	  },
-	  unregisterPartial: function unregisterPartial(name) {
-	    delete this.partials[name];
-	  }
-	};
-
-	function registerDefaultHelpers(instance) {
-	  instance.registerHelper('helperMissing', function () {
-	    if (arguments.length === 1) {
-	      // A missing field in a {{foo}} constuct.
-	      return undefined;
-	    } else {
-	      // Someone is actually trying to call something, blow up.
-	      throw new _Exception2['default']('Missing helper: "' + arguments[arguments.length - 1].name + '"');
-	    }
-	  });
-
-	  instance.registerHelper('blockHelperMissing', function (context, options) {
-	    var inverse = options.inverse,
-	        fn = options.fn;
-
-	    if (context === true) {
-	      return fn(this);
-	    } else if (context === false || context == null) {
-	      return inverse(this);
-	    } else if (isArray(context)) {
-	      if (context.length > 0) {
-	        if (options.ids) {
-	          options.ids = [options.name];
-	        }
-
-	        return instance.helpers.each(context, options);
-	      } else {
-	        return inverse(this);
-	      }
-	    } else {
-	      if (options.data && options.ids) {
-	        var data = createFrame(options.data);
-	        data.contextPath = Utils.appendContextPath(options.data.contextPath, options.name);
-	        options = { data: data };
-	      }
-
-	      return fn(context, options);
-	    }
-	  });
-
-	  instance.registerHelper('each', function (context, options) {
-	    if (!options) {
-	      throw new _Exception2['default']('Must pass iterator to #each');
-	    }
-	
-	    var fn = options.fn,
-	        inverse = options.inverse,
-	        i = 0,
-	        ret = '',
-	        data = undefined,
-	        contextPath = undefined;
-
-	    if (options.data && options.ids) {
-	      contextPath = Utils.appendContextPath(options.data.contextPath, options.ids[0]) + '.';
-	    }
-
-	    if (isFunction(context)) {
-	      context = context.call(this);
-	    }
-
-	    if (options.data) {
-	      data = createFrame(options.data);
-	    }
-
-	    function execIteration(field, index, last) {
-	      if (data) {
-	        data.key = field;
-	        data.index = index;
-	        data.first = index === 0;
-	        data.last = !!last;
-
-	        if (contextPath) {
-	          data.contextPath = contextPath + field;
-	        }
-	      }
-
-	      ret = ret + fn(context[field], {
-	        data: data,
-	        blockParams: Utils.blockParams([context[field], field], [contextPath + field, null])
-	      });
-	    }
-
-	    if (context && typeof context === 'object') {
-	      if (isArray(context)) {
-	        for (var j = context.length; i < j; i++) {
-	          execIteration(i, i, i === context.length - 1);
-	        }
-	      } else {
-	        var priorKey = undefined;
-
-	        for (var key in context) {
-	          if (context.hasOwnProperty(key)) {
-	            // We're running the iterations one step out of sync so we can detect
-	            // the last iteration without have to scan the object twice and create
-	            // an itermediate keys array.
-	            if (priorKey) {
-	              execIteration(priorKey, i - 1);
-	            }
-	            priorKey = key;
-	            i++;
-	          }
-	        }
-	        if (priorKey) {
-	          execIteration(priorKey, i - 1, true);
-	        }
-	      }
-	    }
-
-	    if (i === 0) {
-	      ret = inverse(this);
-	    }
-
-	    return ret;
-	  });
-
-	  instance.registerHelper('if', function (conditional, options) {
-	    if (isFunction(conditional)) {
-	      conditional = conditional.call(this);
-	    }
-
-	    // Default behavior is to render the positive path if the value is truthy and not empty.
-	    // The `includeZero` option may be set to treat the condtional as purely not empty based on the
-	    // behavior of isEmpty. Effectively this determines if 0 is handled by the positive path or negative.
-	    if (!options.hash.includeZero && !conditional || Utils.isEmpty(conditional)) {
-	      return options.inverse(this);
-	    } else {
-	      return options.fn(this);
-	    }
-	  });
-
-	  instance.registerHelper('unless', function (conditional, options) {
-	    return instance.helpers['if'].call(this, conditional, { fn: options.inverse, inverse: options.fn, hash: options.hash });
-	  });
-
-	  instance.registerHelper('with', function (context, options) {
-	    if (isFunction(context)) {
-	      context = context.call(this);
-	    }
-
-	    var fn = options.fn;
-
-	    if (!Utils.isEmpty(context)) {
-	      if (options.data && options.ids) {
-	        var data = createFrame(options.data);
-	        data.contextPath = Utils.appendContextPath(options.data.contextPath, options.ids[0]);
-	        options = { data: data };
-	      }
-
-	      return fn(context, options);
-	    } else {
-	      return options.inverse(this);
-	    }
-	  });
-
-	  instance.registerHelper('log', function (message, options) {
-	    var level = options.data && options.data.level != null ? parseInt(options.data.level, 10) : 1;
-	    instance.log(level, message);
-	  });
-
-	  instance.registerHelper('lookup', function (obj, field) {
-	    return obj && obj[field];
-	  });
-	}
-
-	var logger = {
-	  methodMap: { 0: 'debug', 1: 'info', 2: 'warn', 3: 'error' },
-
-	  // State enum
-	  DEBUG: 0,
-	  INFO: 1,
-	  WARN: 2,
-	  ERROR: 3,
-	  level: 1,
-
-	  // Can be overridden in the host environment
-	  log: function log(level, message) {
-	    if (typeof console !== 'undefined' && logger.level <= level) {
-	      var method = logger.methodMap[level];
-	      (console[method] || console.log).call(console, message); // eslint-disable-line no-console
-	    }
-	  }
-	};
-
-	exports.logger = logger;
-	var log = logger.log;
-
-	exports.log = log;
-
-	function createFrame(object) {
-	  var frame = Utils.extend({}, object);
-	  frame._parent = object;
-	  return frame;
-	}
-
-	/* [args, ]options */
-
-/***/ },
-/* 11 */
-/***/ function(module, exports, __webpack_require__) {
-
-	'use strict';
-
-	exports.__esModule = true;
-	// Build out our basic SafeString type
-	function SafeString(string) {
-	  this.string = string;
-	}
-
-	SafeString.prototype.toString = SafeString.prototype.toHTML = function () {
-	  return '' + this.string;
-	};
-
-	exports['default'] = SafeString;
-	module.exports = exports['default'];
-
-/***/ },
-/* 12 */
-/***/ function(module, exports, __webpack_require__) {
-
-	'use strict';
-
-	exports.__esModule = true;
-
-	var errorProps = ['description', 'fileName', 'lineNumber', 'message', 'name', 'number', 'stack'];
-
-	function Exception(message, node) {
-	  var loc = node && node.loc,
-	      line = undefined,
-	      column = undefined;
-	  if (loc) {
-	    line = loc.start.line;
-	    column = loc.start.column;
-
-	    message += ' - ' + line + ':' + column;
-	  }
-
-	  var tmp = Error.prototype.constructor.call(this, message);
-
-	  // Unfortunately errors are not enumerable in Chrome (at least), so `for prop in tmp` doesn't work.
-	  for (var idx = 0; idx < errorProps.length; idx++) {
-	    this[errorProps[idx]] = tmp[errorProps[idx]];
-	  }
-
-	  if (Error.captureStackTrace) {
-	    Error.captureStackTrace(this, Exception);
-	  }
-
-	  if (loc) {
-	    this.lineNumber = line;
-	    this.column = column;
-	  }
-	}
-
-	Exception.prototype = new Error();
-
-	exports['default'] = Exception;
-	module.exports = exports['default'];
-
-/***/ },
-/* 13 */
-/***/ function(module, exports, __webpack_require__) {
-
-	'use strict';
-
-	exports.__esModule = true;
-	exports.extend = extend;
-
-	// Older IE versions do not directly support indexOf so we must implement our own, sadly.
-	exports.indexOf = indexOf;
-	exports.escapeExpression = escapeExpression;
-	exports.isEmpty = isEmpty;
-	exports.blockParams = blockParams;
-	exports.appendContextPath = appendContextPath;
-	var escape = {
-	  '&': '&amp;',
-	  '<': '&lt;',
-	  '>': '&gt;',
-	  '"': '&quot;',
-	  '\'': '&#x27;',
-	  '`': '&#x60;'
-	};
-
-	var badChars = /[&<>"'`]/g,
-	    possible = /[&<>"'`]/;
-
-	function escapeChar(chr) {
-	  return escape[chr];
-	}
-
-	function extend(obj /* , ...source */) {
-	  for (var i = 1; i < arguments.length; i++) {
-	    for (var key in arguments[i]) {
-	      if (Object.prototype.hasOwnProperty.call(arguments[i], key)) {
-	        obj[key] = arguments[i][key];
-	      }
-	    }
-	  }
-
-	  return obj;
-	}
-
-	var toString = Object.prototype.toString;
-
-	exports.toString = toString;
-	// Sourced from lodash
-	// https://github.com/bestiejs/lodash/blob/master/LICENSE.txt
-	/*eslint-disable func-style, no-var */
-	var isFunction = function isFunction(value) {
-	  return typeof value === 'function';
-	};
-	// fallback for older versions of Chrome and Safari
-	/* istanbul ignore next */
-	if (isFunction(/x/)) {
-	  exports.isFunction = isFunction = function (value) {
-	    return typeof value === 'function' && toString.call(value) === '[object Function]';
-	  };
-	}
-	var isFunction;
-	exports.isFunction = isFunction;
-	/*eslint-enable func-style, no-var */
-
-	/* istanbul ignore next */
-	var isArray = Array.isArray || function (value) {
-	  return value && typeof value === 'object' ? toString.call(value) === '[object Array]' : false;
-	};exports.isArray = isArray;
-
-	function indexOf(array, value) {
-	  for (var i = 0, len = array.length; i < len; i++) {
-	    if (array[i] === value) {
-	      return i;
-	    }
-	  }
-	  return -1;
-	}
-
-	function escapeExpression(string) {
-	  if (typeof string !== 'string') {
-	    // don't escape SafeStrings, since they're already safe
-	    if (string && string.toHTML) {
-	      return string.toHTML();
-	    } else if (string == null) {
-	      return '';
-	    } else if (!string) {
-	      return string + '';
-	    }
-
-	    // Force a string conversion as this will be done by the append regardless and
-	    // the regex test will do this transparently behind the scenes, causing issues if
-	    // an object's to string has escaped characters in it.
-	    string = '' + string;
-	  }
-
-	  if (!possible.test(string)) {
-	    return string;
-	  }
-	  return string.replace(badChars, escapeChar);
-	}
-
-	function isEmpty(value) {
-	  if (!value && value !== 0) {
-	    return true;
-	  } else if (isArray(value) && value.length === 0) {
-	    return true;
-	  } else {
-	    return false;
-	  }
-	}
-
-	function blockParams(params, ids) {
-	  params.path = ids;
-	  return params;
-	}
-
-	function appendContextPath(contextPath, id) {
-	  return (contextPath ? contextPath + '.' : '') + id;
-	}
-
-/***/ },
-/* 14 */
-/***/ function(module, exports, __webpack_require__) {
-
-	'use strict';
-
-	var _interopRequireWildcard = __webpack_require__(9)['default'];
-
-	var _interopRequireDefault = __webpack_require__(8)['default'];
-
-	exports.__esModule = true;
-	exports.checkRevision = checkRevision;
-
-	// TODO: Remove this line and break up compilePartial
-
-	exports.template = template;
-	exports.wrapProgram = wrapProgram;
-	exports.resolvePartial = resolvePartial;
-	exports.invokePartial = invokePartial;
-	exports.noop = noop;
-
-	var _import = __webpack_require__(13);
-
-	var Utils = _interopRequireWildcard(_import);
-
-	var _Exception = __webpack_require__(12);
-
-	var _Exception2 = _interopRequireDefault(_Exception);
-
-	var _COMPILER_REVISION$REVISION_CHANGES$createFrame = __webpack_require__(10);
-
-	function checkRevision(compilerInfo) {
-	  var compilerRevision = compilerInfo && compilerInfo[0] || 1,
-	      currentRevision = _COMPILER_REVISION$REVISION_CHANGES$createFrame.COMPILER_REVISION;
-
-	  if (compilerRevision !== currentRevision) {
-	    if (compilerRevision < currentRevision) {
-	      var runtimeVersions = _COMPILER_REVISION$REVISION_CHANGES$createFrame.REVISION_CHANGES[currentRevision],
-	          compilerVersions = _COMPILER_REVISION$REVISION_CHANGES$createFrame.REVISION_CHANGES[compilerRevision];
-	      throw new _Exception2['default']('Template was precompiled with an older version of Handlebars than the current runtime. ' + 'Please update your precompiler to a newer version (' + runtimeVersions + ') or downgrade your runtime to an older version (' + compilerVersions + ').');
-	    } else {
-	      // Use the embedded version info since the runtime doesn't know about this revision yet
-	      throw new _Exception2['default']('Template was precompiled with a newer version of Handlebars than the current runtime. ' + 'Please update your runtime to a newer version (' + compilerInfo[1] + ').');
-	    }
-	  }
-	}
-
-	function template(templateSpec, env) {
-	  /* istanbul ignore next */
-	  if (!env) {
-	    throw new _Exception2['default']('No environment passed to template');
-	  }
-	  if (!templateSpec || !templateSpec.main) {
-	    throw new _Exception2['default']('Unknown template object: ' + typeof templateSpec);
-	  }
-
-	  // Note: Using env.VM references rather than local var references throughout this section to allow
-	  // for external users to override these as psuedo-supported APIs.
-	  env.VM.checkRevision(templateSpec.compiler);
-
-	  function invokePartialWrapper(partial, context, options) {
-	    if (options.hash) {
-	      context = Utils.extend({}, context, options.hash);
-	    }
-
-	    partial = env.VM.resolvePartial.call(this, partial, context, options);
-	    var result = env.VM.invokePartial.call(this, partial, context, options);
-
-	    if (result == null && env.compile) {
-	      options.partials[options.name] = env.compile(partial, templateSpec.compilerOptions, env);
-	      result = options.partials[options.name](context, options);
-	    }
-	    if (result != null) {
-	      if (options.indent) {
-	        var lines = result.split('\n');
-	        for (var i = 0, l = lines.length; i < l; i++) {
-	          if (!lines[i] && i + 1 === l) {
-	            break;
-	          }
-
-	          lines[i] = options.indent + lines[i];
-	        }
-	        result = lines.join('\n');
-	      }
-	      return result;
-	    } else {
-	      throw new _Exception2['default']('The partial ' + options.name + ' could not be compiled when running in runtime-only mode');
-	    }
-	  }
-
-	  // Just add water
-	  var container = {
-	    strict: function strict(obj, name) {
-	      if (!(name in obj)) {
-	        throw new _Exception2['default']('"' + name + '" not defined in ' + obj);
-	      }
-	      return obj[name];
-	    },
-	    lookup: function lookup(depths, name) {
-	      var len = depths.length;
-	      for (var i = 0; i < len; i++) {
-	        if (depths[i] && depths[i][name] != null) {
-	          return depths[i][name];
-	        }
-	      }
-	    },
-	    lambda: function lambda(current, context) {
-	      return typeof current === 'function' ? current.call(context) : current;
-	    },
-
-	    escapeExpression: Utils.escapeExpression,
-	    invokePartial: invokePartialWrapper,
-
-	    fn: function fn(i) {
-	      return templateSpec[i];
-	    },
-
-	    programs: [],
-	    program: function program(i, data, declaredBlockParams, blockParams, depths) {
-	      var programWrapper = this.programs[i],
-	          fn = this.fn(i);
-	      if (data || depths || blockParams || declaredBlockParams) {
-	        programWrapper = wrapProgram(this, i, fn, data, declaredBlockParams, blockParams, depths);
-	      } else if (!programWrapper) {
-	        programWrapper = this.programs[i] = wrapProgram(this, i, fn);
-	      }
-	      return programWrapper;
-	    },
-
-	    data: function data(value, depth) {
-	      while (value && depth--) {
-	        value = value._parent;
-	      }
-	      return value;
-	    },
-	    merge: function merge(param, common) {
-	      var obj = param || common;
-
-	      if (param && common && param !== common) {
-	        obj = Utils.extend({}, common, param);
-	      }
-
-	      return obj;
-	    },
-
-	    noop: env.VM.noop,
-	    compilerInfo: templateSpec.compiler
-	  };
-
-	  function ret(context) {
-	    var options = arguments[1] === undefined ? {} : arguments[1];
-
-	    var data = options.data;
-
-	    ret._setup(options);
-	    if (!options.partial && templateSpec.useData) {
-	      data = initData(context, data);
-	    }
-	    var depths = undefined,
-	        blockParams = templateSpec.useBlockParams ? [] : undefined;
-	    if (templateSpec.useDepths) {
-	      depths = options.depths ? [context].concat(options.depths) : [context];
-	    }
-
-	    return templateSpec.main.call(container, context, container.helpers, container.partials, data, blockParams, depths);
-	  }
-	  ret.isTop = true;
-
-	  ret._setup = function (options) {
-	    if (!options.partial) {
-	      container.helpers = container.merge(options.helpers, env.helpers);
-
-	      if (templateSpec.usePartial) {
-	        container.partials = container.merge(options.partials, env.partials);
-	      }
-	    } else {
-	      container.helpers = options.helpers;
-	      container.partials = options.partials;
-	    }
-	  };
-
-	  ret._child = function (i, data, blockParams, depths) {
-	    if (templateSpec.useBlockParams && !blockParams) {
-	      throw new _Exception2['default']('must pass block params');
-	    }
-	    if (templateSpec.useDepths && !depths) {
-	      throw new _Exception2['default']('must pass parent depths');
-	    }
-
-	    return wrapProgram(container, i, templateSpec[i], data, 0, blockParams, depths);
-	  };
-	  return ret;
-	}
-
-	function wrapProgram(container, i, fn, data, declaredBlockParams, blockParams, depths) {
-	  function prog(context) {
-	    var options = arguments[1] === undefined ? {} : arguments[1];
-
-	    return fn.call(container, context, container.helpers, container.partials, options.data || data, blockParams && [options.blockParams].concat(blockParams), depths && [context].concat(depths));
-	  }
-	  prog.program = i;
-	  prog.depth = depths ? depths.length : 0;
-	  prog.blockParams = declaredBlockParams || 0;
-	  return prog;
-	}
-
-	function resolvePartial(partial, context, options) {
-	  if (!partial) {
-	    partial = options.partials[options.name];
-	  } else if (!partial.call && !options.name) {
-	    // This is a dynamic partial that returned a string
-	    options.name = partial;
-	    partial = options.partials[partial];
-	  }
-	  return partial;
-	}
-
-	function invokePartial(partial, context, options) {
-	  options.partial = true;
-
-	  if (partial === undefined) {
-	    throw new _Exception2['default']('The partial ' + options.name + ' could not be found');
-	  } else if (partial instanceof Function) {
-	    return partial(context, options);
-	  }
-	}
-
-	function noop() {
-	  return '';
-	}
-
-	function initData(context, data) {
-	  if (!data || !('root' in data)) {
-	    data = data ? _COMPILER_REVISION$REVISION_CHANGES$createFrame.createFrame(data) : {};
-	    data.root = context;
-	  }
-	  return data;
-	}
-
-/***/ },
-/* 15 */
-/***/ function(module, exports, __webpack_require__) {
-
-	"use strict";
-
-	exports.__esModule = true;
-	/* istanbul ignore next */
-	/* Jison generated parser */
-	var handlebars = (function () {
-	    var parser = { trace: function trace() {},
-	        yy: {},
-	        symbols_: { error: 2, root: 3, program: 4, EOF: 5, program_repetition0: 6, statement: 7, mustache: 8, block: 9, rawBlock: 10, partial: 11, content: 12, COMMENT: 13, CONTENT: 14, openRawBlock: 15, END_RAW_BLOCK: 16, OPEN_RAW_BLOCK: 17, helperName: 18, openRawBlock_repetition0: 19, openRawBlock_option0: 20, CLOSE_RAW_BLOCK: 21, openBlock: 22, block_option0: 23, closeBlock: 24, openInverse: 25, block_option1: 26, OPEN_BLOCK: 27, openBlock_repetition0: 28, openBlock_option0: 29, openBlock_option1: 30, CLOSE: 31, OPEN_INVERSE: 32, openInverse_repetition0: 33, openInverse_option0: 34, openInverse_option1: 35, openInverseChain: 36, OPEN_INVERSE_CHAIN: 37, openInverseChain_repetition0: 38, openInverseChain_option0: 39, openInverseChain_option1: 40, inverseAndProgram: 41, INVERSE: 42, inverseChain: 43, inverseChain_option0: 44, OPEN_ENDBLOCK: 45, OPEN: 46, mustache_repetition0: 47, mustache_option0: 48, OPEN_UNESCAPED: 49, mustache_repetition1: 50, mustache_option1: 51, CLOSE_UNESCAPED: 52, OPEN_PARTIAL: 53, partialName: 54, partial_repetition0: 55, partial_option0: 56, param: 57, sexpr: 58, OPEN_SEXPR: 59, sexpr_repetition0: 60, sexpr_option0: 61, CLOSE_SEXPR: 62, hash: 63, hash_repetition_plus0: 64, hashSegment: 65, ID: 66, EQUALS: 67, blockParams: 68, OPEN_BLOCK_PARAMS: 69, blockParams_repetition_plus0: 70, CLOSE_BLOCK_PARAMS: 71, path: 72, dataName: 73, STRING: 74, NUMBER: 75, BOOLEAN: 76, UNDEFINED: 77, NULL: 78, DATA: 79, pathSegments: 80, SEP: 81, $accept: 0, $end: 1 },
-	        terminals_: { 2: "error", 5: "EOF", 13: "COMMENT", 14: "CONTENT", 16: "END_RAW_BLOCK", 17: "OPEN_RAW_BLOCK", 21: "CLOSE_RAW_BLOCK", 27: "OPEN_BLOCK", 31: "CLOSE", 32: "OPEN_INVERSE", 37: "OPEN_INVERSE_CHAIN", 42: "INVERSE", 45: "OPEN_ENDBLOCK", 46: "OPEN", 49: "OPEN_UNESCAPED", 52: "CLOSE_UNESCAPED", 53: "OPEN_PARTIAL", 59: "OPEN_SEXPR", 62: "CLOSE_SEXPR", 66: "ID", 67: "EQUALS", 69: "OPEN_BLOCK_PARAMS", 71: "CLOSE_BLOCK_PARAMS", 74: "STRING", 75: "NUMBER", 76: "BOOLEAN", 77: "UNDEFINED", 78: "NULL", 79: "DATA", 81: "SEP" },
-	        productions_: [0, [3, 2], [4, 1], [7, 1], [7, 1], [7, 1], [7, 1], [7, 1], [7, 1], [12, 1], [10, 3], [15, 5], [9, 4], [9, 4], [22, 6], [25, 6], [36, 6], [41, 2], [43, 3], [43, 1], [24, 3], [8, 5], [8, 5], [11, 5], [57, 1], [57, 1], [58, 5], [63, 1], [65, 3], [68, 3], [18, 1], [18, 1], [18, 1], [18, 1], [18, 1], [18, 1], [18, 1], [54, 1], [54, 1], [73, 2], [72, 1], [80, 3], [80, 1], [6, 0], [6, 2], [19, 0], [19, 2], [20, 0], [20, 1], [23, 0], [23, 1], [26, 0], [26, 1], [28, 0], [28, 2], [29, 0], [29, 1], [30, 0], [30, 1], [33, 0], [33, 2], [34, 0], [34, 1], [35, 0], [35, 1], [38, 0], [38, 2], [39, 0], [39, 1], [40, 0], [40, 1], [44, 0], [44, 1], [47, 0], [47, 2], [48, 0], [48, 1], [50, 0], [50, 2], [51, 0], [51, 1], [55, 0], [55, 2], [56, 0], [56, 1], [60, 0], [60, 2], [61, 0], [61, 1], [64, 1], [64, 2], [70, 1], [70, 2]],
-	        performAction: function anonymous(yytext, yyleng, yylineno, yy, yystate, $$, _$) {
-
-	            var $0 = $$.length - 1;
-	            switch (yystate) {
-	                case 1:
-	                    return $$[$0 - 1];
-	                    break;
-	                case 2:
-	                    this.$ = new yy.Program($$[$0], null, {}, yy.locInfo(this._$));
-	                    break;
-	                case 3:
-	                    this.$ = $$[$0];
-	                    break;
-	                case 4:
-	                    this.$ = $$[$0];
-	                    break;
-	                case 5:
-	                    this.$ = $$[$0];
-	                    break;
-	                case 6:
-	                    this.$ = $$[$0];
-	                    break;
-	                case 7:
-	                    this.$ = $$[$0];
-	                    break;
-	                case 8:
-	                    this.$ = new yy.CommentStatement(yy.stripComment($$[$0]), yy.stripFlags($$[$0], $$[$0]), yy.locInfo(this._$));
-	                    break;
-	                case 9:
-	                    this.$ = new yy.ContentStatement($$[$0], yy.locInfo(this._$));
-	                    break;
-	                case 10:
-	                    this.$ = yy.prepareRawBlock($$[$0 - 2], $$[$0 - 1], $$[$0], this._$);
-	                    break;
-	                case 11:
-	                    this.$ = { path: $$[$0 - 3], params: $$[$0 - 2], hash: $$[$0 - 1] };
-	                    break;
-	                case 12:
-	                    this.$ = yy.prepareBlock($$[$0 - 3], $$[$0 - 2], $$[$0 - 1], $$[$0], false, this._$);
-	                    break;
-	                case 13:
-	                    this.$ = yy.prepareBlock($$[$0 - 3], $$[$0 - 2], $$[$0 - 1], $$[$0], true, this._$);
-	                    break;
-	                case 14:
-	                    this.$ = { path: $$[$0 - 4], params: $$[$0 - 3], hash: $$[$0 - 2], blockParams: $$[$0 - 1], strip: yy.stripFlags($$[$0 - 5], $$[$0]) };
-	                    break;
-	                case 15:
-	                    this.$ = { path: $$[$0 - 4], params: $$[$0 - 3], hash: $$[$0 - 2], blockParams: $$[$0 - 1], strip: yy.stripFlags($$[$0 - 5], $$[$0]) };
-	                    break;
-	                case 16:
-	                    this.$ = { path: $$[$0 - 4], params: $$[$0 - 3], hash: $$[$0 - 2], blockParams: $$[$0 - 1], strip: yy.stripFlags($$[$0 - 5], $$[$0]) };
-	                    break;
-	                case 17:
-	                    this.$ = { strip: yy.stripFlags($$[$0 - 1], $$[$0 - 1]), program: $$[$0] };
-	                    break;
-	                case 18:
-	                    var inverse = yy.prepareBlock($$[$0 - 2], $$[$0 - 1], $$[$0], $$[$0], false, this._$),
-	                        program = new yy.Program([inverse], null, {}, yy.locInfo(this._$));
-	                    program.chained = true;
-
-	                    this.$ = { strip: $$[$0 - 2].strip, program: program, chain: true };
-
-	                    break;
-	                case 19:
-	                    this.$ = $$[$0];
-	                    break;
-	                case 20:
-	                    this.$ = { path: $$[$0 - 1], strip: yy.stripFlags($$[$0 - 2], $$[$0]) };
-	                    break;
-	                case 21:
-	                    this.$ = yy.prepareMustache($$[$0 - 3], $$[$0 - 2], $$[$0 - 1], $$[$0 - 4], yy.stripFlags($$[$0 - 4], $$[$0]), this._$);
-	                    break;
-	                case 22:
-	                    this.$ = yy.prepareMustache($$[$0 - 3], $$[$0 - 2], $$[$0 - 1], $$[$0 - 4], yy.stripFlags($$[$0 - 4], $$[$0]), this._$);
-	                    break;
-	                case 23:
-	                    this.$ = new yy.PartialStatement($$[$0 - 3], $$[$0 - 2], $$[$0 - 1], yy.stripFlags($$[$0 - 4], $$[$0]), yy.locInfo(this._$));
-	                    break;
-	                case 24:
-	                    this.$ = $$[$0];
-	                    break;
-	                case 25:
-	                    this.$ = $$[$0];
-	                    break;
-	                case 26:
-	                    this.$ = new yy.SubExpression($$[$0 - 3], $$[$0 - 2], $$[$0 - 1], yy.locInfo(this._$));
-	                    break;
-	                case 27:
-	                    this.$ = new yy.Hash($$[$0], yy.locInfo(this._$));
-	                    break;
-	                case 28:
-	                    this.$ = new yy.HashPair(yy.id($$[$0 - 2]), $$[$0], yy.locInfo(this._$));
-	                    break;
-	                case 29:
-	                    this.$ = yy.id($$[$0 - 1]);
-	                    break;
-	                case 30:
-	                    this.$ = $$[$0];
-	                    break;
-	                case 31:
-	                    this.$ = $$[$0];
-	                    break;
-	                case 32:
-	                    this.$ = new yy.StringLiteral($$[$0], yy.locInfo(this._$));
-	                    break;
-	                case 33:
-	                    this.$ = new yy.NumberLiteral($$[$0], yy.locInfo(this._$));
-	                    break;
-	                case 34:
-	                    this.$ = new yy.BooleanLiteral($$[$0], yy.locInfo(this._$));
-	                    break;
-	                case 35:
-	                    this.$ = new yy.UndefinedLiteral(yy.locInfo(this._$));
-	                    break;
-	                case 36:
-	                    this.$ = new yy.NullLiteral(yy.locInfo(this._$));
-	                    break;
-	                case 37:
-	                    this.$ = $$[$0];
-	                    break;
-	                case 38:
-	                    this.$ = $$[$0];
-	                    break;
-	                case 39:
-	                    this.$ = yy.preparePath(true, $$[$0], this._$);
-	                    break;
-	                case 40:
-	                    this.$ = yy.preparePath(false, $$[$0], this._$);
-	                    break;
-	                case 41:
-	                    $$[$0 - 2].push({ part: yy.id($$[$0]), original: $$[$0], separator: $$[$0 - 1] });this.$ = $$[$0 - 2];
-	                    break;
-	                case 42:
-	                    this.$ = [{ part: yy.id($$[$0]), original: $$[$0] }];
-	                    break;
-	                case 43:
-	                    this.$ = [];
-	                    break;
-	                case 44:
-	                    $$[$0 - 1].push($$[$0]);
-	                    break;
-	                case 45:
-	                    this.$ = [];
-	                    break;
-	                case 46:
-	                    $$[$0 - 1].push($$[$0]);
-	                    break;
-	                case 53:
-	                    this.$ = [];
-	                    break;
-	                case 54:
-	                    $$[$0 - 1].push($$[$0]);
-	                    break;
-	                case 59:
-	                    this.$ = [];
-	                    break;
-	                case 60:
-	                    $$[$0 - 1].push($$[$0]);
-	                    break;
-	                case 65:
-	                    this.$ = [];
-	                    break;
-	                case 66:
-	                    $$[$0 - 1].push($$[$0]);
-	                    break;
-	                case 73:
-	                    this.$ = [];
-	                    break;
-	                case 74:
-	                    $$[$0 - 1].push($$[$0]);
-	                    break;
-	                case 77:
-	                    this.$ = [];
-	                    break;
-	                case 78:
-	                    $$[$0 - 1].push($$[$0]);
-	                    break;
-	                case 81:
-	                    this.$ = [];
-	                    break;
-	                case 82:
-	                    $$[$0 - 1].push($$[$0]);
-	                    break;
-	                case 85:
-	                    this.$ = [];
-	                    break;
-	                case 86:
-	                    $$[$0 - 1].push($$[$0]);
-	                    break;
-	                case 89:
-	                    this.$ = [$$[$0]];
-	                    break;
-	                case 90:
-	                    $$[$0 - 1].push($$[$0]);
-	                    break;
-	                case 91:
-	                    this.$ = [$$[$0]];
-	                    break;
-	                case 92:
-	                    $$[$0 - 1].push($$[$0]);
-	                    break;
-	            }
-	        },
-	        table: [{ 3: 1, 4: 2, 5: [2, 43], 6: 3, 13: [2, 43], 14: [2, 43], 17: [2, 43], 27: [2, 43], 32: [2, 43], 46: [2, 43], 49: [2, 43], 53: [2, 43] }, { 1: [3] }, { 5: [1, 4] }, { 5: [2, 2], 7: 5, 8: 6, 9: 7, 10: 8, 11: 9, 12: 10, 13: [1, 11], 14: [1, 18], 15: 16, 17: [1, 21], 22: 14, 25: 15, 27: [1, 19], 32: [1, 20], 37: [2, 2], 42: [2, 2], 45: [2, 2], 46: [1, 12], 49: [1, 13], 53: [1, 17] }, { 1: [2, 1] }, { 5: [2, 44], 13: [2, 44], 14: [2, 44], 17: [2, 44], 27: [2, 44], 32: [2, 44], 37: [2, 44], 42: [2, 44], 45: [2, 44], 46: [2, 44], 49: [2, 44], 53: [2, 44] }, { 5: [2, 3], 13: [2, 3], 14: [2, 3], 17: [2, 3], 27: [2, 3], 32: [2, 3], 37: [2, 3], 42: [2, 3], 45: [2, 3], 46: [2, 3], 49: [2, 3], 53: [2, 3] }, { 5: [2, 4], 13: [2, 4], 14: [2, 4], 17: [2, 4], 27: [2, 4], 32: [2, 4], 37: [2, 4], 42: [2, 4], 45: [2, 4], 46: [2, 4], 49: [2, 4], 53: [2, 4] }, { 5: [2, 5], 13: [2, 5], 14: [2, 5], 17: [2, 5], 27: [2, 5], 32: [2, 5], 37: [2, 5], 42: [2, 5], 45: [2, 5], 46: [2, 5], 49: [2, 5], 53: [2, 5] }, { 5: [2, 6], 13: [2, 6], 14: [2, 6], 17: [2, 6], 27: [2, 6], 32: [2, 6], 37: [2, 6], 42: [2, 6], 45: [2, 6], 46: [2, 6], 49: [2, 6], 53: [2, 6] }, { 5: [2, 7], 13: [2, 7], 14: [2, 7], 17: [2, 7], 27: [2, 7], 32: [2, 7], 37: [2, 7], 42: [2, 7], 45: [2, 7], 46: [2, 7], 49: [2, 7], 53: [2, 7] }, { 5: [2, 8], 13: [2, 8], 14: [2, 8], 17: [2, 8], 27: [2, 8], 32: [2, 8], 37: [2, 8], 42: [2, 8], 45: [2, 8], 46: [2, 8], 49: [2, 8], 53: [2, 8] }, { 18: 22, 66: [1, 32], 72: 23, 73: 24, 74: [1, 25], 75: [1, 26], 76: [1, 27], 77: [1, 28], 78: [1, 29], 79: [1, 31], 80: 30 }, { 18: 33, 66: [1, 32], 72: 23, 73: 24, 74: [1, 25], 75: [1, 26], 76: [1, 27], 77: [1, 28], 78: [1, 29], 79: [1, 31], 80: 30 }, { 4: 34, 6: 3, 13: [2, 43], 14: [2, 43], 17: [2, 43], 27: [2, 43], 32: [2, 43], 37: [2, 43], 42: [2, 43], 45: [2, 43], 46: [2, 43], 49: [2, 43], 53: [2, 43] }, { 4: 35, 6: 3, 13: [2, 43], 14: [2, 43], 17: [2, 43], 27: [2, 43], 32: [2, 43], 42: [2, 43], 45: [2, 43], 46: [2, 43], 49: [2, 43], 53: [2, 43] }, { 12: 36, 14: [1, 18] }, { 18: 38, 54: 37, 58: 39, 59: [1, 40], 66: [1, 32], 72: 23, 73: 24, 74: [1, 25], 75: [1, 26], 76: [1, 27], 77: [1, 28], 78: [1, 29], 79: [1, 31], 80: 30 }, { 5: [2, 9], 13: [2, 9], 14: [2, 9], 16: [2, 9], 17: [2, 9], 27: [2, 9], 32: [2, 9], 37: [2, 9], 42: [2, 9], 45: [2, 9], 46: [2, 9], 49: [2, 9], 53: [2, 9] }, { 18: 41, 66: [1, 32], 72: 23, 73: 24, 74: [1, 25], 75: [1, 26], 76: [1, 27], 77: [1, 28], 78: [1, 29], 79: [1, 31], 80: 30 }, { 18: 42, 66: [1, 32], 72: 23, 73: 24, 74: [1, 25], 75: [1, 26], 76: [1, 27], 77: [1, 28], 78: [1, 29], 79: [1, 31], 80: 30 }, { 18: 43, 66: [1, 32], 72: 23, 73: 24, 74: [1, 25], 75: [1, 26], 76: [1, 27], 77: [1, 28], 78: [1, 29], 79: [1, 31], 80: 30 }, { 31: [2, 73], 47: 44, 59: [2, 73], 66: [2, 73], 74: [2, 73], 75: [2, 73], 76: [2, 73], 77: [2, 73], 78: [2, 73], 79: [2, 73] }, { 21: [2, 30], 31: [2, 30], 52: [2, 30], 59: [2, 30], 62: [2, 30], 66: [2, 30], 69: [2, 30], 74: [2, 30], 75: [2, 30], 76: [2, 30], 77: [2, 30], 78: [2, 30], 79: [2, 30] }, { 21: [2, 31], 31: [2, 31], 52: [2, 31], 59: [2, 31], 62: [2, 31], 66: [2, 31], 69: [2, 31], 74: [2, 31], 75: [2, 31], 76: [2, 31], 77: [2, 31], 78: [2, 31], 79: [2, 31] }, { 21: [2, 32], 31: [2, 32], 52: [2, 32], 59: [2, 32], 62: [2, 32], 66: [2, 32], 69: [2, 32], 74: [2, 32], 75: [2, 32], 76: [2, 32], 77: [2, 32], 78: [2, 32], 79: [2, 32] }, { 21: [2, 33], 31: [2, 33], 52: [2, 33], 59: [2, 33], 62: [2, 33], 66: [2, 33], 69: [2, 33], 74: [2, 33], 75: [2, 33], 76: [2, 33], 77: [2, 33], 78: [2, 33], 79: [2, 33] }, { 21: [2, 34], 31: [2, 34], 52: [2, 34], 59: [2, 34], 62: [2, 34], 66: [2, 34], 69: [2, 34], 74: [2, 34], 75: [2, 34], 76: [2, 34], 77: [2, 34], 78: [2, 34], 79: [2, 34] }, { 21: [2, 35], 31: [2, 35], 52: [2, 35], 59: [2, 35], 62: [2, 35], 66: [2, 35], 69: [2, 35], 74: [2, 35], 75: [2, 35], 76: [2, 35], 77: [2, 35], 78: [2, 35], 79: [2, 35] }, { 21: [2, 36], 31: [2, 36], 52: [2, 36], 59: [2, 36], 62: [2, 36], 66: [2, 36], 69: [2, 36], 74: [2, 36], 75: [2, 36], 76: [2, 36], 77: [2, 36], 78: [2, 36], 79: [2, 36] }, { 21: [2, 40], 31: [2, 40], 52: [2, 40], 59: [2, 40], 62: [2, 40], 66: [2, 40], 69: [2, 40], 74: [2, 40], 75: [2, 40], 76: [2, 40], 77: [2, 40], 78: [2, 40], 79: [2, 40], 81: [1, 45] }, { 66: [1, 32], 80: 46 }, { 21: [2, 42], 31: [2, 42], 52: [2, 42], 59: [2, 42], 62: [2, 42], 66: [2, 42], 69: [2, 42], 74: [2, 42], 75: [2, 42], 76: [2, 42], 77: [2, 42], 78: [2, 42], 79: [2, 42], 81: [2, 42] }, { 50: 47, 52: [2, 77], 59: [2, 77], 66: [2, 77], 74: [2, 77], 75: [2, 77], 76: [2, 77], 77: [2, 77], 78: [2, 77], 79: [2, 77] }, { 23: 48, 36: 50, 37: [1, 52], 41: 51, 42: [1, 53], 43: 49, 45: [2, 49] }, { 26: 54, 41: 55, 42: [1, 53], 45: [2, 51] }, { 16: [1, 56] }, { 31: [2, 81], 55: 57, 59: [2, 81], 66: [2, 81], 74: [2, 81], 75: [2, 81], 76: [2, 81], 77: [2, 81], 78: [2, 81], 79: [2, 81] }, { 31: [2, 37], 59: [2, 37], 66: [2, 37], 74: [2, 37], 75: [2, 37], 76: [2, 37], 77: [2, 37], 78: [2, 37], 79: [2, 37] }, { 31: [2, 38], 59: [2, 38], 66: [2, 38], 74: [2, 38], 75: [2, 38], 76: [2, 38], 77: [2, 38], 78: [2, 38], 79: [2, 38] }, { 18: 58, 66: [1, 32], 72: 23, 73: 24, 74: [1, 25], 75: [1, 26], 76: [1, 27], 77: [1, 28], 78: [1, 29], 79: [1, 31], 80: 30 }, { 28: 59, 31: [2, 53], 59: [2, 53], 66: [2, 53], 69: [2, 53], 74: [2, 53], 75: [2, 53], 76: [2, 53], 77: [2, 53], 78: [2, 53], 79: [2, 53] }, { 31: [2, 59], 33: 60, 59: [2, 59], 66: [2, 59], 69: [2, 59], 74: [2, 59], 75: [2, 59], 76: [2, 59], 77: [2, 59], 78: [2, 59], 79: [2, 59] }, { 19: 61, 21: [2, 45], 59: [2, 45], 66: [2, 45], 74: [2, 45], 75: [2, 45], 76: [2, 45], 77: [2, 45], 78: [2, 45], 79: [2, 45] }, { 18: 65, 31: [2, 75], 48: 62, 57: 63, 58: 66, 59: [1, 40], 63: 64, 64: 67, 65: 68, 66: [1, 69], 72: 23, 73: 24, 74: [1, 25], 75: [1, 26], 76: [1, 27], 77: [1, 28], 78: [1, 29], 79: [1, 31], 80: 30 }, { 66: [1, 70] }, { 21: [2, 39], 31: [2, 39], 52: [2, 39], 59: [2, 39], 62: [2, 39], 66: [2, 39], 69: [2, 39], 74: [2, 39], 75: [2, 39], 76: [2, 39], 77: [2, 39], 78: [2, 39], 79: [2, 39], 81: [1, 45] }, { 18: 65, 51: 71, 52: [2, 79], 57: 72, 58: 66, 59: [1, 40], 63: 73, 64: 67, 65: 68, 66: [1, 69], 72: 23, 73: 24, 74: [1, 25], 75: [1, 26], 76: [1, 27], 77: [1, 28], 78: [1, 29], 79: [1, 31], 80: 30 }, { 24: 74, 45: [1, 75] }, { 45: [2, 50] }, { 4: 76, 6: 3, 13: [2, 43], 14: [2, 43], 17: [2, 43], 27: [2, 43], 32: [2, 43], 37: [2, 43], 42: [2, 43], 45: [2, 43], 46: [2, 43], 49: [2, 43], 53: [2, 43] }, { 45: [2, 19] }, { 18: 77, 66: [1, 32], 72: 23, 73: 24, 74: [1, 25], 75: [1, 26], 76: [1, 27], 77: [1, 28], 78: [1, 29], 79: [1, 31], 80: 30 }, { 4: 78, 6: 3, 13: [2, 43], 14: [2, 43], 17: [2, 43], 27: [2, 43], 32: [2, 43], 45: [2, 43], 46: [2, 43], 49: [2, 43], 53: [2, 43] }, { 24: 79, 45: [1, 75] }, { 45: [2, 52] }, { 5: [2, 10], 13: [2, 10], 14: [2, 10], 17: [2, 10], 27: [2, 10], 32: [2, 10], 37: [2, 10], 42: [2, 10], 45: [2, 10], 46: [2, 10], 49: [2, 10], 53: [2, 10] }, { 18: 65, 31: [2, 83], 56: 80, 57: 81, 58: 66, 59: [1, 40], 63: 82, 64: 67, 65: 68, 66: [1, 69], 72: 23, 73: 24, 74: [1, 25], 75: [1, 26], 76: [1, 27], 77: [1, 28], 78: [1, 29], 79: [1, 31], 80: 30 }, { 59: [2, 85], 60: 83, 62: [2, 85], 66: [2, 85], 74: [2, 85], 75: [2, 85], 76: [2, 85], 77: [2, 85], 78: [2, 85], 79: [2, 85] }, { 18: 65, 29: 84, 31: [2, 55], 57: 85, 58: 66, 59: [1, 40], 63: 86, 64: 67, 65: 68, 66: [1, 69], 69: [2, 55], 72: 23, 73: 24, 74: [1, 25], 75: [1, 26], 76: [1, 27], 77: [1, 28], 78: [1, 29], 79: [1, 31], 80: 30 }, { 18: 65, 31: [2, 61], 34: 87, 57: 88, 58: 66, 59: [1, 40], 63: 89, 64: 67, 65: 68, 66: [1, 69], 69: [2, 61], 72: 23, 73: 24, 74: [1, 25], 75: [1, 26], 76: [1, 27], 77: [1, 28], 78: [1, 29], 79: [1, 31], 80: 30 }, { 18: 65, 20: 90, 21: [2, 47], 57: 91, 58: 66, 59: [1, 40], 63: 92, 64: 67, 65: 68, 66: [1, 69], 72: 23, 73: 24, 74: [1, 25], 75: [1, 26], 76: [1, 27], 77: [1, 28], 78: [1, 29], 79: [1, 31], 80: 30 }, { 31: [1, 93] }, { 31: [2, 74], 59: [2, 74], 66: [2, 74], 74: [2, 74], 75: [2, 74], 76: [2, 74], 77: [2, 74], 78: [2, 74], 79: [2, 74] }, { 31: [2, 76] }, { 21: [2, 24], 31: [2, 24], 52: [2, 24], 59: [2, 24], 62: [2, 24], 66: [2, 24], 69: [2, 24], 74: [2, 24], 75: [2, 24], 76: [2, 24], 77: [2, 24], 78: [2, 24], 79: [2, 24] }, { 21: [2, 25], 31: [2, 25], 52: [2, 25], 59: [2, 25], 62: [2, 25], 66: [2, 25], 69: [2, 25], 74: [2, 25], 75: [2, 25], 76: [2, 25], 77: [2, 25], 78: [2, 25], 79: [2, 25] }, { 21: [2, 27], 31: [2, 27], 52: [2, 27], 62: [2, 27], 65: 94, 66: [1, 95], 69: [2, 27] }, { 21: [2, 89], 31: [2, 89], 52: [2, 89], 62: [2, 89], 66: [2, 89], 69: [2, 89] }, { 21: [2, 42], 31: [2, 42], 52: [2, 42], 59: [2, 42], 62: [2, 42], 66: [2, 42], 67: [1, 96], 69: [2, 42], 74: [2, 42], 75: [2, 42], 76: [2, 42], 77: [2, 42], 78: [2, 42], 79: [2, 42], 81: [2, 42] }, { 21: [2, 41], 31: [2, 41], 52: [2, 41], 59: [2, 41], 62: [2, 41], 66: [2, 41], 69: [2, 41], 74: [2, 41], 75: [2, 41], 76: [2, 41], 77: [2, 41], 78: [2, 41], 79: [2, 41], 81: [2, 41] }, { 52: [1, 97] }, { 52: [2, 78], 59: [2, 78], 66: [2, 78], 74: [2, 78], 75: [2, 78], 76: [2, 78], 77: [2, 78], 78: [2, 78], 79: [2, 78] }, { 52: [2, 80] }, { 5: [2, 12], 13: [2, 12], 14: [2, 12], 17: [2, 12], 27: [2, 12], 32: [2, 12], 37: [2, 12], 42: [2, 12], 45: [2, 12], 46: [2, 12], 49: [2, 12], 53: [2, 12] }, { 18: 98, 66: [1, 32], 72: 23, 73: 24, 74: [1, 25], 75: [1, 26], 76: [1, 27], 77: [1, 28], 78: [1, 29], 79: [1, 31], 80: 30 }, { 36: 50, 37: [1, 52], 41: 51, 42: [1, 53], 43: 100, 44: 99, 45: [2, 71] }, { 31: [2, 65], 38: 101, 59: [2, 65], 66: [2, 65], 69: [2, 65], 74: [2, 65], 75: [2, 65], 76: [2, 65], 77: [2, 65], 78: [2, 65], 79: [2, 65] }, { 45: [2, 17] }, { 5: [2, 13], 13: [2, 13], 14: [2, 13], 17: [2, 13], 27: [2, 13], 32: [2, 13], 37: [2, 13], 42: [2, 13], 45: [2, 13], 46: [2, 13], 49: [2, 13], 53: [2, 13] }, { 31: [1, 102] }, { 31: [2, 82], 59: [2, 82], 66: [2, 82], 74: [2, 82], 75: [2, 82], 76: [2, 82], 77: [2, 82], 78: [2, 82], 79: [2, 82] }, { 31: [2, 84] }, { 18: 65, 57: 104, 58: 66, 59: [1, 40], 61: 103, 62: [2, 87], 63: 105, 64: 67, 65: 68, 66: [1, 69], 72: 23, 73: 24, 74: [1, 25], 75: [1, 26], 76: [1, 27], 77: [1, 28], 78: [1, 29], 79: [1, 31], 80: 30 }, { 30: 106, 31: [2, 57], 68: 107, 69: [1, 108] }, { 31: [2, 54], 59: [2, 54], 66: [2, 54], 69: [2, 54], 74: [2, 54], 75: [2, 54], 76: [2, 54], 77: [2, 54], 78: [2, 54], 79: [2, 54] }, { 31: [2, 56], 69: [2, 56] }, { 31: [2, 63], 35: 109, 68: 110, 69: [1, 108] }, { 31: [2, 60], 59: [2, 60], 66: [2, 60], 69: [2, 60], 74: [2, 60], 75: [2, 60], 76: [2, 60], 77: [2, 60], 78: [2, 60], 79: [2, 60] }, { 31: [2, 62], 69: [2, 62] }, { 21: [1, 111] }, { 21: [2, 46], 59: [2, 46], 66: [2, 46], 74: [2, 46], 75: [2, 46], 76: [2, 46], 77: [2, 46], 78: [2, 46], 79: [2, 46] }, { 21: [2, 48] }, { 5: [2, 21], 13: [2, 21], 14: [2, 21], 17: [2, 21], 27: [2, 21], 32: [2, 21], 37: [2, 21], 42: [2, 21], 45: [2, 21], 46: [2, 21], 49: [2, 21], 53: [2, 21] }, { 21: [2, 90], 31: [2, 90], 52: [2, 90], 62: [2, 90], 66: [2, 90], 69: [2, 90] }, { 67: [1, 96] }, { 18: 65, 57: 112, 58: 66, 59: [1, 40], 66: [1, 32], 72: 23, 73: 24, 74: [1, 25], 75: [1, 26], 76: [1, 27], 77: [1, 28], 78: [1, 29], 79: [1, 31], 80: 30 }, { 5: [2, 22], 13: [2, 22], 14: [2, 22], 17: [2, 22], 27: [2, 22], 32: [2, 22], 37: [2, 22], 42: [2, 22], 45: [2, 22], 46: [2, 22], 49: [2, 22], 53: [2, 22] }, { 31: [1, 113] }, { 45: [2, 18] }, { 45: [2, 72] }, { 18: 65, 31: [2, 67], 39: 114, 57: 115, 58: 66, 59: [1, 40], 63: 116, 64: 67, 65: 68, 66: [1, 69], 69: [2, 67], 72: 23, 73: 24, 74: [1, 25], 75: [1, 26], 76: [1, 27], 77: [1, 28], 78: [1, 29], 79: [1, 31], 80: 30 }, { 5: [2, 23], 13: [2, 23], 14: [2, 23], 17: [2, 23], 27: [2, 23], 32: [2, 23], 37: [2, 23], 42: [2, 23], 45: [2, 23], 46: [2, 23], 49: [2, 23], 53: [2, 23] }, { 62: [1, 117] }, { 59: [2, 86], 62: [2, 86], 66: [2, 86], 74: [2, 86], 75: [2, 86], 76: [2, 86], 77: [2, 86], 78: [2, 86], 79: [2, 86] }, { 62: [2, 88] }, { 31: [1, 118] }, { 31: [2, 58] }, { 66: [1, 120], 70: 119 }, { 31: [1, 121] }, { 31: [2, 64] }, { 14: [2, 11] }, { 21: [2, 28], 31: [2, 28], 52: [2, 28], 62: [2, 28], 66: [2, 28], 69: [2, 28] }, { 5: [2, 20], 13: [2, 20], 14: [2, 20], 17: [2, 20], 27: [2, 20], 32: [2, 20], 37: [2, 20], 42: [2, 20], 45: [2, 20], 46: [2, 20], 49: [2, 20], 53: [2, 20] }, { 31: [2, 69], 40: 122, 68: 123, 69: [1, 108] }, { 31: [2, 66], 59: [2, 66], 66: [2, 66], 69: [2, 66], 74: [2, 66], 75: [2, 66], 76: [2, 66], 77: [2, 66], 78: [2, 66], 79: [2, 66] }, { 31: [2, 68], 69: [2, 68] }, { 21: [2, 26], 31: [2, 26], 52: [2, 26], 59: [2, 26], 62: [2, 26], 66: [2, 26], 69: [2, 26], 74: [2, 26], 75: [2, 26], 76: [2, 26], 77: [2, 26], 78: [2, 26], 79: [2, 26] }, { 13: [2, 14], 14: [2, 14], 17: [2, 14], 27: [2, 14], 32: [2, 14], 37: [2, 14], 42: [2, 14], 45: [2, 14], 46: [2, 14], 49: [2, 14], 53: [2, 14] }, { 66: [1, 125], 71: [1, 124] }, { 66: [2, 91], 71: [2, 91] }, { 13: [2, 15], 14: [2, 15], 17: [2, 15], 27: [2, 15], 32: [2, 15], 42: [2, 15], 45: [2, 15], 46: [2, 15], 49: [2, 15], 53: [2, 15] }, { 31: [1, 126] }, { 31: [2, 70] }, { 31: [2, 29] }, { 66: [2, 92], 71: [2, 92] }, { 13: [2, 16], 14: [2, 16], 17: [2, 16], 27: [2, 16], 32: [2, 16], 37: [2, 16], 42: [2, 16], 45: [2, 16], 46: [2, 16], 49: [2, 16], 53: [2, 16] }],
-	        defaultActions: { 4: [2, 1], 49: [2, 50], 51: [2, 19], 55: [2, 52], 64: [2, 76], 73: [2, 80], 78: [2, 17], 82: [2, 84], 92: [2, 48], 99: [2, 18], 100: [2, 72], 105: [2, 88], 107: [2, 58], 110: [2, 64], 111: [2, 11], 123: [2, 70], 124: [2, 29] },
-	        parseError: function parseError(str, hash) {
-	            throw new Error(str);
-	        },
-	        parse: function parse(input) {
-	            var self = this,
-	                stack = [0],
-	                vstack = [null],
-	                lstack = [],
-	                table = this.table,
-	                yytext = "",
-	                yylineno = 0,
-	                yyleng = 0,
-	                recovering = 0,
-	                TERROR = 2,
-	                EOF = 1;
-	            this.lexer.setInput(input);
-	            this.lexer.yy = this.yy;
-	            this.yy.lexer = this.lexer;
-	            this.yy.parser = this;
-	            if (typeof this.lexer.yylloc == "undefined") this.lexer.yylloc = {};
-	            var yyloc = this.lexer.yylloc;
-	            lstack.push(yyloc);
-	            var ranges = this.lexer.options && this.lexer.options.ranges;
-	            if (typeof this.yy.parseError === "function") this.parseError = this.yy.parseError;
-	            function popStack(n) {
-	                stack.length = stack.length - 2 * n;
-	                vstack.length = vstack.length - n;
-	                lstack.length = lstack.length - n;
-	            }
-	            function lex() {
-	                var token;
-	                token = self.lexer.lex() || 1;
-	                if (typeof token !== "number") {
-	                    token = self.symbols_[token] || token;
-	                }
-	                return token;
-	            }
-	            var symbol,
-	                preErrorSymbol,
-	                state,
-	                action,
-	                a,
-	                r,
-	                yyval = {},
-	                p,
-	                len,
-	                newState,
-	                expected;
-	            while (true) {
-	                state = stack[stack.length - 1];
-	                if (this.defaultActions[state]) {
-	                    action = this.defaultActions[state];
-	                } else {
-	                    if (symbol === null || typeof symbol == "undefined") {
-	                        symbol = lex();
-	                    }
-	                    action = table[state] && table[state][symbol];
-	                }
-	                if (typeof action === "undefined" || !action.length || !action[0]) {
-	                    var errStr = "";
-	                    if (!recovering) {
-	                        expected = [];
-	                        for (p in table[state]) if (this.terminals_[p] && p > 2) {
-	                            expected.push("'" + this.terminals_[p] + "'");
-	                        }
-	                        if (this.lexer.showPosition) {
-	                            errStr = "Parse error on line " + (yylineno + 1) + ":\n" + this.lexer.showPosition() + "\nExpecting " + expected.join(", ") + ", got '" + (this.terminals_[symbol] || symbol) + "'";
-	                        } else {
-	                            errStr = "Parse error on line " + (yylineno + 1) + ": Unexpected " + (symbol == 1 ? "end of input" : "'" + (this.terminals_[symbol] || symbol) + "'");
-	                        }
-	                        this.parseError(errStr, { text: this.lexer.match, token: this.terminals_[symbol] || symbol, line: this.lexer.yylineno, loc: yyloc, expected: expected });
-	                    }
-	                }
-	                if (action[0] instanceof Array && action.length > 1) {
-	                    throw new Error("Parse Error: multiple actions possible at state: " + state + ", token: " + symbol);
-	                }
-	                switch (action[0]) {
-	                    case 1:
-	                        stack.push(symbol);
-	                        vstack.push(this.lexer.yytext);
-	                        lstack.push(this.lexer.yylloc);
-	                        stack.push(action[1]);
-	                        symbol = null;
-	                        if (!preErrorSymbol) {
-	                            yyleng = this.lexer.yyleng;
-	                            yytext = this.lexer.yytext;
-	                            yylineno = this.lexer.yylineno;
-	                            yyloc = this.lexer.yylloc;
-	                            if (recovering > 0) recovering--;
-	                        } else {
-	                            symbol = preErrorSymbol;
-	                            preErrorSymbol = null;
-	                        }
-	                        break;
-	                    case 2:
-	                        len = this.productions_[action[1]][1];
-	                        yyval.$ = vstack[vstack.length - len];
-	                        yyval._$ = { first_line: lstack[lstack.length - (len || 1)].first_line, last_line: lstack[lstack.length - 1].last_line, first_column: lstack[lstack.length - (len || 1)].first_column, last_column: lstack[lstack.length - 1].last_column };
-	                        if (ranges) {
-	                            yyval._$.range = [lstack[lstack.length - (len || 1)].range[0], lstack[lstack.length - 1].range[1]];
-	                        }
-	                        r = this.performAction.call(yyval, yytext, yyleng, yylineno, this.yy, action[1], vstack, lstack);
-	                        if (typeof r !== "undefined") {
-	                            return r;
-	                        }
-	                        if (len) {
-	                            stack = stack.slice(0, -1 * len * 2);
-	                            vstack = vstack.slice(0, -1 * len);
-	                            lstack = lstack.slice(0, -1 * len);
-	                        }
-	                        stack.push(this.productions_[action[1]][0]);
-	                        vstack.push(yyval.$);
-	                        lstack.push(yyval._$);
-	                        newState = table[stack[stack.length - 2]][stack[stack.length - 1]];
-	                        stack.push(newState);
-	                        break;
-	                    case 3:
-	                        return true;
-	                }
-	            }
-	            return true;
-	        }
-	    };
-	    /* Jison generated lexer */
-	    var lexer = (function () {
-	        var lexer = { EOF: 1,
-	            parseError: function parseError(str, hash) {
-	                if (this.yy.parser) {
-	                    this.yy.parser.parseError(str, hash);
-	                } else {
-	                    throw new Error(str);
-	                }
-	            },
-	            setInput: function setInput(input) {
-	                this._input = input;
-	                this._more = this._less = this.done = false;
-	                this.yylineno = this.yyleng = 0;
-	                this.yytext = this.matched = this.match = "";
-	                this.conditionStack = ["INITIAL"];
-	                this.yylloc = { first_line: 1, first_column: 0, last_line: 1, last_column: 0 };
-	                if (this.options.ranges) this.yylloc.range = [0, 0];
-	                this.offset = 0;
-	                return this;
-	            },
-	            input: function input() {
-	                var ch = this._input[0];
-	                this.yytext += ch;
-	                this.yyleng++;
-	                this.offset++;
-	                this.match += ch;
-	                this.matched += ch;
-	                var lines = ch.match(/(?:\r\n?|\n).*/g);
-	                if (lines) {
-	                    this.yylineno++;
-	                    this.yylloc.last_line++;
-	                } else {
-	                    this.yylloc.last_column++;
-	                }
-	                if (this.options.ranges) this.yylloc.range[1]++;
-
-	                this._input = this._input.slice(1);
-	                return ch;
-	            },
-	            unput: function unput(ch) {
-	                var len = ch.length;
-	                var lines = ch.split(/(?:\r\n?|\n)/g);
-
-	                this._input = ch + this._input;
-	                this.yytext = this.yytext.substr(0, this.yytext.length - len - 1);
-	                //this.yyleng -= len;
-	                this.offset -= len;
-	                var oldLines = this.match.split(/(?:\r\n?|\n)/g);
-	                this.match = this.match.substr(0, this.match.length - 1);
-	                this.matched = this.matched.substr(0, this.matched.length - 1);
-
-	                if (lines.length - 1) this.yylineno -= lines.length - 1;
-	                var r = this.yylloc.range;
-
-	                this.yylloc = { first_line: this.yylloc.first_line,
-	                    last_line: this.yylineno + 1,
-	                    first_column: this.yylloc.first_column,
-	                    last_column: lines ? (lines.length === oldLines.length ? this.yylloc.first_column : 0) + oldLines[oldLines.length - lines.length].length - lines[0].length : this.yylloc.first_column - len
-	                };
-
-	                if (this.options.ranges) {
-	                    this.yylloc.range = [r[0], r[0] + this.yyleng - len];
-	                }
-	                return this;
-	            },
-	            more: function more() {
-	                this._more = true;
-	                return this;
-	            },
-	            less: function less(n) {
-	                this.unput(this.match.slice(n));
-	            },
-	            pastInput: function pastInput() {
-	                var past = this.matched.substr(0, this.matched.length - this.match.length);
-	                return (past.length > 20 ? "..." : "") + past.substr(-20).replace(/\n/g, "");
-	            },
-	            upcomingInput: function upcomingInput() {
-	                var next = this.match;
-	                if (next.length < 20) {
-	                    next += this._input.substr(0, 20 - next.length);
-	                }
-	                return (next.substr(0, 20) + (next.length > 20 ? "..." : "")).replace(/\n/g, "");
-	            },
-	            showPosition: function showPosition() {
-	                var pre = this.pastInput();
-	                var c = new Array(pre.length + 1).join("-");
-	                return pre + this.upcomingInput() + "\n" + c + "^";
-	            },
-	            next: function next() {
-	                if (this.done) {
-	                    return this.EOF;
-	                }
-	                if (!this._input) this.done = true;
-
-	                var token, match, tempMatch, index, col, lines;
-	                if (!this._more) {
-	                    this.yytext = "";
-	                    this.match = "";
-	                }
-	                var rules = this._currentRules();
-	                for (var i = 0; i < rules.length; i++) {
-	                    tempMatch = this._input.match(this.rules[rules[i]]);
-	                    if (tempMatch && (!match || tempMatch[0].length > match[0].length)) {
-	                        match = tempMatch;
-	                        index = i;
-	                        if (!this.options.flex) break;
-	                    }
-	                }
-	                if (match) {
-	                    lines = match[0].match(/(?:\r\n?|\n).*/g);
-	                    if (lines) this.yylineno += lines.length;
-	                    this.yylloc = { first_line: this.yylloc.last_line,
-	                        last_line: this.yylineno + 1,
-	                        first_column: this.yylloc.last_column,
-	                        last_column: lines ? lines[lines.length - 1].length - lines[lines.length - 1].match(/\r?\n?/)[0].length : this.yylloc.last_column + match[0].length };
-	                    this.yytext += match[0];
-	                    this.match += match[0];
-	                    this.matches = match;
-	                    this.yyleng = this.yytext.length;
-	                    if (this.options.ranges) {
-	                        this.yylloc.range = [this.offset, this.offset += this.yyleng];
-	                    }
-	                    this._more = false;
-	                    this._input = this._input.slice(match[0].length);
-	                    this.matched += match[0];
-	                    token = this.performAction.call(this, this.yy, this, rules[index], this.conditionStack[this.conditionStack.length - 1]);
-	                    if (this.done && this._input) this.done = false;
-	                    if (token) {
-	                        return token;
-	                    } else {
-	                        return;
-	                    }
-	                }
-	                if (this._input === "") {
-	                    return this.EOF;
-	                } else {
-	                    return this.parseError("Lexical error on line " + (this.yylineno + 1) + ". Unrecognized text.\n" + this.showPosition(), { text: "", token: null, line: this.yylineno });
-	                }
-	            },
-	            lex: function lex() {
-	                var r = this.next();
-	                if (typeof r !== "undefined") {
-	                    return r;
-	                } else {
-	                    return this.lex();
-	                }
-	            },
-	            begin: function begin(condition) {
-	                this.conditionStack.push(condition);
-	            },
-	            popState: function popState() {
-	                return this.conditionStack.pop();
-	            },
-	            _currentRules: function _currentRules() {
-	                return this.conditions[this.conditionStack[this.conditionStack.length - 1]].rules;
-	            },
-	            topState: function topState() {
-	                return this.conditionStack[this.conditionStack.length - 2];
-	            },
-	            pushState: function begin(condition) {
-	                this.begin(condition);
-	            } };
-	        lexer.options = {};
-	        lexer.performAction = function anonymous(yy, yy_, $avoiding_name_collisions, YY_START) {
-
-	            function strip(start, end) {
-	                return yy_.yytext = yy_.yytext.substr(start, yy_.yyleng - end);
-	            }
-
-	            var YYSTATE = YY_START;
-	            switch ($avoiding_name_collisions) {
-	                case 0:
-	                    if (yy_.yytext.slice(-2) === "\\\\") {
-	                        strip(0, 1);
-	                        this.begin("mu");
-	                    } else if (yy_.yytext.slice(-1) === "\\") {
-	                        strip(0, 1);
-	                        this.begin("emu");
-	                    } else {
-	                        this.begin("mu");
-	                    }
-	                    if (yy_.yytext) {
-	                        return 14;
-	                    }break;
-	                case 1:
-	                    return 14;
-	                    break;
-	                case 2:
-	                    this.popState();
-	                    return 14;
-
-	                    break;
-	                case 3:
-	                    yy_.yytext = yy_.yytext.substr(5, yy_.yyleng - 9);
-	                    this.popState();
-	                    return 16;
-
-	                    break;
-	                case 4:
-	                    return 14;
-	                    break;
-	                case 5:
-	                    this.popState();
-	                    return 13;
-
-	                    break;
-	                case 6:
-	                    return 59;
-	                    break;
-	                case 7:
-	                    return 62;
-	                    break;
-	                case 8:
-	                    return 17;
-	                    break;
-	                case 9:
-	                    this.popState();
-	                    this.begin("raw");
-	                    return 21;
-
-	                    break;
-	                case 10:
-	                    return 53;
-	                    break;
-	                case 11:
-	                    return 27;
-	                    break;
-	                case 12:
-	                    return 45;
-	                    break;
-	                case 13:
-	                    this.popState();return 42;
-	                    break;
-	                case 14:
-	                    this.popState();return 42;
-	                    break;
-	                case 15:
-	                    return 32;
-	                    break;
-	                case 16:
-	                    return 37;
-	                    break;
-	                case 17:
-	                    return 49;
-	                    break;
-	                case 18:
-	                    return 46;
-	                    break;
-	                case 19:
-	                    this.unput(yy_.yytext);
-	                    this.popState();
-	                    this.begin("com");
-
-	                    break;
-	                case 20:
-	                    this.popState();
-	                    return 13;
-
-	                    break;
-	                case 21:
-	                    return 46;
-	                    break;
-	                case 22:
-	                    return 67;
-	                    break;
-	                case 23:
-	                    return 66;
-	                    break;
-	                case 24:
-	                    return 66;
-	                    break;
-	                case 25:
-	                    return 81;
-	                    break;
-	                case 26:
-	                    // ignore whitespace
-	                    break;
-	                case 27:
-	                    this.popState();return 52;
-	                    break;
-	                case 28:
-	                    this.popState();return 31;
-	                    break;
-	                case 29:
-	                    yy_.yytext = strip(1, 2).replace(/\\"/g, "\"");return 74;
-	                    break;
-	                case 30:
-	                    yy_.yytext = strip(1, 2).replace(/\\'/g, "'");return 74;
-	                    break;
-	                case 31:
-	                    return 79;
-	                    break;
-	                case 32:
-	                    return 76;
-	                    break;
-	                case 33:
-	                    return 76;
-	                    break;
-	                case 34:
-	                    return 77;
-	                    break;
-	                case 35:
-	                    return 78;
-	                    break;
-	                case 36:
-	                    return 75;
-	                    break;
-	                case 37:
-	                    return 69;
-	                    break;
-	                case 38:
-	                    return 71;
-	                    break;
-	                case 39:
-	                    return 66;
-	                    break;
-	                case 40:
-	                    return 66;
-	                    break;
-	                case 41:
-	                    return "INVALID";
-	                    break;
-	                case 42:
-	                    return 5;
-	                    break;
-	            }
-	        };
-	        lexer.rules = [/^(?:[^\x00]*?(?=(\{\{)))/, /^(?:[^\x00]+)/, /^(?:[^\x00]{2,}?(?=(\{\{|\\\{\{|\\\\\{\{|$)))/, /^(?:\{\{\{\{\/[^\s!"#%-,\.\/;->@\[-\^`\{-~]+(?=[=}\s\/.])\}\}\}\})/, /^(?:[^\x00]*?(?=(\{\{\{\{\/)))/, /^(?:[\s\S]*?--(~)?\}\})/, /^(?:\()/, /^(?:\))/, /^(?:\{\{\{\{)/, /^(?:\}\}\}\})/, /^(?:\{\{(~)?>)/, /^(?:\{\{(~)?#)/, /^(?:\{\{(~)?\/)/, /^(?:\{\{(~)?\^\s*(~)?\}\})/, /^(?:\{\{(~)?\s*else\s*(~)?\}\})/, /^(?:\{\{(~)?\^)/, /^(?:\{\{(~)?\s*else\b)/, /^(?:\{\{(~)?\{)/, /^(?:\{\{(~)?&)/, /^(?:\{\{(~)?!--)/, /^(?:\{\{(~)?![\s\S]*?\}\})/, /^(?:\{\{(~)?)/, /^(?:=)/, /^(?:\.\.)/, /^(?:\.(?=([=~}\s\/.)|])))/, /^(?:[\/.])/, /^(?:\s+)/, /^(?:\}(~)?\}\})/, /^(?:(~)?\}\})/, /^(?:"(\\["]|[^"])*")/, /^(?:'(\\[']|[^'])*')/, /^(?:@)/, /^(?:true(?=([~}\s)])))/, /^(?:false(?=([~}\s)])))/, /^(?:undefined(?=([~}\s)])))/, /^(?:null(?=([~}\s)])))/, /^(?:-?[0-9]+(?:\.[0-9]+)?(?=([~}\s)])))/, /^(?:as\s+\|)/, /^(?:\|)/, /^(?:([^\s!"#%-,\.\/;->@\[-\^`\{-~]+(?=([=~}\s\/.)|]))))/, /^(?:\[[^\]]*\])/, /^(?:.)/, /^(?:$)/];
-	        lexer.conditions = { mu: { rules: [6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42], inclusive: false }, emu: { rules: [2], inclusive: false }, com: { rules: [5], inclusive: false }, raw: { rules: [3, 4], inclusive: false }, INITIAL: { rules: [0, 1, 42], inclusive: true } };
-	        return lexer;
-	    })();
-	    parser.lexer = lexer;
-	    function Parser() {
-	        this.yy = {};
-	    }Parser.prototype = parser;parser.Parser = Parser;
-	    return new Parser();
-	})();exports["default"] = handlebars;
-	module.exports = exports["default"];
-
-/***/ },
-/* 16 */
-/***/ function(module, exports, __webpack_require__) {
-
-	'use strict';
-
-	var _interopRequireDefault = __webpack_require__(8)['default'];
-
-	exports.__esModule = true;
-
-	var _Visitor = __webpack_require__(6);
-
-	var _Visitor2 = _interopRequireDefault(_Visitor);
-
-	function WhitespaceControl() {}
-	WhitespaceControl.prototype = new _Visitor2['default']();
-
-	WhitespaceControl.prototype.Program = function (program) {
-	  var isRoot = !this.isRootSeen;
-	  this.isRootSeen = true;
-
-	  var body = program.body;
-	  for (var i = 0, l = body.length; i < l; i++) {
-	    var current = body[i],
-	        strip = this.accept(current);
-
-	    if (!strip) {
-	      continue;
-	    }
-
-	    var _isPrevWhitespace = isPrevWhitespace(body, i, isRoot),
-	        _isNextWhitespace = isNextWhitespace(body, i, isRoot),
-	        openStandalone = strip.openStandalone && _isPrevWhitespace,
-	        closeStandalone = strip.closeStandalone && _isNextWhitespace,
-	        inlineStandalone = strip.inlineStandalone && _isPrevWhitespace && _isNextWhitespace;
-
-	    if (strip.close) {
-	      omitRight(body, i, true);
-	    }
-	    if (strip.open) {
-	      omitLeft(body, i, true);
-	    }
-
-	    if (inlineStandalone) {
-	      omitRight(body, i);
-
-	      if (omitLeft(body, i)) {
-	        // If we are on a standalone node, save the indent info for partials
-	        if (current.type === 'PartialStatement') {
-	          // Pull out the whitespace from the final line
-	          current.indent = /([ \t]+$)/.exec(body[i - 1].original)[1];
-	        }
-	      }
-	    }
-	    if (openStandalone) {
-	      omitRight((current.program || current.inverse).body);
-
-	      // Strip out the previous content node if it's whitespace only
-	      omitLeft(body, i);
-	    }
-	    if (closeStandalone) {
-	      // Always strip the next node
-	      omitRight(body, i);
-
-	      omitLeft((current.inverse || current.program).body);
-	    }
-	  }
-
-	  return program;
-	};
-	WhitespaceControl.prototype.BlockStatement = function (block) {
-	  this.accept(block.program);
-	  this.accept(block.inverse);
-
-	  // Find the inverse program that is involed with whitespace stripping.
-	  var program = block.program || block.inverse,
-	      inverse = block.program && block.inverse,
-	      firstInverse = inverse,
-	      lastInverse = inverse;
-
-	  if (inverse && inverse.chained) {
-	    firstInverse = inverse.body[0].program;
-
-	    // Walk the inverse chain to find the last inverse that is actually in the chain.
-	    while (lastInverse.chained) {
-	      lastInverse = lastInverse.body[lastInverse.body.length - 1].program;
-	    }
-	  }
-
-	  var strip = {
-	    open: block.openStrip.open,
-	    close: block.closeStrip.close,
-
-	    // Determine the standalone candiacy. Basically flag our content as being possibly standalone
-	    // so our parent can determine if we actually are standalone
-	    openStandalone: isNextWhitespace(program.body),
-	    closeStandalone: isPrevWhitespace((firstInverse || program).body)
-	  };
-
-	  if (block.openStrip.close) {
-	    omitRight(program.body, null, true);
-	  }
-
-	  if (inverse) {
-	    var inverseStrip = block.inverseStrip;
-
-	    if (inverseStrip.open) {
-	      omitLeft(program.body, null, true);
-	    }
-
-	    if (inverseStrip.close) {
-	      omitRight(firstInverse.body, null, true);
-	    }
-	    if (block.closeStrip.open) {
-	      omitLeft(lastInverse.body, null, true);
-	    }
-
-	    // Find standalone else statments
-	    if (isPrevWhitespace(program.body) && isNextWhitespace(firstInverse.body)) {
-	      omitLeft(program.body);
-	      omitRight(firstInverse.body);
-	    }
-	  } else if (block.closeStrip.open) {
-	    omitLeft(program.body, null, true);
-	  }
-
-	  return strip;
-	};
-
-	WhitespaceControl.prototype.MustacheStatement = function (mustache) {
-	  return mustache.strip;
-	};
-
-	WhitespaceControl.prototype.PartialStatement = WhitespaceControl.prototype.CommentStatement = function (node) {
-	  /* istanbul ignore next */
-	  var strip = node.strip || {};
-	  return {
-	    inlineStandalone: true,
-	    open: strip.open,
-	    close: strip.close
-	  };
-	};
-
-	function isPrevWhitespace(body, i, isRoot) {
-	  if (i === undefined) {
-	    i = body.length;
-	  }
-
-	  // Nodes that end with newlines are considered whitespace (but are special
-	  // cased for strip operations)
-	  var prev = body[i - 1],
-	      sibling = body[i - 2];
-	  if (!prev) {
-	    return isRoot;
-	  }
-
-	  if (prev.type === 'ContentStatement') {
-	    return (sibling || !isRoot ? /\r?\n\s*?$/ : /(^|\r?\n)\s*?$/).test(prev.original);
-	  }
-	}
-	function isNextWhitespace(body, i, isRoot) {
-	  if (i === undefined) {
-	    i = -1;
-	  }
-
-	  var next = body[i + 1],
-	      sibling = body[i + 2];
-	  if (!next) {
-	    return isRoot;
-	  }
-
-	  if (next.type === 'ContentStatement') {
-	    return (sibling || !isRoot ? /^\s*?\r?\n/ : /^\s*?(\r?\n|$)/).test(next.original);
-	  }
-	}
-
-	// Marks the node to the right of the position as omitted.
-	// I.e. {{foo}}' ' will mark the ' ' node as omitted.
-	//
-	// If i is undefined, then the first child will be marked as such.
-	//
-	// If mulitple is truthy then all whitespace will be stripped out until non-whitespace
-	// content is met.
-	function omitRight(body, i, multiple) {
-	  var current = body[i == null ? 0 : i + 1];
-	  if (!current || current.type !== 'ContentStatement' || !multiple && current.rightStripped) {
-	    return;
-	  }
-
-	  var original = current.value;
-	  current.value = current.value.replace(multiple ? /^\s+/ : /^[ \t]*\r?\n?/, '');
-	  current.rightStripped = current.value !== original;
-	}
-
-	// Marks the node to the left of the position as omitted.
-	// I.e. ' '{{foo}} will mark the ' ' node as omitted.
-	//
-	// If i is undefined then the last child will be marked as such.
-	//
-	// If mulitple is truthy then all whitespace will be stripped out until non-whitespace
-	// content is met.
-	function omitLeft(body, i, multiple) {
-	  var current = body[i == null ? body.length - 1 : i - 1];
-	  if (!current || current.type !== 'ContentStatement' || !multiple && current.leftStripped) {
-	    return;
-	  }
-
-	  // We omit the last node if it's whitespace only and not preceeded by a non-content node.
-	  var original = current.value;
-	  current.value = current.value.replace(multiple ? /\s+$/ : /[ \t]+$/, '');
-	  current.leftStripped = current.value !== original;
-	  return current.leftStripped;
-	}
-
-	exports['default'] = WhitespaceControl;
-	module.exports = exports['default'];
-
-/***/ },
-/* 17 */
-/***/ function(module, exports, __webpack_require__) {
-
-	'use strict';
-
-	var _interopRequireDefault = __webpack_require__(8)['default'];
-
-	exports.__esModule = true;
-	exports.SourceLocation = SourceLocation;
-	exports.id = id;
-	exports.stripFlags = stripFlags;
-	exports.stripComment = stripComment;
-	exports.preparePath = preparePath;
-	exports.prepareMustache = prepareMustache;
-	exports.prepareRawBlock = prepareRawBlock;
-	exports.prepareBlock = prepareBlock;
-
-	var _Exception = __webpack_require__(12);
-
-	var _Exception2 = _interopRequireDefault(_Exception);
-
-	function SourceLocation(source, locInfo) {
-	  this.source = source;
-	  this.start = {
-	    line: locInfo.first_line,
-	    column: locInfo.first_column
-	  };
-	  this.end = {
-	    line: locInfo.last_line,
-	    column: locInfo.last_column
-	  };
-	}
-
-	function id(token) {
-	  if (/^\[.*\]$/.test(token)) {
-	    return token.substr(1, token.length - 2);
-	  } else {
-	    return token;
-	  }
-	}
-
-	function stripFlags(open, close) {
-	  return {
-	    open: open.charAt(2) === '~',
-	    close: close.charAt(close.length - 3) === '~'
-	  };
-	}
-
-	function stripComment(comment) {
-	  return comment.replace(/^\{\{~?\!-?-?/, '').replace(/-?-?~?\}\}$/, '');
-	}
-
-	function preparePath(data, parts, locInfo) {
-	  locInfo = this.locInfo(locInfo);
-
-	  var original = data ? '@' : '',
-	      dig = [],
-	      depth = 0,
-	      depthString = '';
-
-	  for (var i = 0, l = parts.length; i < l; i++) {
-	    var part = parts[i].part,
-
-	    // If we have [] syntax then we do not treat path references as operators,
-	    // i.e. foo.[this] resolves to approximately context.foo['this']
-	    isLiteral = parts[i].original !== part;
-	    original += (parts[i].separator || '') + part;
-
-	    if (!isLiteral && (part === '..' || part === '.' || part === 'this')) {
-	      if (dig.length > 0) {
-	        throw new _Exception2['default']('Invalid path: ' + original, { loc: locInfo });
-	      } else if (part === '..') {
-	        depth++;
-	        depthString += '../';
-	      }
-	    } else {
-	      dig.push(part);
-	    }
-	  }
-
-	  return new this.PathExpression(data, depth, dig, original, locInfo);
-	}
-
-	function prepareMustache(path, params, hash, open, strip, locInfo) {
-	  // Must use charAt to support IE pre-10
-	  var escapeFlag = open.charAt(3) || open.charAt(2),
-	      escaped = escapeFlag !== '{' && escapeFlag !== '&';
-
-	  return new this.MustacheStatement(path, params, hash, escaped, strip, this.locInfo(locInfo));
-	}
-
-	function prepareRawBlock(openRawBlock, content, close, locInfo) {
-	  if (openRawBlock.path.original !== close) {
-	    var errorNode = { loc: openRawBlock.path.loc };
-
-	    throw new _Exception2['default'](openRawBlock.path.original + ' doesn\'t match ' + close, errorNode);
-	  }
-
-	  locInfo = this.locInfo(locInfo);
-	  var program = new this.Program([content], null, {}, locInfo);
-
-	  return new this.BlockStatement(openRawBlock.path, openRawBlock.params, openRawBlock.hash, program, undefined, {}, {}, {}, locInfo);
-	}
-
-	function prepareBlock(openBlock, program, inverseAndProgram, close, inverted, locInfo) {
-	  // When we are chaining inverse calls, we will not have a close path
-	  if (close && close.path && openBlock.path.original !== close.path.original) {
-	    var errorNode = { loc: openBlock.path.loc };
-
-	    throw new _Exception2['default'](openBlock.path.original + ' doesn\'t match ' + close.path.original, errorNode);
-	  }
-
-	  program.blockParams = openBlock.blockParams;
-
-	  var inverse = undefined,
-	      inverseStrip = undefined;
-
-	  if (inverseAndProgram) {
-	    if (inverseAndProgram.chain) {
-	      inverseAndProgram.program.body[0].closeStrip = close.strip;
-	    }
-
-	    inverseStrip = inverseAndProgram.strip;
-	    inverse = inverseAndProgram.program;
-	  }
-
-	  if (inverted) {
-	    inverted = inverse;
-	    inverse = program;
-	    program = inverted;
-	  }
-
-	  return new this.BlockStatement(openBlock.path, openBlock.params, openBlock.hash, program, inverse, openBlock.strip, inverseStrip, close && close.strip, this.locInfo(locInfo));
-	}
-
-/***/ },
-/* 18 */
-/***/ function(module, exports, __webpack_require__) {
-
-	'use strict';
-
-	exports.__esModule = true;
-	/*global define */
-
-	var _isArray = __webpack_require__(13);
-
-	var SourceNode = undefined;
-
-	try {
-	  /* istanbul ignore next */
-	  if (false) {
-	    // We don't support this in AMD environments. For these environments, we asusme that
-	    // they are running on the browser and thus have no need for the source-map library.
-	    var SourceMap = require('source-map');
-	    SourceNode = SourceMap.SourceNode;
-	  }
-	} catch (err) {}
-
-	/* istanbul ignore if: tested but not covered in istanbul due to dist build  */
-	if (!SourceNode) {
-	  SourceNode = function (line, column, srcFile, chunks) {
-	    this.src = '';
-	    if (chunks) {
-	      this.add(chunks);
-	    }
-	  };
-	  /* istanbul ignore next */
-	  SourceNode.prototype = {
-	    add: function add(chunks) {
-	      if (_isArray.isArray(chunks)) {
-	        chunks = chunks.join('');
-	      }
-	      this.src += chunks;
-	    },
-	    prepend: function prepend(chunks) {
-	      if (_isArray.isArray(chunks)) {
-	        chunks = chunks.join('');
-	      }
-	      this.src = chunks + this.src;
-	    },
-	    toStringWithSourceMap: function toStringWithSourceMap() {
-	      return { code: this.toString() };
-	    },
-	    toString: function toString() {
-	      return this.src;
-	    }
-	  };
-	}
-
-	function castChunk(chunk, codeGen, loc) {
-	  if (_isArray.isArray(chunk)) {
-	    var ret = [];
-
-	    for (var i = 0, len = chunk.length; i < len; i++) {
-	      ret.push(codeGen.wrap(chunk[i], loc));
-	    }
-	    return ret;
-	  } else if (typeof chunk === 'boolean' || typeof chunk === 'number') {
-	    // Handle primitives that the SourceNode will throw up on
-	    return chunk + '';
-	  }
-	  return chunk;
-	}
-
-	function CodeGen(srcFile) {
-	  this.srcFile = srcFile;
-	  this.source = [];
-	}
-
-	CodeGen.prototype = {
-	  prepend: function prepend(source, loc) {
-	    this.source.unshift(this.wrap(source, loc));
-	  },
-	  push: function push(source, loc) {
-	    this.source.push(this.wrap(source, loc));
-	  },
-
-	  merge: function merge() {
-	    var source = this.empty();
-	    this.each(function (line) {
-	      source.add(['  ', line, '\n']);
-	    });
-	    return source;
-	  },
-
-	  each: function each(iter) {
-	    for (var i = 0, len = this.source.length; i < len; i++) {
-	      iter(this.source[i]);
-	    }
-	  },
-
-	  empty: function empty() {
-	    var loc = arguments[0] === undefined ? this.currentLocation || { start: {} } : arguments[0];
-
-	    return new SourceNode(loc.start.line, loc.start.column, this.srcFile);
-	  },
-	  wrap: function wrap(chunk) {
-	    var loc = arguments[1] === undefined ? this.currentLocation || { start: {} } : arguments[1];
-
-	    if (chunk instanceof SourceNode) {
-	      return chunk;
-	    }
-
-	    chunk = castChunk(chunk, this, loc);
-
-	    return new SourceNode(loc.start.line, loc.start.column, this.srcFile, chunk);
-	  },
-
-	  functionCall: function functionCall(fn, type, params) {
-	    params = this.generateList(params);
-	    return this.wrap([fn, type ? '.' + type + '(' : '(', params, ')']);
-	  },
-
-	  quotedString: function quotedString(str) {
-	    return '"' + (str + '').replace(/\\/g, '\\\\').replace(/"/g, '\\"').replace(/\n/g, '\\n').replace(/\r/g, '\\r').replace(/\u2028/g, '\\u2028') // Per Ecma-262 7.3 + 7.8.4
-	    .replace(/\u2029/g, '\\u2029') + '"';
-	  },
-
-	  objectLiteral: function objectLiteral(obj) {
-	    var pairs = [];
-
-	    for (var key in obj) {
-	      if (obj.hasOwnProperty(key)) {
-	        var value = castChunk(obj[key], this);
-	        if (value !== 'undefined') {
-	          pairs.push([this.quotedString(key), ':', value]);
-	        }
-	      }
-	    }
-
-	    var ret = this.generateList(pairs);
-	    ret.prepend('{');
-	    ret.add('}');
-	    return ret;
-	  },
-
-	  generateList: function generateList(entries, loc) {
-	    var ret = this.empty(loc);
-
-	    for (var i = 0, len = entries.length; i < len; i++) {
-	      if (i) {
-	        ret.add(',');
-	      }
-
-	      ret.add(castChunk(entries[i], this, loc));
-	    }
-
-	    return ret;
-	  },
-
-	  generateArray: function generateArray(entries, loc) {
-	    var ret = this.generateList(entries, loc);
-	    ret.prepend('[');
-	    ret.add(']');
-
-	    return ret;
-	  }
-	};
-
-	exports['default'] = CodeGen;
-	module.exports = exports['default'];
-
-	/* NOP */
-
-/***/ }
-/******/ ])
-});
-;
\ No newline at end of file
diff --git a/src/Jackett/Content/index.html b/src/Jackett/Content/index.html
index 22157c4ffb595b1c4b64c29fa7cc3e6d1e06b8b0..e4293852280021f64617d1b5507b4d42fcaac117 100644
--- a/src/Jackett/Content/index.html
+++ b/src/Jackett/Content/index.html
@@ -6,12 +6,14 @@
 
     <link rel='shortcut icon' type='image/x-icon' href='/favicon.ico' />
 
-    <script src="/jquery-2.1.3.min.js"></script>
-    <script src="/jquery.dataTables.js"></script>
-    <script src="/handlebars.js"></script>
-    <script src="/handlebars-intl.min.js"></script>
+    <script src="/libs/jquery.min.js"></script>
+    <script src="/libs/jquery.dataTables.min.js"></script>
+    <script src="/libs/handlebars.min.js"></script>
+    <script src="/libs/moment.min.js"></script>
+    <script src="/libs/handlebarsmoment.js"></script>
     <script src="/bootstrap/bootstrap.min.js"></script>
-    <script src="/bootstrap-notify.js"></script>
+    <script src="/libs/bootstrap-notify.js"></script>
+    <script src="https://www.google.com/recaptcha/api.js?onload=onloadCallback&render=explicit" async defer></script>
 
     <link href="/bootstrap/bootstrap.min.css" rel="stylesheet">
     <link href="/animate.css" rel="stylesheet">
@@ -19,6 +21,93 @@
     <link href="/css/jquery.dataTables.css" rel="stylesheet">
     <link rel="stylesheet" href="/css/font-awesome.min.css">
 
+
+    <script id="setup-item-nonlocalrecaptcha" type="text/x-handlebars-template">
+        <div class="setup-item-recaptcha">
+            <p>This site requires you to enter a ReCaptcha however this only works when accessing Jackett via localhost or 127.0.0.1. If you cannot access Jackett using that hostname then alternatively you can enter the cookie for the site manually.  <a href="https://github.com/zone117x/Jackett/wiki/Finding-cookies" target="_blank">See here</a> on how get the cookies.</p>
+            <div class="setup-item-label">Full cookie header</div>
+            <input class="form-control" type="text" value="" />
+        </div>
+    </script>
+    <script id="setup-item" type="text/x-handlebars-template">
+        <div class="setup-item form-group" data-id="{{id}}" data-value="{{value}}" data-type="{{type}}">
+            <div class="setup-item-label">{{name}}</div>
+            <div class="setup-item-value">{{{value_element}}}</div>
+        </div>
+    </script>
+    <script id="setup-item-inputstring" type="text/x-handlebars-template">
+        <div class="setup-item-inputstring">
+            {{#if ispassword}}
+            <input class="form-control" type="password" value="{{{value}}}" />
+            {{else}}
+            <input class="form-control" type="text" value="{{{value}}}" />
+            {{/if}}
+        </div>
+    </script>
+    <script id="setup-item-inputbool" type="text/x-handlebars-template">
+        <div class="setup-item-inputbool">
+            {{#if value}}
+            <input type="checkbox" data-id="{{id}}" class="form-control" checked />
+            {{else}}
+            <input type="checkbox" data-id="{{id}}" class="form-control" />
+            {{/if}}
+        </div>
+    </script>
+    <script id="setup-item-recaptcha" type="text/x-handlebars-template">
+        <div class="jackettrecaptcha">
+        </div>
+    </script>
+    <script id="setup-item-displayimage" type="text/x-handlebars-template">
+        <img class="setup-item-displayimage" src="{{{value}}}" />
+    </script>
+    <script id="setup-item-displayinfo" type="text/x-handlebars-template">
+        <div class="setup-item-displayinfo alert alert-info" role="alert">{{{value}}}</div>
+    </script>
+    <script id="setup-item-hiddendata" type="text/x-handlebars-template">
+        <div class="setup-item-hiddendata">
+            <input class="form-control" type="text" value="{{{value}}}" />
+        </div>
+    </script>
+
+    <script id="configured-indexer" type="text/x-handlebars-template">
+        <div class="configured-indexer indexer card">
+            <div class="indexer-logo"><img alt="{{name}}" title="{{name}}" src="/logos/{{id}}.png" /></div>
+            <div class="indexer-buttons">
+                <button class="btn btn-primary btn-sm indexer-setup" data-id="{{id}}">
+                    <span class="glyphicon glyphicon-wrench" aria-hidden="true"></span>
+                </button>
+                <button class="btn btn-danger btn-sm indexer-button-delete" data-id="{{id}}">
+                    <span class="glyphicon glyphicon-trash" aria-hidden="true"></span>
+                </button>
+                <a class="btn btn-info btn-sm" target="_blank" href="{{site_link}}">
+                    <span class="glyphicon glyphicon-new-window" aria-hidden="true"></span>
+                </a>
+                <button class="btn btn-warning btn-sm indexer-button-test" data-id="{{id}}">
+                    Test <span class="glyphicon glyphicon-screenshot" aria-hidden="true"></span>
+                </button>
+            </div>
+            <div class="indexer-host">
+                <b>Torznab Host:</b>
+                <input class="form-control" type="text" value="{{torznab_host}}" placeholder="Torznab Host" readonly="">
+                <b>CouchPotato Host:</b>
+                {{#if potatoenabled}}
+
+                <input class="form-control" type="text" value="{{potato_host}}" placeholder="Torznab Host" readonly="">
+                {{else}}
+                <input class="form-control" type="text" value="Not availible" placeholder="Torznab Host" readonly="">
+                {{/if}}
+            </div>
+        </div>
+    </script>
+    <script id="unconfigured-indexer" type="text/x-handlebars-template">
+        <div class="unconfigured-indexer card">
+            <div class="indexer-logo"><img alt="{{name}}" title="{{name}}" src="/logos/{{id}}.png" /></div>
+            <div class="indexer-buttons">
+                <a class="btn btn-info" target="_blank" href="{{site_link}}">Visit <span class="glyphicon glyphicon-new-window" aria-hidden="true"></span></a>
+                <button class="indexer-setup btn btn-success" data-id="{{id}}">Setup <span class="glyphicon glyphicon-ok" aria-hidden="true"></span></button>
+            </div>
+        </div>
+    </script>
     <script id="jackett-releases" type="text/x-handlebars-template">
         <div id="select-indexer-modal" class="modal fade" tabindex="-1" role="dialog" aria-hidden="true">
             <div class="modal-dialog modal-lg modal-fillwidth">
@@ -49,14 +138,69 @@
                                 <tr>
                                     <td>{{PublishDate}}</td>
                                     <td>{{FirstSeen}}</td>
-                                    <td>{{formatRelative  PublishDate}}</td>
-                                    <td>{{formatRelative  FirstSeen}}</td>
+                                    <td>{{jacketTimespan PublishDate}}</td>
+                                    <td>{{jacketTimespan FirstSeen}}</td>
                                     <td>{{Tracker}}</td>
                                     <td><a href="{{Comments}}">{{Title}}</a></td>
                                     <td>{{CategoryDesc}}</td>
                                     <td>{{Seeders}}</td>
                                     <td>{{Peers}}</td>
-                                    <td><a href="{{Link}}"><i class="fa fa-download"></i></a></td>
+                                    <td class="downloadcolumn">
+                                        <a class="downloadlink" title="Download locally" href="{{Link}}"><i class="fa fa-download"></i></a>
+                                        {{#if BlackholeLink}}
+                                        <a class="downloadlink jacketdownloadserver" title="Save to server blackhole directory" href="{{BlackholeLink}}"><i class="fa fa-upload"></i></a>
+                                        {{/if}}
+                                    </td>
+                                </tr>
+                                {{/each}}
+                            </tbody>
+                            <tfoot>
+                                <tr>
+                                    <td></td>
+                                    <td></td>
+                                    <td></td>
+                                    <td></td>
+                                    <td></td>
+                                    <td></td>
+                                    <td></td>
+                                    <td></td>
+                                    <td></td>
+                                    <td></td>
+                                </tr>
+                            </tfoot>
+                        </table>
+                    </div>
+                    <div class="modal-footer">
+                        <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
+                    </div>
+                </div>
+            </div>
+        </div>
+    </script>
+
+    <script id="jackett-logs" type="text/x-handlebars-template">
+        <div id="select-indexer-modal" class="modal fade" tabindex="-1" role="dialog" aria-hidden="true">
+            <div class="modal-dialog modal-lg modal-fillwidth">
+                <div class="modal-content">
+                    <div class="modal-header">
+                        <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
+                        <h4 class="modal-title">Server Logs</h4>
+                    </div>
+                    <div class="modal-body">
+                        <table class="dataTable compact cell-border hover stripe">
+                            <thead>
+                                <tr>
+                                    <th style="width: 200px">When</th>
+                                    <th style="width: 80px">Level</th>
+                                    <th>Message</th>
+                                </tr>
+                            </thead>
+                            <tbody>
+                                {{#each logs}}
+                                <tr class="jackettlog{{Level}}">
+                                    <td>{{dateFormat When}}</td>
+                                    <td>{{Level}}</td>
+                                    <td><pre>{{Message}}</pre></td>
                                 </tr>
                                 {{/each}}
                             </tbody>
@@ -108,6 +252,17 @@
             </div>
         </div>
     </script>
+    <script id="add-indexer" type="text/x-handlebars-template">
+        <button class="indexer card add-indexer" data-toggle="modal" data-target="#select-indexer-modal">
+            <div class="indexer-add-content">
+                <span class="glyphicon glyphicon glyphicon-plus" aria-hidden="true"></span>
+                <div class="light-text">Add</div>
+            </div>
+        </button>
+    </script>
+    <script id="spinner" type="text/x-handlebars-template">
+        <span class="spinner glyphicon glyphicon-refresh"></span>
+    </script>
 
     <title>Jackett</title>
 </head>
@@ -124,7 +279,6 @@
                 <li>In Sonarr go to <b>Settings > Indexers > Add > Torznab > Custom</b></li>
                 <li>For <b>URL</b> enter the <b>Torznab Host</b> of one of the indexers below</li>
                 <li>For <b>API key</b> using the key below</li>
-                <li>Turn off <b>Enable RageID Lookup</b></li>
             </ol>
             <span class="input-header">API Key: </span>
             <input id="api-key-input" class="form-control input-right" type="text" value="" placeholder="API Key" readonly="">
@@ -156,6 +310,13 @@
             <button id="change-jackett-port" class="btn btn-primary btn-sm">
                 Apply server settings <span class="glyphicon glyphicon-ok-wrench" aria-hidden="true"></span>
             </button>
+            <button id="view-jackett-logs" class="btn btn-danger btn-sm">
+                View logs <span class="glyphicon glyphicon-ok-wrench" aria-hidden="true"></span>
+            </button>
+        </div>
+        <div class="input-area">
+            <span class="input-header">Manual download blackhole directory: </span>
+            <input id="jackett-savedir" class="form-control input-right" type="text" value="" placeholder="c:\torrents\">
         </div>
         <div class="input-area">
             <span class="input-header">External access: </span>
@@ -186,85 +347,6 @@
     </div>
 
     <div id="modals"></div>
-
-    <div id="templates">
-        <button class="indexer card add-indexer" data-toggle="modal" data-target="#select-indexer-modal">
-            <div class="indexer-add-content">
-                <span class="glyphicon glyphicon glyphicon-plus" aria-hidden="true"></span>
-                <div class="light-text">Add</div>
-            </div>
-        </button>
-
-        <div class="configured-indexer indexer card">
-            <div class="indexer-logo"><img alt="{{name}}" title="{{name}}" src="/logos/{{id}}.png" /></div>
-            <div class="indexer-buttons">
-                <button class="btn btn-primary btn-sm indexer-setup" data-id="{{id}}">
-                    <span class="glyphicon glyphicon-wrench" aria-hidden="true"></span>
-                </button>
-                <button class="btn btn-danger btn-sm indexer-button-delete" data-id="{{id}}">
-                    <span class="glyphicon glyphicon-trash" aria-hidden="true"></span>
-                </button>
-                <a class="btn btn-info btn-sm" target="_blank" href="{{site_link}}">
-                    <span class="glyphicon glyphicon-new-window" aria-hidden="true"></span>
-                </a>
-                <button class="btn btn-warning btn-sm indexer-button-test" data-id="{{id}}">
-                    Test <span class="glyphicon glyphicon-screenshot" aria-hidden="true"></span>
-                </button>
-            </div>
-            <div class="indexer-host">
-                <b>Torznab Host:</b>
-                <input class="form-control" type="text" value="{{torznab_host}}" placeholder="Torznab Host" readonly="">
-                <b>CouchPotato Host:</b>
-                {{#if potatoenabled}}
-               
-                <input class="form-control" type="text" value="{{potato_host}}" placeholder="Torznab Host" readonly="">
-                {{else}}
-                <input class="form-control" type="text" value="Not availible" placeholder="Torznab Host" readonly="">
-                {{/if}}
-            </div>
-        </div>
-
-        <div class="unconfigured-indexer card">
-            <div class="indexer-logo"><img alt="{{name}}" title="{{name}}" src="/logos/{{id}}.png" /></div>
-            <div class="indexer-buttons">
-                <a class="btn btn-info" target="_blank" href="{{site_link}}">Visit <span class="glyphicon glyphicon-new-window" aria-hidden="true"></span></a>
-                <button class="indexer-setup btn btn-success" data-id="{{id}}">Setup <span class="glyphicon glyphicon-ok" aria-hidden="true"></span></button>
-            </div>
-        </div>
-
-
-        <div class="setup-item form-group" data-id="{{id}}" data-value="{{value}}" data-type="{{type}}">
-            <div class="setup-item-label">{{name}}</div>
-            <div class="setup-item-value">{{{value_element}}}</div>
-        </div>
-        <div class="setup-item-inputstring">
-            {{#if ispassword}}
-            <input class="form-control" type="password" value="{{{value}}}" />
-            {{else}}
-            <input class="form-control" type="text" value="{{{value}}}" />
-            {{/if}}
-        </div>
-
-        <div class="setup-item-inputbool">
-            {{#if value}}
-            <input type="checkbox" data-id="{{id}}" class="form-control" checked />
-            {{else}}
-            <input type="checkbox" data-id="{{id}}" class="form-control" />
-            {{/if}}
-        </div>
-        <img class="setup-item-displayimage" src="{{{value}}}" />
-        <div class="setup-item-displayinfo alert alert-info" role="alert">{{{value}}}</div>
-        <div class="setup-item-hiddendata">
-            <input class="form-control" type="text" value="{{{value}}}" />
-        </div>
-
-        <span class="spinner glyphicon glyphicon-refresh"></span>
-
-
-    </div>
-
-
     <script src="/custom.js"></script>
-
 </body>
 </html>
\ No newline at end of file
diff --git a/src/Jackett/Content/jquery-2.1.3.min.js b/src/Jackett/Content/jquery-2.1.3.min.js
deleted file mode 100644
index 25714ed29ab6fcf0355da4b45ac602fac0154efb..0000000000000000000000000000000000000000
--- a/src/Jackett/Content/jquery-2.1.3.min.js
+++ /dev/null
@@ -1,4 +0,0 @@
-/*! jQuery v2.1.3 | (c) 2005, 2014 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.3",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=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=hb(),z=hb(),A=hb(),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-]+))$/,ab=/[+~]/,bb=/'|\\/g,cb=new RegExp("\\\\([\\da-f]{1,6}"+L+"?|("+L+")|.)","ig"),db=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)},eb=function(){m()};try{H.apply(E=I.call(v.childNodes),v.childNodes),E[v.childNodes.length].nodeType}catch(fb){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 gb(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(bb,"\\$&"):b.setAttribute("id",s),s="[id='"+s+"'] ",l=o.length;while(l--)o[l]=s+rb(o[l]);w=ab.test(a)&&pb(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 hb(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function ib(a){return a[u]=!0,a}function jb(a){var b=n.createElement("div");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function kb(a,b){var c=a.split("|"),e=a.length;while(e--)d.attrHandle[c[e]]=b}function lb(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 mb(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function nb(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function ob(a){return ib(function(b){return b=+b,ib(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 pb(a){return a&&"undefined"!=typeof a.getElementsByTagName&&a}c=gb.support={},f=gb.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?"HTML"!==b.nodeName:!1},m=gb.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",eb,!1):e.attachEvent&&e.attachEvent("onunload",eb)),p=!f(g),c.attributes=jb(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=jb(function(a){return a.appendChild(g.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=$.test(g.getElementsByClassName),c.getById=jb(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(cb,db);return function(a){return a.getAttribute("id")===b}}):(delete d.find.ID,d.filter.ID=function(a){var b=a.replace(cb,db);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))&&(jb(function(a){o.appendChild(a).innerHTML="<a id='"+u+"'></a><select id='"+u+"-\f]' msallowcapture=''><option selected=''></option></select>",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(".#.+[+~]")}),jb(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))&&jb(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 lb(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?lb(h[d],i[d]):h[d]===v?-1:i[d]===v?1:0},g):n},gb.matches=function(a,b){return gb(a,null,null,b)},gb.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 gb(b,n,null,[a]).length>0},gb.contains=function(a,b){return(a.ownerDocument||a)!==n&&m(a),t(a,b)},gb.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},gb.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},gb.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=gb.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=gb.selectors={cacheLength:50,createPseudo:ib,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(cb,db),a[3]=(a[3]||a[4]||a[5]||"").replace(cb,db),"~="===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]||gb.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]&&gb.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(cb,db).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=gb.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()]||gb.error("unsupported pseudo: "+a);return e[u]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?ib(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:ib(function(a){var b=[],c=[],d=h(a.replace(R,"$1"));return d[u]?ib(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:ib(function(a){return function(b){return gb(a,b).length>0}}),contains:ib(function(a){return a=a.replace(cb,db),function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:ib(function(a){return W.test(a||"")||gb.error("unsupported lang: "+a),a=a.replace(cb,db).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:ob(function(){return[0]}),last:ob(function(a,b){return[b-1]}),eq:ob(function(a,b,c){return[0>c?c+b:c]}),even:ob(function(a,b){for(var c=0;b>c;c+=2)a.push(c);return a}),odd:ob(function(a,b){for(var c=1;b>c;c+=2)a.push(c);return a}),lt:ob(function(a,b,c){for(var d=0>c?c+b:c;--d>=0;)a.push(d);return a}),gt:ob(function(a,b,c){for(var d=0>c?c+b:c;++d<b;)a.push(d);return a})}},d.pseudos.nth=d.pseudos.eq;for(b in{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})d.pseudos[b]=mb(b);for(b in{submit:!0,reset:!0})d.pseudos[b]=nb(b);function qb(){}qb.prototype=d.filters=d.pseudos,d.setFilters=new qb,g=gb.tokenize=function(a,b){var c,e,f,g,h,i,j,k=z[a+" "];if(k)return b?0:k.slice(0);h=a,i=[],j=d.preFilter;while(h){(!c||(e=S.exec(h)))&&(e&&(h=h.slice(e[0].length)||h),i.push(f=[])),c=!1,(e=T.exec(h))&&(c=e.shift(),f.push({value:c,type:e[0].replace(R," ")}),h=h.slice(c.length));for(g in d.filter)!(e=X[g].exec(h))||j[g]&&!(e=j[g](e))||(c=e.shift(),f.push({value:c,type:g,matches:e}),h=h.slice(c.length));if(!c)break}return b?h.length:h?gb.error(a):z(a,i).slice(0)};function rb(a){for(var b=0,c=a.length,d="";c>b;b++)d+=a[b].value;return d}function sb(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 tb(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 ub(a,b,c){for(var d=0,e=b.length;e>d;d++)gb(a,b[d],c);return c}function vb(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 wb(a,b,c,d,e,f){return d&&!d[u]&&(d=wb(d)),e&&!e[u]&&(e=wb(e,f)),ib(function(f,g,h,i){var j,k,l,m=[],n=[],o=g.length,p=f||ub(b||"*",h.nodeType?[h]:h,[]),q=!a||!f&&b?p:vb(p,m,a,h,i),r=c?e||(f?a:o||d)?[]:g:q;if(c&&c(q,r,h,i),d){j=vb(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=vb(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):H.apply(g,r)})}function xb(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],h=g||d.relative[" "],i=g?1:0,k=sb(function(a){return a===b},h,!0),l=sb(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=[sb(tb(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 wb(i>1&&tb(m),i>1&&rb(a.slice(0,i-1).concat({value:" "===a[i-2].type?"*":""})).replace(R,"$1"),c,e>i&&xb(a.slice(i,e)),f>e&&xb(a=a.slice(e)),f>e&&rb(a))}m.push(c)}return tb(m)}function yb(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=vb(s)}H.apply(i,s),k&&!f&&s.length>0&&p+b.length>1&&gb.uniqueSort(i)}return k&&(w=v,j=t),r};return c?ib(f):f}return h=gb.compile=function(a,b){var c,d=[],e=[],f=A[a+" "];if(!f){b||(b=g(a)),c=b.length;while(c--)f=xb(b[c]),f[u]?d.push(f):e.push(f);f=A(a,yb(e,d)),f.selector=a}return f},i=gb.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(cb,db),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(cb,db),ab.test(j[0].type)&&pb(b.parentNode)||b))){if(j.splice(i,1),a=f.length&&rb(j),!a)return H.apply(e,f),e;break}}}return(n||h(a,o))(f,b,!p,e,ab.test(a)&&pb(b.parentNode)||b),e},c.sortStable=u.split("").sort(B).join("")===u,c.detectDuplicates=!!l,m(),c.sortDetached=jb(function(a){return 1&a.compareDocumentPosition(n.createElement("div"))}),jb(function(a){return a.innerHTML="<a href='#'></a>","#"===a.firstChild.getAttribute("href")})||kb("type|href|height|width",function(a,b,c){return c?void 0:a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&jb(function(a){return a.innerHTML="<input/>",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||kb("value",function(a,b,c){return c||"input"!==a.nodeName.toLowerCase()?void 0:a.defaultValue}),jb(function(a){return null==a.getAttribute("disabled")})||kb(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}),gb}(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.length<c?n.queue(this[0],a):void 0===b?this:this.each(function(){var c=n.queue(this,a,b);n._queueHooks(this,a),"fx"===a&&"inprogress"!==c[0]&&n.dequeue(this,a)})},dequeue:function(a){return this.each(function(){n.dequeue(this,a)})},clearQueue:function(a){return this.queue(a||"fx",[])},promise:function(a,b){var c,d=1,e=n.Deferred(),f=this,g=this.length,h=function(){--d||e.resolveWith(f,[f])};"string"!=typeof a&&(b=a,a=void 0),a=a||"fx";while(g--)c=L.get(f[g],a+"queueHooks"),c&&c.empty&&(d++,c.empty.add(h));return h(),e.promise(b)}});var Q=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,R=["Top","Right","Bottom","Left"],S=function(a,b){return a=b||a,"none"===n.css(a,"display")||!n.contains(a.ownerDocument,a)},T=/^(?:checkbox|radio)$/i;!function(){var a=l.createDocumentFragment(),b=a.appendChild(l.createElement("div")),c=l.createElement("input");c.setAttribute("type","radio"),c.setAttribute("checked","checked"),c.setAttribute("name","t"),b.appendChild(c),k.checkClone=b.cloneNode(!0).cloneNode(!0).lastChild.checked,b.innerHTML="<textarea>x</textarea>",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<b.length&&g.push({elem:this,handlers:b.slice(h)}),g},props:"altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(a,b){return null==a.which&&(a.which=null!=b.charCode?b.charCode:b.keyCode),a}},mouseHooks:{props:"button buttons clientX clientY offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(a,b){var c,d,e,f=b.button;return null==a.pageX&&null!=b.clientX&&(c=a.target.ownerDocument||l,d=c.documentElement,e=c.body,a.pageX=b.clientX+(d&&d.scrollLeft||e&&e.scrollLeft||0)-(d&&d.clientLeft||e&&e.clientLeft||0),a.pageY=b.clientY+(d&&d.scrollTop||e&&e.scrollTop||0)-(d&&d.clientTop||e&&e.clientTop||0)),a.which||void 0===f||(a.which=1&f?1:2&f?3:4&f?2:0),a}},fix:function(a){if(a[n.expando])return a;var b,c,d,e=a.type,f=a,g=this.fixHooks[e];g||(this.fixHooks[e]=g=W.test(e)?this.mouseHooks:V.test(e)?this.keyHooks:{}),d=g.props?this.props.concat(g.props):this.props,a=new n.Event(f),b=d.length;while(b--)c=d[b],a[c]=f[c];return a.target||(a.target=l),3===a.target.nodeType&&(a.target=a.target.parentNode),g.filter?g.filter(a,f):a},special:{load:{noBubble:!0},focus:{trigger:function(){return this!==_()&&this.focus?(this.focus(),!1):void 0},delegateType:"focusin"},blur:{trigger:function(){return this===_()&&this.blur?(this.blur(),!1):void 0},delegateType:"focusout"},click:{trigger:function(){return"checkbox"===this.type&&this.click&&n.nodeName(this,"input")?(this.click(),!1):void 0},_default:function(a){return n.nodeName(a.target,"a")}},beforeunload:{postDispatch:function(a){void 0!==a.result&&a.originalEvent&&(a.originalEvent.returnValue=a.result)}}},simulate:function(a,b,c,d){var e=n.extend(new n.Event,c,{type:a,isSimulated:!0,originalEvent:{}});d?n.event.trigger(e,null,b):n.event.dispatch.call(b,e),e.isDefaultPrevented()&&c.preventDefault()}},n.removeEvent=function(a,b,c){a.removeEventListener&&a.removeEventListener(b,c,!1)},n.Event=function(a,b){return this instanceof n.Event?(a&&a.type?(this.originalEvent=a,this.type=a.type,this.isDefaultPrevented=a.defaultPrevented||void 0===a.defaultPrevented&&a.returnValue===!1?Z:$):this.type=a,b&&n.extend(this,b),this.timeStamp=a&&a.timeStamp||n.now(),void(this[n.expando]=!0)):new n.Event(a,b)},n.Event.prototype={isDefaultPrevented:$,isPropagationStopped:$,isImmediatePropagationStopped:$,preventDefault:function(){var a=this.originalEvent;this.isDefaultPrevented=Z,a&&a.preventDefault&&a.preventDefault()},stopPropagation:function(){var a=this.originalEvent;this.isPropagationStopped=Z,a&&a.stopPropagation&&a.stopPropagation()},stopImmediatePropagation:function(){var a=this.originalEvent;this.isImmediatePropagationStopped=Z,a&&a.stopImmediatePropagation&&a.stopImmediatePropagation(),this.stopPropagation()}},n.each({mouseenter:"mouseover",mouseleave:"mouseout",pointerenter:"pointerover",pointerleave:"pointerout"},function(a,b){n.event.special[a]={delegateType:b,bindType:b,handle:function(a){var c,d=this,e=a.relatedTarget,f=a.handleObj;return(!e||e!==d&&!n.contains(d,e))&&(a.type=f.origType,c=f.handler.apply(this,arguments),a.type=b),c}}}),k.focusinBubbles||n.each({focus:"focusin",blur:"focusout"},function(a,b){var c=function(a){n.event.simulate(b,a.target,n.event.fix(a),!0)};n.event.special[b]={setup:function(){var d=this.ownerDocument||this,e=L.access(d,b);e||d.addEventListener(a,c,!0),L.access(d,b,(e||0)+1)},teardown:function(){var d=this.ownerDocument||this,e=L.access(d,b)-1;e?L.access(d,b,e):(d.removeEventListener(a,c,!0),L.remove(d,b))}}}),n.fn.extend({on:function(a,b,c,d,e){var f,g;if("object"==typeof a){"string"!=typeof b&&(c=c||b,b=void 0);for(g in a)this.on(g,b,c,a[g],e);return this}if(null==c&&null==d?(d=b,c=b=void 0):null==d&&("string"==typeof b?(d=c,c=void 0):(d=c,c=b,b=void 0)),d===!1)d=$;else if(!d)return this;return 1===e&&(f=d,d=function(a){return n().off(a),f.apply(this,arguments)},d.guid=f.guid||(f.guid=n.guid++)),this.each(function(){n.event.add(this,a,d,c,b)})},one:function(a,b,c,d){return this.on(a,b,c,d,1)},off:function(a,b,c){var d,e;if(a&&a.preventDefault&&a.handleObj)return d=a.handleObj,n(a.delegateTarget).off(d.namespace?d.origType+"."+d.namespace:d.origType,d.selector,d.handler),this;if("object"==typeof a){for(e in a)this.off(e,b,a[e]);return this}return(b===!1||"function"==typeof b)&&(c=b,b=void 0),c===!1&&(c=$),this.each(function(){n.event.remove(this,a,c,b)})},trigger:function(a,b){return this.each(function(){n.event.trigger(a,b,this)})},triggerHandler:function(a,b){var c=this[0];return c?n.event.trigger(a,b,c,!0):void 0}});var ab=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,bb=/<([\w:]+)/,cb=/<|&#?\w+;/,db=/<(?:script|style|link)/i,eb=/checked\s*(?:[^=]|=\s*.checked.)/i,fb=/^$|\/(?:java|ecma)script/i,gb=/^true\/(.*)/,hb=/^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g,ib={option:[1,"<select multiple='multiple'>","</select>"],thead:[1,"<table>","</table>"],col:[2,"<table><colgroup>","</colgroup></table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],_default:[0,"",""]};ib.optgroup=ib.option,ib.tbody=ib.tfoot=ib.colgroup=ib.caption=ib.thead,ib.th=ib.td;function jb(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 kb(a){return a.type=(null!==a.getAttribute("type"))+"/"+a.type,a}function lb(a){var b=gb.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function mb(a,b){for(var c=0,d=a.length;d>c;c++)L.set(a[c],"globalEval",!b||L.get(b[c],"globalEval"))}function nb(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 ob(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 pb(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=ob(h),f=ob(a),d=0,e=f.length;e>d;d++)pb(f[d],g[d]);if(b)if(c)for(f=f||ob(a),g=g||ob(h),d=0,e=f.length;e>d;d++)nb(f[d],g[d]);else nb(a,h);return g=ob(h,"script"),g.length>0&&mb(g,!i&&ob(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(cb.test(e)){f=f||k.appendChild(b.createElement("div")),g=(bb.exec(e)||["",""])[1].toLowerCase(),h=ib[g]||ib._default,f.innerHTML=h[1]+e.replace(ab,"<$1></$2>")+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=ob(k.appendChild(e),"script"),i&&mb(f),c)){j=0;while(e=f[j++])fb.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=jb(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=jb(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(ob(c)),c.parentNode&&(b&&n.contains(c.ownerDocument,c)&&mb(ob(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(ob(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&&!db.test(a)&&!ib[(bb.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(ab,"<$1></$2>");try{for(;d>c;c++)b=this[c]||{},1===b.nodeType&&(n.cleanData(ob(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(ob(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&&eb.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(ob(c,"script"),kb),g=f.length;l>j;j++)h=c,j!==o&&(h=n.clone(h,!0,!0),g&&n.merge(f,ob(h,"script"))),b.call(this[j],h,j);if(g)for(i=f[f.length-1].ownerDocument,n.map(f,lb),j=0;g>j;j++)h=f[j],fb.test(h.type||"")&&!L.access(h,"globalEval")&&n.contains(i,h)&&(h.src?n._evalUrl&&n._evalUrl(h.src):n.globalEval(h.textContent.replace(hb,"")))}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 qb,rb={};function sb(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 tb(a){var b=l,c=rb[a];return c||(c=sb(a,b),"none"!==c&&c||(qb=(qb||n("<iframe frameborder='0' width='0' height='0'/>")).appendTo(b.documentElement),b=qb[0].contentDocument,b.write(),b.close(),c=sb(a,b),qb.detach()),rb[a]=c),c}var ub=/^margin/,vb=new RegExp("^("+Q+")(?!px)[a-z%]+$","i"),wb=function(b){return b.ownerDocument.defaultView.opener?b.ownerDocument.defaultView.getComputedStyle(b,null):a.getComputedStyle(b,null)};function xb(a,b,c){var d,e,f,g,h=a.style;return c=c||wb(a),c&&(g=c.getPropertyValue(b)||c[b]),c&&(""!==g||n.contains(a.ownerDocument,a)||(g=n.style(a,b)),vb.test(g)&&ub.test(b)&&(d=h.width,e=h.minWidth,f=h.maxWidth,h.minWidth=h.maxWidth=h.width=g,g=c.width,h.width=d,h.minWidth=e,h.maxWidth=f)),void 0!==g?g+"":g}function yb(a,b){return{get:function(){return a()?void delete this.get:(this.get=b).apply(this,arguments)}}}!function(){var b,c,d=l.documentElement,e=l.createElement("div"),f=l.createElement("div");if(f.style){f.style.backgroundClip="content-box",f.cloneNode(!0).style.backgroundClip="",k.clearCloneStyle="content-box"===f.style.backgroundClip,e.style.cssText="border:0;width:0;height:0;top:0;left:-9999px;margin-top:1px;position:absolute",e.appendChild(f);function g(){f.style.cssText="-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;display:block;margin-top:1%;top:1%;border:1px;padding:1px;width:4px;position:absolute",f.innerHTML="",d.appendChild(e);var g=a.getComputedStyle(f,null);b="1%"!==g.top,c="4px"===g.width,d.removeChild(e)}a.getComputedStyle&&n.extend(k,{pixelPosition:function(){return g(),b},boxSizingReliable:function(){return null==c&&g(),c},reliableMarginRight:function(){var b,c=f.appendChild(l.createElement("div"));return c.style.cssText=f.style.cssText="-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;display:block;margin:0;border:0;padding:0",c.style.marginRight=c.style.width="0",f.style.width="1px",d.appendChild(e),b=!parseFloat(a.getComputedStyle(c,null).marginRight),d.removeChild(e),f.removeChild(c),b}})}}(),n.swap=function(a,b,c,d){var e,f,g={};for(f in b)g[f]=a.style[f],a.style[f]=b[f];e=c.apply(a,d||[]);for(f in b)a.style[f]=g[f];return e};var zb=/^(none|table(?!-c[ea]).+)/,Ab=new RegExp("^("+Q+")(.*)$","i"),Bb=new RegExp("^([+-])=("+Q+")","i"),Cb={position:"absolute",visibility:"hidden",display:"block"},Db={letterSpacing:"0",fontWeight:"400"},Eb=["Webkit","O","Moz","ms"];function Fb(a,b){if(b in a)return b;var c=b[0].toUpperCase()+b.slice(1),d=b,e=Eb.length;while(e--)if(b=Eb[e]+c,b in a)return b;return d}function Gb(a,b,c){var d=Ab.exec(b);return d?Math.max(0,d[1]-(c||0))+(d[2]||"px"):b}function Hb(a,b,c,d,e){for(var f=c===(d?"border":"content")?4:"width"===b?1:0,g=0;4>f;f+=2)"margin"===c&&(g+=n.css(a,c+R[f],!0,e)),d?("content"===c&&(g-=n.css(a,"padding"+R[f],!0,e)),"margin"!==c&&(g-=n.css(a,"border"+R[f]+"Width",!0,e))):(g+=n.css(a,"padding"+R[f],!0,e),"padding"!==c&&(g+=n.css(a,"border"+R[f]+"Width",!0,e)));return g}function Ib(a,b,c){var d=!0,e="width"===b?a.offsetWidth:a.offsetHeight,f=wb(a),g="border-box"===n.css(a,"boxSizing",!1,f);if(0>=e||null==e){if(e=xb(a,b,f),(0>e||null==e)&&(e=a.style[b]),vb.test(e))return e;d=g&&(k.boxSizingReliable()||e===a.style[b]),e=parseFloat(e)||0}return e+Hb(a,b,c||(g?"border":"content"),d,f)+"px"}function Jb(a,b){for(var c,d,e,f=[],g=0,h=a.length;h>g;g++)d=a[g],d.style&&(f[g]=L.get(d,"olddisplay"),c=d.style.display,b?(f[g]||"none"!==c||(d.style.display=""),""===d.style.display&&S(d)&&(f[g]=L.access(d,"olddisplay",tb(d.nodeName)))):(e=S(d),"none"===c&&e||L.set(d,"olddisplay",e?c:n.css(d,"display"))));for(g=0;h>g;g++)d=a[g],d.style&&(b&&"none"!==d.style.display&&""!==d.style.display||(d.style.display=b?f[g]||"":"none"));return a}n.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=xb(a,"opacity");return""===c?"1":c}}}},cssNumber:{columnCount:!0,fillOpacity:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":"cssFloat"},style:function(a,b,c,d){if(a&&3!==a.nodeType&&8!==a.nodeType&&a.style){var e,f,g,h=n.camelCase(b),i=a.style;return b=n.cssProps[h]||(n.cssProps[h]=Fb(i,h)),g=n.cssHooks[b]||n.cssHooks[h],void 0===c?g&&"get"in g&&void 0!==(e=g.get(a,!1,d))?e:i[b]:(f=typeof c,"string"===f&&(e=Bb.exec(c))&&(c=(e[1]+1)*e[2]+parseFloat(n.css(a,b)),f="number"),null!=c&&c===c&&("number"!==f||n.cssNumber[h]||(c+="px"),k.clearCloneStyle||""!==c||0!==b.indexOf("background")||(i[b]="inherit"),g&&"set"in g&&void 0===(c=g.set(a,c,d))||(i[b]=c)),void 0)}},css:function(a,b,c,d){var e,f,g,h=n.camelCase(b);return b=n.cssProps[h]||(n.cssProps[h]=Fb(a.style,h)),g=n.cssHooks[b]||n.cssHooks[h],g&&"get"in g&&(e=g.get(a,!0,c)),void 0===e&&(e=xb(a,b,d)),"normal"===e&&b in Db&&(e=Db[b]),""===c||c?(f=parseFloat(e),c===!0||n.isNumeric(f)?f||0:e):e}}),n.each(["height","width"],function(a,b){n.cssHooks[b]={get:function(a,c,d){return c?zb.test(n.css(a,"display"))&&0===a.offsetWidth?n.swap(a,Cb,function(){return Ib(a,b,d)}):Ib(a,b,d):void 0},set:function(a,c,d){var e=d&&wb(a);return Gb(a,c,d?Hb(a,b,d,"border-box"===n.css(a,"boxSizing",!1,e),e):0)}}}),n.cssHooks.marginRight=yb(k.reliableMarginRight,function(a,b){return b?n.swap(a,{display:"inline-block"},xb,[a,"marginRight"]):void 0}),n.each({margin:"",padding:"",border:"Width"},function(a,b){n.cssHooks[a+b]={expand:function(c){for(var d=0,e={},f="string"==typeof c?c.split(" "):[c];4>d;d++)e[a+R[d]+b]=f[d]||f[d-2]||f[0];return e}},ub.test(a)||(n.cssHooks[a+b].set=Gb)}),n.fn.extend({css:function(a,b){return J(this,function(a,b,c){var d,e,f={},g=0;if(n.isArray(b)){for(d=wb(a),e=b.length;e>g;g++)f[b[g]]=n.css(a,b[g],!1,d);return f}return void 0!==c?n.style(a,b,c):n.css(a,b)},a,b,arguments.length>1)},show:function(){return Jb(this,!0)},hide:function(){return Jb(this)},toggle:function(a){return"boolean"==typeof a?a?this.show():this.hide():this.each(function(){S(this)?n(this).show():n(this).hide()})}});function Kb(a,b,c,d,e){return new Kb.prototype.init(a,b,c,d,e)}n.Tween=Kb,Kb.prototype={constructor:Kb,init:function(a,b,c,d,e,f){this.elem=a,this.prop=c,this.easing=e||"swing",this.options=b,this.start=this.now=this.cur(),this.end=d,this.unit=f||(n.cssNumber[c]?"":"px")},cur:function(){var a=Kb.propHooks[this.prop];return a&&a.get?a.get(this):Kb.propHooks._default.get(this)},run:function(a){var b,c=Kb.propHooks[this.prop];return this.pos=b=this.options.duration?n.easing[this.easing](a,this.options.duration*a,0,1,this.options.duration):a,this.now=(this.end-this.start)*b+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),c&&c.set?c.set(this):Kb.propHooks._default.set(this),this}},Kb.prototype.init.prototype=Kb.prototype,Kb.propHooks={_default:{get:function(a){var b;return null==a.elem[a.prop]||a.elem.style&&null!=a.elem.style[a.prop]?(b=n.css(a.elem,a.prop,""),b&&"auto"!==b?b:0):a.elem[a.prop]},set:function(a){n.fx.step[a.prop]?n.fx.step[a.prop](a):a.elem.style&&(null!=a.elem.style[n.cssProps[a.prop]]||n.cssHooks[a.prop])?n.style(a.elem,a.prop,a.now+a.unit):a.elem[a.prop]=a.now}}},Kb.propHooks.scrollTop=Kb.propHooks.scrollLeft={set:function(a){a.elem.nodeType&&a.elem.parentNode&&(a.elem[a.prop]=a.now)}},n.easing={linear:function(a){return a},swing:function(a){return.5-Math.cos(a*Math.PI)/2}},n.fx=Kb.prototype.init,n.fx.step={};var Lb,Mb,Nb=/^(?:toggle|show|hide)$/,Ob=new RegExp("^(?:([+-])=|)("+Q+")([a-z%]*)$","i"),Pb=/queueHooks$/,Qb=[Vb],Rb={"*":[function(a,b){var c=this.createTween(a,b),d=c.cur(),e=Ob.exec(b),f=e&&e[3]||(n.cssNumber[a]?"":"px"),g=(n.cssNumber[a]||"px"!==f&&+d)&&Ob.exec(n.css(c.elem,a)),h=1,i=20;if(g&&g[3]!==f){f=f||g[3],e=e||[],g=+d||1;do h=h||".5",g/=h,n.style(c.elem,a,g+f);while(h!==(h=c.cur()/d)&&1!==h&&--i)}return e&&(g=c.start=+g||+d||0,c.unit=f,c.end=e[1]?g+(e[1]+1)*e[2]:+e[2]),c}]};function Sb(){return setTimeout(function(){Lb=void 0}),Lb=n.now()}function Tb(a,b){var c,d=0,e={height:a};for(b=b?1:0;4>d;d+=2-b)c=R[d],e["margin"+c]=e["padding"+c]=a;return b&&(e.opacity=e.width=a),e}function Ub(a,b,c){for(var d,e=(Rb[b]||[]).concat(Rb["*"]),f=0,g=e.length;g>f;f++)if(d=e[f].call(c,b,a))return d}function Vb(a,b,c){var d,e,f,g,h,i,j,k,l=this,m={},o=a.style,p=a.nodeType&&S(a),q=L.get(a,"fxshow");c.queue||(h=n._queueHooks(a,"fx"),null==h.unqueued&&(h.unqueued=0,i=h.empty.fire,h.empty.fire=function(){h.unqueued||i()}),h.unqueued++,l.always(function(){l.always(function(){h.unqueued--,n.queue(a,"fx").length||h.empty.fire()})})),1===a.nodeType&&("height"in b||"width"in b)&&(c.overflow=[o.overflow,o.overflowX,o.overflowY],j=n.css(a,"display"),k="none"===j?L.get(a,"olddisplay")||tb(a.nodeName):j,"inline"===k&&"none"===n.css(a,"float")&&(o.display="inline-block")),c.overflow&&(o.overflow="hidden",l.always(function(){o.overflow=c.overflow[0],o.overflowX=c.overflow[1],o.overflowY=c.overflow[2]}));for(d in b)if(e=b[d],Nb.exec(e)){if(delete b[d],f=f||"toggle"===e,e===(p?"hide":"show")){if("show"!==e||!q||void 0===q[d])continue;p=!0}m[d]=q&&q[d]||n.style(a,d)}else j=void 0;if(n.isEmptyObject(m))"inline"===("none"===j?tb(a.nodeName):j)&&(o.display=j);else{q?"hidden"in q&&(p=q.hidden):q=L.access(a,"fxshow",{}),f&&(q.hidden=!p),p?n(a).show():l.done(function(){n(a).hide()}),l.done(function(){var b;L.remove(a,"fxshow");for(b in m)n.style(a,b,m[b])});for(d in m)g=Ub(p?q[d]:0,d,l),d in q||(q[d]=g.start,p&&(g.end=g.start,g.start="width"===d||"height"===d?1:0))}}function Wb(a,b){var c,d,e,f,g;for(c in a)if(d=n.camelCase(c),e=b[d],f=a[c],n.isArray(f)&&(e=f[1],f=a[c]=f[0]),c!==d&&(a[d]=f,delete a[c]),g=n.cssHooks[d],g&&"expand"in g){f=g.expand(f),delete a[d];for(c in f)c in a||(a[c]=f[c],b[c]=e)}else b[d]=e}function Xb(a,b,c){var d,e,f=0,g=Qb.length,h=n.Deferred().always(function(){delete i.elem}),i=function(){if(e)return!1;for(var b=Lb||Sb(),c=Math.max(0,j.startTime+j.duration-b),d=c/j.duration||0,f=1-d,g=0,i=j.tweens.length;i>g;g++)j.tweens[g].run(f);return h.notifyWith(a,[j,f,c]),1>f&&i?c:(h.resolveWith(a,[j]),!1)},j=h.promise({elem:a,props:n.extend({},b),opts:n.extend(!0,{specialEasing:{}},c),originalProperties:b,originalOptions:c,startTime:Lb||Sb(),duration:c.duration,tweens:[],createTween:function(b,c){var d=n.Tween(a,j.opts,b,c,j.opts.specialEasing[b]||j.opts.easing);return j.tweens.push(d),d},stop:function(b){var c=0,d=b?j.tweens.length:0;if(e)return this;for(e=!0;d>c;c++)j.tweens[c].run(1);return b?h.resolveWith(a,[j,b]):h.rejectWith(a,[j,b]),this}}),k=j.props;for(Wb(k,j.opts.specialEasing);g>f;f++)if(d=Qb[f].call(j,a,k,j.opts))return d;return n.map(k,Ub,j),n.isFunction(j.opts.start)&&j.opts.start.call(a,j),n.fx.timer(n.extend(i,{elem:a,anim:j,queue:j.opts.queue})),j.progress(j.opts.progress).done(j.opts.done,j.opts.complete).fail(j.opts.fail).always(j.opts.always)}n.Animation=n.extend(Xb,{tweener:function(a,b){n.isFunction(a)?(b=a,a=["*"]):a=a.split(" ");for(var c,d=0,e=a.length;e>d;d++)c=a[d],Rb[c]=Rb[c]||[],Rb[c].unshift(b)},prefilter:function(a,b){b?Qb.unshift(a):Qb.push(a)}}),n.speed=function(a,b,c){var d=a&&"object"==typeof a?n.extend({},a):{complete:c||!c&&b||n.isFunction(a)&&a,duration:a,easing:c&&b||b&&!n.isFunction(b)&&b};return d.duration=n.fx.off?0:"number"==typeof d.duration?d.duration:d.duration in n.fx.speeds?n.fx.speeds[d.duration]:n.fx.speeds._default,(null==d.queue||d.queue===!0)&&(d.queue="fx"),d.old=d.complete,d.complete=function(){n.isFunction(d.old)&&d.old.call(this),d.queue&&n.dequeue(this,d.queue)},d},n.fn.extend({fadeTo:function(a,b,c,d){return this.filter(S).css("opacity",0).show().end().animate({opacity:b},a,c,d)},animate:function(a,b,c,d){var e=n.isEmptyObject(a),f=n.speed(b,c,d),g=function(){var b=Xb(this,n.extend({},a),f);(e||L.get(this,"finish"))&&b.stop(!0)};return g.finish=g,e||f.queue===!1?this.each(g):this.queue(f.queue,g)},stop:function(a,b,c){var d=function(a){var b=a.stop;delete a.stop,b(c)};return"string"!=typeof a&&(c=b,b=a,a=void 0),b&&a!==!1&&this.queue(a||"fx",[]),this.each(function(){var b=!0,e=null!=a&&a+"queueHooks",f=n.timers,g=L.get(this);if(e)g[e]&&g[e].stop&&d(g[e]);else for(e in g)g[e]&&g[e].stop&&Pb.test(e)&&d(g[e]);for(e=f.length;e--;)f[e].elem!==this||null!=a&&f[e].queue!==a||(f[e].anim.stop(c),b=!1,f.splice(e,1));(b||!c)&&n.dequeue(this,a)})},finish:function(a){return a!==!1&&(a=a||"fx"),this.each(function(){var b,c=L.get(this),d=c[a+"queue"],e=c[a+"queueHooks"],f=n.timers,g=d?d.length:0;for(c.finish=!0,n.queue(this,a,[]),e&&e.stop&&e.stop.call(this,!0),b=f.length;b--;)f[b].elem===this&&f[b].queue===a&&(f[b].anim.stop(!0),f.splice(b,1));for(b=0;g>b;b++)d[b]&&d[b].finish&&d[b].finish.call(this);delete c.finish})}}),n.each(["toggle","show","hide"],function(a,b){var c=n.fn[b];n.fn[b]=function(a,d,e){return null==a||"boolean"==typeof a?c.apply(this,arguments):this.animate(Tb(b,!0),a,d,e)}}),n.each({slideDown:Tb("show"),slideUp:Tb("hide"),slideToggle:Tb("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){n.fn[a]=function(a,c,d){return this.animate(b,a,c,d)}}),n.timers=[],n.fx.tick=function(){var a,b=0,c=n.timers;for(Lb=n.now();b<c.length;b++)a=c[b],a()||c[b]!==a||c.splice(b--,1);c.length||n.fx.stop(),Lb=void 0},n.fx.timer=function(a){n.timers.push(a),a()?n.fx.start():n.timers.pop()},n.fx.interval=13,n.fx.start=function(){Mb||(Mb=setInterval(n.fx.tick,n.fx.interval))},n.fx.stop=function(){clearInterval(Mb),Mb=null},n.fx.speeds={slow:600,fast:200,_default:400},n.fn.delay=function(a,b){return a=n.fx?n.fx.speeds[a]||a:a,b=b||"fx",this.queue(b,function(b,c){var d=setTimeout(b,a);c.stop=function(){clearTimeout(d)}})},function(){var a=l.createElement("input"),b=l.createElement("select"),c=b.appendChild(l.createElement("option"));a.type="checkbox",k.checkOn=""!==a.value,k.optSelected=c.selected,b.disabled=!0,k.optDisabled=!c.disabled,a=l.createElement("input"),a.value="t",a.type="radio",k.radioValue="t"===a.value}();var Yb,Zb,$b=n.expr.attrHandle;n.fn.extend({attr:function(a,b){return J(this,n.attr,a,b,arguments.length>1)},removeAttr:function(a){return this.each(function(){n.removeAttr(this,a)})}}),n.extend({attr:function(a,b,c){var d,e,f=a.nodeType;if(a&&3!==f&&8!==f&&2!==f)return typeof a.getAttribute===U?n.prop(a,b,c):(1===f&&n.isXMLDoc(a)||(b=b.toLowerCase(),d=n.attrHooks[b]||(n.expr.match.bool.test(b)?Zb:Yb)),void 0===c?d&&"get"in d&&null!==(e=d.get(a,b))?e:(e=n.find.attr(a,b),null==e?void 0:e):null!==c?d&&"set"in d&&void 0!==(e=d.set(a,c,b))?e:(a.setAttribute(b,c+""),c):void n.removeAttr(a,b))
-},removeAttr:function(a,b){var c,d,e=0,f=b&&b.match(E);if(f&&1===a.nodeType)while(c=f[e++])d=n.propFix[c]||c,n.expr.match.bool.test(c)&&(a[d]=!1),a.removeAttribute(c)},attrHooks:{type:{set:function(a,b){if(!k.radioValue&&"radio"===b&&n.nodeName(a,"input")){var c=a.value;return a.setAttribute("type",b),c&&(a.value=c),b}}}}}),Zb={set:function(a,b,c){return b===!1?n.removeAttr(a,c):a.setAttribute(c,c),c}},n.each(n.expr.match.bool.source.match(/\w+/g),function(a,b){var c=$b[b]||n.find.attr;$b[b]=function(a,b,d){var e,f;return d||(f=$b[b],$b[b]=e,e=null!=c(a,b,d)?b.toLowerCase():null,$b[b]=f),e}});var _b=/^(?:input|select|textarea|button)$/i;n.fn.extend({prop:function(a,b){return J(this,n.prop,a,b,arguments.length>1)},removeProp:function(a){return this.each(function(){delete this[n.propFix[a]||a]})}}),n.extend({propFix:{"for":"htmlFor","class":"className"},prop:function(a,b,c){var d,e,f,g=a.nodeType;if(a&&3!==g&&8!==g&&2!==g)return f=1!==g||!n.isXMLDoc(a),f&&(b=n.propFix[b]||b,e=n.propHooks[b]),void 0!==c?e&&"set"in e&&void 0!==(d=e.set(a,c,b))?d:a[b]=c:e&&"get"in e&&null!==(d=e.get(a,b))?d:a[b]},propHooks:{tabIndex:{get:function(a){return a.hasAttribute("tabindex")||_b.test(a.nodeName)||a.href?a.tabIndex:-1}}}}),k.optSelected||(n.propHooks.selected={get:function(a){var b=a.parentNode;return b&&b.parentNode&&b.parentNode.selectedIndex,null}}),n.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){n.propFix[this.toLowerCase()]=this});var ac=/[\t\r\n\f]/g;n.fn.extend({addClass:function(a){var b,c,d,e,f,g,h="string"==typeof a&&a,i=0,j=this.length;if(n.isFunction(a))return this.each(function(b){n(this).addClass(a.call(this,b,this.className))});if(h)for(b=(a||"").match(E)||[];j>i;i++)if(c=this[i],d=1===c.nodeType&&(c.className?(" "+c.className+" ").replace(ac," "):" ")){f=0;while(e=b[f++])d.indexOf(" "+e+" ")<0&&(d+=e+" ");g=n.trim(d),c.className!==g&&(c.className=g)}return this},removeClass:function(a){var b,c,d,e,f,g,h=0===arguments.length||"string"==typeof a&&a,i=0,j=this.length;if(n.isFunction(a))return this.each(function(b){n(this).removeClass(a.call(this,b,this.className))});if(h)for(b=(a||"").match(E)||[];j>i;i++)if(c=this[i],d=1===c.nodeType&&(c.className?(" "+c.className+" ").replace(ac," "):"")){f=0;while(e=b[f++])while(d.indexOf(" "+e+" ")>=0)d=d.replace(" "+e+" "," ");g=a?n.trim(d):"",c.className!==g&&(c.className=g)}return this},toggleClass:function(a,b){var c=typeof a;return"boolean"==typeof b&&"string"===c?b?this.addClass(a):this.removeClass(a):this.each(n.isFunction(a)?function(c){n(this).toggleClass(a.call(this,c,this.className,b),b)}:function(){if("string"===c){var b,d=0,e=n(this),f=a.match(E)||[];while(b=f[d++])e.hasClass(b)?e.removeClass(b):e.addClass(b)}else(c===U||"boolean"===c)&&(this.className&&L.set(this,"__className__",this.className),this.className=this.className||a===!1?"":L.get(this,"__className__")||"")})},hasClass:function(a){for(var b=" "+a+" ",c=0,d=this.length;d>c;c++)if(1===this[c].nodeType&&(" "+this[c].className+" ").replace(ac," ").indexOf(b)>=0)return!0;return!1}});var bc=/\r/g;n.fn.extend({val:function(a){var b,c,d,e=this[0];{if(arguments.length)return d=n.isFunction(a),this.each(function(c){var e;1===this.nodeType&&(e=d?a.call(this,c,n(this).val()):a,null==e?e="":"number"==typeof e?e+="":n.isArray(e)&&(e=n.map(e,function(a){return null==a?"":a+""})),b=n.valHooks[this.type]||n.valHooks[this.nodeName.toLowerCase()],b&&"set"in b&&void 0!==b.set(this,e,"value")||(this.value=e))});if(e)return b=n.valHooks[e.type]||n.valHooks[e.nodeName.toLowerCase()],b&&"get"in b&&void 0!==(c=b.get(e,"value"))?c:(c=e.value,"string"==typeof c?c.replace(bc,""):null==c?"":c)}}}),n.extend({valHooks:{option:{get:function(a){var b=n.find.attr(a,"value");return null!=b?b:n.trim(n.text(a))}},select:{get:function(a){for(var b,c,d=a.options,e=a.selectedIndex,f="select-one"===a.type||0>e,g=f?null:[],h=f?e+1:d.length,i=0>e?h:f?e:0;h>i;i++)if(c=d[i],!(!c.selected&&i!==e||(k.optDisabled?c.disabled:null!==c.getAttribute("disabled"))||c.parentNode.disabled&&n.nodeName(c.parentNode,"optgroup"))){if(b=n(c).val(),f)return b;g.push(b)}return g},set:function(a,b){var c,d,e=a.options,f=n.makeArray(b),g=e.length;while(g--)d=e[g],(d.selected=n.inArray(d.value,f)>=0)&&(c=!0);return c||(a.selectedIndex=-1),f}}}}),n.each(["radio","checkbox"],function(){n.valHooks[this]={set:function(a,b){return n.isArray(b)?a.checked=n.inArray(n(a).val(),b)>=0:void 0}},k.checkOn||(n.valHooks[this].get=function(a){return null===a.getAttribute("value")?"on":a.value})}),n.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu".split(" "),function(a,b){n.fn[b]=function(a,c){return arguments.length>0?this.on(b,null,a,c):this.trigger(b)}}),n.fn.extend({hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)},bind:function(a,b,c){return this.on(a,null,b,c)},unbind:function(a,b){return this.off(a,null,b)},delegate:function(a,b,c,d){return this.on(b,a,c,d)},undelegate:function(a,b,c){return 1===arguments.length?this.off(a,"**"):this.off(b,a||"**",c)}});var cc=n.now(),dc=/\?/;n.parseJSON=function(a){return JSON.parse(a+"")},n.parseXML=function(a){var b,c;if(!a||"string"!=typeof a)return null;try{c=new DOMParser,b=c.parseFromString(a,"text/xml")}catch(d){b=void 0}return(!b||b.getElementsByTagName("parsererror").length)&&n.error("Invalid XML: "+a),b};var ec=/#.*$/,fc=/([?&])_=[^&]*/,gc=/^(.*?):[ \t]*([^\r\n]*)$/gm,hc=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,ic=/^(?:GET|HEAD)$/,jc=/^\/\//,kc=/^([\w.+-]+:)(?:\/\/(?:[^\/?#]*@|)([^\/?#:]*)(?::(\d+)|)|)/,lc={},mc={},nc="*/".concat("*"),oc=a.location.href,pc=kc.exec(oc.toLowerCase())||[];function qc(a){return function(b,c){"string"!=typeof b&&(c=b,b="*");var d,e=0,f=b.toLowerCase().match(E)||[];if(n.isFunction(c))while(d=f[e++])"+"===d[0]?(d=d.slice(1)||"*",(a[d]=a[d]||[]).unshift(c)):(a[d]=a[d]||[]).push(c)}}function rc(a,b,c,d){var e={},f=a===mc;function g(h){var i;return e[h]=!0,n.each(a[h]||[],function(a,h){var j=h(b,c,d);return"string"!=typeof j||f||e[j]?f?!(i=j):void 0:(b.dataTypes.unshift(j),g(j),!1)}),i}return g(b.dataTypes[0])||!e["*"]&&g("*")}function sc(a,b){var c,d,e=n.ajaxSettings.flatOptions||{};for(c in b)void 0!==b[c]&&((e[c]?a:d||(d={}))[c]=b[c]);return d&&n.extend(!0,a,d),a}function tc(a,b,c){var d,e,f,g,h=a.contents,i=a.dataTypes;while("*"===i[0])i.shift(),void 0===d&&(d=a.mimeType||b.getResponseHeader("Content-Type"));if(d)for(e in h)if(h[e]&&h[e].test(d)){i.unshift(e);break}if(i[0]in c)f=i[0];else{for(e in c){if(!i[0]||a.converters[e+" "+i[0]]){f=e;break}g||(g=e)}f=f||g}return f?(f!==i[0]&&i.unshift(f),c[f]):void 0}function uc(a,b,c,d){var e,f,g,h,i,j={},k=a.dataTypes.slice();if(k[1])for(g in a.converters)j[g.toLowerCase()]=a.converters[g];f=k.shift();while(f)if(a.responseFields[f]&&(c[a.responseFields[f]]=b),!i&&d&&a.dataFilter&&(b=a.dataFilter(b,a.dataType)),i=f,f=k.shift())if("*"===f)f=i;else if("*"!==i&&i!==f){if(g=j[i+" "+f]||j["* "+f],!g)for(e in j)if(h=e.split(" "),h[1]===f&&(g=j[i+" "+h[0]]||j["* "+h[0]])){g===!0?g=j[e]:j[e]!==!0&&(f=h[0],k.unshift(h[1]));break}if(g!==!0)if(g&&a["throws"])b=g(b);else try{b=g(b)}catch(l){return{state:"parsererror",error:g?l:"No conversion from "+i+" to "+f}}}return{state:"success",data:b}}n.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:oc,type:"GET",isLocal:hc.test(pc[1]),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":nc,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":n.parseJSON,"text xml":n.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(a,b){return b?sc(sc(a,n.ajaxSettings),b):sc(n.ajaxSettings,a)},ajaxPrefilter:qc(lc),ajaxTransport:qc(mc),ajax:function(a,b){"object"==typeof a&&(b=a,a=void 0),b=b||{};var c,d,e,f,g,h,i,j,k=n.ajaxSetup({},b),l=k.context||k,m=k.context&&(l.nodeType||l.jquery)?n(l):n.event,o=n.Deferred(),p=n.Callbacks("once memory"),q=k.statusCode||{},r={},s={},t=0,u="canceled",v={readyState:0,getResponseHeader:function(a){var b;if(2===t){if(!f){f={};while(b=gc.exec(e))f[b[1].toLowerCase()]=b[2]}b=f[a.toLowerCase()]}return null==b?null:b},getAllResponseHeaders:function(){return 2===t?e:null},setRequestHeader:function(a,b){var c=a.toLowerCase();return t||(a=s[c]=s[c]||a,r[a]=b),this},overrideMimeType:function(a){return t||(k.mimeType=a),this},statusCode:function(a){var b;if(a)if(2>t)for(b in a)q[b]=[q[b],a[b]];else v.always(a[v.status]);return this},abort:function(a){var b=a||u;return c&&c.abort(b),x(0,b),this}};if(o.promise(v).complete=p.add,v.success=v.done,v.error=v.fail,k.url=((a||k.url||oc)+"").replace(ec,"").replace(jc,pc[1]+"//"),k.type=b.method||b.type||k.method||k.type,k.dataTypes=n.trim(k.dataType||"*").toLowerCase().match(E)||[""],null==k.crossDomain&&(h=kc.exec(k.url.toLowerCase()),k.crossDomain=!(!h||h[1]===pc[1]&&h[2]===pc[2]&&(h[3]||("http:"===h[1]?"80":"443"))===(pc[3]||("http:"===pc[1]?"80":"443")))),k.data&&k.processData&&"string"!=typeof k.data&&(k.data=n.param(k.data,k.traditional)),rc(lc,k,b,v),2===t)return v;i=n.event&&k.global,i&&0===n.active++&&n.event.trigger("ajaxStart"),k.type=k.type.toUpperCase(),k.hasContent=!ic.test(k.type),d=k.url,k.hasContent||(k.data&&(d=k.url+=(dc.test(d)?"&":"?")+k.data,delete k.data),k.cache===!1&&(k.url=fc.test(d)?d.replace(fc,"$1_="+cc++):d+(dc.test(d)?"&":"?")+"_="+cc++)),k.ifModified&&(n.lastModified[d]&&v.setRequestHeader("If-Modified-Since",n.lastModified[d]),n.etag[d]&&v.setRequestHeader("If-None-Match",n.etag[d])),(k.data&&k.hasContent&&k.contentType!==!1||b.contentType)&&v.setRequestHeader("Content-Type",k.contentType),v.setRequestHeader("Accept",k.dataTypes[0]&&k.accepts[k.dataTypes[0]]?k.accepts[k.dataTypes[0]]+("*"!==k.dataTypes[0]?", "+nc+"; q=0.01":""):k.accepts["*"]);for(j in k.headers)v.setRequestHeader(j,k.headers[j]);if(k.beforeSend&&(k.beforeSend.call(l,v,k)===!1||2===t))return v.abort();u="abort";for(j in{success:1,error:1,complete:1})v[j](k[j]);if(c=rc(mc,k,b,v)){v.readyState=1,i&&m.trigger("ajaxSend",[v,k]),k.async&&k.timeout>0&&(g=setTimeout(function(){v.abort("timeout")},k.timeout));try{t=1,c.send(r,x)}catch(w){if(!(2>t))throw w;x(-1,w)}}else x(-1,"No Transport");function x(a,b,f,h){var j,r,s,u,w,x=b;2!==t&&(t=2,g&&clearTimeout(g),c=void 0,e=h||"",v.readyState=a>0?4:0,j=a>=200&&300>a||304===a,f&&(u=tc(k,v,f)),u=uc(k,u,v,j),j?(k.ifModified&&(w=v.getResponseHeader("Last-Modified"),w&&(n.lastModified[d]=w),w=v.getResponseHeader("etag"),w&&(n.etag[d]=w)),204===a||"HEAD"===k.type?x="nocontent":304===a?x="notmodified":(x=u.state,r=u.data,s=u.error,j=!s)):(s=x,(a||!x)&&(x="error",0>a&&(a=0))),v.status=a,v.statusText=(b||x)+"",j?o.resolveWith(l,[r,x,v]):o.rejectWith(l,[v,x,s]),v.statusCode(q),q=void 0,i&&m.trigger(j?"ajaxSuccess":"ajaxError",[v,k,j?r:s]),p.fireWith(l,[v,x]),i&&(m.trigger("ajaxComplete",[v,k]),--n.active||n.event.trigger("ajaxStop")))}return v},getJSON:function(a,b,c){return n.get(a,b,c,"json")},getScript:function(a,b){return n.get(a,void 0,b,"script")}}),n.each(["get","post"],function(a,b){n[b]=function(a,c,d,e){return n.isFunction(c)&&(e=e||d,d=c,c=void 0),n.ajax({url:a,type:b,dataType:e,data:c,success:d})}}),n._evalUrl=function(a){return n.ajax({url:a,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0})},n.fn.extend({wrapAll:function(a){var b;return n.isFunction(a)?this.each(function(b){n(this).wrapAll(a.call(this,b))}):(this[0]&&(b=n(a,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstElementChild)a=a.firstElementChild;return a}).append(this)),this)},wrapInner:function(a){return this.each(n.isFunction(a)?function(b){n(this).wrapInner(a.call(this,b))}:function(){var b=n(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=n.isFunction(a);return this.each(function(c){n(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(){return this.parent().each(function(){n.nodeName(this,"body")||n(this).replaceWith(this.childNodes)}).end()}}),n.expr.filters.hidden=function(a){return a.offsetWidth<=0&&a.offsetHeight<=0},n.expr.filters.visible=function(a){return!n.expr.filters.hidden(a)};var vc=/%20/g,wc=/\[\]$/,xc=/\r?\n/g,yc=/^(?:submit|button|image|reset|file)$/i,zc=/^(?:input|select|textarea|keygen)/i;function Ac(a,b,c,d){var e;if(n.isArray(b))n.each(b,function(b,e){c||wc.test(a)?d(a,e):Ac(a+"["+("object"==typeof e?b:"")+"]",e,c,d)});else if(c||"object"!==n.type(b))d(a,b);else for(e in b)Ac(a+"["+e+"]",b[e],c,d)}n.param=function(a,b){var c,d=[],e=function(a,b){b=n.isFunction(b)?b():null==b?"":b,d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};if(void 0===b&&(b=n.ajaxSettings&&n.ajaxSettings.traditional),n.isArray(a)||a.jquery&&!n.isPlainObject(a))n.each(a,function(){e(this.name,this.value)});else for(c in a)Ac(c,a[c],b,e);return d.join("&").replace(vc,"+")},n.fn.extend({serialize:function(){return n.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var a=n.prop(this,"elements");return a?n.makeArray(a):this}).filter(function(){var a=this.type;return this.name&&!n(this).is(":disabled")&&zc.test(this.nodeName)&&!yc.test(a)&&(this.checked||!T.test(a))}).map(function(a,b){var c=n(this).val();return null==c?null:n.isArray(c)?n.map(c,function(a){return{name:b.name,value:a.replace(xc,"\r\n")}}):{name:b.name,value:c.replace(xc,"\r\n")}}).get()}}),n.ajaxSettings.xhr=function(){try{return new XMLHttpRequest}catch(a){}};var Bc=0,Cc={},Dc={0:200,1223:204},Ec=n.ajaxSettings.xhr();a.attachEvent&&a.attachEvent("onunload",function(){for(var a in Cc)Cc[a]()}),k.cors=!!Ec&&"withCredentials"in Ec,k.ajax=Ec=!!Ec,n.ajaxTransport(function(a){var b;return k.cors||Ec&&!a.crossDomain?{send:function(c,d){var e,f=a.xhr(),g=++Bc;if(f.open(a.type,a.url,a.async,a.username,a.password),a.xhrFields)for(e in a.xhrFields)f[e]=a.xhrFields[e];a.mimeType&&f.overrideMimeType&&f.overrideMimeType(a.mimeType),a.crossDomain||c["X-Requested-With"]||(c["X-Requested-With"]="XMLHttpRequest");for(e in c)f.setRequestHeader(e,c[e]);b=function(a){return function(){b&&(delete Cc[g],b=f.onload=f.onerror=null,"abort"===a?f.abort():"error"===a?d(f.status,f.statusText):d(Dc[f.status]||f.status,f.statusText,"string"==typeof f.responseText?{text:f.responseText}:void 0,f.getAllResponseHeaders()))}},f.onload=b(),f.onerror=b("error"),b=Cc[g]=b("abort");try{f.send(a.hasContent&&a.data||null)}catch(h){if(b)throw h}},abort:function(){b&&b()}}:void 0}),n.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/(?:java|ecma)script/},converters:{"text script":function(a){return n.globalEval(a),a}}}),n.ajaxPrefilter("script",function(a){void 0===a.cache&&(a.cache=!1),a.crossDomain&&(a.type="GET")}),n.ajaxTransport("script",function(a){if(a.crossDomain){var b,c;return{send:function(d,e){b=n("<script>").prop({async:!0,charset:a.scriptCharset,src:a.url}).on("load error",c=function(a){b.remove(),c=null,a&&e("error"===a.type?404:200,a.type)}),l.head.appendChild(b[0])},abort:function(){c&&c()}}}});var Fc=[],Gc=/(=)\?(?=&|$)|\?\?/;n.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var a=Fc.pop()||n.expando+"_"+cc++;return this[a]=!0,a}}),n.ajaxPrefilter("json jsonp",function(b,c,d){var e,f,g,h=b.jsonp!==!1&&(Gc.test(b.url)?"url":"string"==typeof b.data&&!(b.contentType||"").indexOf("application/x-www-form-urlencoded")&&Gc.test(b.data)&&"data");return h||"jsonp"===b.dataTypes[0]?(e=b.jsonpCallback=n.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,h?b[h]=b[h].replace(Gc,"$1"+e):b.jsonp!==!1&&(b.url+=(dc.test(b.url)?"&":"?")+b.jsonp+"="+e),b.converters["script json"]=function(){return g||n.error(e+" was not called"),g[0]},b.dataTypes[0]="json",f=a[e],a[e]=function(){g=arguments},d.always(function(){a[e]=f,b[e]&&(b.jsonpCallback=c.jsonpCallback,Fc.push(e)),g&&n.isFunction(f)&&f(g[0]),g=f=void 0}),"script"):void 0}),n.parseHTML=function(a,b,c){if(!a||"string"!=typeof a)return null;"boolean"==typeof b&&(c=b,b=!1),b=b||l;var d=v.exec(a),e=!c&&[];return d?[b.createElement(d[1])]:(d=n.buildFragment([a],b,e),e&&e.length&&n(e).remove(),n.merge([],d.childNodes))};var Hc=n.fn.load;n.fn.load=function(a,b,c){if("string"!=typeof a&&Hc)return Hc.apply(this,arguments);var d,e,f,g=this,h=a.indexOf(" ");return h>=0&&(d=n.trim(a.slice(h)),a=a.slice(0,h)),n.isFunction(b)?(c=b,b=void 0):b&&"object"==typeof b&&(e="POST"),g.length>0&&n.ajax({url:a,type:e,dataType:"html",data:b}).done(function(a){f=arguments,g.html(d?n("<div>").append(n.parseHTML(a)).find(d):a)}).complete(c&&function(a,b){g.each(c,f||[a.responseText,b,a])}),this},n.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(a,b){n.fn[b]=function(a){return this.on(b,a)}}),n.expr.filters.animated=function(a){return n.grep(n.timers,function(b){return a===b.elem}).length};var Ic=a.document.documentElement;function Jc(a){return n.isWindow(a)?a:9===a.nodeType&&a.defaultView}n.offset={setOffset:function(a,b,c){var d,e,f,g,h,i,j,k=n.css(a,"position"),l=n(a),m={};"static"===k&&(a.style.position="relative"),h=l.offset(),f=n.css(a,"top"),i=n.css(a,"left"),j=("absolute"===k||"fixed"===k)&&(f+i).indexOf("auto")>-1,j?(d=l.position(),g=d.top,e=d.left):(g=parseFloat(f)||0,e=parseFloat(i)||0),n.isFunction(b)&&(b=b.call(a,c,h)),null!=b.top&&(m.top=b.top-h.top+g),null!=b.left&&(m.left=b.left-h.left+e),"using"in b?b.using.call(a,m):l.css(m)}},n.fn.extend({offset:function(a){if(arguments.length)return void 0===a?this:this.each(function(b){n.offset.setOffset(this,a,b)});var b,c,d=this[0],e={top:0,left:0},f=d&&d.ownerDocument;if(f)return b=f.documentElement,n.contains(b,d)?(typeof d.getBoundingClientRect!==U&&(e=d.getBoundingClientRect()),c=Jc(f),{top:e.top+c.pageYOffset-b.clientTop,left:e.left+c.pageXOffset-b.clientLeft}):e},position:function(){if(this[0]){var a,b,c=this[0],d={top:0,left:0};return"fixed"===n.css(c,"position")?b=c.getBoundingClientRect():(a=this.offsetParent(),b=this.offset(),n.nodeName(a[0],"html")||(d=a.offset()),d.top+=n.css(a[0],"borderTopWidth",!0),d.left+=n.css(a[0],"borderLeftWidth",!0)),{top:b.top-d.top-n.css(c,"marginTop",!0),left:b.left-d.left-n.css(c,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||Ic;while(a&&!n.nodeName(a,"html")&&"static"===n.css(a,"position"))a=a.offsetParent;return a||Ic})}}),n.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(b,c){var d="pageYOffset"===c;n.fn[b]=function(e){return J(this,function(b,e,f){var g=Jc(b);return void 0===f?g?g[c]:b[e]:void(g?g.scrollTo(d?a.pageXOffset:f,d?f:a.pageYOffset):b[e]=f)},b,e,arguments.length,null)}}),n.each(["top","left"],function(a,b){n.cssHooks[b]=yb(k.pixelPosition,function(a,c){return c?(c=xb(a,b),vb.test(c)?n(a).position()[b]+"px":c):void 0})}),n.each({Height:"height",Width:"width"},function(a,b){n.each({padding:"inner"+a,content:b,"":"outer"+a},function(c,d){n.fn[d]=function(d,e){var f=arguments.length&&(c||"boolean"!=typeof d),g=c||(d===!0||e===!0?"margin":"border");return J(this,function(b,c,d){var e;return n.isWindow(b)?b.document.documentElement["client"+a]:9===b.nodeType?(e=b.documentElement,Math.max(b.body["scroll"+a],e["scroll"+a],b.body["offset"+a],e["offset"+a],e["client"+a])):void 0===d?n.css(b,c,g):n.style(b,c,d,g)},b,f?d:void 0,f,null)}})}),n.fn.size=function(){return this.length},n.fn.andSelf=n.fn.addBack,"function"==typeof define&&define.amd&&define("jquery",[],function(){return n});var Kc=a.jQuery,Lc=a.$;return n.noConflict=function(b){return a.$===n&&(a.$=Lc),b&&a.jQuery===n&&(a.jQuery=Kc),n},typeof b===U&&(a.jQuery=a.$=n),n});
diff --git a/src/Jackett/Content/jquery.dataTables.js b/src/Jackett/Content/jquery.dataTables.js
deleted file mode 100644
index d65932e464dea1a139dd59ee45dcaf7d09701c21..0000000000000000000000000000000000000000
--- a/src/Jackett/Content/jquery.dataTables.js
+++ /dev/null
@@ -1,14593 +0,0 @@
-/*! DataTables 1.10.7
- * ©2008-2014 SpryMedia Ltd - datatables.net/license
- */
-
-/**
- * @summary     DataTables
- * @description Paginate, search and order HTML tables
- * @version     1.10.7
- * @file        jquery.dataTables.js
- * @author      SpryMedia Ltd (www.sprymedia.co.uk)
- * @contact     www.sprymedia.co.uk/contact
- * @copyright   Copyright 2008-2014 SpryMedia Ltd.
- *
- * This source file is free software, available under the following license:
- *   MIT license - http://datatables.net/license
- *
- * This source file is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.
- *
- * For details please refer to: http://www.datatables.net
- */
-
-/*jslint evil: true, undef: true, browser: true */
-/*globals $,require,jQuery,define,_selector_run,_selector_opts,_selector_first,_selector_row_indexes,_ext,_Api,_api_register,_api_registerPlural,_re_new_lines,_re_html,_re_formatted_numeric,_re_escape_regex,_empty,_intVal,_numToDecimal,_isNumber,_isHtml,_htmlNumeric,_pluck,_pluck_order,_range,_stripHtml,_unique,_fnBuildAjax,_fnAjaxUpdate,_fnAjaxParameters,_fnAjaxUpdateDraw,_fnAjaxDataSrc,_fnAddColumn,_fnColumnOptions,_fnAdjustColumnSizing,_fnVisibleToColumnIndex,_fnColumnIndexToVisible,_fnVisbleColumns,_fnGetColumns,_fnColumnTypes,_fnApplyColumnDefs,_fnHungarianMap,_fnCamelToHungarian,_fnLanguageCompat,_fnBrowserDetect,_fnAddData,_fnAddTr,_fnNodeToDataIndex,_fnNodeToColumnIndex,_fnGetCellData,_fnSetCellData,_fnSplitObjNotation,_fnGetObjectDataFn,_fnSetObjectDataFn,_fnGetDataMaster,_fnClearTable,_fnDeleteIndex,_fnInvalidate,_fnGetRowElements,_fnCreateTr,_fnBuildHead,_fnDrawHead,_fnDraw,_fnReDraw,_fnAddOptionsHtml,_fnDetectHeader,_fnGetUniqueThs,_fnFeatureHtmlFilter,_fnFilterComplete,_fnFilterCustom,_fnFilterColumn,_fnFilter,_fnFilterCreateSearch,_fnEscapeRegex,_fnFilterData,_fnFeatureHtmlInfo,_fnUpdateInfo,_fnInfoMacros,_fnInitialise,_fnInitComplete,_fnLengthChange,_fnFeatureHtmlLength,_fnFeatureHtmlPaginate,_fnPageChange,_fnFeatureHtmlProcessing,_fnProcessingDisplay,_fnFeatureHtmlTable,_fnScrollDraw,_fnApplyToChildren,_fnCalculateColumnWidths,_fnThrottle,_fnConvertToWidth,_fnScrollingWidthAdjust,_fnGetWidestNode,_fnGetMaxLenString,_fnStringToCss,_fnScrollBarWidth,_fnSortFlatten,_fnSort,_fnSortAria,_fnSortListener,_fnSortAttachListener,_fnSortingClasses,_fnSortData,_fnSaveState,_fnLoadState,_fnSettingsFromNode,_fnLog,_fnMap,_fnBindAction,_fnCallbackReg,_fnCallbackFire,_fnLengthOverflow,_fnRenderer,_fnDataSource,_fnRowAttributes*/
-
-(/** @lends <global> */function (window, document, undefined) {
-
-    (function (factory) {
-        "use strict";
-
-        if (typeof define === 'function' && define.amd) {
-            // Define as an AMD module if possible
-            define('datatables', ['jquery'], factory);
-        }
-        else if (typeof exports === 'object') {
-            // Node/CommonJS
-            module.exports = factory(require('jquery'));
-        }
-        else if (jQuery && !jQuery.fn.dataTable) {
-            // Define using browser globals otherwise
-            // Prevent multiple instantiations if the script is loaded twice
-            factory(jQuery);
-        }
-    }
-    (/** @lends <global> */function ($) {
-        "use strict";
-
-        /**
-         * DataTables is a plug-in for the jQuery Javascript library. It is a highly
-         * flexible tool, based upon the foundations of progressive enhancement,
-         * which will add advanced interaction controls to any HTML table. For a
-         * full list of features please refer to
-         * [DataTables.net](href="http://datatables.net).
-         *
-         * Note that the `DataTable` object is not a global variable but is aliased
-         * to `jQuery.fn.DataTable` and `jQuery.fn.dataTable` through which it may
-         * be  accessed.
-         *
-         *  @class
-         *  @param {object} [init={}] Configuration object for DataTables. Options
-         *    are defined by {@link DataTable.defaults}
-         *  @requires jQuery 1.7+
-         *
-         *  @example
-         *    // Basic initialisation
-         *    $(document).ready( function {
-         *      $('#example').dataTable();
-         *    } );
-         *
-         *  @example
-         *    // Initialisation with configuration options - in this case, disable
-         *    // pagination and sorting.
-         *    $(document).ready( function {
-         *      $('#example').dataTable( {
-         *        "paginate": false,
-         *        "sort": false
-         *      } );
-         *    } );
-         */
-        var DataTable;
-
-
-        /*
-         * It is useful to have variables which are scoped locally so only the
-         * DataTables functions can access them and they don't leak into global space.
-         * At the same time these functions are often useful over multiple files in the
-         * core and API, so we list, or at least document, all variables which are used
-         * by DataTables as private variables here. This also ensures that there is no
-         * clashing of variable names and that they can easily referenced for reuse.
-         */
-
-
-        // Defined else where
-        //  _selector_run
-        //  _selector_opts
-        //  _selector_first
-        //  _selector_row_indexes
-
-        var _ext; // DataTable.ext
-        var _Api; // DataTable.Api
-        var _api_register; // DataTable.Api.register
-        var _api_registerPlural; // DataTable.Api.registerPlural
-
-        var _re_dic = {};
-        var _re_new_lines = /[\r\n]/g;
-        var _re_html = /<.*?>/g;
-        var _re_date_start = /^[\w\+\-]/;
-        var _re_date_end = /[\w\+\-]$/;
-
-        // Escape regular expression special characters
-        var _re_escape_regex = new RegExp('(\\' + ['/', '.', '*', '+', '?', '|', '(', ')', '[', ']', '{', '}', '\\', '$', '^', '-'].join('|\\') + ')', 'g');
-
-        // http://en.wikipedia.org/wiki/Foreign_exchange_market
-        // - \u20BD - Russian ruble.
-        // - \u20a9 - South Korean Won
-        // - \u20BA - Turkish Lira
-        // - \u20B9 - Indian Rupee
-        // - R - Brazil (R$) and South Africa
-        // - fr - Swiss Franc
-        // - kr - Swedish krona, Norwegian krone and Danish krone
-        // - \u2009 is thin space and \u202F is narrow no-break space, both used in many
-        //   standards as thousands separators.
-        var _re_formatted_numeric = /[',$£€¥%\u2009\u202F\u20BD\u20a9\u20BArfk]/gi;
-
-
-        var _empty = function (d) {
-            return !d || d === true || d === '-' ? true : false;
-        };
-
-
-        var _intVal = function (s) {
-            var integer = parseInt(s, 10);
-            return !isNaN(integer) && isFinite(s) ? integer : null;
-        };
-
-        // Convert from a formatted number with characters other than `.` as the
-        // decimal place, to a Javascript number
-        var _numToDecimal = function (num, decimalPoint) {
-            // Cache created regular expressions for speed as this function is called often
-            if (!_re_dic[decimalPoint]) {
-                _re_dic[decimalPoint] = new RegExp(_fnEscapeRegex(decimalPoint), 'g');
-            }
-            return typeof num === 'string' && decimalPoint !== '.' ?
-                num.replace(/\./g, '').replace(_re_dic[decimalPoint], '.') :
-                num;
-        };
-
-
-        var _isNumber = function (d, decimalPoint, formatted) {
-            var strType = typeof d === 'string';
-
-            // If empty return immediately so there must be a number if it is a
-            // formatted string (this stops the string "k", or "kr", etc being detected
-            // as a formatted number for currency
-            if (_empty(d)) {
-                return true;
-            }
-
-            if (decimalPoint && strType) {
-                d = _numToDecimal(d, decimalPoint);
-            }
-
-            if (formatted && strType) {
-                d = d.replace(_re_formatted_numeric, '');
-            }
-
-            return !isNaN(parseFloat(d)) && isFinite(d);
-        };
-
-
-        // A string without HTML in it can be considered to be HTML still
-        var _isHtml = function (d) {
-            return _empty(d) || typeof d === 'string';
-        };
-
-
-        var _htmlNumeric = function (d, decimalPoint, formatted) {
-            if (_empty(d)) {
-                return true;
-            }
-
-            var html = _isHtml(d);
-            return !html ?
-                null :
-                _isNumber(_stripHtml(d), decimalPoint, formatted) ?
-                    true :
-                    null;
-        };
-
-
-        var _pluck = function (a, prop, prop2) {
-            var out = [];
-            var i = 0, ien = a.length;
-
-            // Could have the test in the loop for slightly smaller code, but speed
-            // is essential here
-            if (prop2 !== undefined) {
-                for (; i < ien ; i++) {
-                    if (a[i] && a[i][prop]) {
-                        out.push(a[i][prop][prop2]);
-                    }
-                }
-            }
-            else {
-                for (; i < ien ; i++) {
-                    if (a[i]) {
-                        out.push(a[i][prop]);
-                    }
-                }
-            }
-
-            return out;
-        };
-
-
-        // Basically the same as _pluck, but rather than looping over `a` we use `order`
-        // as the indexes to pick from `a`
-        var _pluck_order = function (a, order, prop, prop2) {
-            var out = [];
-            var i = 0, ien = order.length;
-
-            // Could have the test in the loop for slightly smaller code, but speed
-            // is essential here
-            if (prop2 !== undefined) {
-                for (; i < ien ; i++) {
-                    if (a[order[i]][prop]) {
-                        out.push(a[order[i]][prop][prop2]);
-                    }
-                }
-            }
-            else {
-                for (; i < ien ; i++) {
-                    out.push(a[order[i]][prop]);
-                }
-            }
-
-            return out;
-        };
-
-
-        var _range = function (len, start) {
-            var out = [];
-            var end;
-
-            if (start === undefined) {
-                start = 0;
-                end = len;
-            }
-            else {
-                end = start;
-                start = len;
-            }
-
-            for (var i = start ; i < end ; i++) {
-                out.push(i);
-            }
-
-            return out;
-        };
-
-
-        var _removeEmpty = function (a) {
-            var out = [];
-
-            for (var i = 0, ien = a.length ; i < ien ; i++) {
-                if (a[i]) { // careful - will remove all falsy values!
-                    out.push(a[i]);
-                }
-            }
-
-            return out;
-        };
-
-
-        var _stripHtml = function (d) {
-            return d.replace(_re_html, '');
-        };
-
-
-        /**
-         * Find the unique elements in a source array.
-         *
-         * @param  {array} src Source array
-         * @return {array} Array of unique items
-         * @ignore
-         */
-        var _unique = function (src) {
-            // A faster unique method is to use object keys to identify used values,
-            // but this doesn't work with arrays or objects, which we must also
-            // consider. See jsperf.com/compare-array-unique-versions/4 for more
-            // information.
-            var
-                out = [],
-                val,
-                i, ien = src.length,
-                j, k = 0;
-
-            again: for (i = 0 ; i < ien ; i++) {
-                val = src[i];
-
-                for (j = 0 ; j < k ; j++) {
-                    if (out[j] === val) {
-                        continue again;
-                    }
-                }
-
-                out.push(val);
-                k++;
-            }
-
-            return out;
-        };
-
-
-
-        /**
-         * Create a mapping object that allows camel case parameters to be looked up
-         * for their Hungarian counterparts. The mapping is stored in a private
-         * parameter called `_hungarianMap` which can be accessed on the source object.
-         *  @param {object} o
-         *  @memberof DataTable#oApi
-         */
-        function _fnHungarianMap(o) {
-            var
-                hungarian = 'a aa ai ao as b fn i m o s ',
-                match,
-                newKey,
-                map = {};
-
-            $.each(o, function (key, val) {
-                match = key.match(/^([^A-Z]+?)([A-Z])/);
-
-                if (match && hungarian.indexOf(match[1] + ' ') !== -1) {
-                    newKey = key.replace(match[0], match[2].toLowerCase());
-                    map[newKey] = key;
-
-                    if (match[1] === 'o') {
-                        _fnHungarianMap(o[key]);
-                    }
-                }
-            });
-
-            o._hungarianMap = map;
-        }
-
-
-        /**
-         * Convert from camel case parameters to Hungarian, based on a Hungarian map
-         * created by _fnHungarianMap.
-         *  @param {object} src The model object which holds all parameters that can be
-         *    mapped.
-         *  @param {object} user The object to convert from camel case to Hungarian.
-         *  @param {boolean} force When set to `true`, properties which already have a
-         *    Hungarian value in the `user` object will be overwritten. Otherwise they
-         *    won't be.
-         *  @memberof DataTable#oApi
-         */
-        function _fnCamelToHungarian(src, user, force) {
-            if (!src._hungarianMap) {
-                _fnHungarianMap(src);
-            }
-
-            var hungarianKey;
-
-            $.each(user, function (key, val) {
-                hungarianKey = src._hungarianMap[key];
-
-                if (hungarianKey !== undefined && (force || user[hungarianKey] === undefined)) {
-                    // For objects, we need to buzz down into the object to copy parameters
-                    if (hungarianKey.charAt(0) === 'o') {
-                        // Copy the camelCase options over to the hungarian
-                        if (!user[hungarianKey]) {
-                            user[hungarianKey] = {};
-                        }
-                        $.extend(true, user[hungarianKey], user[key]);
-
-                        _fnCamelToHungarian(src[hungarianKey], user[hungarianKey], force);
-                    }
-                    else {
-                        user[hungarianKey] = user[key];
-                    }
-                }
-            });
-        }
-
-
-        /**
-         * Language compatibility - when certain options are given, and others aren't, we
-         * need to duplicate the values over, in order to provide backwards compatibility
-         * with older language files.
-         *  @param {object} oSettings dataTables settings object
-         *  @memberof DataTable#oApi
-         */
-        function _fnLanguageCompat(lang) {
-            var defaults = DataTable.defaults.oLanguage;
-            var zeroRecords = lang.sZeroRecords;
-
-            /* Backwards compatibility - if there is no sEmptyTable given, then use the same as
-             * sZeroRecords - assuming that is given.
-             */
-            if (!lang.sEmptyTable && zeroRecords &&
-                defaults.sEmptyTable === "No data available in table") {
-                _fnMap(lang, lang, 'sZeroRecords', 'sEmptyTable');
-            }
-
-            /* Likewise with loading records */
-            if (!lang.sLoadingRecords && zeroRecords &&
-                defaults.sLoadingRecords === "Loading...") {
-                _fnMap(lang, lang, 'sZeroRecords', 'sLoadingRecords');
-            }
-
-            // Old parameter name of the thousands separator mapped onto the new
-            if (lang.sInfoThousands) {
-                lang.sThousands = lang.sInfoThousands;
-            }
-
-            var decimal = lang.sDecimal;
-            if (decimal) {
-                _addNumericSort(decimal);
-            }
-        }
-
-
-        /**
-         * Map one parameter onto another
-         *  @param {object} o Object to map
-         *  @param {*} knew The new parameter name
-         *  @param {*} old The old parameter name
-         */
-        var _fnCompatMap = function (o, knew, old) {
-            if (o[knew] !== undefined) {
-                o[old] = o[knew];
-            }
-        };
-
-
-        /**
-         * Provide backwards compatibility for the main DT options. Note that the new
-         * options are mapped onto the old parameters, so this is an external interface
-         * change only.
-         *  @param {object} init Object to map
-         */
-        function _fnCompatOpts(init) {
-            _fnCompatMap(init, 'ordering', 'bSort');
-            _fnCompatMap(init, 'orderMulti', 'bSortMulti');
-            _fnCompatMap(init, 'orderClasses', 'bSortClasses');
-            _fnCompatMap(init, 'orderCellsTop', 'bSortCellsTop');
-            _fnCompatMap(init, 'order', 'aaSorting');
-            _fnCompatMap(init, 'orderFixed', 'aaSortingFixed');
-            _fnCompatMap(init, 'paging', 'bPaginate');
-            _fnCompatMap(init, 'pagingType', 'sPaginationType');
-            _fnCompatMap(init, 'pageLength', 'iDisplayLength');
-            _fnCompatMap(init, 'searching', 'bFilter');
-
-            // Column search objects are in an array, so it needs to be converted
-            // element by element
-            var searchCols = init.aoSearchCols;
-
-            if (searchCols) {
-                for (var i = 0, ien = searchCols.length ; i < ien ; i++) {
-                    if (searchCols[i]) {
-                        _fnCamelToHungarian(DataTable.models.oSearch, searchCols[i]);
-                    }
-                }
-            }
-        }
-
-
-        /**
-         * Provide backwards compatibility for column options. Note that the new options
-         * are mapped onto the old parameters, so this is an external interface change
-         * only.
-         *  @param {object} init Object to map
-         */
-        function _fnCompatCols(init) {
-            _fnCompatMap(init, 'orderable', 'bSortable');
-            _fnCompatMap(init, 'orderData', 'aDataSort');
-            _fnCompatMap(init, 'orderSequence', 'asSorting');
-            _fnCompatMap(init, 'orderDataType', 'sortDataType');
-
-            // orderData can be given as an integer
-            var dataSort = init.aDataSort;
-            if (dataSort && !$.isArray(dataSort)) {
-                init.aDataSort = [dataSort];
-            }
-        }
-
-
-        /**
-         * Browser feature detection for capabilities, quirks
-         *  @param {object} settings dataTables settings object
-         *  @memberof DataTable#oApi
-         */
-        function _fnBrowserDetect(settings) {
-            var browser = settings.oBrowser;
-
-            // Scrolling feature / quirks detection
-            var n = $('<div/>')
-                .css({
-                    position: 'absolute',
-                    top: 0,
-                    left: 0,
-                    height: 1,
-                    width: 1,
-                    overflow: 'hidden'
-                })
-                .append(
-                    $('<div/>')
-                        .css({
-                            position: 'absolute',
-                            top: 1,
-                            left: 1,
-                            width: 100,
-                            overflow: 'scroll'
-                        })
-                        .append(
-                            $('<div class="test"/>')
-                                .css({
-                                    width: '100%',
-                                    height: 10
-                                })
-                        )
-                )
-                .appendTo('body');
-
-            var test = n.find('.test');
-
-            // IE6/7 will oversize a width 100% element inside a scrolling element, to
-            // include the width of the scrollbar, while other browsers ensure the inner
-            // element is contained without forcing scrolling
-            browser.bScrollOversize = test[0].offsetWidth === 100;
-
-            // In rtl text layout, some browsers (most, but not all) will place the
-            // scrollbar on the left, rather than the right.
-            browser.bScrollbarLeft = Math.round(test.offset().left) !== 1;
-
-            n.remove();
-        }
-
-
-        /**
-         * Array.prototype reduce[Right] method, used for browsers which don't support
-         * JS 1.6. Done this way to reduce code size, since we iterate either way
-         *  @param {object} settings dataTables settings object
-         *  @memberof DataTable#oApi
-         */
-        function _fnReduce(that, fn, init, start, end, inc) {
-            var
-                i = start,
-                value,
-                isSet = false;
-
-            if (init !== undefined) {
-                value = init;
-                isSet = true;
-            }
-
-            while (i !== end) {
-                if (!that.hasOwnProperty(i)) {
-                    continue;
-                }
-
-                value = isSet ?
-                    fn(value, that[i], i, that) :
-                    that[i];
-
-                isSet = true;
-                i += inc;
-            }
-
-            return value;
-        }
-
-        /**
-         * Add a column to the list used for the table with default values
-         *  @param {object} oSettings dataTables settings object
-         *  @param {node} nTh The th element for this column
-         *  @memberof DataTable#oApi
-         */
-        function _fnAddColumn(oSettings, nTh) {
-            // Add column to aoColumns array
-            var oDefaults = DataTable.defaults.column;
-            var iCol = oSettings.aoColumns.length;
-            var oCol = $.extend({}, DataTable.models.oColumn, oDefaults, {
-                "nTh": nTh ? nTh : document.createElement('th'),
-                "sTitle": oDefaults.sTitle ? oDefaults.sTitle : nTh ? nTh.innerHTML : '',
-                "aDataSort": oDefaults.aDataSort ? oDefaults.aDataSort : [iCol],
-                "mData": oDefaults.mData ? oDefaults.mData : iCol,
-                idx: iCol
-            });
-            oSettings.aoColumns.push(oCol);
-
-            // Add search object for column specific search. Note that the `searchCols[ iCol ]`
-            // passed into extend can be undefined. This allows the user to give a default
-            // with only some of the parameters defined, and also not give a default
-            var searchCols = oSettings.aoPreSearchCols;
-            searchCols[iCol] = $.extend({}, DataTable.models.oSearch, searchCols[iCol]);
-
-            // Use the default column options function to initialise classes etc
-            _fnColumnOptions(oSettings, iCol, $(nTh).data());
-        }
-
-
-        /**
-         * Apply options for a column
-         *  @param {object} oSettings dataTables settings object
-         *  @param {int} iCol column index to consider
-         *  @param {object} oOptions object with sType, bVisible and bSearchable etc
-         *  @memberof DataTable#oApi
-         */
-        function _fnColumnOptions(oSettings, iCol, oOptions) {
-            var oCol = oSettings.aoColumns[iCol];
-            var oClasses = oSettings.oClasses;
-            var th = $(oCol.nTh);
-
-            // Try to get width information from the DOM. We can't get it from CSS
-            // as we'd need to parse the CSS stylesheet. `width` option can override
-            if (!oCol.sWidthOrig) {
-                // Width attribute
-                oCol.sWidthOrig = th.attr('width') || null;
-
-                // Style attribute
-                var t = (th.attr('style') || '').match(/width:\s*(\d+[pxem%]+)/);
-                if (t) {
-                    oCol.sWidthOrig = t[1];
-                }
-            }
-
-            /* User specified column options */
-            if (oOptions !== undefined && oOptions !== null) {
-                // Backwards compatibility
-                _fnCompatCols(oOptions);
-
-                // Map camel case parameters to their Hungarian counterparts
-                _fnCamelToHungarian(DataTable.defaults.column, oOptions);
-
-                /* Backwards compatibility for mDataProp */
-                if (oOptions.mDataProp !== undefined && !oOptions.mData) {
-                    oOptions.mData = oOptions.mDataProp;
-                }
-
-                if (oOptions.sType) {
-                    oCol._sManualType = oOptions.sType;
-                }
-
-                // `class` is a reserved word in Javascript, so we need to provide
-                // the ability to use a valid name for the camel case input
-                if (oOptions.className && !oOptions.sClass) {
-                    oOptions.sClass = oOptions.className;
-                }
-
-                $.extend(oCol, oOptions);
-                _fnMap(oCol, oOptions, "sWidth", "sWidthOrig");
-
-                /* iDataSort to be applied (backwards compatibility), but aDataSort will take
-                 * priority if defined
-                 */
-                if (oOptions.iDataSort !== undefined) {
-                    oCol.aDataSort = [oOptions.iDataSort];
-                }
-                _fnMap(oCol, oOptions, "aDataSort");
-            }
-
-            /* Cache the data get and set functions for speed */
-            var mDataSrc = oCol.mData;
-            var mData = _fnGetObjectDataFn(mDataSrc);
-            var mRender = oCol.mRender ? _fnGetObjectDataFn(oCol.mRender) : null;
-
-            var attrTest = function (src) {
-                return typeof src === 'string' && src.indexOf('@') !== -1;
-            };
-            oCol._bAttrSrc = $.isPlainObject(mDataSrc) && (
-                attrTest(mDataSrc.sort) || attrTest(mDataSrc.type) || attrTest(mDataSrc.filter)
-            );
-
-            oCol.fnGetData = function (rowData, type, meta) {
-                var innerData = mData(rowData, type, undefined, meta);
-
-                return mRender && type ?
-                    mRender(innerData, type, rowData, meta) :
-                    innerData;
-            };
-            oCol.fnSetData = function (rowData, val, meta) {
-                return _fnSetObjectDataFn(mDataSrc)(rowData, val, meta);
-            };
-
-            // Indicate if DataTables should read DOM data as an object or array
-            // Used in _fnGetRowElements
-            if (typeof mDataSrc !== 'number') {
-                oSettings._rowReadObject = true;
-            }
-
-            /* Feature sorting overrides column specific when off */
-            if (!oSettings.oFeatures.bSort) {
-                oCol.bSortable = false;
-                th.addClass(oClasses.sSortableNone); // Have to add class here as order event isn't called
-            }
-
-            /* Check that the class assignment is correct for sorting */
-            var bAsc = $.inArray('asc', oCol.asSorting) !== -1;
-            var bDesc = $.inArray('desc', oCol.asSorting) !== -1;
-            if (!oCol.bSortable || (!bAsc && !bDesc)) {
-                oCol.sSortingClass = oClasses.sSortableNone;
-                oCol.sSortingClassJUI = "";
-            }
-            else if (bAsc && !bDesc) {
-                oCol.sSortingClass = oClasses.sSortableAsc;
-                oCol.sSortingClassJUI = oClasses.sSortJUIAscAllowed;
-            }
-            else if (!bAsc && bDesc) {
-                oCol.sSortingClass = oClasses.sSortableDesc;
-                oCol.sSortingClassJUI = oClasses.sSortJUIDescAllowed;
-            }
-            else {
-                oCol.sSortingClass = oClasses.sSortable;
-                oCol.sSortingClassJUI = oClasses.sSortJUI;
-            }
-        }
-
-
-        /**
-         * Adjust the table column widths for new data. Note: you would probably want to
-         * do a redraw after calling this function!
-         *  @param {object} settings dataTables settings object
-         *  @memberof DataTable#oApi
-         */
-        function _fnAdjustColumnSizing(settings) {
-            /* Not interested in doing column width calculation if auto-width is disabled */
-            if (settings.oFeatures.bAutoWidth !== false) {
-                var columns = settings.aoColumns;
-
-                _fnCalculateColumnWidths(settings);
-                for (var i = 0, iLen = columns.length ; i < iLen ; i++) {
-                    columns[i].nTh.style.width = columns[i].sWidth;
-                }
-            }
-
-            var scroll = settings.oScroll;
-            if (scroll.sY !== '' || scroll.sX !== '') {
-                _fnScrollDraw(settings);
-            }
-
-            _fnCallbackFire(settings, null, 'column-sizing', [settings]);
-        }
-
-
-        /**
-         * Covert the index of a visible column to the index in the data array (take account
-         * of hidden columns)
-         *  @param {object} oSettings dataTables settings object
-         *  @param {int} iMatch Visible column index to lookup
-         *  @returns {int} i the data index
-         *  @memberof DataTable#oApi
-         */
-        function _fnVisibleToColumnIndex(oSettings, iMatch) {
-            var aiVis = _fnGetColumns(oSettings, 'bVisible');
-
-            return typeof aiVis[iMatch] === 'number' ?
-                aiVis[iMatch] :
-                null;
-        }
-
-
-        /**
-         * Covert the index of an index in the data array and convert it to the visible
-         *   column index (take account of hidden columns)
-         *  @param {int} iMatch Column index to lookup
-         *  @param {object} oSettings dataTables settings object
-         *  @returns {int} i the data index
-         *  @memberof DataTable#oApi
-         */
-        function _fnColumnIndexToVisible(oSettings, iMatch) {
-            var aiVis = _fnGetColumns(oSettings, 'bVisible');
-            var iPos = $.inArray(iMatch, aiVis);
-
-            return iPos !== -1 ? iPos : null;
-        }
-
-
-        /**
-         * Get the number of visible columns
-         *  @param {object} oSettings dataTables settings object
-         *  @returns {int} i the number of visible columns
-         *  @memberof DataTable#oApi
-         */
-        function _fnVisbleColumns(oSettings) {
-            return _fnGetColumns(oSettings, 'bVisible').length;
-        }
-
-
-        /**
-         * Get an array of column indexes that match a given property
-         *  @param {object} oSettings dataTables settings object
-         *  @param {string} sParam Parameter in aoColumns to look for - typically
-         *    bVisible or bSearchable
-         *  @returns {array} Array of indexes with matched properties
-         *  @memberof DataTable#oApi
-         */
-        function _fnGetColumns(oSettings, sParam) {
-            var a = [];
-
-            $.map(oSettings.aoColumns, function (val, i) {
-                if (val[sParam]) {
-                    a.push(i);
-                }
-            });
-
-            return a;
-        }
-
-
-        /**
-         * Calculate the 'type' of a column
-         *  @param {object} settings dataTables settings object
-         *  @memberof DataTable#oApi
-         */
-        function _fnColumnTypes(settings) {
-            var columns = settings.aoColumns;
-            var data = settings.aoData;
-            var types = DataTable.ext.type.detect;
-            var i, ien, j, jen, k, ken;
-            var col, cell, detectedType, cache;
-
-            // For each column, spin over the 
-            for (i = 0, ien = columns.length ; i < ien ; i++) {
-                col = columns[i];
-                cache = [];
-
-                if (!col.sType && col._sManualType) {
-                    col.sType = col._sManualType;
-                }
-                else if (!col.sType) {
-                    for (j = 0, jen = types.length ; j < jen ; j++) {
-                        for (k = 0, ken = data.length ; k < ken ; k++) {
-                            // Use a cache array so we only need to get the type data
-                            // from the formatter once (when using multiple detectors)
-                            if (cache[k] === undefined) {
-                                cache[k] = _fnGetCellData(settings, k, i, 'type');
-                            }
-
-                            detectedType = types[j](cache[k], settings);
-
-                            // If null, then this type can't apply to this column, so
-                            // rather than testing all cells, break out. There is an
-                            // exception for the last type which is `html`. We need to
-                            // scan all rows since it is possible to mix string and HTML
-                            // types
-                            if (!detectedType && j !== types.length - 1) {
-                                break;
-                            }
-
-                            // Only a single match is needed for html type since it is
-                            // bottom of the pile and very similar to string
-                            if (detectedType === 'html') {
-                                break;
-                            }
-                        }
-
-                        // Type is valid for all data points in the column - use this
-                        // type
-                        if (detectedType) {
-                            col.sType = detectedType;
-                            break;
-                        }
-                    }
-
-                    // Fall back - if no type was detected, always use string
-                    if (!col.sType) {
-                        col.sType = 'string';
-                    }
-                }
-            }
-        }
-
-
-        /**
-         * Take the column definitions and static columns arrays and calculate how
-         * they relate to column indexes. The callback function will then apply the
-         * definition found for a column to a suitable configuration object.
-         *  @param {object} oSettings dataTables settings object
-         *  @param {array} aoColDefs The aoColumnDefs array that is to be applied
-         *  @param {array} aoCols The aoColumns array that defines columns individually
-         *  @param {function} fn Callback function - takes two parameters, the calculated
-         *    column index and the definition for that column.
-         *  @memberof DataTable#oApi
-         */
-        function _fnApplyColumnDefs(oSettings, aoColDefs, aoCols, fn) {
-            var i, iLen, j, jLen, k, kLen, def;
-            var columns = oSettings.aoColumns;
-
-            // Column definitions with aTargets
-            if (aoColDefs) {
-                /* Loop over the definitions array - loop in reverse so first instance has priority */
-                for (i = aoColDefs.length - 1 ; i >= 0 ; i--) {
-                    def = aoColDefs[i];
-
-                    /* Each definition can target multiple columns, as it is an array */
-                    var aTargets = def.targets !== undefined ?
-                        def.targets :
-                        def.aTargets;
-
-                    if (!$.isArray(aTargets)) {
-                        aTargets = [aTargets];
-                    }
-
-                    for (j = 0, jLen = aTargets.length ; j < jLen ; j++) {
-                        if (typeof aTargets[j] === 'number' && aTargets[j] >= 0) {
-                            /* Add columns that we don't yet know about */
-                            while (columns.length <= aTargets[j]) {
-                                _fnAddColumn(oSettings);
-                            }
-
-                            /* Integer, basic index */
-                            fn(aTargets[j], def);
-                        }
-                        else if (typeof aTargets[j] === 'number' && aTargets[j] < 0) {
-                            /* Negative integer, right to left column counting */
-                            fn(columns.length + aTargets[j], def);
-                        }
-                        else if (typeof aTargets[j] === 'string') {
-                            /* Class name matching on TH element */
-                            for (k = 0, kLen = columns.length ; k < kLen ; k++) {
-                                if (aTargets[j] == "_all" ||
-                                     $(columns[k].nTh).hasClass(aTargets[j])) {
-                                    fn(k, def);
-                                }
-                            }
-                        }
-                    }
-                }
-            }
-
-            // Statically defined columns array
-            if (aoCols) {
-                for (i = 0, iLen = aoCols.length ; i < iLen ; i++) {
-                    fn(i, aoCols[i]);
-                }
-            }
-        }
-
-        /**
-         * Add a data array to the table, creating DOM node etc. This is the parallel to
-         * _fnGatherData, but for adding rows from a Javascript source, rather than a
-         * DOM source.
-         *  @param {object} oSettings dataTables settings object
-         *  @param {array} aData data array to be added
-         *  @param {node} [nTr] TR element to add to the table - optional. If not given,
-         *    DataTables will create a row automatically
-         *  @param {array} [anTds] Array of TD|TH elements for the row - must be given
-         *    if nTr is.
-         *  @returns {int} >=0 if successful (index of new aoData entry), -1 if failed
-         *  @memberof DataTable#oApi
-         */
-        function _fnAddData(oSettings, aDataIn, nTr, anTds) {
-            /* Create the object for storing information about this new row */
-            var iRow = oSettings.aoData.length;
-            var oData = $.extend(true, {}, DataTable.models.oRow, {
-                src: nTr ? 'dom' : 'data'
-            });
-
-            oData._aData = aDataIn;
-            oSettings.aoData.push(oData);
-
-            /* Create the cells */
-            var nTd, sThisType;
-            var columns = oSettings.aoColumns;
-            for (var i = 0, iLen = columns.length ; i < iLen ; i++) {
-                // When working with a row, the data source object must be populated. In
-                // all other cases, the data source object is already populated, so we
-                // don't overwrite it, which might break bindings etc
-                if (nTr) {
-                    _fnSetCellData(oSettings, iRow, i, _fnGetCellData(oSettings, iRow, i));
-                }
-                columns[i].sType = null;
-            }
-
-            /* Add to the display array */
-            oSettings.aiDisplayMaster.push(iRow);
-
-            /* Create the DOM information, or register it if already present */
-            if (nTr || !oSettings.oFeatures.bDeferRender) {
-                _fnCreateTr(oSettings, iRow, nTr, anTds);
-            }
-
-            return iRow;
-        }
-
-
-        /**
-         * Add one or more TR elements to the table. Generally we'd expect to
-         * use this for reading data from a DOM sourced table, but it could be
-         * used for an TR element. Note that if a TR is given, it is used (i.e.
-         * it is not cloned).
-         *  @param {object} settings dataTables settings object
-         *  @param {array|node|jQuery} trs The TR element(s) to add to the table
-         *  @returns {array} Array of indexes for the added rows
-         *  @memberof DataTable#oApi
-         */
-        function _fnAddTr(settings, trs) {
-            var row;
-
-            // Allow an individual node to be passed in
-            if (!(trs instanceof $)) {
-                trs = $(trs);
-            }
-
-            return trs.map(function (i, el) {
-                row = _fnGetRowElements(settings, el);
-                return _fnAddData(settings, row.data, el, row.cells);
-            });
-        }
-
-
-        /**
-         * Take a TR element and convert it to an index in aoData
-         *  @param {object} oSettings dataTables settings object
-         *  @param {node} n the TR element to find
-         *  @returns {int} index if the node is found, null if not
-         *  @memberof DataTable#oApi
-         */
-        function _fnNodeToDataIndex(oSettings, n) {
-            return (n._DT_RowIndex !== undefined) ? n._DT_RowIndex : null;
-        }
-
-
-        /**
-         * Take a TD element and convert it into a column data index (not the visible index)
-         *  @param {object} oSettings dataTables settings object
-         *  @param {int} iRow The row number the TD/TH can be found in
-         *  @param {node} n The TD/TH element to find
-         *  @returns {int} index if the node is found, -1 if not
-         *  @memberof DataTable#oApi
-         */
-        function _fnNodeToColumnIndex(oSettings, iRow, n) {
-            return $.inArray(n, oSettings.aoData[iRow].anCells);
-        }
-
-
-        /**
-         * Get the data for a given cell from the internal cache, taking into account data mapping
-         *  @param {object} settings dataTables settings object
-         *  @param {int} rowIdx aoData row id
-         *  @param {int} colIdx Column index
-         *  @param {string} type data get type ('display', 'type' 'filter' 'sort')
-         *  @returns {*} Cell data
-         *  @memberof DataTable#oApi
-         */
-        function _fnGetCellData(settings, rowIdx, colIdx, type) {
-            var draw = settings.iDraw;
-            var col = settings.aoColumns[colIdx];
-            var rowData = settings.aoData[rowIdx]._aData;
-            var defaultContent = col.sDefaultContent;
-            var cellData = col.fnGetData(rowData, type, {
-                settings: settings,
-                row: rowIdx,
-                col: colIdx
-            });
-
-            if (cellData === undefined) {
-                if (settings.iDrawError != draw && defaultContent === null) {
-                    _fnLog(settings, 0, "Requested unknown parameter " +
-                        (typeof col.mData == 'function' ? '{function}' : "'" + col.mData + "'") +
-                        " for row " + rowIdx, 4);
-                    settings.iDrawError = draw;
-                }
-                return defaultContent;
-            }
-
-            /* When the data source is null, we can use default column data */
-            if ((cellData === rowData || cellData === null) && defaultContent !== null) {
-                cellData = defaultContent;
-            }
-            else if (typeof cellData === 'function') {
-                // If the data source is a function, then we run it and use the return,
-                // executing in the scope of the data object (for instances)
-                return cellData.call(rowData);
-            }
-
-            if (cellData === null && type == 'display') {
-                return '';
-            }
-            return cellData;
-        }
-
-
-        /**
-         * Set the value for a specific cell, into the internal data cache
-         *  @param {object} settings dataTables settings object
-         *  @param {int} rowIdx aoData row id
-         *  @param {int} colIdx Column index
-         *  @param {*} val Value to set
-         *  @memberof DataTable#oApi
-         */
-        function _fnSetCellData(settings, rowIdx, colIdx, val) {
-            var col = settings.aoColumns[colIdx];
-            var rowData = settings.aoData[rowIdx]._aData;
-
-            col.fnSetData(rowData, val, {
-                settings: settings,
-                row: rowIdx,
-                col: colIdx
-            });
-        }
-
-
-        // Private variable that is used to match action syntax in the data property object
-        var __reArray = /\[.*?\]$/;
-        var __reFn = /\(\)$/;
-
-        /**
-         * Split string on periods, taking into account escaped periods
-         * @param  {string} str String to split
-         * @return {array} Split string
-         */
-        function _fnSplitObjNotation(str) {
-            return $.map(str.match(/(\\.|[^\.])+/g), function (s) {
-                return s.replace(/\\./g, '.');
-            });
-        }
-
-
-        /**
-         * Return a function that can be used to get data from a source object, taking
-         * into account the ability to use nested objects as a source
-         *  @param {string|int|function} mSource The data source for the object
-         *  @returns {function} Data get function
-         *  @memberof DataTable#oApi
-         */
-        function _fnGetObjectDataFn(mSource) {
-            if ($.isPlainObject(mSource)) {
-                /* Build an object of get functions, and wrap them in a single call */
-                var o = {};
-                $.each(mSource, function (key, val) {
-                    if (val) {
-                        o[key] = _fnGetObjectDataFn(val);
-                    }
-                });
-
-                return function (data, type, row, meta) {
-                    var t = o[type] || o._;
-                    return t !== undefined ?
-                        t(data, type, row, meta) :
-                        data;
-                };
-            }
-            else if (mSource === null) {
-                /* Give an empty string for rendering / sorting etc */
-                return function (data) { // type, row and meta also passed, but not used
-                    return data;
-                };
-            }
-            else if (typeof mSource === 'function') {
-                return function (data, type, row, meta) {
-                    return mSource(data, type, row, meta);
-                };
-            }
-            else if (typeof mSource === 'string' && (mSource.indexOf('.') !== -1 ||
-                      mSource.indexOf('[') !== -1 || mSource.indexOf('(') !== -1)) {
-                /* If there is a . in the source string then the data source is in a
-                 * nested object so we loop over the data for each level to get the next
-                 * level down. On each loop we test for undefined, and if found immediately
-                 * return. This allows entire objects to be missing and sDefaultContent to
-                 * be used if defined, rather than throwing an error
-                 */
-                var fetchData = function (data, type, src) {
-                    var arrayNotation, funcNotation, out, innerSrc;
-
-                    if (src !== "") {
-                        var a = _fnSplitObjNotation(src);
-
-                        for (var i = 0, iLen = a.length ; i < iLen ; i++) {
-                            // Check if we are dealing with special notation
-                            arrayNotation = a[i].match(__reArray);
-                            funcNotation = a[i].match(__reFn);
-
-                            if (arrayNotation) {
-                                // Array notation
-                                a[i] = a[i].replace(__reArray, '');
-
-                                // Condition allows simply [] to be passed in
-                                if (a[i] !== "") {
-                                    data = data[a[i]];
-                                }
-                                out = [];
-
-                                // Get the remainder of the nested object to get
-                                a.splice(0, i + 1);
-                                innerSrc = a.join('.');
-
-                                // Traverse each entry in the array getting the properties requested
-                                for (var j = 0, jLen = data.length ; j < jLen ; j++) {
-                                    out.push(fetchData(data[j], type, innerSrc));
-                                }
-
-                                // If a string is given in between the array notation indicators, that
-                                // is used to join the strings together, otherwise an array is returned
-                                var join = arrayNotation[0].substring(1, arrayNotation[0].length - 1);
-                                data = (join === "") ? out : out.join(join);
-
-                                // The inner call to fetchData has already traversed through the remainder
-                                // of the source requested, so we exit from the loop
-                                break;
-                            }
-                            else if (funcNotation) {
-                                // Function call
-                                a[i] = a[i].replace(__reFn, '');
-                                data = data[a[i]]();
-                                continue;
-                            }
-
-                            if (data === null || data[a[i]] === undefined) {
-                                return undefined;
-                            }
-                            data = data[a[i]];
-                        }
-                    }
-
-                    return data;
-                };
-
-                return function (data, type) { // row and meta also passed, but not used
-                    return fetchData(data, type, mSource);
-                };
-            }
-            else {
-                /* Array or flat object mapping */
-                return function (data, type) { // row and meta also passed, but not used
-                    return data[mSource];
-                };
-            }
-        }
-
-
-        /**
-         * Return a function that can be used to set data from a source object, taking
-         * into account the ability to use nested objects as a source
-         *  @param {string|int|function} mSource The data source for the object
-         *  @returns {function} Data set function
-         *  @memberof DataTable#oApi
-         */
-        function _fnSetObjectDataFn(mSource) {
-            if ($.isPlainObject(mSource)) {
-                /* Unlike get, only the underscore (global) option is used for for
-                 * setting data since we don't know the type here. This is why an object
-                 * option is not documented for `mData` (which is read/write), but it is
-                 * for `mRender` which is read only.
-                 */
-                return _fnSetObjectDataFn(mSource._);
-            }
-            else if (mSource === null) {
-                /* Nothing to do when the data source is null */
-                return function () { };
-            }
-            else if (typeof mSource === 'function') {
-                return function (data, val, meta) {
-                    mSource(data, 'set', val, meta);
-                };
-            }
-            else if (typeof mSource === 'string' && (mSource.indexOf('.') !== -1 ||
-                      mSource.indexOf('[') !== -1 || mSource.indexOf('(') !== -1)) {
-                /* Like the get, we need to get data from a nested object */
-                var setData = function (data, val, src) {
-                    var a = _fnSplitObjNotation(src), b;
-                    var aLast = a[a.length - 1];
-                    var arrayNotation, funcNotation, o, innerSrc;
-
-                    for (var i = 0, iLen = a.length - 1 ; i < iLen ; i++) {
-                        // Check if we are dealing with an array notation request
-                        arrayNotation = a[i].match(__reArray);
-                        funcNotation = a[i].match(__reFn);
-
-                        if (arrayNotation) {
-                            a[i] = a[i].replace(__reArray, '');
-                            data[a[i]] = [];
-
-                            // Get the remainder of the nested object to set so we can recurse
-                            b = a.slice();
-                            b.splice(0, i + 1);
-                            innerSrc = b.join('.');
-
-                            // Traverse each entry in the array setting the properties requested
-                            for (var j = 0, jLen = val.length ; j < jLen ; j++) {
-                                o = {};
-                                setData(o, val[j], innerSrc);
-                                data[a[i]].push(o);
-                            }
-
-                            // The inner call to setData has already traversed through the remainder
-                            // of the source and has set the data, thus we can exit here
-                            return;
-                        }
-                        else if (funcNotation) {
-                            // Function call
-                            a[i] = a[i].replace(__reFn, '');
-                            data = data[a[i]](val);
-                        }
-
-                        // If the nested object doesn't currently exist - since we are
-                        // trying to set the value - create it
-                        if (data[a[i]] === null || data[a[i]] === undefined) {
-                            data[a[i]] = {};
-                        }
-                        data = data[a[i]];
-                    }
-
-                    // Last item in the input - i.e, the actual set
-                    if (aLast.match(__reFn)) {
-                        // Function call
-                        data = data[aLast.replace(__reFn, '')](val);
-                    }
-                    else {
-                        // If array notation is used, we just want to strip it and use the property name
-                        // and assign the value. If it isn't used, then we get the result we want anyway
-                        data[aLast.replace(__reArray, '')] = val;
-                    }
-                };
-
-                return function (data, val) { // meta is also passed in, but not used
-                    return setData(data, val, mSource);
-                };
-            }
-            else {
-                /* Array or flat object mapping */
-                return function (data, val) { // meta is also passed in, but not used
-                    data[mSource] = val;
-                };
-            }
-        }
-
-
-        /**
-         * Return an array with the full table data
-         *  @param {object} oSettings dataTables settings object
-         *  @returns array {array} aData Master data array
-         *  @memberof DataTable#oApi
-         */
-        function _fnGetDataMaster(settings) {
-            return _pluck(settings.aoData, '_aData');
-        }
-
-
-        /**
-         * Nuke the table
-         *  @param {object} oSettings dataTables settings object
-         *  @memberof DataTable#oApi
-         */
-        function _fnClearTable(settings) {
-            settings.aoData.length = 0;
-            settings.aiDisplayMaster.length = 0;
-            settings.aiDisplay.length = 0;
-        }
-
-
-        /**
-        * Take an array of integers (index array) and remove a target integer (value - not
-        * the key!)
-        *  @param {array} a Index array to target
-        *  @param {int} iTarget value to find
-        *  @memberof DataTable#oApi
-        */
-        function _fnDeleteIndex(a, iTarget, splice) {
-            var iTargetIndex = -1;
-
-            for (var i = 0, iLen = a.length ; i < iLen ; i++) {
-                if (a[i] == iTarget) {
-                    iTargetIndex = i;
-                }
-                else if (a[i] > iTarget) {
-                    a[i]--;
-                }
-            }
-
-            if (iTargetIndex != -1 && splice === undefined) {
-                a.splice(iTargetIndex, 1);
-            }
-        }
-
-
-        /**
-         * Mark cached data as invalid such that a re-read of the data will occur when
-         * the cached data is next requested. Also update from the data source object.
-         *
-         * @param {object} settings DataTables settings object
-         * @param {int}    rowIdx   Row index to invalidate
-         * @param {string} [src]    Source to invalidate from: undefined, 'auto', 'dom'
-         *     or 'data'
-         * @param {int}    [colIdx] Column index to invalidate. If undefined the whole
-         *     row will be invalidated
-         * @memberof DataTable#oApi
-         *
-         * @todo For the modularisation of v1.11 this will need to become a callback, so
-         *   the sort and filter methods can subscribe to it. That will required
-         *   initialisation options for sorting, which is why it is not already baked in
-         */
-        function _fnInvalidate(settings, rowIdx, src, colIdx) {
-            var row = settings.aoData[rowIdx];
-            var i, ien;
-            var cellWrite = function (cell, col) {
-                // This is very frustrating, but in IE if you just write directly
-                // to innerHTML, and elements that are overwritten are GC'ed,
-                // even if there is a reference to them elsewhere
-                while (cell.childNodes.length) {
-                    cell.removeChild(cell.firstChild);
-                }
-
-                cell.innerHTML = _fnGetCellData(settings, rowIdx, col, 'display');
-            };
-
-            // Are we reading last data from DOM or the data object?
-            if (src === 'dom' || ((!src || src === 'auto') && row.src === 'dom')) {
-                // Read the data from the DOM
-                row._aData = _fnGetRowElements(
-                        settings, row, colIdx, colIdx === undefined ? undefined : row._aData
-                    )
-                    .data;
-            }
-            else {
-                // Reading from data object, update the DOM
-                var cells = row.anCells;
-
-                if (cells) {
-                    if (colIdx !== undefined) {
-                        cellWrite(cells[colIdx], colIdx);
-                    }
-                    else {
-                        for (i = 0, ien = cells.length ; i < ien ; i++) {
-                            cellWrite(cells[i], i);
-                        }
-                    }
-                }
-            }
-
-            // For both row and cell invalidation, the cached data for sorting and
-            // filtering is nulled out
-            row._aSortData = null;
-            row._aFilterData = null;
-
-            // Invalidate the type for a specific column (if given) or all columns since
-            // the data might have changed
-            var cols = settings.aoColumns;
-            if (colIdx !== undefined) {
-                cols[colIdx].sType = null;
-            }
-            else {
-                for (i = 0, ien = cols.length ; i < ien ; i++) {
-                    cols[i].sType = null;
-                }
-
-                // Update DataTables special `DT_*` attributes for the row
-                _fnRowAttributes(row);
-            }
-        }
-
-
-        /**
-         * Build a data source object from an HTML row, reading the contents of the
-         * cells that are in the row.
-         *
-         * @param {object} settings DataTables settings object
-         * @param {node|object} TR element from which to read data or existing row
-         *   object from which to re-read the data from the cells
-         * @param {int} [colIdx] Optional column index
-         * @param {array|object} [d] Data source object. If `colIdx` is given then this
-         *   parameter should also be given and will be used to write the data into.
-         *   Only the column in question will be written
-         * @returns {object} Object with two parameters: `data` the data read, in
-         *   document order, and `cells` and array of nodes (they can be useful to the
-         *   caller, so rather than needing a second traversal to get them, just return
-         *   them from here).
-         * @memberof DataTable#oApi
-         */
-        function _fnGetRowElements(settings, row, colIdx, d) {
-            var
-                tds = [],
-                td = row.firstChild,
-                name, col, o, i = 0, contents,
-                columns = settings.aoColumns,
-                objectRead = settings._rowReadObject;
-
-            // Allow the data object to be passed in, or construct
-            d = d || objectRead ? {} : [];
-
-            var attr = function (str, td) {
-                if (typeof str === 'string') {
-                    var idx = str.indexOf('@');
-
-                    if (idx !== -1) {
-                        var attr = str.substring(idx + 1);
-                        var setter = _fnSetObjectDataFn(str);
-                        setter(d, td.getAttribute(attr));
-                    }
-                }
-            };
-
-            // Read data from a cell and store into the data object
-            var cellProcess = function (cell) {
-                if (colIdx === undefined || colIdx === i) {
-                    col = columns[i];
-                    contents = $.trim(cell.innerHTML);
-
-                    if (col && col._bAttrSrc) {
-                        var setter = _fnSetObjectDataFn(col.mData._);
-                        setter(d, contents);
-
-                        attr(col.mData.sort, cell);
-                        attr(col.mData.type, cell);
-                        attr(col.mData.filter, cell);
-                    }
-                    else {
-                        // Depending on the `data` option for the columns the data can
-                        // be read to either an object or an array.
-                        if (objectRead) {
-                            if (!col._setter) {
-                                // Cache the setter function
-                                col._setter = _fnSetObjectDataFn(col.mData);
-                            }
-                            col._setter(d, contents);
-                        }
-                        else {
-                            d[i] = contents;
-                        }
-                    }
-                }
-
-                i++;
-            };
-
-            if (td) {
-                // `tr` element was passed in
-                while (td) {
-                    name = td.nodeName.toUpperCase();
-
-                    if (name == "TD" || name == "TH") {
-                        cellProcess(td);
-                        tds.push(td);
-                    }
-
-                    td = td.nextSibling;
-                }
-            }
-            else {
-                // Existing row object passed in
-                tds = row.anCells;
-
-                for (var j = 0, jen = tds.length ; j < jen ; j++) {
-                    cellProcess(tds[j]);
-                }
-            }
-
-            return {
-                data: d,
-                cells: tds
-            };
-        }
-        /**
-         * Create a new TR element (and it's TD children) for a row
-         *  @param {object} oSettings dataTables settings object
-         *  @param {int} iRow Row to consider
-         *  @param {node} [nTrIn] TR element to add to the table - optional. If not given,
-         *    DataTables will create a row automatically
-         *  @param {array} [anTds] Array of TD|TH elements for the row - must be given
-         *    if nTr is.
-         *  @memberof DataTable#oApi
-         */
-        function _fnCreateTr(oSettings, iRow, nTrIn, anTds) {
-            var
-                row = oSettings.aoData[iRow],
-                rowData = row._aData,
-                cells = [],
-                nTr, nTd, oCol,
-                i, iLen;
-
-            if (row.nTr === null) {
-                nTr = nTrIn || document.createElement('tr');
-
-                row.nTr = nTr;
-                row.anCells = cells;
-
-                /* Use a private property on the node to allow reserve mapping from the node
-                 * to the aoData array for fast look up
-                 */
-                nTr._DT_RowIndex = iRow;
-
-                /* Special parameters can be given by the data source to be used on the row */
-                _fnRowAttributes(row);
-
-                /* Process each column */
-                for (i = 0, iLen = oSettings.aoColumns.length ; i < iLen ; i++) {
-                    oCol = oSettings.aoColumns[i];
-
-                    nTd = nTrIn ? anTds[i] : document.createElement(oCol.sCellType);
-                    cells.push(nTd);
-
-                    // Need to create the HTML if new, or if a rendering function is defined
-                    if (!nTrIn || oCol.mRender || oCol.mData !== i) {
-                        nTd.innerHTML = _fnGetCellData(oSettings, iRow, i, 'display');
-                    }
-
-                    /* Add user defined class */
-                    if (oCol.sClass) {
-                        nTd.className += ' ' + oCol.sClass;
-                    }
-
-                    // Visibility - add or remove as required
-                    if (oCol.bVisible && !nTrIn) {
-                        nTr.appendChild(nTd);
-                    }
-                    else if (!oCol.bVisible && nTrIn) {
-                        nTd.parentNode.removeChild(nTd);
-                    }
-
-                    if (oCol.fnCreatedCell) {
-                        oCol.fnCreatedCell.call(oSettings.oInstance,
-                            nTd, _fnGetCellData(oSettings, iRow, i), rowData, iRow, i
-                        );
-                    }
-                }
-
-                _fnCallbackFire(oSettings, 'aoRowCreatedCallback', null, [nTr, rowData, iRow]);
-            }
-
-            // Remove once webkit bug 131819 and Chromium bug 365619 have been resolved
-            // and deployed
-            row.nTr.setAttribute('role', 'row');
-        }
-
-
-        /**
-         * Add attributes to a row based on the special `DT_*` parameters in a data
-         * source object.
-         *  @param {object} DataTables row object for the row to be modified
-         *  @memberof DataTable#oApi
-         */
-        function _fnRowAttributes(row) {
-            var tr = row.nTr;
-            var data = row._aData;
-
-            if (tr) {
-                if (data.DT_RowId) {
-                    tr.id = data.DT_RowId;
-                }
-
-                if (data.DT_RowClass) {
-                    // Remove any classes added by DT_RowClass before
-                    var a = data.DT_RowClass.split(' ');
-                    row.__rowc = row.__rowc ?
-                        _unique(row.__rowc.concat(a)) :
-                        a;
-
-                    $(tr)
-                        .removeClass(row.__rowc.join(' '))
-                        .addClass(data.DT_RowClass);
-                }
-
-                if (data.DT_RowAttr) {
-                    $(tr).attr(data.DT_RowAttr);
-                }
-
-                if (data.DT_RowData) {
-                    $(tr).data(data.DT_RowData);
-                }
-            }
-        }
-
-
-        /**
-         * Create the HTML header for the table
-         *  @param {object} oSettings dataTables settings object
-         *  @memberof DataTable#oApi
-         */
-        function _fnBuildHead(oSettings) {
-            var i, ien, cell, row, column;
-            var thead = oSettings.nTHead;
-            var tfoot = oSettings.nTFoot;
-            var createHeader = $('th, td', thead).length === 0;
-            var classes = oSettings.oClasses;
-            var columns = oSettings.aoColumns;
-
-            if (createHeader) {
-                row = $('<tr/>').appendTo(thead);
-            }
-
-            for (i = 0, ien = columns.length ; i < ien ; i++) {
-                column = columns[i];
-                cell = $(column.nTh).addClass(column.sClass);
-
-                if (createHeader) {
-                    cell.appendTo(row);
-                }
-
-                // 1.11 move into sorting
-                if (oSettings.oFeatures.bSort) {
-                    cell.addClass(column.sSortingClass);
-
-                    if (column.bSortable !== false) {
-                        cell
-                            .attr('tabindex', oSettings.iTabIndex)
-                            .attr('aria-controls', oSettings.sTableId);
-
-                        _fnSortAttachListener(oSettings, column.nTh, i);
-                    }
-                }
-
-                if (column.sTitle != cell.html()) {
-                    cell.html(column.sTitle);
-                }
-
-                _fnRenderer(oSettings, 'header')(
-                    oSettings, cell, column, classes
-                );
-            }
-
-            if (createHeader) {
-                _fnDetectHeader(oSettings.aoHeader, thead);
-            }
-
-            /* ARIA role for the rows */
-            $(thead).find('>tr').attr('role', 'row');
-
-            /* Deal with the footer - add classes if required */
-            $(thead).find('>tr>th, >tr>td').addClass(classes.sHeaderTH);
-            $(tfoot).find('>tr>th, >tr>td').addClass(classes.sFooterTH);
-
-            // Cache the footer cells. Note that we only take the cells from the first
-            // row in the footer. If there is more than one row the user wants to
-            // interact with, they need to use the table().foot() method. Note also this
-            // allows cells to be used for multiple columns using colspan
-            if (tfoot !== null) {
-                var cells = oSettings.aoFooter[0];
-
-                for (i = 0, ien = cells.length ; i < ien ; i++) {
-                    column = columns[i];
-                    column.nTf = cells[i].cell;
-
-                    if (column.sClass) {
-                        $(column.nTf).addClass(column.sClass);
-                    }
-                }
-            }
-        }
-
-
-        /**
-         * Draw the header (or footer) element based on the column visibility states. The
-         * methodology here is to use the layout array from _fnDetectHeader, modified for
-         * the instantaneous column visibility, to construct the new layout. The grid is
-         * traversed over cell at a time in a rows x columns grid fashion, although each
-         * cell insert can cover multiple elements in the grid - which is tracks using the
-         * aApplied array. Cell inserts in the grid will only occur where there isn't
-         * already a cell in that position.
-         *  @param {object} oSettings dataTables settings object
-         *  @param array {objects} aoSource Layout array from _fnDetectHeader
-         *  @param {boolean} [bIncludeHidden=false] If true then include the hidden columns in the calc,
-         *  @memberof DataTable#oApi
-         */
-        function _fnDrawHead(oSettings, aoSource, bIncludeHidden) {
-            var i, iLen, j, jLen, k, kLen, n, nLocalTr;
-            var aoLocal = [];
-            var aApplied = [];
-            var iColumns = oSettings.aoColumns.length;
-            var iRowspan, iColspan;
-
-            if (!aoSource) {
-                return;
-            }
-
-            if (bIncludeHidden === undefined) {
-                bIncludeHidden = false;
-            }
-
-            /* Make a copy of the master layout array, but without the visible columns in it */
-            for (i = 0, iLen = aoSource.length ; i < iLen ; i++) {
-                aoLocal[i] = aoSource[i].slice();
-                aoLocal[i].nTr = aoSource[i].nTr;
-
-                /* Remove any columns which are currently hidden */
-                for (j = iColumns - 1 ; j >= 0 ; j--) {
-                    if (!oSettings.aoColumns[j].bVisible && !bIncludeHidden) {
-                        aoLocal[i].splice(j, 1);
-                    }
-                }
-
-                /* Prep the applied array - it needs an element for each row */
-                aApplied.push([]);
-            }
-
-            for (i = 0, iLen = aoLocal.length ; i < iLen ; i++) {
-                nLocalTr = aoLocal[i].nTr;
-
-                /* All cells are going to be replaced, so empty out the row */
-                if (nLocalTr) {
-                    while ((n = nLocalTr.firstChild)) {
-                        nLocalTr.removeChild(n);
-                    }
-                }
-
-                for (j = 0, jLen = aoLocal[i].length ; j < jLen ; j++) {
-                    iRowspan = 1;
-                    iColspan = 1;
-
-                    /* Check to see if there is already a cell (row/colspan) covering our target
-                     * insert point. If there is, then there is nothing to do.
-                     */
-                    if (aApplied[i][j] === undefined) {
-                        nLocalTr.appendChild(aoLocal[i][j].cell);
-                        aApplied[i][j] = 1;
-
-                        /* Expand the cell to cover as many rows as needed */
-                        while (aoLocal[i + iRowspan] !== undefined &&
-                                aoLocal[i][j].cell == aoLocal[i + iRowspan][j].cell) {
-                            aApplied[i + iRowspan][j] = 1;
-                            iRowspan++;
-                        }
-
-                        /* Expand the cell to cover as many columns as needed */
-                        while (aoLocal[i][j + iColspan] !== undefined &&
-                                aoLocal[i][j].cell == aoLocal[i][j + iColspan].cell) {
-                            /* Must update the applied array over the rows for the columns */
-                            for (k = 0 ; k < iRowspan ; k++) {
-                                aApplied[i + k][j + iColspan] = 1;
-                            }
-                            iColspan++;
-                        }
-
-                        /* Do the actual expansion in the DOM */
-                        $(aoLocal[i][j].cell)
-                            .attr('rowspan', iRowspan)
-                            .attr('colspan', iColspan);
-                    }
-                }
-            }
-        }
-
-
-        /**
-         * Insert the required TR nodes into the table for display
-         *  @param {object} oSettings dataTables settings object
-         *  @memberof DataTable#oApi
-         */
-        function _fnDraw(oSettings) {
-            /* Provide a pre-callback function which can be used to cancel the draw is false is returned */
-            var aPreDraw = _fnCallbackFire(oSettings, 'aoPreDrawCallback', 'preDraw', [oSettings]);
-            if ($.inArray(false, aPreDraw) !== -1) {
-                _fnProcessingDisplay(oSettings, false);
-                return;
-            }
-
-            var i, iLen, n;
-            var anRows = [];
-            var iRowCount = 0;
-            var asStripeClasses = oSettings.asStripeClasses;
-            var iStripes = asStripeClasses.length;
-            var iOpenRows = oSettings.aoOpenRows.length;
-            var oLang = oSettings.oLanguage;
-            var iInitDisplayStart = oSettings.iInitDisplayStart;
-            var bServerSide = _fnDataSource(oSettings) == 'ssp';
-            var aiDisplay = oSettings.aiDisplay;
-
-            oSettings.bDrawing = true;
-
-            /* Check and see if we have an initial draw position from state saving */
-            if (iInitDisplayStart !== undefined && iInitDisplayStart !== -1) {
-                oSettings._iDisplayStart = bServerSide ?
-                    iInitDisplayStart :
-                    iInitDisplayStart >= oSettings.fnRecordsDisplay() ?
-                        0 :
-                        iInitDisplayStart;
-
-                oSettings.iInitDisplayStart = -1;
-            }
-
-            var iDisplayStart = oSettings._iDisplayStart;
-            var iDisplayEnd = oSettings.fnDisplayEnd();
-
-            /* Server-side processing draw intercept */
-            if (oSettings.bDeferLoading) {
-                oSettings.bDeferLoading = false;
-                oSettings.iDraw++;
-                _fnProcessingDisplay(oSettings, false);
-            }
-            else if (!bServerSide) {
-                oSettings.iDraw++;
-            }
-            else if (!oSettings.bDestroying && !_fnAjaxUpdate(oSettings)) {
-                return;
-            }
-
-            if (aiDisplay.length !== 0) {
-                var iStart = bServerSide ? 0 : iDisplayStart;
-                var iEnd = bServerSide ? oSettings.aoData.length : iDisplayEnd;
-
-                for (var j = iStart ; j < iEnd ; j++) {
-                    var iDataIndex = aiDisplay[j];
-                    var aoData = oSettings.aoData[iDataIndex];
-                    if (aoData.nTr === null) {
-                        _fnCreateTr(oSettings, iDataIndex);
-                    }
-
-                    var nRow = aoData.nTr;
-
-                    /* Remove the old striping classes and then add the new one */
-                    if (iStripes !== 0) {
-                        var sStripe = asStripeClasses[iRowCount % iStripes];
-                        if (aoData._sRowStripe != sStripe) {
-                            $(nRow).removeClass(aoData._sRowStripe).addClass(sStripe);
-                            aoData._sRowStripe = sStripe;
-                        }
-                    }
-
-                    // Row callback functions - might want to manipulate the row
-                    // iRowCount and j are not currently documented. Are they at all
-                    // useful?
-                    _fnCallbackFire(oSettings, 'aoRowCallback', null,
-                        [nRow, aoData._aData, iRowCount, j]);
-
-                    anRows.push(nRow);
-                    iRowCount++;
-                }
-            }
-            else {
-                /* Table is empty - create a row with an empty message in it */
-                var sZero = oLang.sZeroRecords;
-                if (oSettings.iDraw == 1 && _fnDataSource(oSettings) == 'ajax') {
-                    sZero = oLang.sLoadingRecords;
-                }
-                else if (oLang.sEmptyTable && oSettings.fnRecordsTotal() === 0) {
-                    sZero = oLang.sEmptyTable;
-                }
-
-                anRows[0] = $('<tr/>', { 'class': iStripes ? asStripeClasses[0] : '' })
-                    .append($('<td />', {
-                        'valign': 'top',
-                        'colSpan': _fnVisbleColumns(oSettings),
-                        'class': oSettings.oClasses.sRowEmpty
-                    }).html(sZero))[0];
-            }
-
-            /* Header and footer callbacks */
-            _fnCallbackFire(oSettings, 'aoHeaderCallback', 'header', [$(oSettings.nTHead).children('tr')[0],
-                _fnGetDataMaster(oSettings), iDisplayStart, iDisplayEnd, aiDisplay]);
-
-            _fnCallbackFire(oSettings, 'aoFooterCallback', 'footer', [$(oSettings.nTFoot).children('tr')[0],
-                _fnGetDataMaster(oSettings), iDisplayStart, iDisplayEnd, aiDisplay]);
-
-            var body = $(oSettings.nTBody);
-
-            body.children().detach();
-            body.append($(anRows));
-
-            /* Call all required callback functions for the end of a draw */
-            _fnCallbackFire(oSettings, 'aoDrawCallback', 'draw', [oSettings]);
-
-            /* Draw is complete, sorting and filtering must be as well */
-            oSettings.bSorted = false;
-            oSettings.bFiltered = false;
-            oSettings.bDrawing = false;
-        }
-
-
-        /**
-         * Redraw the table - taking account of the various features which are enabled
-         *  @param {object} oSettings dataTables settings object
-         *  @param {boolean} [holdPosition] Keep the current paging position. By default
-         *    the paging is reset to the first page
-         *  @memberof DataTable#oApi
-         */
-        function _fnReDraw(settings, holdPosition) {
-            var
-                features = settings.oFeatures,
-                sort = features.bSort,
-                filter = features.bFilter;
-
-            if (sort) {
-                _fnSort(settings);
-            }
-
-            if (filter) {
-                _fnFilterComplete(settings, settings.oPreviousSearch);
-            }
-            else {
-                // No filtering, so we want to just use the display master
-                settings.aiDisplay = settings.aiDisplayMaster.slice();
-            }
-
-            if (holdPosition !== true) {
-                settings._iDisplayStart = 0;
-            }
-
-            // Let any modules know about the draw hold position state (used by
-            // scrolling internally)
-            settings._drawHold = holdPosition;
-
-            _fnDraw(settings);
-
-            settings._drawHold = false;
-        }
-
-
-        /**
-         * Add the options to the page HTML for the table
-         *  @param {object} oSettings dataTables settings object
-         *  @memberof DataTable#oApi
-         */
-        function _fnAddOptionsHtml(oSettings) {
-            var classes = oSettings.oClasses;
-            var table = $(oSettings.nTable);
-            var holding = $('<div/>').insertBefore(table); // Holding element for speed
-            var features = oSettings.oFeatures;
-
-            // All DataTables are wrapped in a div
-            var insert = $('<div/>', {
-                id: oSettings.sTableId + '_wrapper',
-                'class': classes.sWrapper + (oSettings.nTFoot ? '' : ' ' + classes.sNoFooter)
-            });
-
-            oSettings.nHolding = holding[0];
-            oSettings.nTableWrapper = insert[0];
-            oSettings.nTableReinsertBefore = oSettings.nTable.nextSibling;
-
-            /* Loop over the user set positioning and place the elements as needed */
-            var aDom = oSettings.sDom.split('');
-            var featureNode, cOption, nNewNode, cNext, sAttr, j;
-            for (var i = 0 ; i < aDom.length ; i++) {
-                featureNode = null;
-                cOption = aDom[i];
-
-                if (cOption == '<') {
-                    /* New container div */
-                    nNewNode = $('<div/>')[0];
-
-                    /* Check to see if we should append an id and/or a class name to the container */
-                    cNext = aDom[i + 1];
-                    if (cNext == "'" || cNext == '"') {
-                        sAttr = "";
-                        j = 2;
-                        while (aDom[i + j] != cNext) {
-                            sAttr += aDom[i + j];
-                            j++;
-                        }
-
-                        /* Replace jQuery UI constants @todo depreciated */
-                        if (sAttr == "H") {
-                            sAttr = classes.sJUIHeader;
-                        }
-                        else if (sAttr == "F") {
-                            sAttr = classes.sJUIFooter;
-                        }
-
-                        /* The attribute can be in the format of "#id.class", "#id" or "class" This logic
-                         * breaks the string into parts and applies them as needed
-                         */
-                        if (sAttr.indexOf('.') != -1) {
-                            var aSplit = sAttr.split('.');
-                            nNewNode.id = aSplit[0].substr(1, aSplit[0].length - 1);
-                            nNewNode.className = aSplit[1];
-                        }
-                        else if (sAttr.charAt(0) == "#") {
-                            nNewNode.id = sAttr.substr(1, sAttr.length - 1);
-                        }
-                        else {
-                            nNewNode.className = sAttr;
-                        }
-
-                        i += j; /* Move along the position array */
-                    }
-
-                    insert.append(nNewNode);
-                    insert = $(nNewNode);
-                }
-                else if (cOption == '>') {
-                    /* End container div */
-                    insert = insert.parent();
-                }
-                    // @todo Move options into their own plugins?
-                else if (cOption == 'l' && features.bPaginate && features.bLengthChange) {
-                    /* Length */
-                    featureNode = _fnFeatureHtmlLength(oSettings);
-                }
-                else if (cOption == 'f' && features.bFilter) {
-                    /* Filter */
-                    featureNode = _fnFeatureHtmlFilter(oSettings);
-                }
-                else if (cOption == 'r' && features.bProcessing) {
-                    /* pRocessing */
-                    featureNode = _fnFeatureHtmlProcessing(oSettings);
-                }
-                else if (cOption == 't') {
-                    /* Table */
-                    featureNode = _fnFeatureHtmlTable(oSettings);
-                }
-                else if (cOption == 'i' && features.bInfo) {
-                    /* Info */
-                    featureNode = _fnFeatureHtmlInfo(oSettings);
-                }
-                else if (cOption == 'p' && features.bPaginate) {
-                    /* Pagination */
-                    featureNode = _fnFeatureHtmlPaginate(oSettings);
-                }
-                else if (DataTable.ext.feature.length !== 0) {
-                    /* Plug-in features */
-                    var aoFeatures = DataTable.ext.feature;
-                    for (var k = 0, kLen = aoFeatures.length ; k < kLen ; k++) {
-                        if (cOption == aoFeatures[k].cFeature) {
-                            featureNode = aoFeatures[k].fnInit(oSettings);
-                            break;
-                        }
-                    }
-                }
-
-                /* Add to the 2D features array */
-                if (featureNode) {
-                    var aanFeatures = oSettings.aanFeatures;
-
-                    if (!aanFeatures[cOption]) {
-                        aanFeatures[cOption] = [];
-                    }
-
-                    aanFeatures[cOption].push(featureNode);
-                    insert.append(featureNode);
-                }
-            }
-
-            /* Built our DOM structure - replace the holding div with what we want */
-            holding.replaceWith(insert);
-        }
-
-
-        /**
-         * Use the DOM source to create up an array of header cells. The idea here is to
-         * create a layout grid (array) of rows x columns, which contains a reference
-         * to the cell that that point in the grid (regardless of col/rowspan), such that
-         * any column / row could be removed and the new grid constructed
-         *  @param array {object} aLayout Array to store the calculated layout in
-         *  @param {node} nThead The header/footer element for the table
-         *  @memberof DataTable#oApi
-         */
-        function _fnDetectHeader(aLayout, nThead) {
-            var nTrs = $(nThead).children('tr');
-            var nTr, nCell;
-            var i, k, l, iLen, jLen, iColShifted, iColumn, iColspan, iRowspan;
-            var bUnique;
-            var fnShiftCol = function (a, i, j) {
-                var k = a[i];
-                while (k[j]) {
-                    j++;
-                }
-                return j;
-            };
-
-            aLayout.splice(0, aLayout.length);
-
-            /* We know how many rows there are in the layout - so prep it */
-            for (i = 0, iLen = nTrs.length ; i < iLen ; i++) {
-                aLayout.push([]);
-            }
-
-            /* Calculate a layout array */
-            for (i = 0, iLen = nTrs.length ; i < iLen ; i++) {
-                nTr = nTrs[i];
-                iColumn = 0;
-
-                /* For every cell in the row... */
-                nCell = nTr.firstChild;
-                while (nCell) {
-                    if (nCell.nodeName.toUpperCase() == "TD" ||
-                         nCell.nodeName.toUpperCase() == "TH") {
-                        /* Get the col and rowspan attributes from the DOM and sanitise them */
-                        iColspan = nCell.getAttribute('colspan') * 1;
-                        iRowspan = nCell.getAttribute('rowspan') * 1;
-                        iColspan = (!iColspan || iColspan === 0 || iColspan === 1) ? 1 : iColspan;
-                        iRowspan = (!iRowspan || iRowspan === 0 || iRowspan === 1) ? 1 : iRowspan;
-
-                        /* There might be colspan cells already in this row, so shift our target
-                         * accordingly
-                         */
-                        iColShifted = fnShiftCol(aLayout, i, iColumn);
-
-                        /* Cache calculation for unique columns */
-                        bUnique = iColspan === 1 ? true : false;
-
-                        /* If there is col / rowspan, copy the information into the layout grid */
-                        for (l = 0 ; l < iColspan ; l++) {
-                            for (k = 0 ; k < iRowspan ; k++) {
-                                aLayout[i + k][iColShifted + l] = {
-                                    "cell": nCell,
-                                    "unique": bUnique
-                                };
-                                aLayout[i + k].nTr = nTr;
-                            }
-                        }
-                    }
-                    nCell = nCell.nextSibling;
-                }
-            }
-        }
-
-
-        /**
-         * Get an array of unique th elements, one for each column
-         *  @param {object} oSettings dataTables settings object
-         *  @param {node} nHeader automatically detect the layout from this node - optional
-         *  @param {array} aLayout thead/tfoot layout from _fnDetectHeader - optional
-         *  @returns array {node} aReturn list of unique th's
-         *  @memberof DataTable#oApi
-         */
-        function _fnGetUniqueThs(oSettings, nHeader, aLayout) {
-            var aReturn = [];
-            if (!aLayout) {
-                aLayout = oSettings.aoHeader;
-                if (nHeader) {
-                    aLayout = [];
-                    _fnDetectHeader(aLayout, nHeader);
-                }
-            }
-
-            for (var i = 0, iLen = aLayout.length ; i < iLen ; i++) {
-                for (var j = 0, jLen = aLayout[i].length ; j < jLen ; j++) {
-                    if (aLayout[i][j].unique &&
-                         (!aReturn[j] || !oSettings.bSortCellsTop)) {
-                        aReturn[j] = aLayout[i][j].cell;
-                    }
-                }
-            }
-
-            return aReturn;
-        }
-
-        /**
-         * Create an Ajax call based on the table's settings, taking into account that
-         * parameters can have multiple forms, and backwards compatibility.
-         *
-         * @param {object} oSettings dataTables settings object
-         * @param {array} data Data to send to the server, required by
-         *     DataTables - may be augmented by developer callbacks
-         * @param {function} fn Callback function to run when data is obtained
-         */
-        function _fnBuildAjax(oSettings, data, fn) {
-            // Compatibility with 1.9-, allow fnServerData and event to manipulate
-            _fnCallbackFire(oSettings, 'aoServerParams', 'serverParams', [data]);
-
-            // Convert to object based for 1.10+ if using the old array scheme which can
-            // come from server-side processing or serverParams
-            if (data && $.isArray(data)) {
-                var tmp = {};
-                var rbracket = /(.*?)\[\]$/;
-
-                $.each(data, function (key, val) {
-                    var match = val.name.match(rbracket);
-
-                    if (match) {
-                        // Support for arrays
-                        var name = match[0];
-
-                        if (!tmp[name]) {
-                            tmp[name] = [];
-                        }
-                        tmp[name].push(val.value);
-                    }
-                    else {
-                        tmp[val.name] = val.value;
-                    }
-                });
-                data = tmp;
-            }
-
-            var ajaxData;
-            var ajax = oSettings.ajax;
-            var instance = oSettings.oInstance;
-            var callback = function (json) {
-                _fnCallbackFire(oSettings, null, 'xhr', [oSettings, json, oSettings.jqXHR]);
-                fn(json);
-            };
-
-            if ($.isPlainObject(ajax) && ajax.data) {
-                ajaxData = ajax.data;
-
-                var newData = $.isFunction(ajaxData) ?
-                    ajaxData(data, oSettings) :  // fn can manipulate data or return
-                    ajaxData;                      // an object object or array to merge
-
-                // If the function returned something, use that alone
-                data = $.isFunction(ajaxData) && newData ?
-                    newData :
-                    $.extend(true, data, newData);
-
-                // Remove the data property as we've resolved it already and don't want
-                // jQuery to do it again (it is restored at the end of the function)
-                delete ajax.data;
-            }
-
-            var baseAjax = {
-                "data": data,
-                "success": function (json) {
-                    var error = json.error || json.sError;
-                    if (error) {
-                        _fnLog(oSettings, 0, error);
-                    }
-
-                    oSettings.json = json;
-                    callback(json);
-                },
-                "dataType": "json",
-                "cache": false,
-                "type": oSettings.sServerMethod,
-                "error": function (xhr, error, thrown) {
-                    var ret = _fnCallbackFire(oSettings, null, 'xhr', [oSettings, null, oSettings.jqXHR]);
-
-                    if ($.inArray(true, ret) === -1) {
-                        if (error == "parsererror") {
-                            _fnLog(oSettings, 0, 'Invalid JSON response', 1);
-                        }
-                        else if (xhr.readyState === 4) {
-                            _fnLog(oSettings, 0, 'Ajax error', 7);
-                        }
-                    }
-
-                    _fnProcessingDisplay(oSettings, false);
-                }
-            };
-
-            // Store the data submitted for the API
-            oSettings.oAjaxData = data;
-
-            // Allow plug-ins and external processes to modify the data
-            _fnCallbackFire(oSettings, null, 'preXhr', [oSettings, data]);
-
-            if (oSettings.fnServerData) {
-                // DataTables 1.9- compatibility
-                oSettings.fnServerData.call(instance,
-                    oSettings.sAjaxSource,
-                    $.map(data, function (val, key) { // Need to convert back to 1.9 trad format
-                        return { name: key, value: val };
-                    }),
-                    callback,
-                    oSettings
-                );
-            }
-            else if (oSettings.sAjaxSource || typeof ajax === 'string') {
-                // DataTables 1.9- compatibility
-                oSettings.jqXHR = $.ajax($.extend(baseAjax, {
-                    url: ajax || oSettings.sAjaxSource
-                }));
-            }
-            else if ($.isFunction(ajax)) {
-                // Is a function - let the caller define what needs to be done
-                oSettings.jqXHR = ajax.call(instance, data, callback, oSettings);
-            }
-            else {
-                // Object to extend the base settings
-                oSettings.jqXHR = $.ajax($.extend(baseAjax, ajax));
-
-                // Restore for next time around
-                ajax.data = ajaxData;
-            }
-        }
-
-
-        /**
-         * Update the table using an Ajax call
-         *  @param {object} settings dataTables settings object
-         *  @returns {boolean} Block the table drawing or not
-         *  @memberof DataTable#oApi
-         */
-        function _fnAjaxUpdate(settings) {
-            if (settings.bAjaxDataGet) {
-                settings.iDraw++;
-                _fnProcessingDisplay(settings, true);
-
-                _fnBuildAjax(
-                    settings,
-                    _fnAjaxParameters(settings),
-                    function (json) {
-                        _fnAjaxUpdateDraw(settings, json);
-                    }
-                );
-
-                return false;
-            }
-            return true;
-        }
-
-
-        /**
-         * Build up the parameters in an object needed for a server-side processing
-         * request. Note that this is basically done twice, is different ways - a modern
-         * method which is used by default in DataTables 1.10 which uses objects and
-         * arrays, or the 1.9- method with is name / value pairs. 1.9 method is used if
-         * the sAjaxSource option is used in the initialisation, or the legacyAjax
-         * option is set.
-         *  @param {object} oSettings dataTables settings object
-         *  @returns {bool} block the table drawing or not
-         *  @memberof DataTable#oApi
-         */
-        function _fnAjaxParameters(settings) {
-            var
-                columns = settings.aoColumns,
-                columnCount = columns.length,
-                features = settings.oFeatures,
-                preSearch = settings.oPreviousSearch,
-                preColSearch = settings.aoPreSearchCols,
-                i, data = [], dataProp, column, columnSearch,
-                sort = _fnSortFlatten(settings),
-                displayStart = settings._iDisplayStart,
-                displayLength = features.bPaginate !== false ?
-                    settings._iDisplayLength :
-                    -1;
-
-            var param = function (name, value) {
-                data.push({ 'name': name, 'value': value });
-            };
-
-            // DataTables 1.9- compatible method
-            param('sEcho', settings.iDraw);
-            param('iColumns', columnCount);
-            param('sColumns', _pluck(columns, 'sName').join(','));
-            param('iDisplayStart', displayStart);
-            param('iDisplayLength', displayLength);
-
-            // DataTables 1.10+ method
-            var d = {
-                draw: settings.iDraw,
-                columns: [],
-                order: [],
-                start: displayStart,
-                length: displayLength,
-                search: {
-                    value: preSearch.sSearch,
-                    regex: preSearch.bRegex
-                }
-            };
-
-            for (i = 0 ; i < columnCount ; i++) {
-                column = columns[i];
-                columnSearch = preColSearch[i];
-                dataProp = typeof column.mData == "function" ? 'function' : column.mData;
-
-                d.columns.push({
-                    data: dataProp,
-                    name: column.sName,
-                    searchable: column.bSearchable,
-                    orderable: column.bSortable,
-                    search: {
-                        value: columnSearch.sSearch,
-                        regex: columnSearch.bRegex
-                    }
-                });
-
-                param("mDataProp_" + i, dataProp);
-
-                if (features.bFilter) {
-                    param('sSearch_' + i, columnSearch.sSearch);
-                    param('bRegex_' + i, columnSearch.bRegex);
-                    param('bSearchable_' + i, column.bSearchable);
-                }
-
-                if (features.bSort) {
-                    param('bSortable_' + i, column.bSortable);
-                }
-            }
-
-            if (features.bFilter) {
-                param('sSearch', preSearch.sSearch);
-                param('bRegex', preSearch.bRegex);
-            }
-
-            if (features.bSort) {
-                $.each(sort, function (i, val) {
-                    d.order.push({ column: val.col, dir: val.dir });
-
-                    param('iSortCol_' + i, val.col);
-                    param('sSortDir_' + i, val.dir);
-                });
-
-                param('iSortingCols', sort.length);
-            }
-
-            // If the legacy.ajax parameter is null, then we automatically decide which
-            // form to use, based on sAjaxSource
-            var legacy = DataTable.ext.legacy.ajax;
-            if (legacy === null) {
-                return settings.sAjaxSource ? data : d;
-            }
-
-            // Otherwise, if legacy has been specified then we use that to decide on the
-            // form
-            return legacy ? data : d;
-        }
-
-
-        /**
-         * Data the data from the server (nuking the old) and redraw the table
-         *  @param {object} oSettings dataTables settings object
-         *  @param {object} json json data return from the server.
-         *  @param {string} json.sEcho Tracking flag for DataTables to match requests
-         *  @param {int} json.iTotalRecords Number of records in the data set, not accounting for filtering
-         *  @param {int} json.iTotalDisplayRecords Number of records in the data set, accounting for filtering
-         *  @param {array} json.aaData The data to display on this page
-         *  @param {string} [json.sColumns] Column ordering (sName, comma separated)
-         *  @memberof DataTable#oApi
-         */
-        function _fnAjaxUpdateDraw(settings, json) {
-            // v1.10 uses camelCase variables, while 1.9 uses Hungarian notation.
-            // Support both
-            var compat = function (old, modern) {
-                return json[old] !== undefined ? json[old] : json[modern];
-            };
-
-            var data = _fnAjaxDataSrc(settings, json);
-            var draw = compat('sEcho', 'draw');
-            var recordsTotal = compat('iTotalRecords', 'recordsTotal');
-            var recordsFiltered = compat('iTotalDisplayRecords', 'recordsFiltered');
-
-            if (draw) {
-                // Protect against out of sequence returns
-                if (draw * 1 < settings.iDraw) {
-                    return;
-                }
-                settings.iDraw = draw * 1;
-            }
-
-            _fnClearTable(settings);
-            settings._iRecordsTotal = parseInt(recordsTotal, 10);
-            settings._iRecordsDisplay = parseInt(recordsFiltered, 10);
-
-            for (var i = 0, ien = data.length ; i < ien ; i++) {
-                _fnAddData(settings, data[i]);
-            }
-            settings.aiDisplay = settings.aiDisplayMaster.slice();
-
-            settings.bAjaxDataGet = false;
-            _fnDraw(settings);
-
-            if (!settings._bInitComplete) {
-                _fnInitComplete(settings, json);
-            }
-
-            settings.bAjaxDataGet = true;
-            _fnProcessingDisplay(settings, false);
-        }
-
-
-        /**
-         * Get the data from the JSON data source to use for drawing a table. Using
-         * `_fnGetObjectDataFn` allows the data to be sourced from a property of the
-         * source object, or from a processing function.
-         *  @param {object} oSettings dataTables settings object
-         *  @param  {object} json Data source object / array from the server
-         *  @return {array} Array of data to use
-         */
-        function _fnAjaxDataSrc(oSettings, json) {
-            var dataSrc = $.isPlainObject(oSettings.ajax) && oSettings.ajax.dataSrc !== undefined ?
-                oSettings.ajax.dataSrc :
-                oSettings.sAjaxDataProp; // Compatibility with 1.9-.
-
-            // Compatibility with 1.9-. In order to read from aaData, check if the
-            // default has been changed, if not, check for aaData
-            if (dataSrc === 'data') {
-                return json.aaData || json[dataSrc];
-            }
-
-            return dataSrc !== "" ?
-                _fnGetObjectDataFn(dataSrc)(json) :
-                json;
-        }
-
-        /**
-         * Generate the node required for filtering text
-         *  @returns {node} Filter control element
-         *  @param {object} oSettings dataTables settings object
-         *  @memberof DataTable#oApi
-         */
-        function _fnFeatureHtmlFilter(settings) {
-            var classes = settings.oClasses;
-            var tableId = settings.sTableId;
-            var language = settings.oLanguage;
-            var previousSearch = settings.oPreviousSearch;
-            var features = settings.aanFeatures;
-            var input = '<input type="search" class="' + classes.sFilterInput + '"/>';
-
-            var str = language.sSearch;
-            str = str.match(/_INPUT_/) ?
-                str.replace('_INPUT_', input) :
-                str + input;
-
-            var filter = $('<div/>', {
-                'id': !features.f ? tableId + '_filter' : null,
-                'class': classes.sFilter
-            })
-                .append($('<label/>').append(str));
-
-            var searchFn = function () {
-                /* Update all other filter input elements for the new display */
-                var n = features.f;
-                var val = !this.value ? "" : this.value; // mental IE8 fix :-(
-
-                /* Now do the filter */
-                if (val != previousSearch.sSearch) {
-                    _fnFilterComplete(settings, {
-                        "sSearch": val,
-                        "bRegex": previousSearch.bRegex,
-                        "bSmart": previousSearch.bSmart,
-                        "bCaseInsensitive": previousSearch.bCaseInsensitive
-                    });
-
-                    // Need to redraw, without resorting
-                    settings._iDisplayStart = 0;
-                    _fnDraw(settings);
-                }
-            };
-
-            var searchDelay = settings.searchDelay !== null ?
-                settings.searchDelay :
-                _fnDataSource(settings) === 'ssp' ?
-                    400 :
-                    0;
-
-            var jqFilter = $('input', filter)
-                .val(previousSearch.sSearch)
-                .attr('placeholder', language.sSearchPlaceholder)
-                .bind(
-                    'keyup.DT search.DT input.DT paste.DT cut.DT',
-                    searchDelay ?
-                        _fnThrottle(searchFn, searchDelay) :
-                        searchFn
-                )
-                .bind('keypress.DT', function (e) {
-                    /* Prevent form submission */
-                    if (e.keyCode == 13) {
-                        return false;
-                    }
-                })
-                .attr('aria-controls', tableId);
-
-            // Update the input elements whenever the table is filtered
-            $(settings.nTable).on('search.dt.DT', function (ev, s) {
-                if (settings === s) {
-                    // IE9 throws an 'unknown error' if document.activeElement is used
-                    // inside an iframe or frame...
-                    try {
-                        if (jqFilter[0] !== document.activeElement) {
-                            jqFilter.val(previousSearch.sSearch);
-                        }
-                    }
-                    catch (e) { }
-                }
-            });
-
-            return filter[0];
-        }
-
-
-        /**
-         * Filter the table using both the global filter and column based filtering
-         *  @param {object} oSettings dataTables settings object
-         *  @param {object} oSearch search information
-         *  @param {int} [iForce] force a research of the master array (1) or not (undefined or 0)
-         *  @memberof DataTable#oApi
-         */
-        function _fnFilterComplete(oSettings, oInput, iForce) {
-            var oPrevSearch = oSettings.oPreviousSearch;
-            var aoPrevSearch = oSettings.aoPreSearchCols;
-            var fnSaveFilter = function (oFilter) {
-                /* Save the filtering values */
-                oPrevSearch.sSearch = oFilter.sSearch;
-                oPrevSearch.bRegex = oFilter.bRegex;
-                oPrevSearch.bSmart = oFilter.bSmart;
-                oPrevSearch.bCaseInsensitive = oFilter.bCaseInsensitive;
-            };
-            var fnRegex = function (o) {
-                // Backwards compatibility with the bEscapeRegex option
-                return o.bEscapeRegex !== undefined ? !o.bEscapeRegex : o.bRegex;
-            };
-
-            // Resolve any column types that are unknown due to addition or invalidation
-            // @todo As per sort - can this be moved into an event handler?
-            _fnColumnTypes(oSettings);
-
-            /* In server-side processing all filtering is done by the server, so no point hanging around here */
-            if (_fnDataSource(oSettings) != 'ssp') {
-                /* Global filter */
-                _fnFilter(oSettings, oInput.sSearch, iForce, fnRegex(oInput), oInput.bSmart, oInput.bCaseInsensitive);
-                fnSaveFilter(oInput);
-
-                /* Now do the individual column filter */
-                for (var i = 0 ; i < aoPrevSearch.length ; i++) {
-                    _fnFilterColumn(oSettings, aoPrevSearch[i].sSearch, i, fnRegex(aoPrevSearch[i]),
-                        aoPrevSearch[i].bSmart, aoPrevSearch[i].bCaseInsensitive);
-                }
-
-                /* Custom filtering */
-                _fnFilterCustom(oSettings);
-            }
-            else {
-                fnSaveFilter(oInput);
-            }
-
-            /* Tell the draw function we have been filtering */
-            oSettings.bFiltered = true;
-            _fnCallbackFire(oSettings, null, 'search', [oSettings]);
-        }
-
-
-        /**
-         * Apply custom filtering functions
-         *  @param {object} oSettings dataTables settings object
-         *  @memberof DataTable#oApi
-         */
-        function _fnFilterCustom(settings) {
-            var filters = DataTable.ext.search;
-            var displayRows = settings.aiDisplay;
-            var row, rowIdx;
-
-            for (var i = 0, ien = filters.length ; i < ien ; i++) {
-                var rows = [];
-
-                // Loop over each row and see if it should be included
-                for (var j = 0, jen = displayRows.length ; j < jen ; j++) {
-                    rowIdx = displayRows[j];
-                    row = settings.aoData[rowIdx];
-
-                    if (filters[i](settings, row._aFilterData, rowIdx, row._aData, j)) {
-                        rows.push(rowIdx);
-                    }
-                }
-
-                // So the array reference doesn't break set the results into the
-                // existing array
-                displayRows.length = 0;
-                displayRows.push.apply(displayRows, rows);
-            }
-        }
-
-
-        /**
-         * Filter the table on a per-column basis
-         *  @param {object} oSettings dataTables settings object
-         *  @param {string} sInput string to filter on
-         *  @param {int} iColumn column to filter
-         *  @param {bool} bRegex treat search string as a regular expression or not
-         *  @param {bool} bSmart use smart filtering or not
-         *  @param {bool} bCaseInsensitive Do case insenstive matching or not
-         *  @memberof DataTable#oApi
-         */
-        function _fnFilterColumn(settings, searchStr, colIdx, regex, smart, caseInsensitive) {
-            if (searchStr === '') {
-                return;
-            }
-
-            var data;
-            var display = settings.aiDisplay;
-            var rpSearch = _fnFilterCreateSearch(searchStr, regex, smart, caseInsensitive);
-
-            for (var i = display.length - 1 ; i >= 0 ; i--) {
-                data = settings.aoData[display[i]]._aFilterData[colIdx];
-
-                if (!rpSearch.test(data)) {
-                    display.splice(i, 1);
-                }
-            }
-        }
-
-
-        /**
-         * Filter the data table based on user input and draw the table
-         *  @param {object} settings dataTables settings object
-         *  @param {string} input string to filter on
-         *  @param {int} force optional - force a research of the master array (1) or not (undefined or 0)
-         *  @param {bool} regex treat as a regular expression or not
-         *  @param {bool} smart perform smart filtering or not
-         *  @param {bool} caseInsensitive Do case insenstive matching or not
-         *  @memberof DataTable#oApi
-         */
-        function _fnFilter(settings, input, force, regex, smart, caseInsensitive) {
-            var rpSearch = _fnFilterCreateSearch(input, regex, smart, caseInsensitive);
-            var prevSearch = settings.oPreviousSearch.sSearch;
-            var displayMaster = settings.aiDisplayMaster;
-            var display, invalidated, i;
-
-            // Need to take account of custom filtering functions - always filter
-            if (DataTable.ext.search.length !== 0) {
-                force = true;
-            }
-
-            // Check if any of the rows were invalidated
-            invalidated = _fnFilterData(settings);
-
-            // If the input is blank - we just want the full data set
-            if (input.length <= 0) {
-                settings.aiDisplay = displayMaster.slice();
-            }
-            else {
-                // New search - start from the master array
-                if (invalidated ||
-                     force ||
-                     prevSearch.length > input.length ||
-                     input.indexOf(prevSearch) !== 0 ||
-                     settings.bSorted // On resort, the display master needs to be
-                    // re-filtered since indexes will have changed
-                ) {
-                    settings.aiDisplay = displayMaster.slice();
-                }
-
-                // Search the display array
-                display = settings.aiDisplay;
-
-                for (i = display.length - 1 ; i >= 0 ; i--) {
-                    if (!rpSearch.test(settings.aoData[display[i]]._sFilterRow)) {
-                        display.splice(i, 1);
-                    }
-                }
-            }
-        }
-
-
-        /**
-         * Build a regular expression object suitable for searching a table
-         *  @param {string} sSearch string to search for
-         *  @param {bool} bRegex treat as a regular expression or not
-         *  @param {bool} bSmart perform smart filtering or not
-         *  @param {bool} bCaseInsensitive Do case insensitive matching or not
-         *  @returns {RegExp} constructed object
-         *  @memberof DataTable#oApi
-         */
-        function _fnFilterCreateSearch(search, regex, smart, caseInsensitive) {
-            search = regex ?
-                search :
-                _fnEscapeRegex(search);
-
-            if (smart) {
-                /* For smart filtering we want to allow the search to work regardless of
-                 * word order. We also want double quoted text to be preserved, so word
-                 * order is important - a la google. So this is what we want to
-                 * generate:
-                 * 
-                 * ^(?=.*?\bone\b)(?=.*?\btwo three\b)(?=.*?\bfour\b).*$
-                 */
-                var a = $.map(search.match(/"[^"]+"|[^ ]+/g) || [''], function (word) {
-                    if (word.charAt(0) === '"') {
-                        var m = word.match(/^"(.*)"$/);
-                        word = m ? m[1] : word;
-                    }
-
-                    return word.replace('"', '');
-                });
-
-                search = '^(?=.*?' + a.join(')(?=.*?') + ').*$';
-            }
-
-            return new RegExp(search, caseInsensitive ? 'i' : '');
-        }
-
-
-        /**
-         * Escape a string such that it can be used in a regular expression
-         *  @param {string} sVal string to escape
-         *  @returns {string} escaped string
-         *  @memberof DataTable#oApi
-         */
-        function _fnEscapeRegex(sVal) {
-            return sVal.replace(_re_escape_regex, '\\$1');
-        }
-
-
-
-        var __filter_div = $('<div>')[0];
-        var __filter_div_textContent = __filter_div.textContent !== undefined;
-
-        // Update the filtering data for each row if needed (by invalidation or first run)
-        function _fnFilterData(settings) {
-            var columns = settings.aoColumns;
-            var column;
-            var i, j, ien, jen, filterData, cellData, row;
-            var fomatters = DataTable.ext.type.search;
-            var wasInvalidated = false;
-
-            for (i = 0, ien = settings.aoData.length ; i < ien ; i++) {
-                row = settings.aoData[i];
-
-                if (!row._aFilterData) {
-                    filterData = [];
-
-                    for (j = 0, jen = columns.length ; j < jen ; j++) {
-                        column = columns[j];
-
-                        if (column.bSearchable) {
-                            cellData = _fnGetCellData(settings, i, j, 'filter');
-
-                            if (fomatters[column.sType]) {
-                                cellData = fomatters[column.sType](cellData);
-                            }
-
-                            // Search in DataTables 1.10 is string based. In 1.11 this
-                            // should be altered to also allow strict type checking.
-                            if (cellData === null) {
-                                cellData = '';
-                            }
-
-                            if (typeof cellData !== 'string' && cellData.toString) {
-                                cellData = cellData.toString();
-                            }
-                        }
-                        else {
-                            cellData = '';
-                        }
-
-                        // If it looks like there is an HTML entity in the string,
-                        // attempt to decode it so sorting works as expected. Note that
-                        // we could use a single line of jQuery to do this, but the DOM
-                        // method used here is much faster http://jsperf.com/html-decode
-                        if (cellData.indexOf && cellData.indexOf('&') !== -1) {
-                            __filter_div.innerHTML = cellData;
-                            cellData = __filter_div_textContent ?
-                                __filter_div.textContent :
-                                __filter_div.innerText;
-                        }
-
-                        if (cellData.replace) {
-                            cellData = cellData.replace(/[\r\n]/g, '');
-                        }
-
-                        filterData.push(cellData);
-                    }
-
-                    row._aFilterData = filterData;
-                    row._sFilterRow = filterData.join('  ');
-                    wasInvalidated = true;
-                }
-            }
-
-            return wasInvalidated;
-        }
-
-
-        /**
-         * Convert from the internal Hungarian notation to camelCase for external
-         * interaction
-         *  @param {object} obj Object to convert
-         *  @returns {object} Inverted object
-         *  @memberof DataTable#oApi
-         */
-        function _fnSearchToCamel(obj) {
-            return {
-                search: obj.sSearch,
-                smart: obj.bSmart,
-                regex: obj.bRegex,
-                caseInsensitive: obj.bCaseInsensitive
-            };
-        }
-
-
-
-        /**
-         * Convert from camelCase notation to the internal Hungarian. We could use the
-         * Hungarian convert function here, but this is cleaner
-         *  @param {object} obj Object to convert
-         *  @returns {object} Inverted object
-         *  @memberof DataTable#oApi
-         */
-        function _fnSearchToHung(obj) {
-            return {
-                sSearch: obj.search,
-                bSmart: obj.smart,
-                bRegex: obj.regex,
-                bCaseInsensitive: obj.caseInsensitive
-            };
-        }
-
-        /**
-         * Generate the node required for the info display
-         *  @param {object} oSettings dataTables settings object
-         *  @returns {node} Information element
-         *  @memberof DataTable#oApi
-         */
-        function _fnFeatureHtmlInfo(settings) {
-            var
-                tid = settings.sTableId,
-                nodes = settings.aanFeatures.i,
-                n = $('<div/>', {
-                    'class': settings.oClasses.sInfo,
-                    'id': !nodes ? tid + '_info' : null
-                });
-
-            if (!nodes) {
-                // Update display on each draw
-                settings.aoDrawCallback.push({
-                    "fn": _fnUpdateInfo,
-                    "sName": "information"
-                });
-
-                n
-                    .attr('role', 'status')
-                    .attr('aria-live', 'polite');
-
-                // Table is described by our info div
-                $(settings.nTable).attr('aria-describedby', tid + '_info');
-            }
-
-            return n[0];
-        }
-
-
-        /**
-         * Update the information elements in the display
-         *  @param {object} settings dataTables settings object
-         *  @memberof DataTable#oApi
-         */
-        function _fnUpdateInfo(settings) {
-            /* Show information about the table */
-            var nodes = settings.aanFeatures.i;
-            if (nodes.length === 0) {
-                return;
-            }
-
-            var
-                lang = settings.oLanguage,
-                start = settings._iDisplayStart + 1,
-                end = settings.fnDisplayEnd(),
-                max = settings.fnRecordsTotal(),
-                total = settings.fnRecordsDisplay(),
-                out = total ?
-                    lang.sInfo :
-                    lang.sInfoEmpty;
-
-            if (total !== max) {
-                /* Record set after filtering */
-                out += ' ' + lang.sInfoFiltered;
-            }
-
-            // Convert the macros
-            out += lang.sInfoPostFix;
-            out = _fnInfoMacros(settings, out);
-
-            var callback = lang.fnInfoCallback;
-            if (callback !== null) {
-                out = callback.call(settings.oInstance,
-                    settings, start, end, max, total, out
-                );
-            }
-
-            $(nodes).html(out);
-        }
-
-
-        function _fnInfoMacros(settings, str) {
-            // When infinite scrolling, we are always starting at 1. _iDisplayStart is used only
-            // internally
-            var
-                formatter = settings.fnFormatNumber,
-                start = settings._iDisplayStart + 1,
-                len = settings._iDisplayLength,
-                vis = settings.fnRecordsDisplay(),
-                all = len === -1;
-
-            return str.
-                replace(/_START_/g, formatter.call(settings, start)).
-                replace(/_END_/g, formatter.call(settings, settings.fnDisplayEnd())).
-                replace(/_MAX_/g, formatter.call(settings, settings.fnRecordsTotal())).
-                replace(/_TOTAL_/g, formatter.call(settings, vis)).
-                replace(/_PAGE_/g, formatter.call(settings, all ? 1 : Math.ceil(start / len))).
-                replace(/_PAGES_/g, formatter.call(settings, all ? 1 : Math.ceil(vis / len)));
-        }
-
-
-
-        /**
-         * Draw the table for the first time, adding all required features
-         *  @param {object} settings dataTables settings object
-         *  @memberof DataTable#oApi
-         */
-        function _fnInitialise(settings) {
-            var i, iLen, iAjaxStart = settings.iInitDisplayStart;
-            var columns = settings.aoColumns, column;
-            var features = settings.oFeatures;
-
-            /* Ensure that the table data is fully initialised */
-            if (!settings.bInitialised) {
-                setTimeout(function () { _fnInitialise(settings); }, 200);
-                return;
-            }
-
-            /* Show the display HTML options */
-            _fnAddOptionsHtml(settings);
-
-            /* Build and draw the header / footer for the table */
-            _fnBuildHead(settings);
-            _fnDrawHead(settings, settings.aoHeader);
-            _fnDrawHead(settings, settings.aoFooter);
-
-            /* Okay to show that something is going on now */
-            _fnProcessingDisplay(settings, true);
-
-            /* Calculate sizes for columns */
-            if (features.bAutoWidth) {
-                _fnCalculateColumnWidths(settings);
-            }
-
-            for (i = 0, iLen = columns.length ; i < iLen ; i++) {
-                column = columns[i];
-
-                if (column.sWidth) {
-                    column.nTh.style.width = _fnStringToCss(column.sWidth);
-                }
-            }
-
-            // If there is default sorting required - let's do it. The sort function
-            // will do the drawing for us. Otherwise we draw the table regardless of the
-            // Ajax source - this allows the table to look initialised for Ajax sourcing
-            // data (show 'loading' message possibly)
-            _fnReDraw(settings);
-
-            // Server-side processing init complete is done by _fnAjaxUpdateDraw
-            var dataSrc = _fnDataSource(settings);
-            if (dataSrc != 'ssp') {
-                // if there is an ajax source load the data
-                if (dataSrc == 'ajax') {
-                    _fnBuildAjax(settings, [], function (json) {
-                        var aData = _fnAjaxDataSrc(settings, json);
-
-                        // Got the data - add it to the table
-                        for (i = 0 ; i < aData.length ; i++) {
-                            _fnAddData(settings, aData[i]);
-                        }
-
-                        // Reset the init display for cookie saving. We've already done
-                        // a filter, and therefore cleared it before. So we need to make
-                        // it appear 'fresh'
-                        settings.iInitDisplayStart = iAjaxStart;
-
-                        _fnReDraw(settings);
-
-                        _fnProcessingDisplay(settings, false);
-                        _fnInitComplete(settings, json);
-                    }, settings);
-                }
-                else {
-                    _fnProcessingDisplay(settings, false);
-                    _fnInitComplete(settings);
-                }
-            }
-        }
-
-
-        /**
-         * Draw the table for the first time, adding all required features
-         *  @param {object} oSettings dataTables settings object
-         *  @param {object} [json] JSON from the server that completed the table, if using Ajax source
-         *    with client-side processing (optional)
-         *  @memberof DataTable#oApi
-         */
-        function _fnInitComplete(settings, json) {
-            settings._bInitComplete = true;
-
-            // On an Ajax load we now have data and therefore want to apply the column
-            // sizing
-            if (json) {
-                _fnAdjustColumnSizing(settings);
-            }
-
-            _fnCallbackFire(settings, 'aoInitComplete', 'init', [settings, json]);
-        }
-
-
-        function _fnLengthChange(settings, val) {
-            var len = parseInt(val, 10);
-            settings._iDisplayLength = len;
-
-            _fnLengthOverflow(settings);
-
-            // Fire length change event
-            _fnCallbackFire(settings, null, 'length', [settings, len]);
-        }
-
-
-        /**
-         * Generate the node required for user display length changing
-         *  @param {object} settings dataTables settings object
-         *  @returns {node} Display length feature node
-         *  @memberof DataTable#oApi
-         */
-        function _fnFeatureHtmlLength(settings) {
-            var
-                classes = settings.oClasses,
-                tableId = settings.sTableId,
-                menu = settings.aLengthMenu,
-                d2 = $.isArray(menu[0]),
-                lengths = d2 ? menu[0] : menu,
-                language = d2 ? menu[1] : menu;
-
-            var select = $('<select/>', {
-                'name': tableId + '_length',
-                'aria-controls': tableId,
-                'class': classes.sLengthSelect
-            });
-
-            for (var i = 0, ien = lengths.length ; i < ien ; i++) {
-                select[0][i] = new Option(language[i], lengths[i]);
-            }
-
-            var div = $('<div><label/></div>').addClass(classes.sLength);
-            if (!settings.aanFeatures.l) {
-                div[0].id = tableId + '_length';
-            }
-
-            div.children().append(
-                settings.oLanguage.sLengthMenu.replace('_MENU_', select[0].outerHTML)
-            );
-
-            // Can't use `select` variable as user might provide their own and the
-            // reference is broken by the use of outerHTML
-            $('select', div)
-                .val(settings._iDisplayLength)
-                .bind('change.DT', function (e) {
-                    _fnLengthChange(settings, $(this).val());
-                    _fnDraw(settings);
-                });
-
-            // Update node value whenever anything changes the table's length
-            $(settings.nTable).bind('length.dt.DT', function (e, s, len) {
-                if (settings === s) {
-                    $('select', div).val(len);
-                }
-            });
-
-            return div[0];
-        }
-
-
-
-        /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
-         * Note that most of the paging logic is done in
-         * DataTable.ext.pager
-         */
-
-        /**
-         * Generate the node required for default pagination
-         *  @param {object} oSettings dataTables settings object
-         *  @returns {node} Pagination feature node
-         *  @memberof DataTable#oApi
-         */
-        function _fnFeatureHtmlPaginate(settings) {
-            var
-                type = settings.sPaginationType,
-                plugin = DataTable.ext.pager[type],
-                modern = typeof plugin === 'function',
-                redraw = function (settings) {
-                    _fnDraw(settings);
-                },
-                node = $('<div/>').addClass(settings.oClasses.sPaging + type)[0],
-                features = settings.aanFeatures;
-
-            if (!modern) {
-                plugin.fnInit(settings, node, redraw);
-            }
-
-            /* Add a draw callback for the pagination on first instance, to update the paging display */
-            if (!features.p) {
-                node.id = settings.sTableId + '_paginate';
-
-                settings.aoDrawCallback.push({
-                    "fn": function (settings) {
-                        if (modern) {
-                            var
-                                start = settings._iDisplayStart,
-                                len = settings._iDisplayLength,
-                                visRecords = settings.fnRecordsDisplay(),
-                                all = len === -1,
-                                page = all ? 0 : Math.ceil(start / len),
-                                pages = all ? 1 : Math.ceil(visRecords / len),
-                                buttons = plugin(page, pages),
-                                i, ien;
-
-                            for (i = 0, ien = features.p.length ; i < ien ; i++) {
-                                _fnRenderer(settings, 'pageButton')(
-                                    settings, features.p[i], i, buttons, page, pages
-                                );
-                            }
-                        }
-                        else {
-                            plugin.fnUpdate(settings, redraw);
-                        }
-                    },
-                    "sName": "pagination"
-                });
-            }
-
-            return node;
-        }
-
-
-        /**
-         * Alter the display settings to change the page
-         *  @param {object} settings DataTables settings object
-         *  @param {string|int} action Paging action to take: "first", "previous",
-         *    "next" or "last" or page number to jump to (integer)
-         *  @param [bool] redraw Automatically draw the update or not
-         *  @returns {bool} true page has changed, false - no change
-         *  @memberof DataTable#oApi
-         */
-        function _fnPageChange(settings, action, redraw) {
-            var
-                start = settings._iDisplayStart,
-                len = settings._iDisplayLength,
-                records = settings.fnRecordsDisplay();
-
-            if (records === 0 || len === -1) {
-                start = 0;
-            }
-            else if (typeof action === "number") {
-                start = action * len;
-
-                if (start > records) {
-                    start = 0;
-                }
-            }
-            else if (action == "first") {
-                start = 0;
-            }
-            else if (action == "previous") {
-                start = len >= 0 ?
-                    start - len :
-                    0;
-
-                if (start < 0) {
-                    start = 0;
-                }
-            }
-            else if (action == "next") {
-                if (start + len < records) {
-                    start += len;
-                }
-            }
-            else if (action == "last") {
-                start = Math.floor((records - 1) / len) * len;
-            }
-            else {
-                _fnLog(settings, 0, "Unknown paging action: " + action, 5);
-            }
-
-            var changed = settings._iDisplayStart !== start;
-            settings._iDisplayStart = start;
-
-            if (changed) {
-                _fnCallbackFire(settings, null, 'page', [settings]);
-
-                if (redraw) {
-                    _fnDraw(settings);
-                }
-            }
-
-            return changed;
-        }
-
-
-
-        /**
-         * Generate the node required for the processing node
-         *  @param {object} settings dataTables settings object
-         *  @returns {node} Processing element
-         *  @memberof DataTable#oApi
-         */
-        function _fnFeatureHtmlProcessing(settings) {
-            return $('<div/>', {
-                'id': !settings.aanFeatures.r ? settings.sTableId + '_processing' : null,
-                'class': settings.oClasses.sProcessing
-            })
-                .html(settings.oLanguage.sProcessing)
-                .insertBefore(settings.nTable)[0];
-        }
-
-
-        /**
-         * Display or hide the processing indicator
-         *  @param {object} settings dataTables settings object
-         *  @param {bool} show Show the processing indicator (true) or not (false)
-         *  @memberof DataTable#oApi
-         */
-        function _fnProcessingDisplay(settings, show) {
-            if (settings.oFeatures.bProcessing) {
-                $(settings.aanFeatures.r).css('display', show ? 'block' : 'none');
-            }
-
-            _fnCallbackFire(settings, null, 'processing', [settings, show]);
-        }
-
-        /**
-         * Add any control elements for the table - specifically scrolling
-         *  @param {object} settings dataTables settings object
-         *  @returns {node} Node to add to the DOM
-         *  @memberof DataTable#oApi
-         */
-        function _fnFeatureHtmlTable(settings) {
-            var table = $(settings.nTable);
-
-            // Add the ARIA grid role to the table
-            table.attr('role', 'grid');
-
-            // Scrolling from here on in
-            var scroll = settings.oScroll;
-
-            if (scroll.sX === '' && scroll.sY === '') {
-                return settings.nTable;
-            }
-
-            var scrollX = scroll.sX;
-            var scrollY = scroll.sY;
-            var classes = settings.oClasses;
-            var caption = table.children('caption');
-            var captionSide = caption.length ? caption[0]._captionSide : null;
-            var headerClone = $(table[0].cloneNode(false));
-            var footerClone = $(table[0].cloneNode(false));
-            var footer = table.children('tfoot');
-            var _div = '<div/>';
-            var size = function (s) {
-                return !s ? null : _fnStringToCss(s);
-            };
-
-            // This is fairly messy, but with x scrolling enabled, if the table has a
-            // width attribute, regardless of any width applied using the column width
-            // options, the browser will shrink or grow the table as needed to fit into
-            // that 100%. That would make the width options useless. So we remove it.
-            // This is okay, under the assumption that width:100% is applied to the
-            // table in CSS (it is in the default stylesheet) which will set the table
-            // width as appropriate (the attribute and css behave differently...)
-            if (scroll.sX && table.attr('width') === '100%') {
-                table.removeAttr('width');
-            }
-
-            if (!footer.length) {
-                footer = null;
-            }
-
-            /*
-             * The HTML structure that we want to generate in this function is:
-             *  div - scroller
-             *    div - scroll head
-             *      div - scroll head inner
-             *        table - scroll head table
-             *          thead - thead
-             *    div - scroll body
-             *      table - table (master table)
-             *        thead - thead clone for sizing
-             *        tbody - tbody
-             *    div - scroll foot
-             *      div - scroll foot inner
-             *        table - scroll foot table
-             *          tfoot - tfoot
-             */
-            var scroller = $(_div, { 'class': classes.sScrollWrapper })
-                .append(
-                    $(_div, { 'class': classes.sScrollHead })
-                        .css({
-                            overflow: 'hidden',
-                            position: 'relative',
-                            border: 0,
-                            width: scrollX ? size(scrollX) : '100%'
-                        })
-                        .append(
-                            $(_div, { 'class': classes.sScrollHeadInner })
-                                .css({
-                                    'box-sizing': 'content-box',
-                                    width: scroll.sXInner || '100%'
-                                })
-                                .append(
-                                    headerClone
-                                        .removeAttr('id')
-                                        .css('margin-left', 0)
-                                        .append(captionSide === 'top' ? caption : null)
-                                        .append(
-                                            table.children('thead')
-                                        )
-                                )
-                        )
-                )
-                .append(
-                    $(_div, { 'class': classes.sScrollBody })
-                        .css({
-                            overflow: 'auto',
-                            height: size(scrollY),
-                            width: size(scrollX)
-                        })
-                        .append(table)
-                );
-
-            if (footer) {
-                scroller.append(
-                    $(_div, { 'class': classes.sScrollFoot })
-                        .css({
-                            overflow: 'hidden',
-                            border: 0,
-                            width: scrollX ? size(scrollX) : '100%'
-                        })
-                        .append(
-                            $(_div, { 'class': classes.sScrollFootInner })
-                                .append(
-                                    footerClone
-                                        .removeAttr('id')
-                                        .css('margin-left', 0)
-                                        .append(captionSide === 'bottom' ? caption : null)
-                                        .append(
-                                            table.children('tfoot')
-                                        )
-                                )
-                        )
-                );
-            }
-
-            var children = scroller.children();
-            var scrollHead = children[0];
-            var scrollBody = children[1];
-            var scrollFoot = footer ? children[2] : null;
-
-            // When the body is scrolled, then we also want to scroll the headers
-            if (scrollX) {
-                $(scrollBody).on('scroll.DT', function (e) {
-                    var scrollLeft = this.scrollLeft;
-
-                    scrollHead.scrollLeft = scrollLeft;
-
-                    if (footer) {
-                        scrollFoot.scrollLeft = scrollLeft;
-                    }
-                });
-            }
-
-            settings.nScrollHead = scrollHead;
-            settings.nScrollBody = scrollBody;
-            settings.nScrollFoot = scrollFoot;
-
-            // On redraw - align columns
-            settings.aoDrawCallback.push({
-                "fn": _fnScrollDraw,
-                "sName": "scrolling"
-            });
-
-            return scroller[0];
-        }
-
-
-
-        /**
-         * Update the header, footer and body tables for resizing - i.e. column
-         * alignment.
-         *
-         * Welcome to the most horrible function DataTables. The process that this
-         * function follows is basically:
-         *   1. Re-create the table inside the scrolling div
-         *   2. Take live measurements from the DOM
-         *   3. Apply the measurements to align the columns
-         *   4. Clean up
-         *
-         *  @param {object} settings dataTables settings object
-         *  @memberof DataTable#oApi
-         */
-        function _fnScrollDraw(settings) {
-            // Given that this is such a monster function, a lot of variables are use
-            // to try and keep the minimised size as small as possible
-            var
-                scroll = settings.oScroll,
-                scrollX = scroll.sX,
-                scrollXInner = scroll.sXInner,
-                scrollY = scroll.sY,
-                barWidth = scroll.iBarWidth,
-                divHeader = $(settings.nScrollHead),
-                divHeaderStyle = divHeader[0].style,
-                divHeaderInner = divHeader.children('div'),
-                divHeaderInnerStyle = divHeaderInner[0].style,
-                divHeaderTable = divHeaderInner.children('table'),
-                divBodyEl = settings.nScrollBody,
-                divBody = $(divBodyEl),
-                divBodyStyle = divBodyEl.style,
-                divFooter = $(settings.nScrollFoot),
-                divFooterInner = divFooter.children('div'),
-                divFooterTable = divFooterInner.children('table'),
-                header = $(settings.nTHead),
-                table = $(settings.nTable),
-                tableEl = table[0],
-                tableStyle = tableEl.style,
-                footer = settings.nTFoot ? $(settings.nTFoot) : null,
-                browser = settings.oBrowser,
-                ie67 = browser.bScrollOversize,
-                headerTrgEls, footerTrgEls,
-                headerSrcEls, footerSrcEls,
-                headerCopy, footerCopy,
-                headerWidths = [], footerWidths = [],
-                headerContent = [],
-                idx, correction, sanityWidth,
-                zeroOut = function (nSizer) {
-                    var style = nSizer.style;
-                    style.paddingTop = "0";
-                    style.paddingBottom = "0";
-                    style.borderTopWidth = "0";
-                    style.borderBottomWidth = "0";
-                    style.height = 0;
-                };
-
-            /*
-             * 1. Re-create the table inside the scrolling div
-             */
-
-            // Remove the old minimised thead and tfoot elements in the inner table
-            table.children('thead, tfoot').remove();
-
-            // Clone the current header and footer elements and then place it into the inner table
-            headerCopy = header.clone().prependTo(table);
-            headerTrgEls = header.find('tr'); // original header is in its own table
-            headerSrcEls = headerCopy.find('tr');
-            headerCopy.find('th, td').removeAttr('tabindex');
-
-            if (footer) {
-                footerCopy = footer.clone().prependTo(table);
-                footerTrgEls = footer.find('tr'); // the original tfoot is in its own table and must be sized
-                footerSrcEls = footerCopy.find('tr');
-            }
-
-
-            /*
-             * 2. Take live measurements from the DOM - do not alter the DOM itself!
-             */
-
-            // Remove old sizing and apply the calculated column widths
-            // Get the unique column headers in the newly created (cloned) header. We want to apply the
-            // calculated sizes to this header
-            if (!scrollX) {
-                divBodyStyle.width = '100%';
-                divHeader[0].style.width = '100%';
-            }
-
-            $.each(_fnGetUniqueThs(settings, headerCopy), function (i, el) {
-                idx = _fnVisibleToColumnIndex(settings, i);
-                el.style.width = settings.aoColumns[idx].sWidth;
-            });
-
-            if (footer) {
-                _fnApplyToChildren(function (n) {
-                    n.style.width = "";
-                }, footerSrcEls);
-            }
-
-            // If scroll collapse is enabled, when we put the headers back into the body for sizing, we
-            // will end up forcing the scrollbar to appear, making our measurements wrong for when we
-            // then hide it (end of this function), so add the header height to the body scroller.
-            if (scroll.bCollapse && scrollY !== "") {
-                divBodyStyle.height = (divBody[0].offsetHeight + header[0].offsetHeight) + "px";
-            }
-
-            // Size the table as a whole
-            sanityWidth = table.outerWidth();
-            if (scrollX === "") {
-                // No x scrolling
-                tableStyle.width = "100%";
-
-                // IE7 will make the width of the table when 100% include the scrollbar
-                // - which is shouldn't. When there is a scrollbar we need to take this
-                // into account.
-                if (ie67 && (table.find('tbody').height() > divBodyEl.offsetHeight ||
-                    divBody.css('overflow-y') == "scroll")
-                ) {
-                    tableStyle.width = _fnStringToCss(table.outerWidth() - barWidth);
-                }
-            }
-            else {
-                // x scrolling
-                if (scrollXInner !== "") {
-                    // x scroll inner has been given - use it
-                    tableStyle.width = _fnStringToCss(scrollXInner);
-                }
-                else if (sanityWidth == divBody.width() && divBody.height() < table.height()) {
-                    // There is y-scrolling - try to take account of the y scroll bar
-                    tableStyle.width = _fnStringToCss(sanityWidth - barWidth);
-                    if (table.outerWidth() > sanityWidth - barWidth) {
-                        // Not possible to take account of it
-                        tableStyle.width = _fnStringToCss(sanityWidth);
-                    }
-                }
-                else {
-                    // When all else fails
-                    tableStyle.width = _fnStringToCss(sanityWidth);
-                }
-            }
-
-            // Recalculate the sanity width - now that we've applied the required width,
-            // before it was a temporary variable. This is required because the column
-            // width calculation is done before this table DOM is created.
-            sanityWidth = table.outerWidth();
-
-            // Hidden header should have zero height, so remove padding and borders. Then
-            // set the width based on the real headers
-
-            // Apply all styles in one pass
-            _fnApplyToChildren(zeroOut, headerSrcEls);
-
-            // Read all widths in next pass
-            _fnApplyToChildren(function (nSizer) {
-                headerContent.push(nSizer.innerHTML);
-                headerWidths.push(_fnStringToCss($(nSizer).css('width')));
-            }, headerSrcEls);
-
-            // Apply all widths in final pass
-            _fnApplyToChildren(function (nToSize, i) {
-                nToSize.style.width = headerWidths[i];
-            }, headerTrgEls);
-
-            $(headerSrcEls).height(0);
-
-            /* Same again with the footer if we have one */
-            if (footer) {
-                _fnApplyToChildren(zeroOut, footerSrcEls);
-
-                _fnApplyToChildren(function (nSizer) {
-                    footerWidths.push(_fnStringToCss($(nSizer).css('width')));
-                }, footerSrcEls);
-
-                _fnApplyToChildren(function (nToSize, i) {
-                    nToSize.style.width = footerWidths[i];
-                }, footerTrgEls);
-
-                $(footerSrcEls).height(0);
-            }
-
-
-            /*
-             * 3. Apply the measurements
-             */
-
-            // "Hide" the header and footer that we used for the sizing. We need to keep
-            // the content of the cell so that the width applied to the header and body
-            // both match, but we want to hide it completely. We want to also fix their
-            // width to what they currently are
-            _fnApplyToChildren(function (nSizer, i) {
-                nSizer.innerHTML = '<div class="dataTables_sizing" style="height:0;overflow:hidden;">' + headerContent[i] + '</div>';
-                nSizer.style.width = headerWidths[i];
-            }, headerSrcEls);
-
-            if (footer) {
-                _fnApplyToChildren(function (nSizer, i) {
-                    nSizer.innerHTML = "";
-                    nSizer.style.width = footerWidths[i];
-                }, footerSrcEls);
-            }
-
-            // Sanity check that the table is of a sensible width. If not then we are going to get
-            // misalignment - try to prevent this by not allowing the table to shrink below its min width
-            if (table.outerWidth() < sanityWidth) {
-                // The min width depends upon if we have a vertical scrollbar visible or not */
-                correction = ((divBodyEl.scrollHeight > divBodyEl.offsetHeight ||
-                    divBody.css('overflow-y') == "scroll")) ?
-                        sanityWidth + barWidth :
-                        sanityWidth;
-
-                // IE6/7 are a law unto themselves...
-                if (ie67 && (divBodyEl.scrollHeight >
-                    divBodyEl.offsetHeight || divBody.css('overflow-y') == "scroll")
-                ) {
-                    tableStyle.width = _fnStringToCss(correction - barWidth);
-                }
-
-                // And give the user a warning that we've stopped the table getting too small
-                if (scrollX === "" || scrollXInner !== "") {
-                    _fnLog(settings, 1, 'Possible column misalignment', 6);
-                }
-            }
-            else {
-                correction = '100%';
-            }
-
-            // Apply to the container elements
-            divBodyStyle.width = _fnStringToCss(correction);
-            divHeaderStyle.width = _fnStringToCss(correction);
-
-            if (footer) {
-                settings.nScrollFoot.style.width = _fnStringToCss(correction);
-            }
-
-
-            /*
-             * 4. Clean up
-             */
-            if (!scrollY) {
-                /* IE7< puts a vertical scrollbar in place (when it shouldn't be) due to subtracting
-                 * the scrollbar height from the visible display, rather than adding it on. We need to
-                 * set the height in order to sort this. Don't want to do it in any other browsers.
-                 */
-                if (ie67) {
-                    divBodyStyle.height = _fnStringToCss(tableEl.offsetHeight + barWidth);
-                }
-            }
-
-            if (scrollY && scroll.bCollapse) {
-                divBodyStyle.height = _fnStringToCss(scrollY);
-
-                var iExtra = (scrollX && tableEl.offsetWidth > divBodyEl.offsetWidth) ?
-                    barWidth :
-                    0;
-
-                if (tableEl.offsetHeight < divBodyEl.offsetHeight) {
-                    divBodyStyle.height = _fnStringToCss(tableEl.offsetHeight + iExtra);
-                }
-            }
-
-            /* Finally set the width's of the header and footer tables */
-            var iOuterWidth = table.outerWidth();
-            divHeaderTable[0].style.width = _fnStringToCss(iOuterWidth);
-            divHeaderInnerStyle.width = _fnStringToCss(iOuterWidth);
-
-            // Figure out if there are scrollbar present - if so then we need a the header and footer to
-            // provide a bit more space to allow "overflow" scrolling (i.e. past the scrollbar)
-            var bScrolling = table.height() > divBodyEl.clientHeight || divBody.css('overflow-y') == "scroll";
-            var padding = 'padding' + (browser.bScrollbarLeft ? 'Left' : 'Right');
-            divHeaderInnerStyle[padding] = bScrolling ? barWidth + "px" : "0px";
-
-            if (footer) {
-                divFooterTable[0].style.width = _fnStringToCss(iOuterWidth);
-                divFooterInner[0].style.width = _fnStringToCss(iOuterWidth);
-                divFooterInner[0].style[padding] = bScrolling ? barWidth + "px" : "0px";
-            }
-
-            /* Adjust the position of the header in case we loose the y-scrollbar */
-            divBody.scroll();
-
-            // If sorting or filtering has occurred, jump the scrolling back to the top
-            // only if we aren't holding the position
-            if ((settings.bSorted || settings.bFiltered) && !settings._drawHold) {
-                divBodyEl.scrollTop = 0;
-            }
-        }
-
-
-
-        /**
-         * Apply a given function to the display child nodes of an element array (typically
-         * TD children of TR rows
-         *  @param {function} fn Method to apply to the objects
-         *  @param array {nodes} an1 List of elements to look through for display children
-         *  @param array {nodes} an2 Another list (identical structure to the first) - optional
-         *  @memberof DataTable#oApi
-         */
-        function _fnApplyToChildren(fn, an1, an2) {
-            var index = 0, i = 0, iLen = an1.length;
-            var nNode1, nNode2;
-
-            while (i < iLen) {
-                nNode1 = an1[i].firstChild;
-                nNode2 = an2 ? an2[i].firstChild : null;
-
-                while (nNode1) {
-                    if (nNode1.nodeType === 1) {
-                        if (an2) {
-                            fn(nNode1, nNode2, index);
-                        }
-                        else {
-                            fn(nNode1, index);
-                        }
-
-                        index++;
-                    }
-
-                    nNode1 = nNode1.nextSibling;
-                    nNode2 = an2 ? nNode2.nextSibling : null;
-                }
-
-                i++;
-            }
-        }
-
-
-
-        var __re_html_remove = /<.*?>/g;
-
-
-        /**
-         * Calculate the width of columns for the table
-         *  @param {object} oSettings dataTables settings object
-         *  @memberof DataTable#oApi
-         */
-        function _fnCalculateColumnWidths(oSettings) {
-            var
-                table = oSettings.nTable,
-                columns = oSettings.aoColumns,
-                scroll = oSettings.oScroll,
-                scrollY = scroll.sY,
-                scrollX = scroll.sX,
-                scrollXInner = scroll.sXInner,
-                columnCount = columns.length,
-                visibleColumns = _fnGetColumns(oSettings, 'bVisible'),
-                headerCells = $('th', oSettings.nTHead),
-                tableWidthAttr = table.getAttribute('width'), // from DOM element
-                tableContainer = table.parentNode,
-                userInputs = false,
-                i, column, columnIdx, width, outerWidth;
-
-            var styleWidth = table.style.width;
-            if (styleWidth && styleWidth.indexOf('%') !== -1) {
-                tableWidthAttr = styleWidth;
-            }
-
-            /* Convert any user input sizes into pixel sizes */
-            for (i = 0 ; i < visibleColumns.length ; i++) {
-                column = columns[visibleColumns[i]];
-
-                if (column.sWidth !== null) {
-                    column.sWidth = _fnConvertToWidth(column.sWidthOrig, tableContainer);
-
-                    userInputs = true;
-                }
-            }
-
-            /* If the number of columns in the DOM equals the number that we have to
-             * process in DataTables, then we can use the offsets that are created by
-             * the web- browser. No custom sizes can be set in order for this to happen,
-             * nor scrolling used
-             */
-            if (!userInputs && !scrollX && !scrollY &&
-                columnCount == _fnVisbleColumns(oSettings) &&
-                columnCount == headerCells.length
-            ) {
-                for (i = 0 ; i < columnCount ; i++) {
-                    columns[i].sWidth = _fnStringToCss(headerCells.eq(i).width());
-                }
-            }
-            else {
-                // Otherwise construct a single row, worst case, table with the widest
-                // node in the data, assign any user defined widths, then insert it into
-                // the DOM and allow the browser to do all the hard work of calculating
-                // table widths
-                var tmpTable = $(table).clone() // don't use cloneNode - IE8 will remove events on the main table
-                    .css('visibility', 'hidden')
-                    .removeAttr('id');
-
-                // Clean up the table body
-                tmpTable.find('tbody tr').remove();
-                var tr = $('<tr/>').appendTo(tmpTable.find('tbody'));
-
-                // Remove any assigned widths from the footer (from scrolling)
-                tmpTable.find('tfoot th, tfoot td').css('width', '');
-
-                // Apply custom sizing to the cloned header
-                headerCells = _fnGetUniqueThs(oSettings, tmpTable.find('thead')[0]);
-
-                for (i = 0 ; i < visibleColumns.length ; i++) {
-                    column = columns[visibleColumns[i]];
-
-                    headerCells[i].style.width = column.sWidthOrig !== null && column.sWidthOrig !== '' ?
-                        _fnStringToCss(column.sWidthOrig) :
-                        '';
-                }
-
-                // Find the widest cell for each column and put it into the table
-                if (oSettings.aoData.length) {
-                    for (i = 0 ; i < visibleColumns.length ; i++) {
-                        columnIdx = visibleColumns[i];
-                        column = columns[columnIdx];
-
-                        $(_fnGetWidestNode(oSettings, columnIdx))
-                            .clone(false)
-                            .append(column.sContentPadding)
-                            .appendTo(tr);
-                    }
-                }
-
-                // Table has been built, attach to the document so we can work with it
-                tmpTable.appendTo(tableContainer);
-
-                // When scrolling (X or Y) we want to set the width of the table as 
-                // appropriate. However, when not scrolling leave the table width as it
-                // is. This results in slightly different, but I think correct behaviour
-                if (scrollX && scrollXInner) {
-                    tmpTable.width(scrollXInner);
-                }
-                else if (scrollX) {
-                    tmpTable.css('width', 'auto');
-
-                    if (tmpTable.width() < tableContainer.offsetWidth) {
-                        tmpTable.width(tableContainer.offsetWidth);
-                    }
-                }
-                else if (scrollY) {
-                    tmpTable.width(tableContainer.offsetWidth);
-                }
-                else if (tableWidthAttr) {
-                    tmpTable.width(tableWidthAttr);
-                }
-
-                // Take into account the y scrollbar
-                _fnScrollingWidthAdjust(oSettings, tmpTable[0]);
-
-                // Browsers need a bit of a hand when a width is assigned to any columns
-                // when x-scrolling as they tend to collapse the table to the min-width,
-                // even if we sent the column widths. So we need to keep track of what
-                // the table width should be by summing the user given values, and the
-                // automatic values
-                if (scrollX) {
-                    var total = 0;
-
-                    for (i = 0 ; i < visibleColumns.length ; i++) {
-                        column = columns[visibleColumns[i]];
-                        outerWidth = $(headerCells[i]).outerWidth();
-
-                        total += column.sWidthOrig === null ?
-                            outerWidth :
-                            parseInt(column.sWidth, 10) + outerWidth - $(headerCells[i]).width();
-                    }
-
-                    tmpTable.width(_fnStringToCss(total));
-                    table.style.width = _fnStringToCss(total);
-                }
-
-                // Get the width of each column in the constructed table
-                for (i = 0 ; i < visibleColumns.length ; i++) {
-                    column = columns[visibleColumns[i]];
-                    width = $(headerCells[i]).width();
-
-                    if (width) {
-                        column.sWidth = _fnStringToCss(width);
-                    }
-                }
-
-                table.style.width = _fnStringToCss(tmpTable.css('width'));
-
-                // Finished with the table - ditch it
-                tmpTable.remove();
-            }
-
-            // If there is a width attr, we want to attach an event listener which
-            // allows the table sizing to automatically adjust when the window is
-            // resized. Use the width attr rather than CSS, since we can't know if the
-            // CSS is a relative value or absolute - DOM read is always px.
-            if (tableWidthAttr) {
-                table.style.width = _fnStringToCss(tableWidthAttr);
-            }
-
-            if ((tableWidthAttr || scrollX) && !oSettings._reszEvt) {
-                var bindResize = function () {
-                    $(window).bind('resize.DT-' + oSettings.sInstance, _fnThrottle(function () {
-                        _fnAdjustColumnSizing(oSettings);
-                    }));
-                };
-
-                // IE6/7 will crash if we bind a resize event handler on page load.
-                // To be removed in 1.11 which drops IE6/7 support
-                if (oSettings.oBrowser.bScrollOversize) {
-                    setTimeout(bindResize, 1000);
-                }
-                else {
-                    bindResize();
-                }
-
-                oSettings._reszEvt = true;
-            }
-        }
-
-
-        /**
-         * Throttle the calls to a function. Arguments and context are maintained for
-         * the throttled function
-         *  @param {function} fn Function to be called
-         *  @param {int} [freq=200] call frequency in mS
-         *  @returns {function} wrapped function
-         *  @memberof DataTable#oApi
-         */
-        function _fnThrottle(fn, freq) {
-            var
-                frequency = freq !== undefined ? freq : 200,
-                last,
-                timer;
-
-            return function () {
-                var
-                    that = this,
-                    now = +new Date(),
-                    args = arguments;
-
-                if (last && now < last + frequency) {
-                    clearTimeout(timer);
-
-                    timer = setTimeout(function () {
-                        last = undefined;
-                        fn.apply(that, args);
-                    }, frequency);
-                }
-                else {
-                    last = now;
-                    fn.apply(that, args);
-                }
-            };
-        }
-
-
-        /**
-         * Convert a CSS unit width to pixels (e.g. 2em)
-         *  @param {string} width width to be converted
-         *  @param {node} parent parent to get the with for (required for relative widths) - optional
-         *  @returns {int} width in pixels
-         *  @memberof DataTable#oApi
-         */
-        function _fnConvertToWidth(width, parent) {
-            if (!width) {
-                return 0;
-            }
-
-            var n = $('<div/>')
-                .css('width', _fnStringToCss(width))
-                .appendTo(parent || document.body);
-
-            var val = n[0].offsetWidth;
-            n.remove();
-
-            return val;
-        }
-
-
-        /**
-         * Adjust a table's width to take account of vertical scroll bar
-         *  @param {object} oSettings dataTables settings object
-         *  @param {node} n table node
-         *  @memberof DataTable#oApi
-         */
-
-        function _fnScrollingWidthAdjust(settings, n) {
-            var scroll = settings.oScroll;
-
-            if (scroll.sX || scroll.sY) {
-                // When y-scrolling only, we want to remove the width of the scroll bar
-                // so the table + scroll bar will fit into the area available, otherwise
-                // we fix the table at its current size with no adjustment
-                var correction = !scroll.sX ? scroll.iBarWidth : 0;
-                n.style.width = _fnStringToCss($(n).outerWidth() - correction);
-            }
-        }
-
-
-        /**
-         * Get the widest node
-         *  @param {object} settings dataTables settings object
-         *  @param {int} colIdx column of interest
-         *  @returns {node} widest table node
-         *  @memberof DataTable#oApi
-         */
-        function _fnGetWidestNode(settings, colIdx) {
-            var idx = _fnGetMaxLenString(settings, colIdx);
-            if (idx < 0) {
-                return null;
-            }
-
-            var data = settings.aoData[idx];
-            return !data.nTr ? // Might not have been created when deferred rendering
-                $('<td/>').html(_fnGetCellData(settings, idx, colIdx, 'display'))[0] :
-                data.anCells[colIdx];
-        }
-
-
-        /**
-         * Get the maximum strlen for each data column
-         *  @param {object} settings dataTables settings object
-         *  @param {int} colIdx column of interest
-         *  @returns {string} max string length for each column
-         *  @memberof DataTable#oApi
-         */
-        function _fnGetMaxLenString(settings, colIdx) {
-            var s, max = -1, maxIdx = -1;
-
-            for (var i = 0, ien = settings.aoData.length ; i < ien ; i++) {
-                s = _fnGetCellData(settings, i, colIdx, 'display') + '';
-                s = s.replace(__re_html_remove, '');
-
-                if (s.length > max) {
-                    max = s.length;
-                    maxIdx = i;
-                }
-            }
-
-            return maxIdx;
-        }
-
-
-        /**
-         * Append a CSS unit (only if required) to a string
-         *  @param {string} value to css-ify
-         *  @returns {string} value with css unit
-         *  @memberof DataTable#oApi
-         */
-        function _fnStringToCss(s) {
-            if (s === null) {
-                return '0px';
-            }
-
-            if (typeof s == 'number') {
-                return s < 0 ?
-                    '0px' :
-                    s + 'px';
-            }
-
-            // Check it has a unit character already
-            return s.match(/\d$/) ?
-                s + 'px' :
-                s;
-        }
-
-
-        /**
-         * Get the width of a scroll bar in this browser being used
-         *  @returns {int} width in pixels
-         *  @memberof DataTable#oApi
-         */
-        function _fnScrollBarWidth() {
-            // On first run a static variable is set, since this is only needed once.
-            // Subsequent runs will just use the previously calculated value
-            var width = DataTable.__scrollbarWidth;
-
-            if (width === undefined) {
-                var sizer = $('<p/>').css({
-                    position: 'absolute',
-                    top: 0,
-                    left: 0,
-                    width: '100%',
-                    height: 150,
-                    padding: 0,
-                    overflow: 'scroll',
-                    visibility: 'hidden'
-                })
-                    .appendTo('body');
-
-                width = sizer[0].offsetWidth - sizer[0].clientWidth;
-                DataTable.__scrollbarWidth = width;
-
-                sizer.remove();
-            }
-
-            return width;
-        }
-
-
-
-        function _fnSortFlatten(settings) {
-            var
-                i, iLen, k, kLen,
-                aSort = [],
-                aiOrig = [],
-                aoColumns = settings.aoColumns,
-                aDataSort, iCol, sType, srcCol,
-                fixed = settings.aaSortingFixed,
-                fixedObj = $.isPlainObject(fixed),
-                nestedSort = [],
-                add = function (a) {
-                    if (a.length && !$.isArray(a[0])) {
-                        // 1D array
-                        nestedSort.push(a);
-                    }
-                    else {
-                        // 2D array
-                        nestedSort.push.apply(nestedSort, a);
-                    }
-                };
-
-            // Build the sort array, with pre-fix and post-fix options if they have been
-            // specified
-            if ($.isArray(fixed)) {
-                add(fixed);
-            }
-
-            if (fixedObj && fixed.pre) {
-                add(fixed.pre);
-            }
-
-            add(settings.aaSorting);
-
-            if (fixedObj && fixed.post) {
-                add(fixed.post);
-            }
-
-            for (i = 0 ; i < nestedSort.length ; i++) {
-                srcCol = nestedSort[i][0];
-                aDataSort = aoColumns[srcCol].aDataSort;
-
-                for (k = 0, kLen = aDataSort.length ; k < kLen ; k++) {
-                    iCol = aDataSort[k];
-                    sType = aoColumns[iCol].sType || 'string';
-
-                    if (nestedSort[i]._idx === undefined) {
-                        nestedSort[i]._idx = $.inArray(nestedSort[i][1], aoColumns[iCol].asSorting);
-                    }
-
-                    aSort.push({
-                        src: srcCol,
-                        col: iCol,
-                        dir: nestedSort[i][1],
-                        index: nestedSort[i]._idx,
-                        type: sType,
-                        formatter: DataTable.ext.type.order[sType + "-pre"]
-                    });
-                }
-            }
-
-            return aSort;
-        }
-
-        /**
-         * Change the order of the table
-         *  @param {object} oSettings dataTables settings object
-         *  @memberof DataTable#oApi
-         *  @todo This really needs split up!
-         */
-        function _fnSort(oSettings) {
-            var
-                i, ien, iLen, j, jLen, k, kLen,
-                sDataType, nTh,
-                aiOrig = [],
-                oExtSort = DataTable.ext.type.order,
-                aoData = oSettings.aoData,
-                aoColumns = oSettings.aoColumns,
-                aDataSort, data, iCol, sType, oSort,
-                formatters = 0,
-                sortCol,
-                displayMaster = oSettings.aiDisplayMaster,
-                aSort;
-
-            // Resolve any column types that are unknown due to addition or invalidation
-            // @todo Can this be moved into a 'data-ready' handler which is called when
-            //   data is going to be used in the table?
-            _fnColumnTypes(oSettings);
-
-            aSort = _fnSortFlatten(oSettings);
-
-            for (i = 0, ien = aSort.length ; i < ien ; i++) {
-                sortCol = aSort[i];
-
-                // Track if we can use the fast sort algorithm
-                if (sortCol.formatter) {
-                    formatters++;
-                }
-
-                // Load the data needed for the sort, for each cell
-                _fnSortData(oSettings, sortCol.col);
-            }
-
-            /* No sorting required if server-side or no sorting array */
-            if (_fnDataSource(oSettings) != 'ssp' && aSort.length !== 0) {
-                // Create a value - key array of the current row positions such that we can use their
-                // current position during the sort, if values match, in order to perform stable sorting
-                for (i = 0, iLen = displayMaster.length ; i < iLen ; i++) {
-                    aiOrig[displayMaster[i]] = i;
-                }
-
-                /* Do the sort - here we want multi-column sorting based on a given data source (column)
-                 * and sorting function (from oSort) in a certain direction. It's reasonably complex to
-                 * follow on it's own, but this is what we want (example two column sorting):
-                 *  fnLocalSorting = function(a,b){
-                 *    var iTest;
-                 *    iTest = oSort['string-asc']('data11', 'data12');
-                 *      if (iTest !== 0)
-                 *        return iTest;
-                 *    iTest = oSort['numeric-desc']('data21', 'data22');
-                 *    if (iTest !== 0)
-                 *      return iTest;
-                 *    return oSort['numeric-asc']( aiOrig[a], aiOrig[b] );
-                 *  }
-                 * Basically we have a test for each sorting column, if the data in that column is equal,
-                 * test the next column. If all columns match, then we use a numeric sort on the row
-                 * positions in the original data array to provide a stable sort.
-                 *
-                 * Note - I know it seems excessive to have two sorting methods, but the first is around
-                 * 15% faster, so the second is only maintained for backwards compatibility with sorting
-                 * methods which do not have a pre-sort formatting function.
-                 */
-                if (formatters === aSort.length) {
-                    // All sort types have formatting functions
-                    displayMaster.sort(function (a, b) {
-                        var
-                            x, y, k, test, sort,
-                            len = aSort.length,
-                            dataA = aoData[a]._aSortData,
-                            dataB = aoData[b]._aSortData;
-
-                        for (k = 0 ; k < len ; k++) {
-                            sort = aSort[k];
-
-                            x = dataA[sort.col];
-                            y = dataB[sort.col];
-
-                            test = x < y ? -1 : x > y ? 1 : 0;
-                            if (test !== 0) {
-                                return sort.dir === 'asc' ? test : -test;
-                            }
-                        }
-
-                        x = aiOrig[a];
-                        y = aiOrig[b];
-                        return x < y ? -1 : x > y ? 1 : 0;
-                    });
-                }
-                else {
-                    // Depreciated - remove in 1.11 (providing a plug-in option)
-                    // Not all sort types have formatting methods, so we have to call their sorting
-                    // methods.
-                    displayMaster.sort(function (a, b) {
-                        var
-                            x, y, k, l, test, sort, fn,
-                            len = aSort.length,
-                            dataA = aoData[a]._aSortData,
-                            dataB = aoData[b]._aSortData;
-
-                        for (k = 0 ; k < len ; k++) {
-                            sort = aSort[k];
-
-                            x = dataA[sort.col];
-                            y = dataB[sort.col];
-
-                            fn = oExtSort[sort.type + "-" + sort.dir] || oExtSort["string-" + sort.dir];
-                            test = fn(x, y);
-                            if (test !== 0) {
-                                return test;
-                            }
-                        }
-
-                        x = aiOrig[a];
-                        y = aiOrig[b];
-                        return x < y ? -1 : x > y ? 1 : 0;
-                    });
-                }
-            }
-
-            /* Tell the draw function that we have sorted the data */
-            oSettings.bSorted = true;
-        }
-
-
-        function _fnSortAria(settings) {
-            var label;
-            var nextSort;
-            var columns = settings.aoColumns;
-            var aSort = _fnSortFlatten(settings);
-            var oAria = settings.oLanguage.oAria;
-
-            // ARIA attributes - need to loop all columns, to update all (removing old
-            // attributes as needed)
-            for (var i = 0, iLen = columns.length ; i < iLen ; i++) {
-                var col = columns[i];
-                var asSorting = col.asSorting;
-                var sTitle = col.sTitle.replace(/<.*?>/g, "");
-                var th = col.nTh;
-
-                // IE7 is throwing an error when setting these properties with jQuery's
-                // attr() and removeAttr() methods...
-                th.removeAttribute('aria-sort');
-
-                /* In ARIA only the first sorting column can be marked as sorting - no multi-sort option */
-                if (col.bSortable) {
-                    if (aSort.length > 0 && aSort[0].col == i) {
-                        th.setAttribute('aria-sort', aSort[0].dir == "asc" ? "ascending" : "descending");
-                        nextSort = asSorting[aSort[0].index + 1] || asSorting[0];
-                    }
-                    else {
-                        nextSort = asSorting[0];
-                    }
-
-                    label = sTitle + (nextSort === "asc" ?
-                        oAria.sSortAscending :
-                        oAria.sSortDescending
-                    );
-                }
-                else {
-                    label = sTitle;
-                }
-
-                th.setAttribute('aria-label', label);
-            }
-        }
-
-
-        /**
-         * Function to run on user sort request
-         *  @param {object} settings dataTables settings object
-         *  @param {node} attachTo node to attach the handler to
-         *  @param {int} colIdx column sorting index
-         *  @param {boolean} [append=false] Append the requested sort to the existing
-         *    sort if true (i.e. multi-column sort)
-         *  @param {function} [callback] callback function
-         *  @memberof DataTable#oApi
-         */
-        function _fnSortListener(settings, colIdx, append, callback) {
-            var col = settings.aoColumns[colIdx];
-            var sorting = settings.aaSorting;
-            var asSorting = col.asSorting;
-            var nextSortIdx;
-            var next = function (a, overflow) {
-                var idx = a._idx;
-                if (idx === undefined) {
-                    idx = $.inArray(a[1], asSorting);
-                }
-
-                return idx + 1 < asSorting.length ?
-                    idx + 1 :
-                    overflow ?
-                        null :
-                        0;
-            };
-
-            // Convert to 2D array if needed
-            if (typeof sorting[0] === 'number') {
-                sorting = settings.aaSorting = [sorting];
-            }
-
-            // If appending the sort then we are multi-column sorting
-            if (append && settings.oFeatures.bSortMulti) {
-                // Are we already doing some kind of sort on this column?
-                var sortIdx = $.inArray(colIdx, _pluck(sorting, '0'));
-
-                if (sortIdx !== -1) {
-                    // Yes, modify the sort
-                    nextSortIdx = next(sorting[sortIdx], true);
-
-                    if (nextSortIdx === null && sorting.length === 1) {
-                        nextSortIdx = 0; // can't remove sorting completely
-                    }
-
-                    if (nextSortIdx === null) {
-                        sorting.splice(sortIdx, 1);
-                    }
-                    else {
-                        sorting[sortIdx][1] = asSorting[nextSortIdx];
-                        sorting[sortIdx]._idx = nextSortIdx;
-                    }
-                }
-                else {
-                    // No sort on this column yet
-                    sorting.push([colIdx, asSorting[0], 0]);
-                    sorting[sorting.length - 1]._idx = 0;
-                }
-            }
-            else if (sorting.length && sorting[0][0] == colIdx) {
-                // Single column - already sorting on this column, modify the sort
-                nextSortIdx = next(sorting[0]);
-
-                sorting.length = 1;
-                sorting[0][1] = asSorting[nextSortIdx];
-                sorting[0]._idx = nextSortIdx;
-            }
-            else {
-                // Single column - sort only on this column
-                sorting.length = 0;
-                sorting.push([colIdx, asSorting[0]]);
-                sorting[0]._idx = 0;
-            }
-
-            // Run the sort by calling a full redraw
-            _fnReDraw(settings);
-
-            // callback used for async user interaction
-            if (typeof callback == 'function') {
-                callback(settings);
-            }
-        }
-
-
-        /**
-         * Attach a sort handler (click) to a node
-         *  @param {object} settings dataTables settings object
-         *  @param {node} attachTo node to attach the handler to
-         *  @param {int} colIdx column sorting index
-         *  @param {function} [callback] callback function
-         *  @memberof DataTable#oApi
-         */
-        function _fnSortAttachListener(settings, attachTo, colIdx, callback) {
-            var col = settings.aoColumns[colIdx];
-
-            _fnBindAction(attachTo, {}, function (e) {
-                /* If the column is not sortable - don't to anything */
-                if (col.bSortable === false) {
-                    return;
-                }
-
-                // If processing is enabled use a timeout to allow the processing
-                // display to be shown - otherwise to it synchronously
-                if (settings.oFeatures.bProcessing) {
-                    _fnProcessingDisplay(settings, true);
-
-                    setTimeout(function () {
-                        _fnSortListener(settings, colIdx, e.shiftKey, callback);
-
-                        // In server-side processing, the draw callback will remove the
-                        // processing display
-                        if (_fnDataSource(settings) !== 'ssp') {
-                            _fnProcessingDisplay(settings, false);
-                        }
-                    }, 0);
-                }
-                else {
-                    _fnSortListener(settings, colIdx, e.shiftKey, callback);
-                }
-            });
-        }
-
-
-        /**
-         * Set the sorting classes on table's body, Note: it is safe to call this function
-         * when bSort and bSortClasses are false
-         *  @param {object} oSettings dataTables settings object
-         *  @memberof DataTable#oApi
-         */
-        function _fnSortingClasses(settings) {
-            var oldSort = settings.aLastSort;
-            var sortClass = settings.oClasses.sSortColumn;
-            var sort = _fnSortFlatten(settings);
-            var features = settings.oFeatures;
-            var i, ien, colIdx;
-
-            if (features.bSort && features.bSortClasses) {
-                // Remove old sorting classes
-                for (i = 0, ien = oldSort.length ; i < ien ; i++) {
-                    colIdx = oldSort[i].src;
-
-                    // Remove column sorting
-                    $(_pluck(settings.aoData, 'anCells', colIdx))
-                        .removeClass(sortClass + (i < 2 ? i + 1 : 3));
-                }
-
-                // Add new column sorting
-                for (i = 0, ien = sort.length ; i < ien ; i++) {
-                    colIdx = sort[i].src;
-
-                    $(_pluck(settings.aoData, 'anCells', colIdx))
-                        .addClass(sortClass + (i < 2 ? i + 1 : 3));
-                }
-            }
-
-            settings.aLastSort = sort;
-        }
-
-
-        // Get the data to sort a column, be it from cache, fresh (populating the
-        // cache), or from a sort formatter
-        function _fnSortData(settings, idx) {
-            // Custom sorting function - provided by the sort data type
-            var column = settings.aoColumns[idx];
-            var customSort = DataTable.ext.order[column.sSortDataType];
-            var customData;
-
-            if (customSort) {
-                customData = customSort.call(settings.oInstance, settings, idx,
-                    _fnColumnIndexToVisible(settings, idx)
-                );
-            }
-
-            // Use / populate cache
-            var row, cellData;
-            var formatter = DataTable.ext.type.order[column.sType + "-pre"];
-
-            for (var i = 0, ien = settings.aoData.length ; i < ien ; i++) {
-                row = settings.aoData[i];
-
-                if (!row._aSortData) {
-                    row._aSortData = [];
-                }
-
-                if (!row._aSortData[idx] || customSort) {
-                    cellData = customSort ?
-                        customData[i] : // If there was a custom sort function, use data from there
-                        _fnGetCellData(settings, i, idx, 'sort');
-
-                    row._aSortData[idx] = formatter ?
-                        formatter(cellData) :
-                        cellData;
-                }
-            }
-        }
-
-
-
-        /**
-         * Save the state of a table
-         *  @param {object} oSettings dataTables settings object
-         *  @memberof DataTable#oApi
-         */
-        function _fnSaveState(settings) {
-            if (!settings.oFeatures.bStateSave || settings.bDestroying) {
-                return;
-            }
-
-            /* Store the interesting variables */
-            var state = {
-                time: +new Date(),
-                start: settings._iDisplayStart,
-                length: settings._iDisplayLength,
-                order: $.extend(true, [], settings.aaSorting),
-                search: _fnSearchToCamel(settings.oPreviousSearch),
-                columns: $.map(settings.aoColumns, function (col, i) {
-                    return {
-                        visible: col.bVisible,
-                        search: _fnSearchToCamel(settings.aoPreSearchCols[i])
-                    };
-                })
-            };
-
-            _fnCallbackFire(settings, "aoStateSaveParams", 'stateSaveParams', [settings, state]);
-
-            settings.oSavedState = state;
-            settings.fnStateSaveCallback.call(settings.oInstance, settings, state);
-        }
-
-
-        /**
-         * Attempt to load a saved table state
-         *  @param {object} oSettings dataTables settings object
-         *  @param {object} oInit DataTables init object so we can override settings
-         *  @memberof DataTable#oApi
-         */
-        function _fnLoadState(settings, oInit) {
-            var i, ien;
-            var columns = settings.aoColumns;
-
-            if (!settings.oFeatures.bStateSave) {
-                return;
-            }
-
-            var state = settings.fnStateLoadCallback.call(settings.oInstance, settings);
-            if (!state || !state.time) {
-                return;
-            }
-
-            /* Allow custom and plug-in manipulation functions to alter the saved data set and
-             * cancelling of loading by returning false
-             */
-            var abStateLoad = _fnCallbackFire(settings, 'aoStateLoadParams', 'stateLoadParams', [settings, state]);
-            if ($.inArray(false, abStateLoad) !== -1) {
-                return;
-            }
-
-            /* Reject old data */
-            var duration = settings.iStateDuration;
-            if (duration > 0 && state.time < +new Date() - (duration * 1000)) {
-                return;
-            }
-
-            // Number of columns have changed - all bets are off, no restore of settings
-            if (columns.length !== state.columns.length) {
-                return;
-            }
-
-            // Store the saved state so it might be accessed at any time
-            settings.oLoadedState = $.extend(true, {}, state);
-
-            // Restore key features - todo - for 1.11 this needs to be done by
-            // subscribed events
-            if (state.start !== undefined) {
-                settings._iDisplayStart = state.start;
-                settings.iInitDisplayStart = state.start;
-            }
-            if (state.length !== undefined) {
-                settings._iDisplayLength = state.length;
-            }
-
-            // Order
-            if (state.order !== undefined) {
-                settings.aaSorting = [];
-                $.each(state.order, function (i, col) {
-                    settings.aaSorting.push(col[0] >= columns.length ?
-                        [0, col[1]] :
-                        col
-                    );
-                });
-            }
-
-            // Search
-            if (state.search !== undefined) {
-                $.extend(settings.oPreviousSearch, _fnSearchToHung(state.search));
-            }
-
-            // Columns
-            for (i = 0, ien = state.columns.length ; i < ien ; i++) {
-                var col = state.columns[i];
-
-                // Visibility
-                if (col.visible !== undefined) {
-                    columns[i].bVisible = col.visible;
-                }
-
-                // Search
-                if (col.search !== undefined) {
-                    $.extend(settings.aoPreSearchCols[i], _fnSearchToHung(col.search));
-                }
-            }
-
-            _fnCallbackFire(settings, 'aoStateLoaded', 'stateLoaded', [settings, state]);
-        }
-
-
-        /**
-         * Return the settings object for a particular table
-         *  @param {node} table table we are using as a dataTable
-         *  @returns {object} Settings object - or null if not found
-         *  @memberof DataTable#oApi
-         */
-        function _fnSettingsFromNode(table) {
-            var settings = DataTable.settings;
-            var idx = $.inArray(table, _pluck(settings, 'nTable'));
-
-            return idx !== -1 ?
-                settings[idx] :
-                null;
-        }
-
-
-        /**
-         * Log an error message
-         *  @param {object} settings dataTables settings object
-         *  @param {int} level log error messages, or display them to the user
-         *  @param {string} msg error message
-         *  @param {int} tn Technical note id to get more information about the error.
-         *  @memberof DataTable#oApi
-         */
-        function _fnLog(settings, level, msg, tn) {
-            msg = 'DataTables warning: ' +
-                (settings !== null ? 'table id=' + settings.sTableId + ' - ' : '') + msg;
-
-            if (tn) {
-                msg += '. For more information about this error, please see ' +
-                'http://datatables.net/tn/' + tn;
-            }
-
-            if (!level) {
-                // Backwards compatibility pre 1.10
-                var ext = DataTable.ext;
-                var type = ext.sErrMode || ext.errMode;
-
-                _fnCallbackFire(settings, null, 'error', [settings, tn, msg]);
-
-                if (type == 'alert') {
-                    alert(msg);
-                }
-                else if (type == 'throw') {
-                    throw new Error(msg);
-                }
-                else if (typeof type == 'function') {
-                    type(settings, tn, msg);
-                }
-            }
-            else if (window.console && console.log) {
-                console.log(msg);
-            }
-        }
-
-
-        /**
-         * See if a property is defined on one object, if so assign it to the other object
-         *  @param {object} ret target object
-         *  @param {object} src source object
-         *  @param {string} name property
-         *  @param {string} [mappedName] name to map too - optional, name used if not given
-         *  @memberof DataTable#oApi
-         */
-        function _fnMap(ret, src, name, mappedName) {
-            if ($.isArray(name)) {
-                $.each(name, function (i, val) {
-                    if ($.isArray(val)) {
-                        _fnMap(ret, src, val[0], val[1]);
-                    }
-                    else {
-                        _fnMap(ret, src, val);
-                    }
-                });
-
-                return;
-            }
-
-            if (mappedName === undefined) {
-                mappedName = name;
-            }
-
-            if (src[name] !== undefined) {
-                ret[mappedName] = src[name];
-            }
-        }
-
-
-        /**
-         * Extend objects - very similar to jQuery.extend, but deep copy objects, and
-         * shallow copy arrays. The reason we need to do this, is that we don't want to
-         * deep copy array init values (such as aaSorting) since the dev wouldn't be
-         * able to override them, but we do want to deep copy arrays.
-         *  @param {object} out Object to extend
-         *  @param {object} extender Object from which the properties will be applied to
-         *      out
-         *  @param {boolean} breakRefs If true, then arrays will be sliced to take an
-         *      independent copy with the exception of the `data` or `aaData` parameters
-         *      if they are present. This is so you can pass in a collection to
-         *      DataTables and have that used as your data source without breaking the
-         *      references
-         *  @returns {object} out Reference, just for convenience - out === the return.
-         *  @memberof DataTable#oApi
-         *  @todo This doesn't take account of arrays inside the deep copied objects.
-         */
-        function _fnExtend(out, extender, breakRefs) {
-            var val;
-
-            for (var prop in extender) {
-                if (extender.hasOwnProperty(prop)) {
-                    val = extender[prop];
-
-                    if ($.isPlainObject(val)) {
-                        if (!$.isPlainObject(out[prop])) {
-                            out[prop] = {};
-                        }
-                        $.extend(true, out[prop], val);
-                    }
-                    else if (breakRefs && prop !== 'data' && prop !== 'aaData' && $.isArray(val)) {
-                        out[prop] = val.slice();
-                    }
-                    else {
-                        out[prop] = val;
-                    }
-                }
-            }
-
-            return out;
-        }
-
-
-        /**
-         * Bind an event handers to allow a click or return key to activate the callback.
-         * This is good for accessibility since a return on the keyboard will have the
-         * same effect as a click, if the element has focus.
-         *  @param {element} n Element to bind the action to
-         *  @param {object} oData Data object to pass to the triggered function
-         *  @param {function} fn Callback function for when the event is triggered
-         *  @memberof DataTable#oApi
-         */
-        function _fnBindAction(n, oData, fn) {
-            $(n)
-                .bind('click.DT', oData, function (e) {
-                    n.blur(); // Remove focus outline for mouse users
-                    fn(e);
-                })
-                .bind('keypress.DT', oData, function (e) {
-                    if (e.which === 13) {
-                        e.preventDefault();
-                        fn(e);
-                    }
-                })
-                .bind('selectstart.DT', function () {
-                    /* Take the brutal approach to cancelling text selection */
-                    return false;
-                });
-        }
-
-
-        /**
-         * Register a callback function. Easily allows a callback function to be added to
-         * an array store of callback functions that can then all be called together.
-         *  @param {object} oSettings dataTables settings object
-         *  @param {string} sStore Name of the array storage for the callbacks in oSettings
-         *  @param {function} fn Function to be called back
-         *  @param {string} sName Identifying name for the callback (i.e. a label)
-         *  @memberof DataTable#oApi
-         */
-        function _fnCallbackReg(oSettings, sStore, fn, sName) {
-            if (fn) {
-                oSettings[sStore].push({
-                    "fn": fn,
-                    "sName": sName
-                });
-            }
-        }
-
-
-        /**
-         * Fire callback functions and trigger events. Note that the loop over the
-         * callback array store is done backwards! Further note that you do not want to
-         * fire off triggers in time sensitive applications (for example cell creation)
-         * as its slow.
-         *  @param {object} settings dataTables settings object
-         *  @param {string} callbackArr Name of the array storage for the callbacks in
-         *      oSettings
-         *  @param {string} eventName Name of the jQuery custom event to trigger. If
-         *      null no trigger is fired
-         *  @param {array} args Array of arguments to pass to the callback function /
-         *      trigger
-         *  @memberof DataTable#oApi
-         */
-        function _fnCallbackFire(settings, callbackArr, eventName, args) {
-            var ret = [];
-
-            if (callbackArr) {
-                ret = $.map(settings[callbackArr].slice().reverse(), function (val, i) {
-                    return val.fn.apply(settings.oInstance, args);
-                });
-            }
-
-            if (eventName !== null) {
-                var e = $.Event(eventName + '.dt');
-
-                $(settings.nTable).trigger(e, args);
-
-                ret.push(e.result);
-            }
-
-            return ret;
-        }
-
-
-        function _fnLengthOverflow(settings) {
-            var
-                start = settings._iDisplayStart,
-                end = settings.fnDisplayEnd(),
-                len = settings._iDisplayLength;
-
-            /* If we have space to show extra rows (backing up from the end point - then do so */
-            if (start >= end) {
-                start = end - len;
-            }
-
-            // Keep the start record on the current page
-            start -= (start % len);
-
-            if (len === -1 || start < 0) {
-                start = 0;
-            }
-
-            settings._iDisplayStart = start;
-        }
-
-
-        function _fnRenderer(settings, type) {
-            var renderer = settings.renderer;
-            var host = DataTable.ext.renderer[type];
-
-            if ($.isPlainObject(renderer) && renderer[type]) {
-                // Specific renderer for this type. If available use it, otherwise use
-                // the default.
-                return host[renderer[type]] || host._;
-            }
-            else if (typeof renderer === 'string') {
-                // Common renderer - if there is one available for this type use it,
-                // otherwise use the default
-                return host[renderer] || host._;
-            }
-
-            // Use the default
-            return host._;
-        }
-
-
-        /**
-         * Detect the data source being used for the table. Used to simplify the code
-         * a little (ajax) and to make it compress a little smaller.
-         *
-         *  @param {object} settings dataTables settings object
-         *  @returns {string} Data source
-         *  @memberof DataTable#oApi
-         */
-        function _fnDataSource(settings) {
-            if (settings.oFeatures.bServerSide) {
-                return 'ssp';
-            }
-            else if (settings.ajax || settings.sAjaxSource) {
-                return 'ajax';
-            }
-            return 'dom';
-        }
-
-
-        DataTable = function (options) {
-            /**
-             * Perform a jQuery selector action on the table's TR elements (from the tbody) and
-             * return the resulting jQuery object.
-             *  @param {string|node|jQuery} sSelector jQuery selector or node collection to act on
-             *  @param {object} [oOpts] Optional parameters for modifying the rows to be included
-             *  @param {string} [oOpts.filter=none] Select TR elements that meet the current filter
-             *    criterion ("applied") or all TR elements (i.e. no filter).
-             *  @param {string} [oOpts.order=current] Order of the TR elements in the processed array.
-             *    Can be either 'current', whereby the current sorting of the table is used, or
-             *    'original' whereby the original order the data was read into the table is used.
-             *  @param {string} [oOpts.page=all] Limit the selection to the currently displayed page
-             *    ("current") or not ("all"). If 'current' is given, then order is assumed to be
-             *    'current' and filter is 'applied', regardless of what they might be given as.
-             *  @returns {object} jQuery object, filtered by the given selector.
-             *  @dtopt API
-             *  @deprecated Since v1.10
-             *
-             *  @example
-             *    $(document).ready(function() {
-             *      var oTable = $('#example').dataTable();
-             *
-             *      // Highlight every second row
-             *      oTable.$('tr:odd').css('backgroundColor', 'blue');
-             *    } );
-             *
-             *  @example
-             *    $(document).ready(function() {
-             *      var oTable = $('#example').dataTable();
-             *
-             *      // Filter to rows with 'Webkit' in them, add a background colour and then
-             *      // remove the filter, thus highlighting the 'Webkit' rows only.
-             *      oTable.fnFilter('Webkit');
-             *      oTable.$('tr', {"search": "applied"}).css('backgroundColor', 'blue');
-             *      oTable.fnFilter('');
-             *    } );
-             */
-            this.$ = function (sSelector, oOpts) {
-                return this.api(true).$(sSelector, oOpts);
-            };
-
-
-            /**
-             * Almost identical to $ in operation, but in this case returns the data for the matched
-             * rows - as such, the jQuery selector used should match TR row nodes or TD/TH cell nodes
-             * rather than any descendants, so the data can be obtained for the row/cell. If matching
-             * rows are found, the data returned is the original data array/object that was used to
-             * create the row (or a generated array if from a DOM source).
-             *
-             * This method is often useful in-combination with $ where both functions are given the
-             * same parameters and the array indexes will match identically.
-             *  @param {string|node|jQuery} sSelector jQuery selector or node collection to act on
-             *  @param {object} [oOpts] Optional parameters for modifying the rows to be included
-             *  @param {string} [oOpts.filter=none] Select elements that meet the current filter
-             *    criterion ("applied") or all elements (i.e. no filter).
-             *  @param {string} [oOpts.order=current] Order of the data in the processed array.
-             *    Can be either 'current', whereby the current sorting of the table is used, or
-             *    'original' whereby the original order the data was read into the table is used.
-             *  @param {string} [oOpts.page=all] Limit the selection to the currently displayed page
-             *    ("current") or not ("all"). If 'current' is given, then order is assumed to be
-             *    'current' and filter is 'applied', regardless of what they might be given as.
-             *  @returns {array} Data for the matched elements. If any elements, as a result of the
-             *    selector, were not TR, TD or TH elements in the DataTable, they will have a null
-             *    entry in the array.
-             *  @dtopt API
-             *  @deprecated Since v1.10
-             *
-             *  @example
-             *    $(document).ready(function() {
-             *      var oTable = $('#example').dataTable();
-             *
-             *      // Get the data from the first row in the table
-             *      var data = oTable._('tr:first');
-             *
-             *      // Do something useful with the data
-             *      alert( "First cell is: "+data[0] );
-             *    } );
-             *
-             *  @example
-             *    $(document).ready(function() {
-             *      var oTable = $('#example').dataTable();
-             *
-             *      // Filter to 'Webkit' and get all data for
-             *      oTable.fnFilter('Webkit');
-             *      var data = oTable._('tr', {"search": "applied"});
-             *
-             *      // Do something with the data
-             *      alert( data.length+" rows matched the search" );
-             *    } );
-             */
-            this._ = function (sSelector, oOpts) {
-                return this.api(true).rows(sSelector, oOpts).data();
-            };
-
-
-            /**
-             * Create a DataTables Api instance, with the currently selected tables for
-             * the Api's context.
-             * @param {boolean} [traditional=false] Set the API instance's context to be
-             *   only the table referred to by the `DataTable.ext.iApiIndex` option, as was
-             *   used in the API presented by DataTables 1.9- (i.e. the traditional mode),
-             *   or if all tables captured in the jQuery object should be used.
-             * @return {DataTables.Api}
-             */
-            this.api = function (traditional) {
-                return traditional ?
-                    new _Api(
-                        _fnSettingsFromNode(this[_ext.iApiIndex])
-                    ) :
-                    new _Api(this);
-            };
-
-
-            /**
-             * Add a single new row or multiple rows of data to the table. Please note
-             * that this is suitable for client-side processing only - if you are using
-             * server-side processing (i.e. "bServerSide": true), then to add data, you
-             * must add it to the data source, i.e. the server-side, through an Ajax call.
-             *  @param {array|object} data The data to be added to the table. This can be:
-             *    <ul>
-             *      <li>1D array of data - add a single row with the data provided</li>
-             *      <li>2D array of arrays - add multiple rows in a single call</li>
-             *      <li>object - data object when using <i>mData</i></li>
-             *      <li>array of objects - multiple data objects when using <i>mData</i></li>
-             *    </ul>
-             *  @param {bool} [redraw=true] redraw the table or not
-             *  @returns {array} An array of integers, representing the list of indexes in
-             *    <i>aoData</i> ({@link DataTable.models.oSettings}) that have been added to
-             *    the table.
-             *  @dtopt API
-             *  @deprecated Since v1.10
-             *
-             *  @example
-             *    // Global var for counter
-             *    var giCount = 2;
-             *
-             *    $(document).ready(function() {
-             *      $('#example').dataTable();
-             *    } );
-             *
-             *    function fnClickAddRow() {
-             *      $('#example').dataTable().fnAddData( [
-             *        giCount+".1",
-             *        giCount+".2",
-             *        giCount+".3",
-             *        giCount+".4" ]
-             *      );
-             *
-             *      giCount++;
-             *    }
-             */
-            this.fnAddData = function (data, redraw) {
-                var api = this.api(true);
-
-                /* Check if we want to add multiple rows or not */
-                var rows = $.isArray(data) && ($.isArray(data[0]) || $.isPlainObject(data[0])) ?
-                    api.rows.add(data) :
-                    api.row.add(data);
-
-                if (redraw === undefined || redraw) {
-                    api.draw();
-                }
-
-                return rows.flatten().toArray();
-            };
-
-
-            /**
-             * This function will make DataTables recalculate the column sizes, based on the data
-             * contained in the table and the sizes applied to the columns (in the DOM, CSS or
-             * through the sWidth parameter). This can be useful when the width of the table's
-             * parent element changes (for example a window resize).
-             *  @param {boolean} [bRedraw=true] Redraw the table or not, you will typically want to
-             *  @dtopt API
-             *  @deprecated Since v1.10
-             *
-             *  @example
-             *    $(document).ready(function() {
-             *      var oTable = $('#example').dataTable( {
-             *        "sScrollY": "200px",
-             *        "bPaginate": false
-             *      } );
-             *
-             *      $(window).bind('resize', function () {
-             *        oTable.fnAdjustColumnSizing();
-             *      } );
-             *    } );
-             */
-            this.fnAdjustColumnSizing = function (bRedraw) {
-                var api = this.api(true).columns.adjust();
-                var settings = api.settings()[0];
-                var scroll = settings.oScroll;
-
-                if (bRedraw === undefined || bRedraw) {
-                    api.draw(false);
-                }
-                else if (scroll.sX !== "" || scroll.sY !== "") {
-                    /* If not redrawing, but scrolling, we want to apply the new column sizes anyway */
-                    _fnScrollDraw(settings);
-                }
-            };
-
-
-            /**
-             * Quickly and simply clear a table
-             *  @param {bool} [bRedraw=true] redraw the table or not
-             *  @dtopt API
-             *  @deprecated Since v1.10
-             *
-             *  @example
-             *    $(document).ready(function() {
-             *      var oTable = $('#example').dataTable();
-             *
-             *      // Immediately 'nuke' the current rows (perhaps waiting for an Ajax callback...)
-             *      oTable.fnClearTable();
-             *    } );
-             */
-            this.fnClearTable = function (bRedraw) {
-                var api = this.api(true).clear();
-
-                if (bRedraw === undefined || bRedraw) {
-                    api.draw();
-                }
-            };
-
-
-            /**
-             * The exact opposite of 'opening' a row, this function will close any rows which
-             * are currently 'open'.
-             *  @param {node} nTr the table row to 'close'
-             *  @returns {int} 0 on success, or 1 if failed (can't find the row)
-             *  @dtopt API
-             *  @deprecated Since v1.10
-             *
-             *  @example
-             *    $(document).ready(function() {
-             *      var oTable;
-             *
-             *      // 'open' an information row when a row is clicked on
-             *      $('#example tbody tr').click( function () {
-             *        if ( oTable.fnIsOpen(this) ) {
-             *          oTable.fnClose( this );
-             *        } else {
-             *          oTable.fnOpen( this, "Temporary row opened", "info_row" );
-             *        }
-             *      } );
-             *
-             *      oTable = $('#example').dataTable();
-             *    } );
-             */
-            this.fnClose = function (nTr) {
-                this.api(true).row(nTr).child.hide();
-            };
-
-
-            /**
-             * Remove a row for the table
-             *  @param {mixed} target The index of the row from aoData to be deleted, or
-             *    the TR element you want to delete
-             *  @param {function|null} [callBack] Callback function
-             *  @param {bool} [redraw=true] Redraw the table or not
-             *  @returns {array} The row that was deleted
-             *  @dtopt API
-             *  @deprecated Since v1.10
-             *
-             *  @example
-             *    $(document).ready(function() {
-             *      var oTable = $('#example').dataTable();
-             *
-             *      // Immediately remove the first row
-             *      oTable.fnDeleteRow( 0 );
-             *    } );
-             */
-            this.fnDeleteRow = function (target, callback, redraw) {
-                var api = this.api(true);
-                var rows = api.rows(target);
-                var settings = rows.settings()[0];
-                var data = settings.aoData[rows[0][0]];
-
-                rows.remove();
-
-                if (callback) {
-                    callback.call(this, settings, data);
-                }
-
-                if (redraw === undefined || redraw) {
-                    api.draw();
-                }
-
-                return data;
-            };
-
-
-            /**
-             * Restore the table to it's original state in the DOM by removing all of DataTables
-             * enhancements, alterations to the DOM structure of the table and event listeners.
-             *  @param {boolean} [remove=false] Completely remove the table from the DOM
-             *  @dtopt API
-             *  @deprecated Since v1.10
-             *
-             *  @example
-             *    $(document).ready(function() {
-             *      // This example is fairly pointless in reality, but shows how fnDestroy can be used
-             *      var oTable = $('#example').dataTable();
-             *      oTable.fnDestroy();
-             *    } );
-             */
-            this.fnDestroy = function (remove) {
-                this.api(true).destroy(remove);
-            };
-
-
-            /**
-             * Redraw the table
-             *  @param {bool} [complete=true] Re-filter and resort (if enabled) the table before the draw.
-             *  @dtopt API
-             *  @deprecated Since v1.10
-             *
-             *  @example
-             *    $(document).ready(function() {
-             *      var oTable = $('#example').dataTable();
-             *
-             *      // Re-draw the table - you wouldn't want to do it here, but it's an example :-)
-             *      oTable.fnDraw();
-             *    } );
-             */
-            this.fnDraw = function (complete) {
-                // Note that this isn't an exact match to the old call to _fnDraw - it takes
-                // into account the new data, but can hold position.
-                this.api(true).draw(complete);
-            };
-
-
-            /**
-             * Filter the input based on data
-             *  @param {string} sInput String to filter the table on
-             *  @param {int|null} [iColumn] Column to limit filtering to
-             *  @param {bool} [bRegex=false] Treat as regular expression or not
-             *  @param {bool} [bSmart=true] Perform smart filtering or not
-             *  @param {bool} [bShowGlobal=true] Show the input global filter in it's input box(es)
-             *  @param {bool} [bCaseInsensitive=true] Do case-insensitive matching (true) or not (false)
-             *  @dtopt API
-             *  @deprecated Since v1.10
-             *
-             *  @example
-             *    $(document).ready(function() {
-             *      var oTable = $('#example').dataTable();
-             *
-             *      // Sometime later - filter...
-             *      oTable.fnFilter( 'test string' );
-             *    } );
-             */
-            this.fnFilter = function (sInput, iColumn, bRegex, bSmart, bShowGlobal, bCaseInsensitive) {
-                var api = this.api(true);
-
-                if (iColumn === null || iColumn === undefined) {
-                    api.search(sInput, bRegex, bSmart, bCaseInsensitive);
-                }
-                else {
-                    api.column(iColumn).search(sInput, bRegex, bSmart, bCaseInsensitive);
-                }
-
-                api.draw();
-            };
-
-
-            /**
-             * Get the data for the whole table, an individual row or an individual cell based on the
-             * provided parameters.
-             *  @param {int|node} [src] A TR row node, TD/TH cell node or an integer. If given as
-             *    a TR node then the data source for the whole row will be returned. If given as a
-             *    TD/TH cell node then iCol will be automatically calculated and the data for the
-             *    cell returned. If given as an integer, then this is treated as the aoData internal
-             *    data index for the row (see fnGetPosition) and the data for that row used.
-             *  @param {int} [col] Optional column index that you want the data of.
-             *  @returns {array|object|string} If mRow is undefined, then the data for all rows is
-             *    returned. If mRow is defined, just data for that row, and is iCol is
-             *    defined, only data for the designated cell is returned.
-             *  @dtopt API
-             *  @deprecated Since v1.10
-             *
-             *  @example
-             *    // Row data
-             *    $(document).ready(function() {
-             *      oTable = $('#example').dataTable();
-             *
-             *      oTable.$('tr').click( function () {
-             *        var data = oTable.fnGetData( this );
-             *        // ... do something with the array / object of data for the row
-             *      } );
-             *    } );
-             *
-             *  @example
-             *    // Individual cell data
-             *    $(document).ready(function() {
-             *      oTable = $('#example').dataTable();
-             *
-             *      oTable.$('td').click( function () {
-             *        var sData = oTable.fnGetData( this );
-             *        alert( 'The cell clicked on had the value of '+sData );
-             *      } );
-             *    } );
-             */
-            this.fnGetData = function (src, col) {
-                var api = this.api(true);
-
-                if (src !== undefined) {
-                    var type = src.nodeName ? src.nodeName.toLowerCase() : '';
-
-                    return col !== undefined || type == 'td' || type == 'th' ?
-                        api.cell(src, col).data() :
-                        api.row(src).data() || null;
-                }
-
-                return api.data().toArray();
-            };
-
-
-            /**
-             * Get an array of the TR nodes that are used in the table's body. Note that you will
-             * typically want to use the '$' API method in preference to this as it is more
-             * flexible.
-             *  @param {int} [iRow] Optional row index for the TR element you want
-             *  @returns {array|node} If iRow is undefined, returns an array of all TR elements
-             *    in the table's body, or iRow is defined, just the TR element requested.
-             *  @dtopt API
-             *  @deprecated Since v1.10
-             *
-             *  @example
-             *    $(document).ready(function() {
-             *      var oTable = $('#example').dataTable();
-             *
-             *      // Get the nodes from the table
-             *      var nNodes = oTable.fnGetNodes( );
-             *    } );
-             */
-            this.fnGetNodes = function (iRow) {
-                var api = this.api(true);
-
-                return iRow !== undefined ?
-                    api.row(iRow).node() :
-                    api.rows().nodes().flatten().toArray();
-            };
-
-
-            /**
-             * Get the array indexes of a particular cell from it's DOM element
-             * and column index including hidden columns
-             *  @param {node} node this can either be a TR, TD or TH in the table's body
-             *  @returns {int} If nNode is given as a TR, then a single index is returned, or
-             *    if given as a cell, an array of [row index, column index (visible),
-             *    column index (all)] is given.
-             *  @dtopt API
-             *  @deprecated Since v1.10
-             *
-             *  @example
-             *    $(document).ready(function() {
-             *      $('#example tbody td').click( function () {
-             *        // Get the position of the current data from the node
-             *        var aPos = oTable.fnGetPosition( this );
-             *
-             *        // Get the data array for this row
-             *        var aData = oTable.fnGetData( aPos[0] );
-             *
-             *        // Update the data array and return the value
-             *        aData[ aPos[1] ] = 'clicked';
-             *        this.innerHTML = 'clicked';
-             *      } );
-             *
-             *      // Init DataTables
-             *      oTable = $('#example').dataTable();
-             *    } );
-             */
-            this.fnGetPosition = function (node) {
-                var api = this.api(true);
-                var nodeName = node.nodeName.toUpperCase();
-
-                if (nodeName == 'TR') {
-                    return api.row(node).index();
-                }
-                else if (nodeName == 'TD' || nodeName == 'TH') {
-                    var cell = api.cell(node).index();
-
-                    return [
-                        cell.row,
-                        cell.columnVisible,
-                        cell.column
-                    ];
-                }
-                return null;
-            };
-
-
-            /**
-             * Check to see if a row is 'open' or not.
-             *  @param {node} nTr the table row to check
-             *  @returns {boolean} true if the row is currently open, false otherwise
-             *  @dtopt API
-             *  @deprecated Since v1.10
-             *
-             *  @example
-             *    $(document).ready(function() {
-             *      var oTable;
-             *
-             *      // 'open' an information row when a row is clicked on
-             *      $('#example tbody tr').click( function () {
-             *        if ( oTable.fnIsOpen(this) ) {
-             *          oTable.fnClose( this );
-             *        } else {
-             *          oTable.fnOpen( this, "Temporary row opened", "info_row" );
-             *        }
-             *      } );
-             *
-             *      oTable = $('#example').dataTable();
-             *    } );
-             */
-            this.fnIsOpen = function (nTr) {
-                return this.api(true).row(nTr).child.isShown();
-            };
-
-
-            /**
-             * This function will place a new row directly after a row which is currently
-             * on display on the page, with the HTML contents that is passed into the
-             * function. This can be used, for example, to ask for confirmation that a
-             * particular record should be deleted.
-             *  @param {node} nTr The table row to 'open'
-             *  @param {string|node|jQuery} mHtml The HTML to put into the row
-             *  @param {string} sClass Class to give the new TD cell
-             *  @returns {node} The row opened. Note that if the table row passed in as the
-             *    first parameter, is not found in the table, this method will silently
-             *    return.
-             *  @dtopt API
-             *  @deprecated Since v1.10
-             *
-             *  @example
-             *    $(document).ready(function() {
-             *      var oTable;
-             *
-             *      // 'open' an information row when a row is clicked on
-             *      $('#example tbody tr').click( function () {
-             *        if ( oTable.fnIsOpen(this) ) {
-             *          oTable.fnClose( this );
-             *        } else {
-             *          oTable.fnOpen( this, "Temporary row opened", "info_row" );
-             *        }
-             *      } );
-             *
-             *      oTable = $('#example').dataTable();
-             *    } );
-             */
-            this.fnOpen = function (nTr, mHtml, sClass) {
-                return this.api(true)
-                    .row(nTr)
-                    .child(mHtml, sClass)
-                    .show()
-                    .child()[0];
-            };
-
-
-            /**
-             * Change the pagination - provides the internal logic for pagination in a simple API
-             * function. With this function you can have a DataTables table go to the next,
-             * previous, first or last pages.
-             *  @param {string|int} mAction Paging action to take: "first", "previous", "next" or "last"
-             *    or page number to jump to (integer), note that page 0 is the first page.
-             *  @param {bool} [bRedraw=true] Redraw the table or not
-             *  @dtopt API
-             *  @deprecated Since v1.10
-             *
-             *  @example
-             *    $(document).ready(function() {
-             *      var oTable = $('#example').dataTable();
-             *      oTable.fnPageChange( 'next' );
-             *    } );
-             */
-            this.fnPageChange = function (mAction, bRedraw) {
-                var api = this.api(true).page(mAction);
-
-                if (bRedraw === undefined || bRedraw) {
-                    api.draw(false);
-                }
-            };
-
-
-            /**
-             * Show a particular column
-             *  @param {int} iCol The column whose display should be changed
-             *  @param {bool} bShow Show (true) or hide (false) the column
-             *  @param {bool} [bRedraw=true] Redraw the table or not
-             *  @dtopt API
-             *  @deprecated Since v1.10
-             *
-             *  @example
-             *    $(document).ready(function() {
-             *      var oTable = $('#example').dataTable();
-             *
-             *      // Hide the second column after initialisation
-             *      oTable.fnSetColumnVis( 1, false );
-             *    } );
-             */
-            this.fnSetColumnVis = function (iCol, bShow, bRedraw) {
-                var api = this.api(true).column(iCol).visible(bShow);
-
-                if (bRedraw === undefined || bRedraw) {
-                    api.columns.adjust().draw();
-                }
-            };
-
-
-            /**
-             * Get the settings for a particular table for external manipulation
-             *  @returns {object} DataTables settings object. See
-             *    {@link DataTable.models.oSettings}
-             *  @dtopt API
-             *  @deprecated Since v1.10
-             *
-             *  @example
-             *    $(document).ready(function() {
-             *      var oTable = $('#example').dataTable();
-             *      var oSettings = oTable.fnSettings();
-             *
-             *      // Show an example parameter from the settings
-             *      alert( oSettings._iDisplayStart );
-             *    } );
-             */
-            this.fnSettings = function () {
-                return _fnSettingsFromNode(this[_ext.iApiIndex]);
-            };
-
-
-            /**
-             * Sort the table by a particular column
-             *  @param {int} iCol the data index to sort on. Note that this will not match the
-             *    'display index' if you have hidden data entries
-             *  @dtopt API
-             *  @deprecated Since v1.10
-             *
-             *  @example
-             *    $(document).ready(function() {
-             *      var oTable = $('#example').dataTable();
-             *
-             *      // Sort immediately with columns 0 and 1
-             *      oTable.fnSort( [ [0,'asc'], [1,'asc'] ] );
-             *    } );
-             */
-            this.fnSort = function (aaSort) {
-                this.api(true).order(aaSort).draw();
-            };
-
-
-            /**
-             * Attach a sort listener to an element for a given column
-             *  @param {node} nNode the element to attach the sort listener to
-             *  @param {int} iColumn the column that a click on this node will sort on
-             *  @param {function} [fnCallback] callback function when sort is run
-             *  @dtopt API
-             *  @deprecated Since v1.10
-             *
-             *  @example
-             *    $(document).ready(function() {
-             *      var oTable = $('#example').dataTable();
-             *
-             *      // Sort on column 1, when 'sorter' is clicked on
-             *      oTable.fnSortListener( document.getElementById('sorter'), 1 );
-             *    } );
-             */
-            this.fnSortListener = function (nNode, iColumn, fnCallback) {
-                this.api(true).order.listener(nNode, iColumn, fnCallback);
-            };
-
-
-            /**
-             * Update a table cell or row - this method will accept either a single value to
-             * update the cell with, an array of values with one element for each column or
-             * an object in the same format as the original data source. The function is
-             * self-referencing in order to make the multi column updates easier.
-             *  @param {object|array|string} mData Data to update the cell/row with
-             *  @param {node|int} mRow TR element you want to update or the aoData index
-             *  @param {int} [iColumn] The column to update, give as null or undefined to
-             *    update a whole row.
-             *  @param {bool} [bRedraw=true] Redraw the table or not
-             *  @param {bool} [bAction=true] Perform pre-draw actions or not
-             *  @returns {int} 0 on success, 1 on error
-             *  @dtopt API
-             *  @deprecated Since v1.10
-             *
-             *  @example
-             *    $(document).ready(function() {
-             *      var oTable = $('#example').dataTable();
-             *      oTable.fnUpdate( 'Example update', 0, 0 ); // Single cell
-             *      oTable.fnUpdate( ['a', 'b', 'c', 'd', 'e'], $('tbody tr')[0] ); // Row
-             *    } );
-             */
-            this.fnUpdate = function (mData, mRow, iColumn, bRedraw, bAction) {
-                var api = this.api(true);
-
-                if (iColumn === undefined || iColumn === null) {
-                    api.row(mRow).data(mData);
-                }
-                else {
-                    api.cell(mRow, iColumn).data(mData);
-                }
-
-                if (bAction === undefined || bAction) {
-                    api.columns.adjust();
-                }
-
-                if (bRedraw === undefined || bRedraw) {
-                    api.draw();
-                }
-                return 0;
-            };
-
-
-            /**
-             * Provide a common method for plug-ins to check the version of DataTables being used, in order
-             * to ensure compatibility.
-             *  @param {string} sVersion Version string to check for, in the format "X.Y.Z". Note that the
-             *    formats "X" and "X.Y" are also acceptable.
-             *  @returns {boolean} true if this version of DataTables is greater or equal to the required
-             *    version, or false if this version of DataTales is not suitable
-             *  @method
-             *  @dtopt API
-             *  @deprecated Since v1.10
-             *
-             *  @example
-             *    $(document).ready(function() {
-             *      var oTable = $('#example').dataTable();
-             *      alert( oTable.fnVersionCheck( '1.9.0' ) );
-             *    } );
-             */
-            this.fnVersionCheck = _ext.fnVersionCheck;
-
-
-            var _that = this;
-            var emptyInit = options === undefined;
-            var len = this.length;
-
-            if (emptyInit) {
-                options = {};
-            }
-
-            this.oApi = this.internal = _ext.internal;
-
-            // Extend with old style plug-in API methods
-            for (var fn in DataTable.ext.internal) {
-                if (fn) {
-                    this[fn] = _fnExternApiFunc(fn);
-                }
-            }
-
-            this.each(function () {
-                // For each initialisation we want to give it a clean initialisation
-                // object that can be bashed around
-                var o = {};
-                var oInit = len > 1 ? // optimisation for single table case
-                    _fnExtend(o, options, true) :
-                    options;
-
-                /*global oInit,_that,emptyInit*/
-                var i = 0, iLen, j, jLen, k, kLen;
-                var sId = this.getAttribute('id');
-                var bInitHandedOff = false;
-                var defaults = DataTable.defaults;
-                var $this = $(this);
-
-
-                /* Sanity check */
-                if (this.nodeName.toLowerCase() != 'table') {
-                    _fnLog(null, 0, 'Non-table node initialisation (' + this.nodeName + ')', 2);
-                    return;
-                }
-
-                /* Backwards compatibility for the defaults */
-                _fnCompatOpts(defaults);
-                _fnCompatCols(defaults.column);
-
-                /* Convert the camel-case defaults to Hungarian */
-                _fnCamelToHungarian(defaults, defaults, true);
-                _fnCamelToHungarian(defaults.column, defaults.column, true);
-
-                /* Setting up the initialisation object */
-                _fnCamelToHungarian(defaults, $.extend(oInit, $this.data()));
-
-
-
-                /* Check to see if we are re-initialising a table */
-                var allSettings = DataTable.settings;
-                for (i = 0, iLen = allSettings.length ; i < iLen ; i++) {
-                    var s = allSettings[i];
-
-                    /* Base check on table node */
-                    if (s.nTable == this || s.nTHead.parentNode == this || (s.nTFoot && s.nTFoot.parentNode == this)) {
-                        var bRetrieve = oInit.bRetrieve !== undefined ? oInit.bRetrieve : defaults.bRetrieve;
-                        var bDestroy = oInit.bDestroy !== undefined ? oInit.bDestroy : defaults.bDestroy;
-
-                        if (emptyInit || bRetrieve) {
-                            return s.oInstance;
-                        }
-                        else if (bDestroy) {
-                            s.oInstance.fnDestroy();
-                            break;
-                        }
-                        else {
-                            _fnLog(s, 0, 'Cannot reinitialise DataTable', 3);
-                            return;
-                        }
-                    }
-
-                    /* If the element we are initialising has the same ID as a table which was previously
-                     * initialised, but the table nodes don't match (from before) then we destroy the old
-                     * instance by simply deleting it. This is under the assumption that the table has been
-                     * destroyed by other methods. Anyone using non-id selectors will need to do this manually
-                     */
-                    if (s.sTableId == this.id) {
-                        allSettings.splice(i, 1);
-                        break;
-                    }
-                }
-
-                /* Ensure the table has an ID - required for accessibility */
-                if (sId === null || sId === "") {
-                    sId = "DataTables_Table_" + (DataTable.ext._unique++);
-                    this.id = sId;
-                }
-
-                /* Create the settings object for this table and set some of the default parameters */
-                var oSettings = $.extend(true, {}, DataTable.models.oSettings, {
-                    "sDestroyWidth": $this[0].style.width,
-                    "sInstance": sId,
-                    "sTableId": sId
-                });
-                oSettings.nTable = this;
-                oSettings.oApi = _that.internal;
-                oSettings.oInit = oInit;
-
-                allSettings.push(oSettings);
-
-                // Need to add the instance after the instance after the settings object has been added
-                // to the settings array, so we can self reference the table instance if more than one
-                oSettings.oInstance = (_that.length === 1) ? _that : $this.dataTable();
-
-                // Backwards compatibility, before we apply all the defaults
-                _fnCompatOpts(oInit);
-
-                if (oInit.oLanguage) {
-                    _fnLanguageCompat(oInit.oLanguage);
-                }
-
-                // If the length menu is given, but the init display length is not, use the length menu
-                if (oInit.aLengthMenu && !oInit.iDisplayLength) {
-                    oInit.iDisplayLength = $.isArray(oInit.aLengthMenu[0]) ?
-                        oInit.aLengthMenu[0][0] : oInit.aLengthMenu[0];
-                }
-
-                // Apply the defaults and init options to make a single init object will all
-                // options defined from defaults and instance options.
-                oInit = _fnExtend($.extend(true, {}, defaults), oInit);
-
-
-                // Map the initialisation options onto the settings object
-                _fnMap(oSettings.oFeatures, oInit, [
-                    "bPaginate",
-                    "bLengthChange",
-                    "bFilter",
-                    "bSort",
-                    "bSortMulti",
-                    "bInfo",
-                    "bProcessing",
-                    "bAutoWidth",
-                    "bSortClasses",
-                    "bServerSide",
-                    "bDeferRender"
-                ]);
-                _fnMap(oSettings, oInit, [
-                    "asStripeClasses",
-                    "ajax",
-                    "fnServerData",
-                    "fnFormatNumber",
-                    "sServerMethod",
-                    "aaSorting",
-                    "aaSortingFixed",
-                    "aLengthMenu",
-                    "sPaginationType",
-                    "sAjaxSource",
-                    "sAjaxDataProp",
-                    "iStateDuration",
-                    "sDom",
-                    "bSortCellsTop",
-                    "iTabIndex",
-                    "fnStateLoadCallback",
-                    "fnStateSaveCallback",
-                    "renderer",
-                    "searchDelay",
-                    ["iCookieDuration", "iStateDuration"], // backwards compat
-                    ["oSearch", "oPreviousSearch"],
-                    ["aoSearchCols", "aoPreSearchCols"],
-                    ["iDisplayLength", "_iDisplayLength"],
-                    ["bJQueryUI", "bJUI"]
-                ]);
-                _fnMap(oSettings.oScroll, oInit, [
-                    ["sScrollX", "sX"],
-                    ["sScrollXInner", "sXInner"],
-                    ["sScrollY", "sY"],
-                    ["bScrollCollapse", "bCollapse"]
-                ]);
-                _fnMap(oSettings.oLanguage, oInit, "fnInfoCallback");
-
-                /* Callback functions which are array driven */
-                _fnCallbackReg(oSettings, 'aoDrawCallback', oInit.fnDrawCallback, 'user');
-                _fnCallbackReg(oSettings, 'aoServerParams', oInit.fnServerParams, 'user');
-                _fnCallbackReg(oSettings, 'aoStateSaveParams', oInit.fnStateSaveParams, 'user');
-                _fnCallbackReg(oSettings, 'aoStateLoadParams', oInit.fnStateLoadParams, 'user');
-                _fnCallbackReg(oSettings, 'aoStateLoaded', oInit.fnStateLoaded, 'user');
-                _fnCallbackReg(oSettings, 'aoRowCallback', oInit.fnRowCallback, 'user');
-                _fnCallbackReg(oSettings, 'aoRowCreatedCallback', oInit.fnCreatedRow, 'user');
-                _fnCallbackReg(oSettings, 'aoHeaderCallback', oInit.fnHeaderCallback, 'user');
-                _fnCallbackReg(oSettings, 'aoFooterCallback', oInit.fnFooterCallback, 'user');
-                _fnCallbackReg(oSettings, 'aoInitComplete', oInit.fnInitComplete, 'user');
-                _fnCallbackReg(oSettings, 'aoPreDrawCallback', oInit.fnPreDrawCallback, 'user');
-
-                var oClasses = oSettings.oClasses;
-
-                // @todo Remove in 1.11
-                if (oInit.bJQueryUI) {
-                    /* Use the JUI classes object for display. You could clone the oStdClasses object if
-                     * you want to have multiple tables with multiple independent classes
-                     */
-                    $.extend(oClasses, DataTable.ext.oJUIClasses, oInit.oClasses);
-
-                    if (oInit.sDom === defaults.sDom && defaults.sDom === "lfrtip") {
-                        /* Set the DOM to use a layout suitable for jQuery UI's theming */
-                        oSettings.sDom = '<"H"lfr>t<"F"ip>';
-                    }
-
-                    if (!oSettings.renderer) {
-                        oSettings.renderer = 'jqueryui';
-                    }
-                    else if ($.isPlainObject(oSettings.renderer) && !oSettings.renderer.header) {
-                        oSettings.renderer.header = 'jqueryui';
-                    }
-                }
-                else {
-                    $.extend(oClasses, DataTable.ext.classes, oInit.oClasses);
-                }
-                $this.addClass(oClasses.sTable);
-
-                /* Calculate the scroll bar width and cache it for use later on */
-                if (oSettings.oScroll.sX !== "" || oSettings.oScroll.sY !== "") {
-                    oSettings.oScroll.iBarWidth = _fnScrollBarWidth();
-                }
-                if (oSettings.oScroll.sX === true) { // Easy initialisation of x-scrolling
-                    oSettings.oScroll.sX = '100%';
-                }
-
-                if (oSettings.iInitDisplayStart === undefined) {
-                    /* Display start point, taking into account the save saving */
-                    oSettings.iInitDisplayStart = oInit.iDisplayStart;
-                    oSettings._iDisplayStart = oInit.iDisplayStart;
-                }
-
-                if (oInit.iDeferLoading !== null) {
-                    oSettings.bDeferLoading = true;
-                    var tmp = $.isArray(oInit.iDeferLoading);
-                    oSettings._iRecordsDisplay = tmp ? oInit.iDeferLoading[0] : oInit.iDeferLoading;
-                    oSettings._iRecordsTotal = tmp ? oInit.iDeferLoading[1] : oInit.iDeferLoading;
-                }
-
-                /* Language definitions */
-                var oLanguage = oSettings.oLanguage;
-                $.extend(true, oLanguage, oInit.oLanguage);
-
-                if (oLanguage.sUrl !== "") {
-                    /* Get the language definitions from a file - because this Ajax call makes the language
-                     * get async to the remainder of this function we use bInitHandedOff to indicate that
-                     * _fnInitialise will be fired by the returned Ajax handler, rather than the constructor
-                     */
-                    $.ajax({
-                        dataType: 'json',
-                        url: oLanguage.sUrl,
-                        success: function (json) {
-                            _fnLanguageCompat(json);
-                            _fnCamelToHungarian(defaults.oLanguage, json);
-                            $.extend(true, oLanguage, json);
-                            _fnInitialise(oSettings);
-                        },
-                        error: function () {
-                            // Error occurred loading language file, continue on as best we can
-                            _fnInitialise(oSettings);
-                        }
-                    });
-                    bInitHandedOff = true;
-                }
-
-                /*
-                 * Stripes
-                 */
-                if (oInit.asStripeClasses === null) {
-                    oSettings.asStripeClasses = [
-                        oClasses.sStripeOdd,
-                        oClasses.sStripeEven
-                    ];
-                }
-
-                /* Remove row stripe classes if they are already on the table row */
-                var stripeClasses = oSettings.asStripeClasses;
-                var rowOne = $this.children('tbody').find('tr').eq(0);
-                if ($.inArray(true, $.map(stripeClasses, function (el, i) {
-                    return rowOne.hasClass(el);
-                })) !== -1) {
-                    $('tbody tr', this).removeClass(stripeClasses.join(' '));
-                    oSettings.asDestroyStripes = stripeClasses.slice();
-                }
-
-                /*
-                 * Columns
-                 * See if we should load columns automatically or use defined ones
-                 */
-                var anThs = [];
-                var aoColumnsInit;
-                var nThead = this.getElementsByTagName('thead');
-                if (nThead.length !== 0) {
-                    _fnDetectHeader(oSettings.aoHeader, nThead[0]);
-                    anThs = _fnGetUniqueThs(oSettings);
-                }
-
-                /* If not given a column array, generate one with nulls */
-                if (oInit.aoColumns === null) {
-                    aoColumnsInit = [];
-                    for (i = 0, iLen = anThs.length ; i < iLen ; i++) {
-                        aoColumnsInit.push(null);
-                    }
-                }
-                else {
-                    aoColumnsInit = oInit.aoColumns;
-                }
-
-                /* Add the columns */
-                for (i = 0, iLen = aoColumnsInit.length ; i < iLen ; i++) {
-                    _fnAddColumn(oSettings, anThs ? anThs[i] : null);
-                }
-
-                /* Apply the column definitions */
-                _fnApplyColumnDefs(oSettings, oInit.aoColumnDefs, aoColumnsInit, function (iCol, oDef) {
-                    _fnColumnOptions(oSettings, iCol, oDef);
-                });
-
-                /* HTML5 attribute detection - build an mData object automatically if the
-                 * attributes are found
-                 */
-                if (rowOne.length) {
-                    var a = function (cell, name) {
-                        return cell.getAttribute('data-' + name) !== null ? name : null;
-                    };
-
-                    $.each(_fnGetRowElements(oSettings, rowOne[0]).cells, function (i, cell) {
-                        var col = oSettings.aoColumns[i];
-
-                        if (col.mData === i) {
-                            var sort = a(cell, 'sort') || a(cell, 'order');
-                            var filter = a(cell, 'filter') || a(cell, 'search');
-
-                            if (sort !== null || filter !== null) {
-                                col.mData = {
-                                    _: i + '.display',
-                                    sort: sort !== null ? i + '.@data-' + sort : undefined,
-                                    type: sort !== null ? i + '.@data-' + sort : undefined,
-                                    filter: filter !== null ? i + '.@data-' + filter : undefined
-                                };
-
-                                _fnColumnOptions(oSettings, i);
-                            }
-                        }
-                    });
-                }
-
-                var features = oSettings.oFeatures;
-
-                /* Must be done after everything which can be overridden by the state saving! */
-                if (oInit.bStateSave) {
-                    features.bStateSave = true;
-                    _fnLoadState(oSettings, oInit);
-                    _fnCallbackReg(oSettings, 'aoDrawCallback', _fnSaveState, 'state_save');
-                }
-
-
-                /*
-                 * Sorting
-                 * @todo For modularisation (1.11) this needs to do into a sort start up handler
-                 */
-
-                // If aaSorting is not defined, then we use the first indicator in asSorting
-                // in case that has been altered, so the default sort reflects that option
-                if (oInit.aaSorting === undefined) {
-                    var sorting = oSettings.aaSorting;
-                    for (i = 0, iLen = sorting.length ; i < iLen ; i++) {
-                        sorting[i][1] = oSettings.aoColumns[i].asSorting[0];
-                    }
-                }
-
-                /* Do a first pass on the sorting classes (allows any size changes to be taken into
-                 * account, and also will apply sorting disabled classes if disabled
-                 */
-                _fnSortingClasses(oSettings);
-
-                if (features.bSort) {
-                    _fnCallbackReg(oSettings, 'aoDrawCallback', function () {
-                        if (oSettings.bSorted) {
-                            var aSort = _fnSortFlatten(oSettings);
-                            var sortedColumns = {};
-
-                            $.each(aSort, function (i, val) {
-                                sortedColumns[val.src] = val.dir;
-                            });
-
-                            _fnCallbackFire(oSettings, null, 'order', [oSettings, aSort, sortedColumns]);
-                            _fnSortAria(oSettings);
-                        }
-                    });
-                }
-
-                _fnCallbackReg(oSettings, 'aoDrawCallback', function () {
-                    if (oSettings.bSorted || _fnDataSource(oSettings) === 'ssp' || features.bDeferRender) {
-                        _fnSortingClasses(oSettings);
-                    }
-                }, 'sc');
-
-
-                /*
-                 * Final init
-                 * Cache the header, body and footer as required, creating them if needed
-                 */
-
-                /* Browser support detection */
-                _fnBrowserDetect(oSettings);
-
-                // Work around for Webkit bug 83867 - store the caption-side before removing from doc
-                var captions = $this.children('caption').each(function () {
-                    this._captionSide = $this.css('caption-side');
-                });
-
-                var thead = $this.children('thead');
-                if (thead.length === 0) {
-                    thead = $('<thead/>').appendTo(this);
-                }
-                oSettings.nTHead = thead[0];
-
-                var tbody = $this.children('tbody');
-                if (tbody.length === 0) {
-                    tbody = $('<tbody/>').appendTo(this);
-                }
-                oSettings.nTBody = tbody[0];
-
-                var tfoot = $this.children('tfoot');
-                if (tfoot.length === 0 && captions.length > 0 && (oSettings.oScroll.sX !== "" || oSettings.oScroll.sY !== "")) {
-                    // If we are a scrolling table, and no footer has been given, then we need to create
-                    // a tfoot element for the caption element to be appended to
-                    tfoot = $('<tfoot/>').appendTo(this);
-                }
-
-                if (tfoot.length === 0 || tfoot.children().length === 0) {
-                    $this.addClass(oClasses.sNoFooter);
-                }
-                else if (tfoot.length > 0) {
-                    oSettings.nTFoot = tfoot[0];
-                    _fnDetectHeader(oSettings.aoFooter, oSettings.nTFoot);
-                }
-
-                /* Check if there is data passing into the constructor */
-                if (oInit.aaData) {
-                    for (i = 0 ; i < oInit.aaData.length ; i++) {
-                        _fnAddData(oSettings, oInit.aaData[i]);
-                    }
-                }
-                else if (oSettings.bDeferLoading || _fnDataSource(oSettings) == 'dom') {
-                    /* Grab the data from the page - only do this when deferred loading or no Ajax
-                     * source since there is no point in reading the DOM data if we are then going
-                     * to replace it with Ajax data
-                     */
-                    _fnAddTr(oSettings, $(oSettings.nTBody).children('tr'));
-                }
-
-                /* Copy the data index array */
-                oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
-
-                /* Initialisation complete - table can be drawn */
-                oSettings.bInitialised = true;
-
-                /* Check if we need to initialise the table (it might not have been handed off to the
-                 * language processor)
-                 */
-                if (bInitHandedOff === false) {
-                    _fnInitialise(oSettings);
-                }
-            });
-            _that = null;
-            return this;
-        };
-
-
-
-        /**
-         * Computed structure of the DataTables API, defined by the options passed to
-         * `DataTable.Api.register()` when building the API.
-         *
-         * The structure is built in order to speed creation and extension of the Api
-         * objects since the extensions are effectively pre-parsed.
-         *
-         * The array is an array of objects with the following structure, where this
-         * base array represents the Api prototype base:
-         *
-         *     [
-         *       {
-         *         name:      'data'                -- string   - Property name
-         *         val:       function () {},       -- function - Api method (or undefined if just an object
-         *         methodExt: [ ... ],              -- array    - Array of Api object definitions to extend the method result
-         *         propExt:   [ ... ]               -- array    - Array of Api object definitions to extend the property
-         *       },
-         *       {
-         *         name:     'row'
-         *         val:       {},
-         *         methodExt: [ ... ],
-         *         propExt:   [
-         *           {
-         *             name:      'data'
-         *             val:       function () {},
-         *             methodExt: [ ... ],
-         *             propExt:   [ ... ]
-         *           },
-         *           ...
-         *         ]
-         *       }
-         *     ]
-         *
-         * @type {Array}
-         * @ignore
-         */
-        var __apiStruct = [];
-
-
-        /**
-         * `Array.prototype` reference.
-         *
-         * @type object
-         * @ignore
-         */
-        var __arrayProto = Array.prototype;
-
-
-        /**
-         * Abstraction for `context` parameter of the `Api` constructor to allow it to
-         * take several different forms for ease of use.
-         *
-         * Each of the input parameter types will be converted to a DataTables settings
-         * object where possible.
-         *
-         * @param  {string|node|jQuery|object} mixed DataTable identifier. Can be one
-         *   of:
-         *
-         *   * `string` - jQuery selector. Any DataTables' matching the given selector
-         *     with be found and used.
-         *   * `node` - `TABLE` node which has already been formed into a DataTable.
-         *   * `jQuery` - A jQuery object of `TABLE` nodes.
-         *   * `object` - DataTables settings object
-         *   * `DataTables.Api` - API instance
-         * @return {array|null} Matching DataTables settings objects. `null` or
-         *   `undefined` is returned if no matching DataTable is found.
-         * @ignore
-         */
-        var _toSettings = function (mixed) {
-            var idx, jq;
-            var settings = DataTable.settings;
-            var tables = $.map(settings, function (el, i) {
-                return el.nTable;
-            });
-
-            if (!mixed) {
-                return [];
-            }
-            else if (mixed.nTable && mixed.oApi) {
-                // DataTables settings object
-                return [mixed];
-            }
-            else if (mixed.nodeName && mixed.nodeName.toLowerCase() === 'table') {
-                // Table node
-                idx = $.inArray(mixed, tables);
-                return idx !== -1 ? [settings[idx]] : null;
-            }
-            else if (mixed && typeof mixed.settings === 'function') {
-                return mixed.settings().toArray();
-            }
-            else if (typeof mixed === 'string') {
-                // jQuery selector
-                jq = $(mixed);
-            }
-            else if (mixed instanceof $) {
-                // jQuery object (also DataTables instance)
-                jq = mixed;
-            }
-
-            if (jq) {
-                return jq.map(function (i) {
-                    idx = $.inArray(this, tables);
-                    return idx !== -1 ? settings[idx] : null;
-                }).toArray();
-            }
-        };
-
-
-        /**
-         * DataTables API class - used to control and interface with  one or more
-         * DataTables enhanced tables.
-         *
-         * The API class is heavily based on jQuery, presenting a chainable interface
-         * that you can use to interact with tables. Each instance of the API class has
-         * a "context" - i.e. the tables that it will operate on. This could be a single
-         * table, all tables on a page or a sub-set thereof.
-         *
-         * Additionally the API is designed to allow you to easily work with the data in
-         * the tables, retrieving and manipulating it as required. This is done by
-         * presenting the API class as an array like interface. The contents of the
-         * array depend upon the actions requested by each method (for example
-         * `rows().nodes()` will return an array of nodes, while `rows().data()` will
-         * return an array of objects or arrays depending upon your table's
-         * configuration). The API object has a number of array like methods (`push`,
-         * `pop`, `reverse` etc) as well as additional helper methods (`each`, `pluck`,
-         * `unique` etc) to assist your working with the data held in a table.
-         *
-         * Most methods (those which return an Api instance) are chainable, which means
-         * the return from a method call also has all of the methods available that the
-         * top level object had. For example, these two calls are equivalent:
-         *
-         *     // Not chained
-         *     api.row.add( {...} );
-         *     api.draw();
-         *
-         *     // Chained
-         *     api.row.add( {...} ).draw();
-         *
-         * @class DataTable.Api
-         * @param {array|object|string|jQuery} context DataTable identifier. This is
-         *   used to define which DataTables enhanced tables this API will operate on.
-         *   Can be one of:
-         *
-         *   * `string` - jQuery selector. Any DataTables' matching the given selector
-         *     with be found and used.
-         *   * `node` - `TABLE` node which has already been formed into a DataTable.
-         *   * `jQuery` - A jQuery object of `TABLE` nodes.
-         *   * `object` - DataTables settings object
-         * @param {array} [data] Data to initialise the Api instance with.
-         *
-         * @example
-         *   // Direct initialisation during DataTables construction
-         *   var api = $('#example').DataTable();
-         *
-         * @example
-         *   // Initialisation using a DataTables jQuery object
-         *   var api = $('#example').dataTable().api();
-         *
-         * @example
-         *   // Initialisation as a constructor
-         *   var api = new $.fn.DataTable.Api( 'table.dataTable' );
-         */
-        _Api = function (context, data) {
-            if (!(this instanceof _Api)) {
-                return new _Api(context, data);
-            }
-
-            var settings = [];
-            var ctxSettings = function (o) {
-                var a = _toSettings(o);
-                if (a) {
-                    settings.push.apply(settings, a);
-                }
-            };
-
-            if ($.isArray(context)) {
-                for (var i = 0, ien = context.length ; i < ien ; i++) {
-                    ctxSettings(context[i]);
-                }
-            }
-            else {
-                ctxSettings(context);
-            }
-
-            // Remove duplicates
-            this.context = _unique(settings);
-
-            // Initial data
-            if (data) {
-                this.push.apply(this, data.toArray ? data.toArray() : data);
-            }
-
-            // selector
-            this.selector = {
-                rows: null,
-                cols: null,
-                opts: null
-            };
-
-            _Api.extend(this, this, __apiStruct);
-        };
-
-        DataTable.Api = _Api;
-
-        _Api.prototype = /** @lends DataTables.Api */{
-            any: function () {
-                return this.flatten().length !== 0;
-            },
-
-
-            concat: __arrayProto.concat,
-
-
-            context: [], // array of table settings objects
-
-
-            each: function (fn) {
-                for (var i = 0, ien = this.length ; i < ien; i++) {
-                    fn.call(this, this[i], i, this);
-                }
-
-                return this;
-            },
-
-
-            eq: function (idx) {
-                var ctx = this.context;
-
-                return ctx.length > idx ?
-                    new _Api(ctx[idx], this[idx]) :
-                    null;
-            },
-
-
-            filter: function (fn) {
-                var a = [];
-
-                if (__arrayProto.filter) {
-                    a = __arrayProto.filter.call(this, fn, this);
-                }
-                else {
-                    // Compatibility for browsers without EMCA-252-5 (JS 1.6)
-                    for (var i = 0, ien = this.length ; i < ien ; i++) {
-                        if (fn.call(this, this[i], i, this)) {
-                            a.push(this[i]);
-                        }
-                    }
-                }
-
-                return new _Api(this.context, a);
-            },
-
-
-            flatten: function () {
-                var a = [];
-                return new _Api(this.context, a.concat.apply(a, this.toArray()));
-            },
-
-
-            join: __arrayProto.join,
-
-
-            indexOf: __arrayProto.indexOf || function (obj, start) {
-                for (var i = (start || 0), ien = this.length ; i < ien ; i++) {
-                    if (this[i] === obj) {
-                        return i;
-                    }
-                }
-                return -1;
-            },
-
-            iterator: function (flatten, type, fn, alwaysNew) {
-                var
-                    a = [], ret,
-                    i, ien, j, jen,
-                    context = this.context,
-                    rows, items, item,
-                    selector = this.selector;
-
-                // Argument shifting
-                if (typeof flatten === 'string') {
-                    alwaysNew = fn;
-                    fn = type;
-                    type = flatten;
-                    flatten = false;
-                }
-
-                for (i = 0, ien = context.length ; i < ien ; i++) {
-                    var apiInst = new _Api(context[i]);
-
-                    if (type === 'table') {
-                        ret = fn.call(apiInst, context[i], i);
-
-                        if (ret !== undefined) {
-                            a.push(ret);
-                        }
-                    }
-                    else if (type === 'columns' || type === 'rows') {
-                        // this has same length as context - one entry for each table
-                        ret = fn.call(apiInst, context[i], this[i], i);
-
-                        if (ret !== undefined) {
-                            a.push(ret);
-                        }
-                    }
-                    else if (type === 'column' || type === 'column-rows' || type === 'row' || type === 'cell') {
-                        // columns and rows share the same structure.
-                        // 'this' is an array of column indexes for each context
-                        items = this[i];
-
-                        if (type === 'column-rows') {
-                            rows = _selector_row_indexes(context[i], selector.opts);
-                        }
-
-                        for (j = 0, jen = items.length ; j < jen ; j++) {
-                            item = items[j];
-
-                            if (type === 'cell') {
-                                ret = fn.call(apiInst, context[i], item.row, item.column, i, j);
-                            }
-                            else {
-                                ret = fn.call(apiInst, context[i], item, i, j, rows);
-                            }
-
-                            if (ret !== undefined) {
-                                a.push(ret);
-                            }
-                        }
-                    }
-                }
-
-                if (a.length || alwaysNew) {
-                    var api = new _Api(context, flatten ? a.concat.apply([], a) : a);
-                    var apiSelector = api.selector;
-                    apiSelector.rows = selector.rows;
-                    apiSelector.cols = selector.cols;
-                    apiSelector.opts = selector.opts;
-                    return api;
-                }
-                return this;
-            },
-
-
-            lastIndexOf: __arrayProto.lastIndexOf || function (obj, start) {
-                // Bit cheeky...
-                return this.indexOf.apply(this.toArray.reverse(), arguments);
-            },
-
-
-            length: 0,
-
-
-            map: function (fn) {
-                var a = [];
-
-                if (__arrayProto.map) {
-                    a = __arrayProto.map.call(this, fn, this);
-                }
-                else {
-                    // Compatibility for browsers without EMCA-252-5 (JS 1.6)
-                    for (var i = 0, ien = this.length ; i < ien ; i++) {
-                        a.push(fn.call(this, this[i], i));
-                    }
-                }
-
-                return new _Api(this.context, a);
-            },
-
-
-            pluck: function (prop) {
-                return this.map(function (el) {
-                    return el[prop];
-                });
-            },
-
-            pop: __arrayProto.pop,
-
-
-            push: __arrayProto.push,
-
-
-            // Does not return an API instance
-            reduce: __arrayProto.reduce || function (fn, init) {
-                return _fnReduce(this, fn, init, 0, this.length, 1);
-            },
-
-
-            reduceRight: __arrayProto.reduceRight || function (fn, init) {
-                return _fnReduce(this, fn, init, this.length - 1, -1, -1);
-            },
-
-
-            reverse: __arrayProto.reverse,
-
-
-            // Object with rows, columns and opts
-            selector: null,
-
-
-            shift: __arrayProto.shift,
-
-
-            sort: __arrayProto.sort, // ? name - order?
-
-
-            splice: __arrayProto.splice,
-
-
-            toArray: function () {
-                return __arrayProto.slice.call(this);
-            },
-
-
-            to$: function () {
-                return $(this);
-            },
-
-
-            toJQuery: function () {
-                return $(this);
-            },
-
-
-            unique: function () {
-                return new _Api(this.context, _unique(this));
-            },
-
-
-            unshift: __arrayProto.unshift
-        };
-
-
-        _Api.extend = function (scope, obj, ext) {
-            // Only extend API instances and static properties of the API
-            if (!ext.length || !obj || (!(obj instanceof _Api) && !obj.__dt_wrapper)) {
-                return;
-            }
-
-            var
-                i, ien,
-                j, jen,
-                struct, inner,
-                methodScoping = function (scope, fn, struc) {
-                    return function () {
-                        var ret = fn.apply(scope, arguments);
-
-                        // Method extension
-                        _Api.extend(ret, ret, struc.methodExt);
-                        return ret;
-                    };
-                };
-
-            for (i = 0, ien = ext.length ; i < ien ; i++) {
-                struct = ext[i];
-
-                // Value
-                obj[struct.name] = typeof struct.val === 'function' ?
-                    methodScoping(scope, struct.val, struct) :
-                    $.isPlainObject(struct.val) ?
-					{} :
-                        struct.val;
-
-                obj[struct.name].__dt_wrapper = true;
-
-                // Property extension
-                _Api.extend(scope, obj[struct.name], struct.propExt);
-            }
-        };
-
-
-        // @todo - Is there need for an augment function?
-        // _Api.augment = function ( inst, name )
-        // {
-        // 	// Find src object in the structure from the name
-        // 	var parts = name.split('.');
-
-        // 	_Api.extend( inst, obj );
-        // };
-
-
-        //     [
-        //       {
-        //         name:      'data'                -- string   - Property name
-        //         val:       function () {},       -- function - Api method (or undefined if just an object
-        //         methodExt: [ ... ],              -- array    - Array of Api object definitions to extend the method result
-        //         propExt:   [ ... ]               -- array    - Array of Api object definitions to extend the property
-        //       },
-        //       {
-        //         name:     'row'
-        //         val:       {},
-        //         methodExt: [ ... ],
-        //         propExt:   [
-        //           {
-        //             name:      'data'
-        //             val:       function () {},
-        //             methodExt: [ ... ],
-        //             propExt:   [ ... ]
-        //           },
-        //           ...
-        //         ]
-        //       }
-        //     ]
-
-        _Api.register = _api_register = function (name, val) {
-            if ($.isArray(name)) {
-                for (var j = 0, jen = name.length ; j < jen ; j++) {
-                    _Api.register(name[j], val);
-                }
-                return;
-            }
-
-            var
-                i, ien,
-                heir = name.split('.'),
-                struct = __apiStruct,
-                key, method;
-
-            var find = function (src, name) {
-                for (var i = 0, ien = src.length ; i < ien ; i++) {
-                    if (src[i].name === name) {
-                        return src[i];
-                    }
-                }
-                return null;
-            };
-
-            for (i = 0, ien = heir.length ; i < ien ; i++) {
-                method = heir[i].indexOf('()') !== -1;
-                key = method ?
-                    heir[i].replace('()', '') :
-                    heir[i];
-
-                var src = find(struct, key);
-                if (!src) {
-                    src = {
-                        name: key,
-                        val: {},
-                        methodExt: [],
-                        propExt: []
-                    };
-                    struct.push(src);
-                }
-
-                if (i === ien - 1) {
-                    src.val = val;
-                }
-                else {
-                    struct = method ?
-                        src.methodExt :
-                        src.propExt;
-                }
-            }
-        };
-
-
-        _Api.registerPlural = _api_registerPlural = function (pluralName, singularName, val) {
-            _Api.register(pluralName, val);
-
-            _Api.register(singularName, function () {
-                var ret = val.apply(this, arguments);
-
-                if (ret === this) {
-                    // Returned item is the API instance that was passed in, return it
-                    return this;
-                }
-                else if (ret instanceof _Api) {
-                    // New API instance returned, want the value from the first item
-                    // in the returned array for the singular result.
-                    return ret.length ?
-                        $.isArray(ret[0]) ?
-                            new _Api(ret.context, ret[0]) : // Array results are 'enhanced'
-                            ret[0] :
-                        undefined;
-                }
-
-                // Non-API return - just fire it back
-                return ret;
-            });
-        };
-
-
-        /**
-         * Selector for HTML tables. Apply the given selector to the give array of
-         * DataTables settings objects.
-         *
-         * @param {string|integer} [selector] jQuery selector string or integer
-         * @param  {array} Array of DataTables settings objects to be filtered
-         * @return {array}
-         * @ignore
-         */
-        var __table_selector = function (selector, a) {
-            // Integer is used to pick out a table by index
-            if (typeof selector === 'number') {
-                return [a[selector]];
-            }
-
-            // Perform a jQuery selector on the table nodes
-            var nodes = $.map(a, function (el, i) {
-                return el.nTable;
-            });
-
-            return $(nodes)
-                .filter(selector)
-                .map(function (i) {
-                    // Need to translate back from the table node to the settings
-                    var idx = $.inArray(this, nodes);
-                    return a[idx];
-                })
-                .toArray();
-        };
-
-
-
-        /**
-         * Context selector for the API's context (i.e. the tables the API instance
-         * refers to.
-         *
-         * @name    DataTable.Api#tables
-         * @param {string|integer} [selector] Selector to pick which tables the iterator
-         *   should operate on. If not given, all tables in the current context are
-         *   used. This can be given as a jQuery selector (for example `':gt(0)'`) to
-         *   select multiple tables or as an integer to select a single table.
-         * @returns {DataTable.Api} Returns a new API instance if a selector is given.
-         */
-        _api_register('tables()', function (selector) {
-            // A new instance is created if there was a selector specified
-            return selector ?
-                new _Api(__table_selector(selector, this.context)) :
-                this;
-        });
-
-
-        _api_register('table()', function (selector) {
-            var tables = this.tables(selector);
-            var ctx = tables.context;
-
-            // Truncate to the first matched table
-            return ctx.length ?
-                new _Api(ctx[0]) :
-                tables;
-        });
-
-
-        _api_registerPlural('tables().nodes()', 'table().node()', function () {
-            return this.iterator('table', function (ctx) {
-                return ctx.nTable;
-            }, 1);
-        });
-
-
-        _api_registerPlural('tables().body()', 'table().body()', function () {
-            return this.iterator('table', function (ctx) {
-                return ctx.nTBody;
-            }, 1);
-        });
-
-
-        _api_registerPlural('tables().header()', 'table().header()', function () {
-            return this.iterator('table', function (ctx) {
-                return ctx.nTHead;
-            }, 1);
-        });
-
-
-        _api_registerPlural('tables().footer()', 'table().footer()', function () {
-            return this.iterator('table', function (ctx) {
-                return ctx.nTFoot;
-            }, 1);
-        });
-
-
-        _api_registerPlural('tables().containers()', 'table().container()', function () {
-            return this.iterator('table', function (ctx) {
-                return ctx.nTableWrapper;
-            }, 1);
-        });
-
-
-
-        /**
-         * Redraw the tables in the current context.
-         *
-         * @param {boolean} [reset=true] Reset (default) or hold the current paging
-         *   position. A full re-sort and re-filter is performed when this method is
-         *   called, which is why the pagination reset is the default action.
-         * @returns {DataTables.Api} this
-         */
-        _api_register('draw()', function (resetPaging) {
-            return this.iterator('table', function (settings) {
-                _fnReDraw(settings, resetPaging === false);
-            });
-        });
-
-
-
-        /**
-         * Get the current page index.
-         *
-         * @return {integer} Current page index (zero based)
-         *//**
-	 * Set the current page.
-	 *
-	 * Note that if you attempt to show a page which does not exist, DataTables will
-	 * not throw an error, but rather reset the paging.
-	 *
-	 * @param {integer|string} action The paging action to take. This can be one of:
-	 *  * `integer` - The page index to jump to
-	 *  * `string` - An action to take:
-	 *    * `first` - Jump to first page.
-	 *    * `next` - Jump to the next page
-	 *    * `previous` - Jump to previous page
-	 *    * `last` - Jump to the last page.
-	 * @returns {DataTables.Api} this
-	 */
-        _api_register('page()', function (action) {
-            if (action === undefined) {
-                return this.page.info().page; // not an expensive call
-            }
-
-            // else, have an action to take on all tables
-            return this.iterator('table', function (settings) {
-                _fnPageChange(settings, action);
-            });
-        });
-
-
-        /**
-         * Paging information for the first table in the current context.
-         *
-         * If you require paging information for another table, use the `table()` method
-         * with a suitable selector.
-         *
-         * @return {object} Object with the following properties set:
-         *  * `page` - Current page index (zero based - i.e. the first page is `0`)
-         *  * `pages` - Total number of pages
-         *  * `start` - Display index for the first record shown on the current page
-         *  * `end` - Display index for the last record shown on the current page
-         *  * `length` - Display length (number of records). Note that generally `start
-         *    + length = end`, but this is not always true, for example if there are
-         *    only 2 records to show on the final page, with a length of 10.
-         *  * `recordsTotal` - Full data set length
-         *  * `recordsDisplay` - Data set length once the current filtering criterion
-         *    are applied.
-         */
-        _api_register('page.info()', function (action) {
-            if (this.context.length === 0) {
-                return undefined;
-            }
-
-            var
-                settings = this.context[0],
-                start = settings._iDisplayStart,
-                len = settings._iDisplayLength,
-                visRecords = settings.fnRecordsDisplay(),
-                all = len === -1;
-
-            return {
-                "page": all ? 0 : Math.floor(start / len),
-                "pages": all ? 1 : Math.ceil(visRecords / len),
-                "start": start,
-                "end": settings.fnDisplayEnd(),
-                "length": len,
-                "recordsTotal": settings.fnRecordsTotal(),
-                "recordsDisplay": visRecords
-            };
-        });
-
-
-        /**
-         * Get the current page length.
-         *
-         * @return {integer} Current page length. Note `-1` indicates that all records
-         *   are to be shown.
-         *//**
-	 * Set the current page length.
-	 *
-	 * @param {integer} Page length to set. Use `-1` to show all records.
-	 * @returns {DataTables.Api} this
-	 */
-        _api_register('page.len()', function (len) {
-            // Note that we can't call this function 'length()' because `length`
-            // is a Javascript property of functions which defines how many arguments
-            // the function expects.
-            if (len === undefined) {
-                return this.context.length !== 0 ?
-                    this.context[0]._iDisplayLength :
-                    undefined;
-            }
-
-            // else, set the page length
-            return this.iterator('table', function (settings) {
-                _fnLengthChange(settings, len);
-            });
-        });
-
-
-
-        var __reload = function (settings, holdPosition, callback) {
-            // Use the draw event to trigger a callback
-            if (callback) {
-                var api = new _Api(settings);
-
-                api.one('draw', function () {
-                    callback(api.ajax.json());
-                });
-            }
-
-            if (_fnDataSource(settings) == 'ssp') {
-                _fnReDraw(settings, holdPosition);
-            }
-            else {
-                // Trigger xhr
-                _fnProcessingDisplay(settings, true);
-
-                _fnBuildAjax(settings, [], function (json) {
-                    _fnClearTable(settings);
-
-                    var data = _fnAjaxDataSrc(settings, json);
-                    for (var i = 0, ien = data.length ; i < ien ; i++) {
-                        _fnAddData(settings, data[i]);
-                    }
-
-                    _fnReDraw(settings, holdPosition);
-                    _fnProcessingDisplay(settings, false);
-                });
-            }
-        };
-
-
-        /**
-         * Get the JSON response from the last Ajax request that DataTables made to the
-         * server. Note that this returns the JSON from the first table in the current
-         * context.
-         *
-         * @return {object} JSON received from the server.
-         */
-        _api_register('ajax.json()', function () {
-            var ctx = this.context;
-
-            if (ctx.length > 0) {
-                return ctx[0].json;
-            }
-
-            // else return undefined;
-        });
-
-
-        /**
-         * Get the data submitted in the last Ajax request
-         */
-        _api_register('ajax.params()', function () {
-            var ctx = this.context;
-
-            if (ctx.length > 0) {
-                return ctx[0].oAjaxData;
-            }
-
-            // else return undefined;
-        });
-
-
-        /**
-         * Reload tables from the Ajax data source. Note that this function will
-         * automatically re-draw the table when the remote data has been loaded.
-         *
-         * @param {boolean} [reset=true] Reset (default) or hold the current paging
-         *   position. A full re-sort and re-filter is performed when this method is
-         *   called, which is why the pagination reset is the default action.
-         * @returns {DataTables.Api} this
-         */
-        _api_register('ajax.reload()', function (callback, resetPaging) {
-            return this.iterator('table', function (settings) {
-                __reload(settings, resetPaging === false, callback);
-            });
-        });
-
-
-        /**
-         * Get the current Ajax URL. Note that this returns the URL from the first
-         * table in the current context.
-         *
-         * @return {string} Current Ajax source URL
-         *//**
-	 * Set the Ajax URL. Note that this will set the URL for all tables in the
-	 * current context.
-	 *
-	 * @param {string} url URL to set.
-	 * @returns {DataTables.Api} this
-	 */
-        _api_register('ajax.url()', function (url) {
-            var ctx = this.context;
-
-            if (url === undefined) {
-                // get
-                if (ctx.length === 0) {
-                    return undefined;
-                }
-                ctx = ctx[0];
-
-                return ctx.ajax ?
-                    $.isPlainObject(ctx.ajax) ?
-                        ctx.ajax.url :
-                        ctx.ajax :
-                    ctx.sAjaxSource;
-            }
-
-            // set
-            return this.iterator('table', function (settings) {
-                if ($.isPlainObject(settings.ajax)) {
-                    settings.ajax.url = url;
-                }
-                else {
-                    settings.ajax = url;
-                }
-                // No need to consider sAjaxSource here since DataTables gives priority
-                // to `ajax` over `sAjaxSource`. So setting `ajax` here, renders any
-                // value of `sAjaxSource` redundant.
-            });
-        });
-
-
-        /**
-         * Load data from the newly set Ajax URL. Note that this method is only
-         * available when `ajax.url()` is used to set a URL. Additionally, this method
-         * has the same effect as calling `ajax.reload()` but is provided for
-         * convenience when setting a new URL. Like `ajax.reload()` it will
-         * automatically redraw the table once the remote data has been loaded.
-         *
-         * @returns {DataTables.Api} this
-         */
-        _api_register('ajax.url().load()', function (callback, resetPaging) {
-            // Same as a reload, but makes sense to present it for easy access after a
-            // url change
-            return this.iterator('table', function (ctx) {
-                __reload(ctx, resetPaging === false, callback);
-            });
-        });
-
-
-
-
-        var _selector_run = function (type, selector, selectFn, settings, opts) {
-            var
-                out = [], res,
-                a, i, ien, j, jen,
-                selectorType = typeof selector;
-
-            // Can't just check for isArray here, as an API or jQuery instance might be
-            // given with their array like look
-            if (!selector || selectorType === 'string' || selectorType === 'function' || selector.length === undefined) {
-                selector = [selector];
-            }
-
-            for (i = 0, ien = selector.length ; i < ien ; i++) {
-                a = selector[i] && selector[i].split ?
-                    selector[i].split(',') :
-                    [selector[i]];
-
-                for (j = 0, jen = a.length ; j < jen ; j++) {
-                    res = selectFn(typeof a[j] === 'string' ? $.trim(a[j]) : a[j]);
-
-                    if (res && res.length) {
-                        out.push.apply(out, res);
-                    }
-                }
-            }
-
-            // selector extensions
-            var ext = _ext.selector[type];
-            if (ext.length) {
-                for (i = 0, ien = ext.length ; i < ien ; i++) {
-                    out = ext[i](settings, opts, out);
-                }
-            }
-
-            return out;
-        };
-
-
-        var _selector_opts = function (opts) {
-            if (!opts) {
-                opts = {};
-            }
-
-            // Backwards compatibility for 1.9- which used the terminology filter rather
-            // than search
-            if (opts.filter && opts.search === undefined) {
-                opts.search = opts.filter;
-            }
-
-            return $.extend({
-                search: 'none',
-                order: 'current',
-                page: 'all'
-            }, opts);
-        };
-
-
-        var _selector_first = function (inst) {
-            // Reduce the API instance to the first item found
-            for (var i = 0, ien = inst.length ; i < ien ; i++) {
-                if (inst[i].length > 0) {
-                    // Assign the first element to the first item in the instance
-                    // and truncate the instance and context
-                    inst[0] = inst[i];
-                    inst[0].length = 1;
-                    inst.length = 1;
-                    inst.context = [inst.context[i]];
-
-                    return inst;
-                }
-            }
-
-            // Not found - return an empty instance
-            inst.length = 0;
-            return inst;
-        };
-
-
-        var _selector_row_indexes = function (settings, opts) {
-            var
-                i, ien, tmp, a = [],
-                displayFiltered = settings.aiDisplay,
-                displayMaster = settings.aiDisplayMaster;
-
-            var
-                search = opts.search,  // none, applied, removed
-                order = opts.order,   // applied, current, index (original - compatibility with 1.9)
-                page = opts.page;    // all, current
-
-            if (_fnDataSource(settings) == 'ssp') {
-                // In server-side processing mode, most options are irrelevant since
-                // rows not shown don't exist and the index order is the applied order
-                // Removed is a special case - for consistency just return an empty
-                // array
-                return search === 'removed' ?
-                    [] :
-                    _range(0, displayMaster.length);
-            }
-            else if (page == 'current') {
-                // Current page implies that order=current and fitler=applied, since it is
-                // fairly senseless otherwise, regardless of what order and search actually
-                // are
-                for (i = settings._iDisplayStart, ien = settings.fnDisplayEnd() ; i < ien ; i++) {
-                    a.push(displayFiltered[i]);
-                }
-            }
-            else if (order == 'current' || order == 'applied') {
-                a = search == 'none' ?
-                    displayMaster.slice() :                      // no search
-                    search == 'applied' ?
-                        displayFiltered.slice() :                // applied search
-                        $.map(displayMaster, function (el, i) { // removed search
-                            return $.inArray(el, displayFiltered) === -1 ? el : null;
-                        });
-            }
-            else if (order == 'index' || order == 'original') {
-                for (i = 0, ien = settings.aoData.length ; i < ien ; i++) {
-                    if (search == 'none') {
-                        a.push(i);
-                    }
-                    else { // applied | removed
-                        tmp = $.inArray(i, displayFiltered);
-
-                        if ((tmp === -1 && search == 'removed') ||
-                            (tmp >= 0 && search == 'applied')) {
-                            a.push(i);
-                        }
-                    }
-                }
-            }
-
-            return a;
-        };
-
-
-        /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
-         * Rows
-         *
-         * {}          - no selector - use all available rows
-         * {integer}   - row aoData index
-         * {node}      - TR node
-         * {string}    - jQuery selector to apply to the TR elements
-         * {array}     - jQuery array of nodes, or simply an array of TR nodes
-         *
-         */
-
-
-        var __row_selector = function (settings, selector, opts) {
-            var run = function (sel) {
-                var selInt = _intVal(sel);
-                var i, ien;
-
-                // Short cut - selector is a number and no options provided (default is
-                // all records, so no need to check if the index is in there, since it
-                // must be - dev error if the index doesn't exist).
-                if (selInt !== null && !opts) {
-                    return [selInt];
-                }
-
-                var rows = _selector_row_indexes(settings, opts);
-
-                if (selInt !== null && $.inArray(selInt, rows) !== -1) {
-                    // Selector - integer
-                    return [selInt];
-                }
-                else if (!sel) {
-                    // Selector - none
-                    return rows;
-                }
-
-                // Selector - function
-                if (typeof sel === 'function') {
-                    return $.map(rows, function (idx) {
-                        var row = settings.aoData[idx];
-                        return sel(idx, row._aData, row.nTr) ? idx : null;
-                    });
-                }
-
-                // Get nodes in the order from the `rows` array with null values removed
-                var nodes = _removeEmpty(
-                    _pluck_order(settings.aoData, rows, 'nTr')
-                );
-
-                // Selector - node
-                if (sel.nodeName) {
-                    if ($.inArray(sel, nodes) !== -1) {
-                        return [sel._DT_RowIndex]; // sel is a TR node that is in the table
-                        // and DataTables adds a prop for fast lookup
-                    }
-                }
-
-                // Selector - jQuery selector string, array of nodes or jQuery object/
-                // As jQuery's .filter() allows jQuery objects to be passed in filter,
-                // it also allows arrays, so this will cope with all three options
-                return $(nodes)
-                    .filter(sel)
-                    .map(function () {
-                        return this._DT_RowIndex;
-                    })
-                    .toArray();
-            };
-
-            return _selector_run('row', selector, run, settings, opts);
-        };
-
-
-        _api_register('rows()', function (selector, opts) {
-            // argument shifting
-            if (selector === undefined) {
-                selector = '';
-            }
-            else if ($.isPlainObject(selector)) {
-                opts = selector;
-                selector = '';
-            }
-
-            opts = _selector_opts(opts);
-
-            var inst = this.iterator('table', function (settings) {
-                return __row_selector(settings, selector, opts);
-            }, 1);
-
-            // Want argument shifting here and in __row_selector?
-            inst.selector.rows = selector;
-            inst.selector.opts = opts;
-
-            return inst;
-        });
-
-        _api_register('rows().nodes()', function () {
-            return this.iterator('row', function (settings, row) {
-                return settings.aoData[row].nTr || undefined;
-            }, 1);
-        });
-
-        _api_register('rows().data()', function () {
-            return this.iterator(true, 'rows', function (settings, rows) {
-                return _pluck_order(settings.aoData, rows, '_aData');
-            }, 1);
-        });
-
-        _api_registerPlural('rows().cache()', 'row().cache()', function (type) {
-            return this.iterator('row', function (settings, row) {
-                var r = settings.aoData[row];
-                return type === 'search' ? r._aFilterData : r._aSortData;
-            }, 1);
-        });
-
-        _api_registerPlural('rows().invalidate()', 'row().invalidate()', function (src) {
-            return this.iterator('row', function (settings, row) {
-                _fnInvalidate(settings, row, src);
-            });
-        });
-
-        _api_registerPlural('rows().indexes()', 'row().index()', function () {
-            return this.iterator('row', function (settings, row) {
-                return row;
-            }, 1);
-        });
-
-        _api_registerPlural('rows().remove()', 'row().remove()', function () {
-            var that = this;
-
-            return this.iterator('row', function (settings, row, thatIdx) {
-                var data = settings.aoData;
-
-                data.splice(row, 1);
-
-                // Update the _DT_RowIndex parameter on all rows in the table
-                for (var i = 0, ien = data.length ; i < ien ; i++) {
-                    if (data[i].nTr !== null) {
-                        data[i].nTr._DT_RowIndex = i;
-                    }
-                }
-
-                // Remove the target row from the search array
-                var displayIndex = $.inArray(row, settings.aiDisplay);
-
-                // Delete from the display arrays
-                _fnDeleteIndex(settings.aiDisplayMaster, row);
-                _fnDeleteIndex(settings.aiDisplay, row);
-                _fnDeleteIndex(that[thatIdx], row, false); // maintain local indexes
-
-                // Check for an 'overflow' they case for displaying the table
-                _fnLengthOverflow(settings);
-            });
-        });
-
-
-        _api_register('rows.add()', function (rows) {
-            var newRows = this.iterator('table', function (settings) {
-                var row, i, ien;
-                var out = [];
-
-                for (i = 0, ien = rows.length ; i < ien ; i++) {
-                    row = rows[i];
-
-                    if (row.nodeName && row.nodeName.toUpperCase() === 'TR') {
-                        out.push(_fnAddTr(settings, row)[0]);
-                    }
-                    else {
-                        out.push(_fnAddData(settings, row));
-                    }
-                }
-
-                return out;
-            }, 1);
-
-            // Return an Api.rows() extended instance, so rows().nodes() etc can be used
-            var modRows = this.rows(-1);
-            modRows.pop();
-            modRows.push.apply(modRows, newRows.toArray());
-
-            return modRows;
-        });
-
-
-
-
-
-        /**
-         *
-         */
-        _api_register('row()', function (selector, opts) {
-            return _selector_first(this.rows(selector, opts));
-        });
-
-
-        _api_register('row().data()', function (data) {
-            var ctx = this.context;
-
-            if (data === undefined) {
-                // Get
-                return ctx.length && this.length ?
-                    ctx[0].aoData[this[0]]._aData :
-                    undefined;
-            }
-
-            // Set
-            ctx[0].aoData[this[0]]._aData = data;
-
-            // Automatically invalidate
-            _fnInvalidate(ctx[0], this[0], 'data');
-
-            return this;
-        });
-
-
-        _api_register('row().node()', function () {
-            var ctx = this.context;
-
-            return ctx.length && this.length ?
-                ctx[0].aoData[this[0]].nTr || null :
-                null;
-        });
-
-
-        _api_register('row.add()', function (row) {
-            // Allow a jQuery object to be passed in - only a single row is added from
-            // it though - the first element in the set
-            if (row instanceof $ && row.length) {
-                row = row[0];
-            }
-
-            var rows = this.iterator('table', function (settings) {
-                if (row.nodeName && row.nodeName.toUpperCase() === 'TR') {
-                    return _fnAddTr(settings, row)[0];
-                }
-                return _fnAddData(settings, row);
-            });
-
-            // Return an Api.rows() extended instance, with the newly added row selected
-            return this.row(rows[0]);
-        });
-
-
-
-        var __details_add = function (ctx, row, data, klass) {
-            // Convert to array of TR elements
-            var rows = [];
-            var addRow = function (r, k) {
-                // Recursion to allow for arrays of jQuery objects
-                if ($.isArray(r) || r instanceof $) {
-                    for (var i = 0, ien = r.length ; i < ien ; i++) {
-                        addRow(r[i], k);
-                    }
-                    return;
-                }
-
-                // If we get a TR element, then just add it directly - up to the dev
-                // to add the correct number of columns etc
-                if (r.nodeName && r.nodeName.toLowerCase() === 'tr') {
-                    rows.push(r);
-                }
-                else {
-                    // Otherwise create a row with a wrapper
-                    var created = $('<tr><td/></tr>').addClass(k);
-                    $('td', created)
-                        .addClass(k)
-                        .html(r)
-                        [0].colSpan = _fnVisbleColumns(ctx);
-
-                    rows.push(created[0]);
-                }
-            };
-
-            addRow(data, klass);
-
-            if (row._details) {
-                row._details.remove();
-            }
-
-            row._details = $(rows);
-
-            // If the children were already shown, that state should be retained
-            if (row._detailsShow) {
-                row._details.insertAfter(row.nTr);
-            }
-        };
-
-
-        var __details_remove = function (api, idx) {
-            var ctx = api.context;
-
-            if (ctx.length) {
-                var row = ctx[0].aoData[idx !== undefined ? idx : api[0]];
-
-                if (row._details) {
-                    row._details.remove();
-
-                    row._detailsShow = undefined;
-                    row._details = undefined;
-                }
-            }
-        };
-
-
-        var __details_display = function (api, show) {
-            var ctx = api.context;
-
-            if (ctx.length && api.length) {
-                var row = ctx[0].aoData[api[0]];
-
-                if (row._details) {
-                    row._detailsShow = show;
-
-                    if (show) {
-                        row._details.insertAfter(row.nTr);
-                    }
-                    else {
-                        row._details.detach();
-                    }
-
-                    __details_events(ctx[0]);
-                }
-            }
-        };
-
-
-        var __details_events = function (settings) {
-            var api = new _Api(settings);
-            var namespace = '.dt.DT_details';
-            var drawEvent = 'draw' + namespace;
-            var colvisEvent = 'column-visibility' + namespace;
-            var destroyEvent = 'destroy' + namespace;
-            var data = settings.aoData;
-
-            api.off(drawEvent + ' ' + colvisEvent + ' ' + destroyEvent);
-
-            if (_pluck(data, '_details').length > 0) {
-                // On each draw, insert the required elements into the document
-                api.on(drawEvent, function (e, ctx) {
-                    if (settings !== ctx) {
-                        return;
-                    }
-
-                    api.rows({ page: 'current' }).eq(0).each(function (idx) {
-                        // Internal data grab
-                        var row = data[idx];
-
-                        if (row._detailsShow) {
-                            row._details.insertAfter(row.nTr);
-                        }
-                    });
-                });
-
-                // Column visibility change - update the colspan
-                api.on(colvisEvent, function (e, ctx, idx, vis) {
-                    if (settings !== ctx) {
-                        return;
-                    }
-
-                    // Update the colspan for the details rows (note, only if it already has
-                    // a colspan)
-                    var row, visible = _fnVisbleColumns(ctx);
-
-                    for (var i = 0, ien = data.length ; i < ien ; i++) {
-                        row = data[i];
-
-                        if (row._details) {
-                            row._details.children('td[colspan]').attr('colspan', visible);
-                        }
-                    }
-                });
-
-                // Table destroyed - nuke any child rows
-                api.on(destroyEvent, function (e, ctx) {
-                    if (settings !== ctx) {
-                        return;
-                    }
-
-                    for (var i = 0, ien = data.length ; i < ien ; i++) {
-                        if (data[i]._details) {
-                            __details_remove(api, i);
-                        }
-                    }
-                });
-            }
-        };
-
-        // Strings for the method names to help minification
-        var _emp = '';
-        var _child_obj = _emp + 'row().child';
-        var _child_mth = _child_obj + '()';
-
-        // data can be:
-        //  tr
-        //  string
-        //  jQuery or array of any of the above
-        _api_register(_child_mth, function (data, klass) {
-            var ctx = this.context;
-
-            if (data === undefined) {
-                // get
-                return ctx.length && this.length ?
-                    ctx[0].aoData[this[0]]._details :
-                    undefined;
-            }
-            else if (data === true) {
-                // show
-                this.child.show();
-            }
-            else if (data === false) {
-                // remove
-                __details_remove(this);
-            }
-            else if (ctx.length && this.length) {
-                // set
-                __details_add(ctx[0], ctx[0].aoData[this[0]], data, klass);
-            }
-
-            return this;
-        });
-
-
-        _api_register([
-            _child_obj + '.show()',
-            _child_mth + '.show()' // only when `child()` was called with parameters (without
-        ], function (show) {   // it returns an object and this method is not executed)
-            __details_display(this, true);
-            return this;
-        });
-
-
-        _api_register([
-            _child_obj + '.hide()',
-            _child_mth + '.hide()' // only when `child()` was called with parameters (without
-        ], function () {         // it returns an object and this method is not executed)
-            __details_display(this, false);
-            return this;
-        });
-
-
-        _api_register([
-            _child_obj + '.remove()',
-            _child_mth + '.remove()' // only when `child()` was called with parameters (without
-        ], function () {           // it returns an object and this method is not executed)
-            __details_remove(this);
-            return this;
-        });
-
-
-        _api_register(_child_obj + '.isShown()', function () {
-            var ctx = this.context;
-
-            if (ctx.length && this.length) {
-                // _detailsShown as false or undefined will fall through to return false
-                return ctx[0].aoData[this[0]]._detailsShow || false;
-            }
-            return false;
-        });
-
-
-
-        /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
-         * Columns
-         *
-         * {integer}           - column index (>=0 count from left, <0 count from right)
-         * "{integer}:visIdx"  - visible column index (i.e. translate to column index)  (>=0 count from left, <0 count from right)
-         * "{integer}:visible" - alias for {integer}:visIdx  (>=0 count from left, <0 count from right)
-         * "{string}:name"     - column name
-         * "{string}"          - jQuery selector on column header nodes
-         *
-         */
-
-        // can be an array of these items, comma separated list, or an array of comma
-        // separated lists
-
-        var __re_column_selector = /^(.+):(name|visIdx|visible)$/;
-
-
-        // r1 and r2 are redundant - but it means that the parameters match for the
-        // iterator callback in columns().data()
-        var __columnData = function (settings, column, r1, r2, rows) {
-            var a = [];
-            for (var row = 0, ien = rows.length ; row < ien ; row++) {
-                a.push(_fnGetCellData(settings, rows[row], column));
-            }
-            return a;
-        };
-
-
-        var __column_selector = function (settings, selector, opts) {
-            var
-                columns = settings.aoColumns,
-                names = _pluck(columns, 'sName'),
-                nodes = _pluck(columns, 'nTh');
-
-            var run = function (s) {
-                var selInt = _intVal(s);
-
-                // Selector - all
-                if (s === '') {
-                    return _range(columns.length);
-                }
-
-                // Selector - index
-                if (selInt !== null) {
-                    return [selInt >= 0 ?
-                        selInt : // Count from left
-                        columns.length + selInt // Count from right (+ because its a negative value)
-                    ];
-                }
-
-                // Selector = function
-                if (typeof s === 'function') {
-                    var rows = _selector_row_indexes(settings, opts);
-
-                    return $.map(columns, function (col, idx) {
-                        return s(
-                                idx,
-                                __columnData(settings, idx, 0, 0, rows),
-                                nodes[idx]
-                            ) ? idx : null;
-                    });
-                }
-
-                // jQuery or string selector
-                var match = typeof s === 'string' ?
-                    s.match(__re_column_selector) :
-                    '';
-
-                if (match) {
-                    switch (match[2]) {
-                        case 'visIdx':
-                        case 'visible':
-                            var idx = parseInt(match[1], 10);
-                            // Visible index given, convert to column index
-                            if (idx < 0) {
-                                // Counting from the right
-                                var visColumns = $.map(columns, function (col, i) {
-                                    return col.bVisible ? i : null;
-                                });
-                                return [visColumns[visColumns.length + idx]];
-                            }
-                            // Counting from the left
-                            return [_fnVisibleToColumnIndex(settings, idx)];
-
-                        case 'name':
-                            // match by name. `names` is column index complete and in order
-                            return $.map(names, function (name, i) {
-                                return name === match[1] ? i : null;
-                            });
-                    }
-                }
-                else {
-                    // jQuery selector on the TH elements for the columns
-                    return $(nodes)
-                        .filter(s)
-                        .map(function () {
-                            return $.inArray(this, nodes); // `nodes` is column index complete and in order
-                        })
-                        .toArray();
-                }
-            };
-
-            return _selector_run('column', selector, run, settings, opts);
-        };
-
-
-        var __setColumnVis = function (settings, column, vis, recalc) {
-            var
-                cols = settings.aoColumns,
-                col = cols[column],
-                data = settings.aoData,
-                row, cells, i, ien, tr;
-
-            // Get
-            if (vis === undefined) {
-                return col.bVisible;
-            }
-
-            // Set
-            // No change
-            if (col.bVisible === vis) {
-                return;
-            }
-
-            if (vis) {
-                // Insert column
-                // Need to decide if we should use appendChild or insertBefore
-                var insertBefore = $.inArray(true, _pluck(cols, 'bVisible'), column + 1);
-
-                for (i = 0, ien = data.length ; i < ien ; i++) {
-                    tr = data[i].nTr;
-                    cells = data[i].anCells;
-
-                    if (tr) {
-                        // insertBefore can act like appendChild if 2nd arg is null
-                        tr.insertBefore(cells[column], cells[insertBefore] || null);
-                    }
-                }
-            }
-            else {
-                // Remove column
-                $(_pluck(settings.aoData, 'anCells', column)).detach();
-            }
-
-            // Common actions
-            col.bVisible = vis;
-            _fnDrawHead(settings, settings.aoHeader);
-            _fnDrawHead(settings, settings.aoFooter);
-
-            if (recalc === undefined || recalc) {
-                // Automatically adjust column sizing
-                _fnAdjustColumnSizing(settings);
-
-                // Realign columns for scrolling
-                if (settings.oScroll.sX || settings.oScroll.sY) {
-                    _fnScrollDraw(settings);
-                }
-            }
-
-            _fnCallbackFire(settings, null, 'column-visibility', [settings, column, vis]);
-
-            _fnSaveState(settings);
-        };
-
-
-        _api_register('columns()', function (selector, opts) {
-            // argument shifting
-            if (selector === undefined) {
-                selector = '';
-            }
-            else if ($.isPlainObject(selector)) {
-                opts = selector;
-                selector = '';
-            }
-
-            opts = _selector_opts(opts);
-
-            var inst = this.iterator('table', function (settings) {
-                return __column_selector(settings, selector, opts);
-            }, 1);
-
-            // Want argument shifting here and in _row_selector?
-            inst.selector.cols = selector;
-            inst.selector.opts = opts;
-
-            return inst;
-        });
-
-        _api_registerPlural('columns().header()', 'column().header()', function (selector, opts) {
-            return this.iterator('column', function (settings, column) {
-                return settings.aoColumns[column].nTh;
-            }, 1);
-        });
-
-        _api_registerPlural('columns().footer()', 'column().footer()', function (selector, opts) {
-            return this.iterator('column', function (settings, column) {
-                return settings.aoColumns[column].nTf;
-            }, 1);
-        });
-
-        _api_registerPlural('columns().data()', 'column().data()', function () {
-            return this.iterator('column-rows', __columnData, 1);
-        });
-
-        _api_registerPlural('columns().dataSrc()', 'column().dataSrc()', function () {
-            return this.iterator('column', function (settings, column) {
-                return settings.aoColumns[column].mData;
-            }, 1);
-        });
-
-        _api_registerPlural('columns().cache()', 'column().cache()', function (type) {
-            return this.iterator('column-rows', function (settings, column, i, j, rows) {
-                return _pluck_order(settings.aoData, rows,
-                    type === 'search' ? '_aFilterData' : '_aSortData', column
-                );
-            }, 1);
-        });
-
-        _api_registerPlural('columns().nodes()', 'column().nodes()', function () {
-            return this.iterator('column-rows', function (settings, column, i, j, rows) {
-                return _pluck_order(settings.aoData, rows, 'anCells', column);
-            }, 1);
-        });
-
-        _api_registerPlural('columns().visible()', 'column().visible()', function (vis, calc) {
-            return this.iterator('column', function (settings, column) {
-                if (vis === undefined) {
-                    return settings.aoColumns[column].bVisible;
-                } // else
-                __setColumnVis(settings, column, vis, calc);
-            });
-        });
-
-        _api_registerPlural('columns().indexes()', 'column().index()', function (type) {
-            return this.iterator('column', function (settings, column) {
-                return type === 'visible' ?
-                    _fnColumnIndexToVisible(settings, column) :
-                    column;
-            }, 1);
-        });
-
-        _api_register('columns.adjust()', function () {
-            return this.iterator('table', function (settings) {
-                _fnAdjustColumnSizing(settings);
-            }, 1);
-        });
-
-        _api_register('column.index()', function (type, idx) {
-            if (this.context.length !== 0) {
-                var ctx = this.context[0];
-
-                if (type === 'fromVisible' || type === 'toData') {
-                    return _fnVisibleToColumnIndex(ctx, idx);
-                }
-                else if (type === 'fromData' || type === 'toVisible') {
-                    return _fnColumnIndexToVisible(ctx, idx);
-                }
-            }
-        });
-
-        _api_register('column()', function (selector, opts) {
-            return _selector_first(this.columns(selector, opts));
-        });
-
-
-
-
-        var __cell_selector = function (settings, selector, opts) {
-            var data = settings.aoData;
-            var rows = _selector_row_indexes(settings, opts);
-            var cells = _removeEmpty(_pluck_order(data, rows, 'anCells'));
-            var allCells = $([].concat.apply([], cells));
-            var row;
-            var columns = settings.aoColumns.length;
-            var a, i, ien, j, o, host;
-
-            var run = function (s) {
-                var fnSelector = typeof s === 'function';
-
-                if (s === null || s === undefined || fnSelector) {
-                    // All cells and function selectors
-                    a = [];
-
-                    for (i = 0, ien = rows.length ; i < ien ; i++) {
-                        row = rows[i];
-
-                        for (j = 0 ; j < columns ; j++) {
-                            o = {
-                                row: row,
-                                column: j
-                            };
-
-                            if (fnSelector) {
-                                // Selector - function
-                                host = settings.aoData[row];
-
-                                if (s(o, _fnGetCellData(settings, row, j), host.anCells ? host.anCells[j] : null)) {
-                                    a.push(o);
-                                }
-                            }
-                            else {
-                                // Selector - all
-                                a.push(o);
-                            }
-                        }
-                    }
-
-                    return a;
-                }
-
-                // Selector - index
-                if ($.isPlainObject(s)) {
-                    return [s];
-                }
-
-                // Selector - jQuery filtered cells
-                return allCells
-                    .filter(s)
-                    .map(function (i, el) {
-                        row = el.parentNode._DT_RowIndex;
-
-                        return {
-                            row: row,
-                            column: $.inArray(el, data[row].anCells)
-                        };
-                    })
-                    .toArray();
-            };
-
-            return _selector_run('cell', selector, run, settings, opts);
-        };
-
-
-
-
-        _api_register('cells()', function (rowSelector, columnSelector, opts) {
-            // Argument shifting
-            if ($.isPlainObject(rowSelector)) {
-                // Indexes
-                if (rowSelector.row === undefined) {
-                    // Selector options in first parameter
-                    opts = rowSelector;
-                    rowSelector = null;
-                }
-                else {
-                    // Cell index objects in first parameter
-                    opts = columnSelector;
-                    columnSelector = null;
-                }
-            }
-            if ($.isPlainObject(columnSelector)) {
-                opts = columnSelector;
-                columnSelector = null;
-            }
-
-            // Cell selector
-            if (columnSelector === null || columnSelector === undefined) {
-                return this.iterator('table', function (settings) {
-                    return __cell_selector(settings, rowSelector, _selector_opts(opts));
-                });
-            }
-
-            // Row + column selector
-            var columns = this.columns(columnSelector, opts);
-            var rows = this.rows(rowSelector, opts);
-            var a, i, ien, j, jen;
-
-            var cells = this.iterator('table', function (settings, idx) {
-                a = [];
-
-                for (i = 0, ien = rows[idx].length ; i < ien ; i++) {
-                    for (j = 0, jen = columns[idx].length ; j < jen ; j++) {
-                        a.push({
-                            row: rows[idx][i],
-                            column: columns[idx][j]
-                        });
-                    }
-                }
-
-                return a;
-            }, 1);
-
-            $.extend(cells.selector, {
-                cols: columnSelector,
-                rows: rowSelector,
-                opts: opts
-            });
-
-            return cells;
-        });
-
-
-        _api_registerPlural('cells().nodes()', 'cell().node()', function () {
-            return this.iterator('cell', function (settings, row, column) {
-                var cells = settings.aoData[row].anCells;
-                return cells ?
-                    cells[column] :
-                    undefined;
-            }, 1);
-        });
-
-
-        _api_register('cells().data()', function () {
-            return this.iterator('cell', function (settings, row, column) {
-                return _fnGetCellData(settings, row, column);
-            }, 1);
-        });
-
-
-        _api_registerPlural('cells().cache()', 'cell().cache()', function (type) {
-            type = type === 'search' ? '_aFilterData' : '_aSortData';
-
-            return this.iterator('cell', function (settings, row, column) {
-                return settings.aoData[row][type][column];
-            }, 1);
-        });
-
-
-        _api_registerPlural('cells().render()', 'cell().render()', function (type) {
-            return this.iterator('cell', function (settings, row, column) {
-                return _fnGetCellData(settings, row, column, type);
-            }, 1);
-        });
-
-
-        _api_registerPlural('cells().indexes()', 'cell().index()', function () {
-            return this.iterator('cell', function (settings, row, column) {
-                return {
-                    row: row,
-                    column: column,
-                    columnVisible: _fnColumnIndexToVisible(settings, column)
-                };
-            }, 1);
-        });
-
-
-        _api_registerPlural('cells().invalidate()', 'cell().invalidate()', function (src) {
-            return this.iterator('cell', function (settings, row, column) {
-                _fnInvalidate(settings, row, src, column);
-            });
-        });
-
-
-
-        _api_register('cell()', function (rowSelector, columnSelector, opts) {
-            return _selector_first(this.cells(rowSelector, columnSelector, opts));
-        });
-
-
-        _api_register('cell().data()', function (data) {
-            var ctx = this.context;
-            var cell = this[0];
-
-            if (data === undefined) {
-                // Get
-                return ctx.length && cell.length ?
-                    _fnGetCellData(ctx[0], cell[0].row, cell[0].column) :
-                    undefined;
-            }
-
-            // Set
-            _fnSetCellData(ctx[0], cell[0].row, cell[0].column, data);
-            _fnInvalidate(ctx[0], cell[0].row, 'data', cell[0].column);
-
-            return this;
-        });
-
-
-
-        /**
-         * Get current ordering (sorting) that has been applied to the table.
-         *
-         * @returns {array} 2D array containing the sorting information for the first
-         *   table in the current context. Each element in the parent array represents
-         *   a column being sorted upon (i.e. multi-sorting with two columns would have
-         *   2 inner arrays). The inner arrays may have 2 or 3 elements. The first is
-         *   the column index that the sorting condition applies to, the second is the
-         *   direction of the sort (`desc` or `asc`) and, optionally, the third is the
-         *   index of the sorting order from the `column.sorting` initialisation array.
-         *//**
-	 * Set the ordering for the table.
-	 *
-	 * @param {integer} order Column index to sort upon.
-	 * @param {string} direction Direction of the sort to be applied (`asc` or `desc`)
-	 * @returns {DataTables.Api} this
-	 *//**
-	 * Set the ordering for the table.
-	 *
-	 * @param {array} order 1D array of sorting information to be applied.
-	 * @param {array} [...] Optional additional sorting conditions
-	 * @returns {DataTables.Api} this
-	 *//**
-	 * Set the ordering for the table.
-	 *
-	 * @param {array} order 2D array of sorting information to be applied.
-	 * @returns {DataTables.Api} this
-	 */
-        _api_register('order()', function (order, dir) {
-            var ctx = this.context;
-
-            if (order === undefined) {
-                // get
-                return ctx.length !== 0 ?
-                    ctx[0].aaSorting :
-                    undefined;
-            }
-
-            // set
-            if (typeof order === 'number') {
-                // Simple column / direction passed in
-                order = [[order, dir]];
-            }
-            else if (!$.isArray(order[0])) {
-                // Arguments passed in (list of 1D arrays)
-                order = Array.prototype.slice.call(arguments);
-            }
-            // otherwise a 2D array was passed in
-
-            return this.iterator('table', function (settings) {
-                settings.aaSorting = order.slice();
-            });
-        });
-
-
-        /**
-         * Attach a sort listener to an element for a given column
-         *
-         * @param {node|jQuery|string} node Identifier for the element(s) to attach the
-         *   listener to. This can take the form of a single DOM node, a jQuery
-         *   collection of nodes or a jQuery selector which will identify the node(s).
-         * @param {integer} column the column that a click on this node will sort on
-         * @param {function} [callback] callback function when sort is run
-         * @returns {DataTables.Api} this
-         */
-        _api_register('order.listener()', function (node, column, callback) {
-            return this.iterator('table', function (settings) {
-                _fnSortAttachListener(settings, node, column, callback);
-            });
-        });
-
-
-        // Order by the selected column(s)
-        _api_register([
-            'columns().order()',
-            'column().order()'
-        ], function (dir) {
-            var that = this;
-
-            return this.iterator('table', function (settings, i) {
-                var sort = [];
-
-                $.each(that[i], function (j, col) {
-                    sort.push([col, dir]);
-                });
-
-                settings.aaSorting = sort;
-            });
-        });
-
-
-
-        _api_register('search()', function (input, regex, smart, caseInsen) {
-            var ctx = this.context;
-
-            if (input === undefined) {
-                // get
-                return ctx.length !== 0 ?
-                    ctx[0].oPreviousSearch.sSearch :
-                    undefined;
-            }
-
-            // set
-            return this.iterator('table', function (settings) {
-                if (!settings.oFeatures.bFilter) {
-                    return;
-                }
-
-                _fnFilterComplete(settings, $.extend({}, settings.oPreviousSearch, {
-                    "sSearch": input + "",
-                    "bRegex": regex === null ? false : regex,
-                    "bSmart": smart === null ? true : smart,
-                    "bCaseInsensitive": caseInsen === null ? true : caseInsen
-                }), 1);
-            });
-        });
-
-
-        _api_registerPlural(
-            'columns().search()',
-            'column().search()',
-            function (input, regex, smart, caseInsen) {
-                return this.iterator('column', function (settings, column) {
-                    var preSearch = settings.aoPreSearchCols;
-
-                    if (input === undefined) {
-                        // get
-                        return preSearch[column].sSearch;
-                    }
-
-                    // set
-                    if (!settings.oFeatures.bFilter) {
-                        return;
-                    }
-
-                    $.extend(preSearch[column], {
-                        "sSearch": input + "",
-                        "bRegex": regex === null ? false : regex,
-                        "bSmart": smart === null ? true : smart,
-                        "bCaseInsensitive": caseInsen === null ? true : caseInsen
-                    });
-
-                    _fnFilterComplete(settings, settings.oPreviousSearch, 1);
-                });
-            }
-        );
-
-        /*
-         * State API methods
-         */
-
-        _api_register('state()', function () {
-            return this.context.length ?
-                this.context[0].oSavedState :
-                null;
-        });
-
-
-        _api_register('state.clear()', function () {
-            return this.iterator('table', function (settings) {
-                // Save an empty object
-                settings.fnStateSaveCallback.call(settings.oInstance, settings, {});
-            });
-        });
-
-
-        _api_register('state.loaded()', function () {
-            return this.context.length ?
-                this.context[0].oLoadedState :
-                null;
-        });
-
-
-        _api_register('state.save()', function () {
-            return this.iterator('table', function (settings) {
-                _fnSaveState(settings);
-            });
-        });
-
-
-
-        /**
-         * Provide a common method for plug-ins to check the version of DataTables being
-         * used, in order to ensure compatibility.
-         *
-         *  @param {string} version Version string to check for, in the format "X.Y.Z".
-         *    Note that the formats "X" and "X.Y" are also acceptable.
-         *  @returns {boolean} true if this version of DataTables is greater or equal to
-         *    the required version, or false if this version of DataTales is not
-         *    suitable
-         *  @static
-         *  @dtopt API-Static
-         *
-         *  @example
-         *    alert( $.fn.dataTable.versionCheck( '1.9.0' ) );
-         */
-        DataTable.versionCheck = DataTable.fnVersionCheck = function (version) {
-            var aThis = DataTable.version.split('.');
-            var aThat = version.split('.');
-            var iThis, iThat;
-
-            for (var i = 0, iLen = aThat.length ; i < iLen ; i++) {
-                iThis = parseInt(aThis[i], 10) || 0;
-                iThat = parseInt(aThat[i], 10) || 0;
-
-                // Parts are the same, keep comparing
-                if (iThis === iThat) {
-                    continue;
-                }
-
-                // Parts are different, return immediately
-                return iThis > iThat;
-            }
-
-            return true;
-        };
-
-
-        /**
-         * Check if a `<table>` node is a DataTable table already or not.
-         *
-         *  @param {node|jquery|string} table Table node, jQuery object or jQuery
-         *      selector for the table to test. Note that if more than more than one
-         *      table is passed on, only the first will be checked
-         *  @returns {boolean} true the table given is a DataTable, or false otherwise
-         *  @static
-         *  @dtopt API-Static
-         *
-         *  @example
-         *    if ( ! $.fn.DataTable.isDataTable( '#example' ) ) {
-         *      $('#example').dataTable();
-         *    }
-         */
-        DataTable.isDataTable = DataTable.fnIsDataTable = function (table) {
-            var t = $(table).get(0);
-            var is = false;
-
-            $.each(DataTable.settings, function (i, o) {
-                var head = o.nScrollHead ? $('table', o.nScrollHead)[0] : null;
-                var foot = o.nScrollFoot ? $('table', o.nScrollFoot)[0] : null;
-
-                if (o.nTable === t || head === t || foot === t) {
-                    is = true;
-                }
-            });
-
-            return is;
-        };
-
-
-        /**
-         * Get all DataTable tables that have been initialised - optionally you can
-         * select to get only currently visible tables.
-         *
-         *  @param {boolean} [visible=false] Flag to indicate if you want all (default)
-         *    or visible tables only.
-         *  @returns {array} Array of `table` nodes (not DataTable instances) which are
-         *    DataTables
-         *  @static
-         *  @dtopt API-Static
-         *
-         *  @example
-         *    $.each( $.fn.dataTable.tables(true), function () {
-         *      $(table).DataTable().columns.adjust();
-         *    } );
-         */
-        DataTable.tables = DataTable.fnTables = function (visible) {
-            return $.map(DataTable.settings, function (o) {
-                if (!visible || (visible && $(o.nTable).is(':visible'))) {
-                    return o.nTable;
-                }
-            });
-        };
-
-
-        /**
-         * DataTables utility methods
-         * 
-         * This namespace provides helper methods that DataTables uses internally to
-         * create a DataTable, but which are not exclusively used only for DataTables.
-         * These methods can be used by extension authors to save the duplication of
-         * code.
-         *
-         *  @namespace
-         */
-        DataTable.util = {
-            /**
-             * Throttle the calls to a function. Arguments and context are maintained
-             * for the throttled function.
-             *
-             * @param {function} fn Function to be called
-             * @param {integer} freq Call frequency in mS
-             * @return {function} Wrapped function
-             */
-            throttle: _fnThrottle,
-
-
-            /**
-             * Escape a string such that it can be used in a regular expression
-             *
-             *  @param {string} sVal string to escape
-             *  @returns {string} escaped string
-             */
-            escapeRegex: _fnEscapeRegex
-        };
-
-
-        /**
-         * Convert from camel case parameters to Hungarian notation. This is made public
-         * for the extensions to provide the same ability as DataTables core to accept
-         * either the 1.9 style Hungarian notation, or the 1.10+ style camelCase
-         * parameters.
-         *
-         *  @param {object} src The model object which holds all parameters that can be
-         *    mapped.
-         *  @param {object} user The object to convert from camel case to Hungarian.
-         *  @param {boolean} force When set to `true`, properties which already have a
-         *    Hungarian value in the `user` object will be overwritten. Otherwise they
-         *    won't be.
-         */
-        DataTable.camelToHungarian = _fnCamelToHungarian;
-
-
-
-        /**
-         *
-         */
-        _api_register('$()', function (selector, opts) {
-            var
-                rows = this.rows(opts).nodes(), // Get all rows
-                jqRows = $(rows);
-
-            return $([].concat(
-                jqRows.filter(selector).toArray(),
-                jqRows.find(selector).toArray()
-            ));
-        });
-
-
-        // jQuery functions to operate on the tables
-        $.each(['on', 'one', 'off'], function (i, key) {
-            _api_register(key + '()', function ( /* event, handler */) {
-                var args = Array.prototype.slice.call(arguments);
-
-                // Add the `dt` namespace automatically if it isn't already present
-                if (!args[0].match(/\.dt\b/)) {
-                    args[0] += '.dt';
-                }
-
-                var inst = $(this.tables().nodes());
-                inst[key].apply(inst, args);
-                return this;
-            });
-        });
-
-
-        _api_register('clear()', function () {
-            return this.iterator('table', function (settings) {
-                _fnClearTable(settings);
-            });
-        });
-
-
-        _api_register('settings()', function () {
-            return new _Api(this.context, this.context);
-        });
-
-
-        _api_register('init()', function () {
-            var ctx = this.context;
-            return ctx.length ? ctx[0].oInit : null;
-        });
-
-
-        _api_register('data()', function () {
-            return this.iterator('table', function (settings) {
-                return _pluck(settings.aoData, '_aData');
-            }).flatten();
-        });
-
-
-        _api_register('destroy()', function (remove) {
-            remove = remove || false;
-
-            return this.iterator('table', function (settings) {
-                var orig = settings.nTableWrapper.parentNode;
-                var classes = settings.oClasses;
-                var table = settings.nTable;
-                var tbody = settings.nTBody;
-                var thead = settings.nTHead;
-                var tfoot = settings.nTFoot;
-                var jqTable = $(table);
-                var jqTbody = $(tbody);
-                var jqWrapper = $(settings.nTableWrapper);
-                var rows = $.map(settings.aoData, function (r) { return r.nTr; });
-                var i, ien;
-
-                // Flag to note that the table is currently being destroyed - no action
-                // should be taken
-                settings.bDestroying = true;
-
-                // Fire off the destroy callbacks for plug-ins etc
-                _fnCallbackFire(settings, "aoDestroyCallback", "destroy", [settings]);
-
-                // If not being removed from the document, make all columns visible
-                if (!remove) {
-                    new _Api(settings).columns().visible(true);
-                }
-
-                // Blitz all `DT` namespaced events (these are internal events, the
-                // lowercase, `dt` events are user subscribed and they are responsible
-                // for removing them
-                jqWrapper.unbind('.DT').find(':not(tbody *)').unbind('.DT');
-                $(window).unbind('.DT-' + settings.sInstance);
-
-                // When scrolling we had to break the table up - restore it
-                if (table != thead.parentNode) {
-                    jqTable.children('thead').detach();
-                    jqTable.append(thead);
-                }
-
-                if (tfoot && table != tfoot.parentNode) {
-                    jqTable.children('tfoot').detach();
-                    jqTable.append(tfoot);
-                }
-
-                // Remove the DataTables generated nodes, events and classes
-                jqTable.detach();
-                jqWrapper.detach();
-
-                settings.aaSorting = [];
-                settings.aaSortingFixed = [];
-                _fnSortingClasses(settings);
-
-                $(rows).removeClass(settings.asStripeClasses.join(' '));
-
-                $('th, td', thead).removeClass(classes.sSortable + ' ' +
-                    classes.sSortableAsc + ' ' + classes.sSortableDesc + ' ' + classes.sSortableNone
-                );
-
-                if (settings.bJUI) {
-                    $('th span.' + classes.sSortIcon + ', td span.' + classes.sSortIcon, thead).detach();
-                    $('th, td', thead).each(function () {
-                        var wrapper = $('div.' + classes.sSortJUIWrapper, this);
-                        $(this).append(wrapper.contents());
-                        wrapper.detach();
-                    });
-                }
-
-                if (!remove && orig) {
-                    // insertBefore acts like appendChild if !arg[1]
-                    orig.insertBefore(table, settings.nTableReinsertBefore);
-                }
-
-                // Add the TR elements back into the table in their original order
-                jqTbody.children().detach();
-                jqTbody.append(rows);
-
-                // Restore the width of the original table - was read from the style property,
-                // so we can restore directly to that
-                jqTable
-                    .css('width', settings.sDestroyWidth)
-                    .removeClass(classes.sTable);
-
-                // If the were originally stripe classes - then we add them back here.
-                // Note this is not fool proof (for example if not all rows had stripe
-                // classes - but it's a good effort without getting carried away
-                ien = settings.asDestroyStripes.length;
-
-                if (ien) {
-                    jqTbody.children().each(function (i) {
-                        $(this).addClass(settings.asDestroyStripes[i % ien]);
-                    });
-                }
-
-                /* Remove the settings object from the settings array */
-                var idx = $.inArray(settings, DataTable.settings);
-                if (idx !== -1) {
-                    DataTable.settings.splice(idx, 1);
-                }
-            });
-        });
-
-
-        // Add the `every()` method for rows, columns and cells in a compact form
-        $.each(['column', 'row', 'cell'], function (i, type) {
-            _api_register(type + 's().every()', function (fn) {
-                return this.iterator(type, function (settings, idx, idx2) {
-                    // idx2 is undefined for rows and columns.
-                    fn.call(new _Api(settings)[type](idx, idx2));
-                });
-            });
-        });
-
-
-        // i18n method for extensions to be able to use the language object from the
-        // DataTable
-        _api_register('i18n()', function (token, def, plural) {
-            var ctx = this.context[0];
-            var resolved = _fnGetObjectDataFn(token)(ctx.oLanguage);
-
-            if (resolved === undefined) {
-                resolved = def;
-            }
-
-            if (plural !== undefined && $.isPlainObject(resolved)) {
-                resolved = resolved[plural] !== undefined ?
-                    resolved[plural] :
-                    resolved._;
-            }
-
-            return resolved.replace('%d', plural); // nb: plural might be undefined,
-        });
-
-        /**
-         * Version string for plug-ins to check compatibility. Allowed format is
-         * `a.b.c-d` where: a:int, b:int, c:int, d:string(dev|beta|alpha). `d` is used
-         * only for non-release builds. See http://semver.org/ for more information.
-         *  @member
-         *  @type string
-         *  @default Version number
-         */
-        DataTable.version = "1.10.7";
-
-        /**
-         * Private data store, containing all of the settings objects that are
-         * created for the tables on a given page.
-         *
-         * Note that the `DataTable.settings` object is aliased to
-         * `jQuery.fn.dataTableExt` through which it may be accessed and
-         * manipulated, or `jQuery.fn.dataTable.settings`.
-         *  @member
-         *  @type array
-         *  @default []
-         *  @private
-         */
-        DataTable.settings = [];
-
-        /**
-         * Object models container, for the various models that DataTables has
-         * available to it. These models define the objects that are used to hold
-         * the active state and configuration of the table.
-         *  @namespace
-         */
-        DataTable.models = {};
-
-
-
-        /**
-         * Template object for the way in which DataTables holds information about
-         * search information for the global filter and individual column filters.
-         *  @namespace
-         */
-        DataTable.models.oSearch = {
-            /**
-             * Flag to indicate if the filtering should be case insensitive or not
-             *  @type boolean
-             *  @default true
-             */
-            "bCaseInsensitive": true,
-
-            /**
-             * Applied search term
-             *  @type string
-             *  @default <i>Empty string</i>
-             */
-            "sSearch": "",
-
-            /**
-             * Flag to indicate if the search term should be interpreted as a
-             * regular expression (true) or not (false) and therefore and special
-             * regex characters escaped.
-             *  @type boolean
-             *  @default false
-             */
-            "bRegex": false,
-
-            /**
-             * Flag to indicate if DataTables is to use its smart filtering or not.
-             *  @type boolean
-             *  @default true
-             */
-            "bSmart": true
-        };
-
-
-
-
-        /**
-         * Template object for the way in which DataTables holds information about
-         * each individual row. This is the object format used for the settings
-         * aoData array.
-         *  @namespace
-         */
-        DataTable.models.oRow = {
-            /**
-             * TR element for the row
-             *  @type node
-             *  @default null
-             */
-            "nTr": null,
-
-            /**
-             * Array of TD elements for each row. This is null until the row has been
-             * created.
-             *  @type array nodes
-             *  @default []
-             */
-            "anCells": null,
-
-            /**
-             * Data object from the original data source for the row. This is either
-             * an array if using the traditional form of DataTables, or an object if
-             * using mData options. The exact type will depend on the passed in
-             * data from the data source, or will be an array if using DOM a data
-             * source.
-             *  @type array|object
-             *  @default []
-             */
-            "_aData": [],
-
-            /**
-             * Sorting data cache - this array is ostensibly the same length as the
-             * number of columns (although each index is generated only as it is
-             * needed), and holds the data that is used for sorting each column in the
-             * row. We do this cache generation at the start of the sort in order that
-             * the formatting of the sort data need be done only once for each cell
-             * per sort. This array should not be read from or written to by anything
-             * other than the master sorting methods.
-             *  @type array
-             *  @default null
-             *  @private
-             */
-            "_aSortData": null,
-
-            /**
-             * Per cell filtering data cache. As per the sort data cache, used to
-             * increase the performance of the filtering in DataTables
-             *  @type array
-             *  @default null
-             *  @private
-             */
-            "_aFilterData": null,
-
-            /**
-             * Filtering data cache. This is the same as the cell filtering cache, but
-             * in this case a string rather than an array. This is easily computed with
-             * a join on `_aFilterData`, but is provided as a cache so the join isn't
-             * needed on every search (memory traded for performance)
-             *  @type array
-             *  @default null
-             *  @private
-             */
-            "_sFilterRow": null,
-
-            /**
-             * Cache of the class name that DataTables has applied to the row, so we
-             * can quickly look at this variable rather than needing to do a DOM check
-             * on className for the nTr property.
-             *  @type string
-             *  @default <i>Empty string</i>
-             *  @private
-             */
-            "_sRowStripe": "",
-
-            /**
-             * Denote if the original data source was from the DOM, or the data source
-             * object. This is used for invalidating data, so DataTables can
-             * automatically read data from the original source, unless uninstructed
-             * otherwise.
-             *  @type string
-             *  @default null
-             *  @private
-             */
-            "src": null
-        };
-
-
-        /**
-         * Template object for the column information object in DataTables. This object
-         * is held in the settings aoColumns array and contains all the information that
-         * DataTables needs about each individual column.
-         *
-         * Note that this object is related to {@link DataTable.defaults.column}
-         * but this one is the internal data store for DataTables's cache of columns.
-         * It should NOT be manipulated outside of DataTables. Any configuration should
-         * be done through the initialisation options.
-         *  @namespace
-         */
-        DataTable.models.oColumn = {
-            /**
-             * Column index. This could be worked out on-the-fly with $.inArray, but it
-             * is faster to just hold it as a variable
-             *  @type integer
-             *  @default null
-             */
-            "idx": null,
-
-            /**
-             * A list of the columns that sorting should occur on when this column
-             * is sorted. That this property is an array allows multi-column sorting
-             * to be defined for a column (for example first name / last name columns
-             * would benefit from this). The values are integers pointing to the
-             * columns to be sorted on (typically it will be a single integer pointing
-             * at itself, but that doesn't need to be the case).
-             *  @type array
-             */
-            "aDataSort": null,
-
-            /**
-             * Define the sorting directions that are applied to the column, in sequence
-             * as the column is repeatedly sorted upon - i.e. the first value is used
-             * as the sorting direction when the column if first sorted (clicked on).
-             * Sort it again (click again) and it will move on to the next index.
-             * Repeat until loop.
-             *  @type array
-             */
-            "asSorting": null,
-
-            /**
-             * Flag to indicate if the column is searchable, and thus should be included
-             * in the filtering or not.
-             *  @type boolean
-             */
-            "bSearchable": null,
-
-            /**
-             * Flag to indicate if the column is sortable or not.
-             *  @type boolean
-             */
-            "bSortable": null,
-
-            /**
-             * Flag to indicate if the column is currently visible in the table or not
-             *  @type boolean
-             */
-            "bVisible": null,
-
-            /**
-             * Store for manual type assignment using the `column.type` option. This
-             * is held in store so we can manipulate the column's `sType` property.
-             *  @type string
-             *  @default null
-             *  @private
-             */
-            "_sManualType": null,
-
-            /**
-             * Flag to indicate if HTML5 data attributes should be used as the data
-             * source for filtering or sorting. True is either are.
-             *  @type boolean
-             *  @default false
-             *  @private
-             */
-            "_bAttrSrc": false,
-
-            /**
-             * Developer definable function that is called whenever a cell is created (Ajax source,
-             * etc) or processed for input (DOM source). This can be used as a compliment to mRender
-             * allowing you to modify the DOM element (add background colour for example) when the
-             * element is available.
-             *  @type function
-             *  @param {element} nTd The TD node that has been created
-             *  @param {*} sData The Data for the cell
-             *  @param {array|object} oData The data for the whole row
-             *  @param {int} iRow The row index for the aoData data store
-             *  @default null
-             */
-            "fnCreatedCell": null,
-
-            /**
-             * Function to get data from a cell in a column. You should <b>never</b>
-             * access data directly through _aData internally in DataTables - always use
-             * the method attached to this property. It allows mData to function as
-             * required. This function is automatically assigned by the column
-             * initialisation method
-             *  @type function
-             *  @param {array|object} oData The data array/object for the array
-             *    (i.e. aoData[]._aData)
-             *  @param {string} sSpecific The specific data type you want to get -
-             *    'display', 'type' 'filter' 'sort'
-             *  @returns {*} The data for the cell from the given row's data
-             *  @default null
-             */
-            "fnGetData": null,
-
-            /**
-             * Function to set data for a cell in the column. You should <b>never</b>
-             * set the data directly to _aData internally in DataTables - always use
-             * this method. It allows mData to function as required. This function
-             * is automatically assigned by the column initialisation method
-             *  @type function
-             *  @param {array|object} oData The data array/object for the array
-             *    (i.e. aoData[]._aData)
-             *  @param {*} sValue Value to set
-             *  @default null
-             */
-            "fnSetData": null,
-
-            /**
-             * Property to read the value for the cells in the column from the data
-             * source array / object. If null, then the default content is used, if a
-             * function is given then the return from the function is used.
-             *  @type function|int|string|null
-             *  @default null
-             */
-            "mData": null,
-
-            /**
-             * Partner property to mData which is used (only when defined) to get
-             * the data - i.e. it is basically the same as mData, but without the
-             * 'set' option, and also the data fed to it is the result from mData.
-             * This is the rendering method to match the data method of mData.
-             *  @type function|int|string|null
-             *  @default null
-             */
-            "mRender": null,
-
-            /**
-             * Unique header TH/TD element for this column - this is what the sorting
-             * listener is attached to (if sorting is enabled.)
-             *  @type node
-             *  @default null
-             */
-            "nTh": null,
-
-            /**
-             * Unique footer TH/TD element for this column (if there is one). Not used
-             * in DataTables as such, but can be used for plug-ins to reference the
-             * footer for each column.
-             *  @type node
-             *  @default null
-             */
-            "nTf": null,
-
-            /**
-             * The class to apply to all TD elements in the table's TBODY for the column
-             *  @type string
-             *  @default null
-             */
-            "sClass": null,
-
-            /**
-             * When DataTables calculates the column widths to assign to each column,
-             * it finds the longest string in each column and then constructs a
-             * temporary table and reads the widths from that. The problem with this
-             * is that "mmm" is much wider then "iiii", but the latter is a longer
-             * string - thus the calculation can go wrong (doing it properly and putting
-             * it into an DOM object and measuring that is horribly(!) slow). Thus as
-             * a "work around" we provide this option. It will append its value to the
-             * text that is found to be the longest string for the column - i.e. padding.
-             *  @type string
-             */
-            "sContentPadding": null,
-
-            /**
-             * Allows a default value to be given for a column's data, and will be used
-             * whenever a null data source is encountered (this can be because mData
-             * is set to null, or because the data source itself is null).
-             *  @type string
-             *  @default null
-             */
-            "sDefaultContent": null,
-
-            /**
-             * Name for the column, allowing reference to the column by name as well as
-             * by index (needs a lookup to work by name).
-             *  @type string
-             */
-            "sName": null,
-
-            /**
-             * Custom sorting data type - defines which of the available plug-ins in
-             * afnSortData the custom sorting will use - if any is defined.
-             *  @type string
-             *  @default std
-             */
-            "sSortDataType": 'std',
-
-            /**
-             * Class to be applied to the header element when sorting on this column
-             *  @type string
-             *  @default null
-             */
-            "sSortingClass": null,
-
-            /**
-             * Class to be applied to the header element when sorting on this column -
-             * when jQuery UI theming is used.
-             *  @type string
-             *  @default null
-             */
-            "sSortingClassJUI": null,
-
-            /**
-             * Title of the column - what is seen in the TH element (nTh).
-             *  @type string
-             */
-            "sTitle": null,
-
-            /**
-             * Column sorting and filtering type
-             *  @type string
-             *  @default null
-             */
-            "sType": null,
-
-            /**
-             * Width of the column
-             *  @type string
-             *  @default null
-             */
-            "sWidth": null,
-
-            /**
-             * Width of the column when it was first "encountered"
-             *  @type string
-             *  @default null
-             */
-            "sWidthOrig": null
-        };
-
-
-        /*
-         * Developer note: The properties of the object below are given in Hungarian
-         * notation, that was used as the interface for DataTables prior to v1.10, however
-         * from v1.10 onwards the primary interface is camel case. In order to avoid
-         * breaking backwards compatibility utterly with this change, the Hungarian
-         * version is still, internally the primary interface, but is is not documented
-         * - hence the @name tags in each doc comment. This allows a Javascript function
-         * to create a map from Hungarian notation to camel case (going the other direction
-         * would require each property to be listed, which would at around 3K to the size
-         * of DataTables, while this method is about a 0.5K hit.
-         *
-         * Ultimately this does pave the way for Hungarian notation to be dropped
-         * completely, but that is a massive amount of work and will break current
-         * installs (therefore is on-hold until v2).
-         */
-
-        /**
-         * Initialisation options that can be given to DataTables at initialisation
-         * time.
-         *  @namespace
-         */
-        DataTable.defaults = {
-            /**
-             * An array of data to use for the table, passed in at initialisation which
-             * will be used in preference to any data which is already in the DOM. This is
-             * particularly useful for constructing tables purely in Javascript, for
-             * example with a custom Ajax call.
-             *  @type array
-             *  @default null
-             *
-             *  @dtopt Option
-             *  @name DataTable.defaults.data
-             *
-             *  @example
-             *    // Using a 2D array data source
-             *    $(document).ready( function () {
-             *      $('#example').dataTable( {
-             *        "data": [
-             *          ['Trident', 'Internet Explorer 4.0', 'Win 95+', 4, 'X'],
-             *          ['Trident', 'Internet Explorer 5.0', 'Win 95+', 5, 'C'],
-             *        ],
-             *        "columns": [
-             *          { "title": "Engine" },
-             *          { "title": "Browser" },
-             *          { "title": "Platform" },
-             *          { "title": "Version" },
-             *          { "title": "Grade" }
-             *        ]
-             *      } );
-             *    } );
-             *
-             *  @example
-             *    // Using an array of objects as a data source (`data`)
-             *    $(document).ready( function () {
-             *      $('#example').dataTable( {
-             *        "data": [
-             *          {
-             *            "engine":   "Trident",
-             *            "browser":  "Internet Explorer 4.0",
-             *            "platform": "Win 95+",
-             *            "version":  4,
-             *            "grade":    "X"
-             *          },
-             *          {
-             *            "engine":   "Trident",
-             *            "browser":  "Internet Explorer 5.0",
-             *            "platform": "Win 95+",
-             *            "version":  5,
-             *            "grade":    "C"
-             *          }
-             *        ],
-             *        "columns": [
-             *          { "title": "Engine",   "data": "engine" },
-             *          { "title": "Browser",  "data": "browser" },
-             *          { "title": "Platform", "data": "platform" },
-             *          { "title": "Version",  "data": "version" },
-             *          { "title": "Grade",    "data": "grade" }
-             *        ]
-             *      } );
-             *    } );
-             */
-            "aaData": null,
-
-
-            /**
-             * If ordering is enabled, then DataTables will perform a first pass sort on
-             * initialisation. You can define which column(s) the sort is performed
-             * upon, and the sorting direction, with this variable. The `sorting` array
-             * should contain an array for each column to be sorted initially containing
-             * the column's index and a direction string ('asc' or 'desc').
-             *  @type array
-             *  @default [[0,'asc']]
-             *
-             *  @dtopt Option
-             *  @name DataTable.defaults.order
-             *
-             *  @example
-             *    // Sort by 3rd column first, and then 4th column
-             *    $(document).ready( function() {
-             *      $('#example').dataTable( {
-             *        "order": [[2,'asc'], [3,'desc']]
-             *      } );
-             *    } );
-             *
-             *    // No initial sorting
-             *    $(document).ready( function() {
-             *      $('#example').dataTable( {
-             *        "order": []
-             *      } );
-             *    } );
-             */
-            "aaSorting": [[0, 'asc']],
-
-
-            /**
-             * This parameter is basically identical to the `sorting` parameter, but
-             * cannot be overridden by user interaction with the table. What this means
-             * is that you could have a column (visible or hidden) which the sorting
-             * will always be forced on first - any sorting after that (from the user)
-             * will then be performed as required. This can be useful for grouping rows
-             * together.
-             *  @type array
-             *  @default null
-             *
-             *  @dtopt Option
-             *  @name DataTable.defaults.orderFixed
-             *
-             *  @example
-             *    $(document).ready( function() {
-             *      $('#example').dataTable( {
-             *        "orderFixed": [[0,'asc']]
-             *      } );
-             *    } )
-             */
-            "aaSortingFixed": [],
-
-
-            /**
-             * DataTables can be instructed to load data to display in the table from a
-             * Ajax source. This option defines how that Ajax call is made and where to.
-             *
-             * The `ajax` property has three different modes of operation, depending on
-             * how it is defined. These are:
-             *
-             * * `string` - Set the URL from where the data should be loaded from.
-             * * `object` - Define properties for `jQuery.ajax`.
-             * * `function` - Custom data get function
-             *
-             * `string`
-             * --------
-             *
-             * As a string, the `ajax` property simply defines the URL from which
-             * DataTables will load data.
-             *
-             * `object`
-             * --------
-             *
-             * As an object, the parameters in the object are passed to
-             * [jQuery.ajax](http://api.jquery.com/jQuery.ajax/) allowing fine control
-             * of the Ajax request. DataTables has a number of default parameters which
-             * you can override using this option. Please refer to the jQuery
-             * documentation for a full description of the options available, although
-             * the following parameters provide additional options in DataTables or
-             * require special consideration:
-             *
-             * * `data` - As with jQuery, `data` can be provided as an object, but it
-             *   can also be used as a function to manipulate the data DataTables sends
-             *   to the server. The function takes a single parameter, an object of
-             *   parameters with the values that DataTables has readied for sending. An
-             *   object may be returned which will be merged into the DataTables
-             *   defaults, or you can add the items to the object that was passed in and
-             *   not return anything from the function. This supersedes `fnServerParams`
-             *   from DataTables 1.9-.
-             *
-             * * `dataSrc` - By default DataTables will look for the property `data` (or
-             *   `aaData` for compatibility with DataTables 1.9-) when obtaining data
-             *   from an Ajax source or for server-side processing - this parameter
-             *   allows that property to be changed. You can use Javascript dotted
-             *   object notation to get a data source for multiple levels of nesting, or
-             *   it my be used as a function. As a function it takes a single parameter,
-             *   the JSON returned from the server, which can be manipulated as
-             *   required, with the returned value being that used by DataTables as the
-             *   data source for the table. This supersedes `sAjaxDataProp` from
-             *   DataTables 1.9-.
-             *
-             * * `success` - Should not be overridden it is used internally in
-             *   DataTables. To manipulate / transform the data returned by the server
-             *   use `ajax.dataSrc`, or use `ajax` as a function (see below).
-             *
-             * `function`
-             * ----------
-             *
-             * As a function, making the Ajax call is left up to yourself allowing
-             * complete control of the Ajax request. Indeed, if desired, a method other
-             * than Ajax could be used to obtain the required data, such as Web storage
-             * or an AIR database.
-             *
-             * The function is given four parameters and no return is required. The
-             * parameters are:
-             *
-             * 1. _object_ - Data to send to the server
-             * 2. _function_ - Callback function that must be executed when the required
-             *    data has been obtained. That data should be passed into the callback
-             *    as the only parameter
-             * 3. _object_ - DataTables settings object for the table
-             *
-             * Note that this supersedes `fnServerData` from DataTables 1.9-.
-             *
-             *  @type string|object|function
-             *  @default null
-             *
-             *  @dtopt Option
-             *  @name DataTable.defaults.ajax
-             *  @since 1.10.0
-             *
-             * @example
-             *   // Get JSON data from a file via Ajax.
-             *   // Note DataTables expects data in the form `{ data: [ ...data... ] }` by default).
-             *   $('#example').dataTable( {
-             *     "ajax": "data.json"
-             *   } );
-             *
-             * @example
-             *   // Get JSON data from a file via Ajax, using `dataSrc` to change
-             *   // `data` to `tableData` (i.e. `{ tableData: [ ...data... ] }`)
-             *   $('#example').dataTable( {
-             *     "ajax": {
-             *       "url": "data.json",
-             *       "dataSrc": "tableData"
-             *     }
-             *   } );
-             *
-             * @example
-             *   // Get JSON data from a file via Ajax, using `dataSrc` to read data
-             *   // from a plain array rather than an array in an object
-             *   $('#example').dataTable( {
-             *     "ajax": {
-             *       "url": "data.json",
-             *       "dataSrc": ""
-             *     }
-             *   } );
-             *
-             * @example
-             *   // Manipulate the data returned from the server - add a link to data
-             *   // (note this can, should, be done using `render` for the column - this
-             *   // is just a simple example of how the data can be manipulated).
-             *   $('#example').dataTable( {
-             *     "ajax": {
-             *       "url": "data.json",
-             *       "dataSrc": function ( json ) {
-             *         for ( var i=0, ien=json.length ; i<ien ; i++ ) {
-             *           json[i][0] = '<a href="/message/'+json[i][0]+'>View message</a>';
-             *         }
-             *         return json;
-             *       }
-             *     }
-             *   } );
-             *
-             * @example
-             *   // Add data to the request
-             *   $('#example').dataTable( {
-             *     "ajax": {
-             *       "url": "data.json",
-             *       "data": function ( d ) {
-             *         return {
-             *           "extra_search": $('#extra').val()
-             *         };
-             *       }
-             *     }
-             *   } );
-             *
-             * @example
-             *   // Send request as POST
-             *   $('#example').dataTable( {
-             *     "ajax": {
-             *       "url": "data.json",
-             *       "type": "POST"
-             *     }
-             *   } );
-             *
-             * @example
-             *   // Get the data from localStorage (could interface with a form for
-             *   // adding, editing and removing rows).
-             *   $('#example').dataTable( {
-             *     "ajax": function (data, callback, settings) {
-             *       callback(
-             *         JSON.parse( localStorage.getItem('dataTablesData') )
-             *       );
-             *     }
-             *   } );
-             */
-            "ajax": null,
-
-
-            /**
-             * This parameter allows you to readily specify the entries in the length drop
-             * down menu that DataTables shows when pagination is enabled. It can be
-             * either a 1D array of options which will be used for both the displayed
-             * option and the value, or a 2D array which will use the array in the first
-             * position as the value, and the array in the second position as the
-             * displayed options (useful for language strings such as 'All').
-             *
-             * Note that the `pageLength` property will be automatically set to the
-             * first value given in this array, unless `pageLength` is also provided.
-             *  @type array
-             *  @default [ 10, 25, 50, 100 ]
-             *
-             *  @dtopt Option
-             *  @name DataTable.defaults.lengthMenu
-             *
-             *  @example
-             *    $(document).ready( function() {
-             *      $('#example').dataTable( {
-             *        "lengthMenu": [[10, 25, 50, -1], [10, 25, 50, "All"]]
-             *      } );
-             *    } );
-             */
-            "aLengthMenu": [10, 25, 50, 100],
-
-
-            /**
-             * The `columns` option in the initialisation parameter allows you to define
-             * details about the way individual columns behave. For a full list of
-             * column options that can be set, please see
-             * {@link DataTable.defaults.column}. Note that if you use `columns` to
-             * define your columns, you must have an entry in the array for every single
-             * column that you have in your table (these can be null if you don't which
-             * to specify any options).
-             *  @member
-             *
-             *  @name DataTable.defaults.column
-             */
-            "aoColumns": null,
-
-            /**
-             * Very similar to `columns`, `columnDefs` allows you to target a specific
-             * column, multiple columns, or all columns, using the `targets` property of
-             * each object in the array. This allows great flexibility when creating
-             * tables, as the `columnDefs` arrays can be of any length, targeting the
-             * columns you specifically want. `columnDefs` may use any of the column
-             * options available: {@link DataTable.defaults.column}, but it _must_
-             * have `targets` defined in each object in the array. Values in the `targets`
-             * array may be:
-             *   <ul>
-             *     <li>a string - class name will be matched on the TH for the column</li>
-             *     <li>0 or a positive integer - column index counting from the left</li>
-             *     <li>a negative integer - column index counting from the right</li>
-             *     <li>the string "_all" - all columns (i.e. assign a default)</li>
-             *   </ul>
-             *  @member
-             *
-             *  @name DataTable.defaults.columnDefs
-             */
-            "aoColumnDefs": null,
-
-
-            /**
-             * Basically the same as `search`, this parameter defines the individual column
-             * filtering state at initialisation time. The array must be of the same size
-             * as the number of columns, and each element be an object with the parameters
-             * `search` and `escapeRegex` (the latter is optional). 'null' is also
-             * accepted and the default will be used.
-             *  @type array
-             *  @default []
-             *
-             *  @dtopt Option
-             *  @name DataTable.defaults.searchCols
-             *
-             *  @example
-             *    $(document).ready( function() {
-             *      $('#example').dataTable( {
-             *        "searchCols": [
-             *          null,
-             *          { "search": "My filter" },
-             *          null,
-             *          { "search": "^[0-9]", "escapeRegex": false }
-             *        ]
-             *      } );
-             *    } )
-             */
-            "aoSearchCols": [],
-
-
-            /**
-             * An array of CSS classes that should be applied to displayed rows. This
-             * array may be of any length, and DataTables will apply each class
-             * sequentially, looping when required.
-             *  @type array
-             *  @default null <i>Will take the values determined by the `oClasses.stripe*`
-             *    options</i>
-             *
-             *  @dtopt Option
-             *  @name DataTable.defaults.stripeClasses
-             *
-             *  @example
-             *    $(document).ready( function() {
-             *      $('#example').dataTable( {
-             *        "stripeClasses": [ 'strip1', 'strip2', 'strip3' ]
-             *      } );
-             *    } )
-             */
-            "asStripeClasses": null,
-
-
-            /**
-             * Enable or disable automatic column width calculation. This can be disabled
-             * as an optimisation (it takes some time to calculate the widths) if the
-             * tables widths are passed in using `columns`.
-             *  @type boolean
-             *  @default true
-             *
-             *  @dtopt Features
-             *  @name DataTable.defaults.autoWidth
-             *
-             *  @example
-             *    $(document).ready( function () {
-             *      $('#example').dataTable( {
-             *        "autoWidth": false
-             *      } );
-             *    } );
-             */
-            "bAutoWidth": true,
-
-
-            /**
-             * Deferred rendering can provide DataTables with a huge speed boost when you
-             * are using an Ajax or JS data source for the table. This option, when set to
-             * true, will cause DataTables to defer the creation of the table elements for
-             * each row until they are needed for a draw - saving a significant amount of
-             * time.
-             *  @type boolean
-             *  @default false
-             *
-             *  @dtopt Features
-             *  @name DataTable.defaults.deferRender
-             *
-             *  @example
-             *    $(document).ready( function() {
-             *      $('#example').dataTable( {
-             *        "ajax": "sources/arrays.txt",
-             *        "deferRender": true
-             *      } );
-             *    } );
-             */
-            "bDeferRender": false,
-
-
-            /**
-             * Replace a DataTable which matches the given selector and replace it with
-             * one which has the properties of the new initialisation object passed. If no
-             * table matches the selector, then the new DataTable will be constructed as
-             * per normal.
-             *  @type boolean
-             *  @default false
-             *
-             *  @dtopt Options
-             *  @name DataTable.defaults.destroy
-             *
-             *  @example
-             *    $(document).ready( function() {
-             *      $('#example').dataTable( {
-             *        "srollY": "200px",
-             *        "paginate": false
-             *      } );
-             *
-             *      // Some time later....
-             *      $('#example').dataTable( {
-             *        "filter": false,
-             *        "destroy": true
-             *      } );
-             *    } );
-             */
-            "bDestroy": false,
-
-
-            /**
-             * Enable or disable filtering of data. Filtering in DataTables is "smart" in
-             * that it allows the end user to input multiple words (space separated) and
-             * will match a row containing those words, even if not in the order that was
-             * specified (this allow matching across multiple columns). Note that if you
-             * wish to use filtering in DataTables this must remain 'true' - to remove the
-             * default filtering input box and retain filtering abilities, please use
-             * {@link DataTable.defaults.dom}.
-             *  @type boolean
-             *  @default true
-             *
-             *  @dtopt Features
-             *  @name DataTable.defaults.searching
-             *
-             *  @example
-             *    $(document).ready( function () {
-             *      $('#example').dataTable( {
-             *        "searching": false
-             *      } );
-             *    } );
-             */
-            "bFilter": true,
-
-
-            /**
-             * Enable or disable the table information display. This shows information
-             * about the data that is currently visible on the page, including information
-             * about filtered data if that action is being performed.
-             *  @type boolean
-             *  @default true
-             *
-             *  @dtopt Features
-             *  @name DataTable.defaults.info
-             *
-             *  @example
-             *    $(document).ready( function () {
-             *      $('#example').dataTable( {
-             *        "info": false
-             *      } );
-             *    } );
-             */
-            "bInfo": true,
-
-
-            /**
-             * Enable jQuery UI ThemeRoller support (required as ThemeRoller requires some
-             * slightly different and additional mark-up from what DataTables has
-             * traditionally used).
-             *  @type boolean
-             *  @default false
-             *
-             *  @dtopt Features
-             *  @name DataTable.defaults.jQueryUI
-             *
-             *  @example
-             *    $(document).ready( function() {
-             *      $('#example').dataTable( {
-             *        "jQueryUI": true
-             *      } );
-             *    } );
-             */
-            "bJQueryUI": false,
-
-
-            /**
-             * Allows the end user to select the size of a formatted page from a select
-             * menu (sizes are 10, 25, 50 and 100). Requires pagination (`paginate`).
-             *  @type boolean
-             *  @default true
-             *
-             *  @dtopt Features
-             *  @name DataTable.defaults.lengthChange
-             *
-             *  @example
-             *    $(document).ready( function () {
-             *      $('#example').dataTable( {
-             *        "lengthChange": false
-             *      } );
-             *    } );
-             */
-            "bLengthChange": true,
-
-
-            /**
-             * Enable or disable pagination.
-             *  @type boolean
-             *  @default true
-             *
-             *  @dtopt Features
-             *  @name DataTable.defaults.paging
-             *
-             *  @example
-             *    $(document).ready( function () {
-             *      $('#example').dataTable( {
-             *        "paging": false
-             *      } );
-             *    } );
-             */
-            "bPaginate": true,
-
-
-            /**
-             * Enable or disable the display of a 'processing' indicator when the table is
-             * being processed (e.g. a sort). This is particularly useful for tables with
-             * large amounts of data where it can take a noticeable amount of time to sort
-             * the entries.
-             *  @type boolean
-             *  @default false
-             *
-             *  @dtopt Features
-             *  @name DataTable.defaults.processing
-             *
-             *  @example
-             *    $(document).ready( function () {
-             *      $('#example').dataTable( {
-             *        "processing": true
-             *      } );
-             *    } );
-             */
-            "bProcessing": false,
-
-
-            /**
-             * Retrieve the DataTables object for the given selector. Note that if the
-             * table has already been initialised, this parameter will cause DataTables
-             * to simply return the object that has already been set up - it will not take
-             * account of any changes you might have made to the initialisation object
-             * passed to DataTables (setting this parameter to true is an acknowledgement
-             * that you understand this). `destroy` can be used to reinitialise a table if
-             * you need.
-             *  @type boolean
-             *  @default false
-             *
-             *  @dtopt Options
-             *  @name DataTable.defaults.retrieve
-             *
-             *  @example
-             *    $(document).ready( function() {
-             *      initTable();
-             *      tableActions();
-             *    } );
-             *
-             *    function initTable ()
-             *    {
-             *      return $('#example').dataTable( {
-             *        "scrollY": "200px",
-             *        "paginate": false,
-             *        "retrieve": true
-             *      } );
-             *    }
-             *
-             *    function tableActions ()
-             *    {
-             *      var table = initTable();
-             *      // perform API operations with oTable
-             *    }
-             */
-            "bRetrieve": false,
-
-
-            /**
-             * When vertical (y) scrolling is enabled, DataTables will force the height of
-             * the table's viewport to the given height at all times (useful for layout).
-             * However, this can look odd when filtering data down to a small data set,
-             * and the footer is left "floating" further down. This parameter (when
-             * enabled) will cause DataTables to collapse the table's viewport down when
-             * the result set will fit within the given Y height.
-             *  @type boolean
-             *  @default false
-             *
-             *  @dtopt Options
-             *  @name DataTable.defaults.scrollCollapse
-             *
-             *  @example
-             *    $(document).ready( function() {
-             *      $('#example').dataTable( {
-             *        "scrollY": "200",
-             *        "scrollCollapse": true
-             *      } );
-             *    } );
-             */
-            "bScrollCollapse": false,
-
-
-            /**
-             * Configure DataTables to use server-side processing. Note that the
-             * `ajax` parameter must also be given in order to give DataTables a
-             * source to obtain the required data for each draw.
-             *  @type boolean
-             *  @default false
-             *
-             *  @dtopt Features
-             *  @dtopt Server-side
-             *  @name DataTable.defaults.serverSide
-             *
-             *  @example
-             *    $(document).ready( function () {
-             *      $('#example').dataTable( {
-             *        "serverSide": true,
-             *        "ajax": "xhr.php"
-             *      } );
-             *    } );
-             */
-            "bServerSide": false,
-
-
-            /**
-             * Enable or disable sorting of columns. Sorting of individual columns can be
-             * disabled by the `sortable` option for each column.
-             *  @type boolean
-             *  @default true
-             *
-             *  @dtopt Features
-             *  @name DataTable.defaults.ordering
-             *
-             *  @example
-             *    $(document).ready( function () {
-             *      $('#example').dataTable( {
-             *        "ordering": false
-             *      } );
-             *    } );
-             */
-            "bSort": true,
-
-
-            /**
-             * Enable or display DataTables' ability to sort multiple columns at the
-             * same time (activated by shift-click by the user).
-             *  @type boolean
-             *  @default true
-             *
-             *  @dtopt Options
-             *  @name DataTable.defaults.orderMulti
-             *
-             *  @example
-             *    // Disable multiple column sorting ability
-             *    $(document).ready( function () {
-             *      $('#example').dataTable( {
-             *        "orderMulti": false
-             *      } );
-             *    } );
-             */
-            "bSortMulti": true,
-
-
-            /**
-             * Allows control over whether DataTables should use the top (true) unique
-             * cell that is found for a single column, or the bottom (false - default).
-             * This is useful when using complex headers.
-             *  @type boolean
-             *  @default false
-             *
-             *  @dtopt Options
-             *  @name DataTable.defaults.orderCellsTop
-             *
-             *  @example
-             *    $(document).ready( function() {
-             *      $('#example').dataTable( {
-             *        "orderCellsTop": true
-             *      } );
-             *    } );
-             */
-            "bSortCellsTop": false,
-
-
-            /**
-             * Enable or disable the addition of the classes `sorting\_1`, `sorting\_2` and
-             * `sorting\_3` to the columns which are currently being sorted on. This is
-             * presented as a feature switch as it can increase processing time (while
-             * classes are removed and added) so for large data sets you might want to
-             * turn this off.
-             *  @type boolean
-             *  @default true
-             *
-             *  @dtopt Features
-             *  @name DataTable.defaults.orderClasses
-             *
-             *  @example
-             *    $(document).ready( function () {
-             *      $('#example').dataTable( {
-             *        "orderClasses": false
-             *      } );
-             *    } );
-             */
-            "bSortClasses": true,
-
-
-            /**
-             * Enable or disable state saving. When enabled HTML5 `localStorage` will be
-             * used to save table display information such as pagination information,
-             * display length, filtering and sorting. As such when the end user reloads
-             * the page the display display will match what thy had previously set up.
-             *
-             * Due to the use of `localStorage` the default state saving is not supported
-             * in IE6 or 7. If state saving is required in those browsers, use
-             * `stateSaveCallback` to provide a storage solution such as cookies.
-             *  @type boolean
-             *  @default false
-             *
-             *  @dtopt Features
-             *  @name DataTable.defaults.stateSave
-             *
-             *  @example
-             *    $(document).ready( function () {
-             *      $('#example').dataTable( {
-             *        "stateSave": true
-             *      } );
-             *    } );
-             */
-            "bStateSave": false,
-
-
-            /**
-             * This function is called when a TR element is created (and all TD child
-             * elements have been inserted), or registered if using a DOM source, allowing
-             * manipulation of the TR element (adding classes etc).
-             *  @type function
-             *  @param {node} row "TR" element for the current row
-             *  @param {array} data Raw data array for this row
-             *  @param {int} dataIndex The index of this row in the internal aoData array
-             *
-             *  @dtopt Callbacks
-             *  @name DataTable.defaults.createdRow
-             *
-             *  @example
-             *    $(document).ready( function() {
-             *      $('#example').dataTable( {
-             *        "createdRow": function( row, data, dataIndex ) {
-             *          // Bold the grade for all 'A' grade browsers
-             *          if ( data[4] == "A" )
-             *          {
-             *            $('td:eq(4)', row).html( '<b>A</b>' );
-             *          }
-             *        }
-             *      } );
-             *    } );
-             */
-            "fnCreatedRow": null,
-
-
-            /**
-             * This function is called on every 'draw' event, and allows you to
-             * dynamically modify any aspect you want about the created DOM.
-             *  @type function
-             *  @param {object} settings DataTables settings object
-             *
-             *  @dtopt Callbacks
-             *  @name DataTable.defaults.drawCallback
-             *
-             *  @example
-             *    $(document).ready( function() {
-             *      $('#example').dataTable( {
-             *        "drawCallback": function( settings ) {
-             *          alert( 'DataTables has redrawn the table' );
-             *        }
-             *      } );
-             *    } );
-             */
-            "fnDrawCallback": null,
-
-
-            /**
-             * Identical to fnHeaderCallback() but for the table footer this function
-             * allows you to modify the table footer on every 'draw' event.
-             *  @type function
-             *  @param {node} foot "TR" element for the footer
-             *  @param {array} data Full table data (as derived from the original HTML)
-             *  @param {int} start Index for the current display starting point in the
-             *    display array
-             *  @param {int} end Index for the current display ending point in the
-             *    display array
-             *  @param {array int} display Index array to translate the visual position
-             *    to the full data array
-             *
-             *  @dtopt Callbacks
-             *  @name DataTable.defaults.footerCallback
-             *
-             *  @example
-             *    $(document).ready( function() {
-             *      $('#example').dataTable( {
-             *        "footerCallback": function( tfoot, data, start, end, display ) {
-             *          tfoot.getElementsByTagName('th')[0].innerHTML = "Starting index is "+start;
-             *        }
-             *      } );
-             *    } )
-             */
-            "fnFooterCallback": null,
-
-
-            /**
-             * When rendering large numbers in the information element for the table
-             * (i.e. "Showing 1 to 10 of 57 entries") DataTables will render large numbers
-             * to have a comma separator for the 'thousands' units (e.g. 1 million is
-             * rendered as "1,000,000") to help readability for the end user. This
-             * function will override the default method DataTables uses.
-             *  @type function
-             *  @member
-             *  @param {int} toFormat number to be formatted
-             *  @returns {string} formatted string for DataTables to show the number
-             *
-             *  @dtopt Callbacks
-             *  @name DataTable.defaults.formatNumber
-             *
-             *  @example
-             *    // Format a number using a single quote for the separator (note that
-             *    // this can also be done with the language.thousands option)
-             *    $(document).ready( function() {
-             *      $('#example').dataTable( {
-             *        "formatNumber": function ( toFormat ) {
-             *          return toFormat.toString().replace(
-             *            /\B(?=(\d{3})+(?!\d))/g, "'"
-             *          );
-             *        };
-             *      } );
-             *    } );
-             */
-            "fnFormatNumber": function (toFormat) {
-                return toFormat.toString().replace(
-                    /\B(?=(\d{3})+(?!\d))/g,
-                    this.oLanguage.sThousands
-                );
-            },
-
-
-            /**
-             * This function is called on every 'draw' event, and allows you to
-             * dynamically modify the header row. This can be used to calculate and
-             * display useful information about the table.
-             *  @type function
-             *  @param {node} head "TR" element for the header
-             *  @param {array} data Full table data (as derived from the original HTML)
-             *  @param {int} start Index for the current display starting point in the
-             *    display array
-             *  @param {int} end Index for the current display ending point in the
-             *    display array
-             *  @param {array int} display Index array to translate the visual position
-             *    to the full data array
-             *
-             *  @dtopt Callbacks
-             *  @name DataTable.defaults.headerCallback
-             *
-             *  @example
-             *    $(document).ready( function() {
-             *      $('#example').dataTable( {
-             *        "fheaderCallback": function( head, data, start, end, display ) {
-             *          head.getElementsByTagName('th')[0].innerHTML = "Displaying "+(end-start)+" records";
-             *        }
-             *      } );
-             *    } )
-             */
-            "fnHeaderCallback": null,
-
-
-            /**
-             * The information element can be used to convey information about the current
-             * state of the table. Although the internationalisation options presented by
-             * DataTables are quite capable of dealing with most customisations, there may
-             * be times where you wish to customise the string further. This callback
-             * allows you to do exactly that.
-             *  @type function
-             *  @param {object} oSettings DataTables settings object
-             *  @param {int} start Starting position in data for the draw
-             *  @param {int} end End position in data for the draw
-             *  @param {int} max Total number of rows in the table (regardless of
-             *    filtering)
-             *  @param {int} total Total number of rows in the data set, after filtering
-             *  @param {string} pre The string that DataTables has formatted using it's
-             *    own rules
-             *  @returns {string} The string to be displayed in the information element.
-             *
-             *  @dtopt Callbacks
-             *  @name DataTable.defaults.infoCallback
-             *
-             *  @example
-             *    $('#example').dataTable( {
-             *      "infoCallback": function( settings, start, end, max, total, pre ) {
-             *        return start +" to "+ end;
-             *      }
-             *    } );
-             */
-            "fnInfoCallback": null,
-
-
-            /**
-             * Called when the table has been initialised. Normally DataTables will
-             * initialise sequentially and there will be no need for this function,
-             * however, this does not hold true when using external language information
-             * since that is obtained using an async XHR call.
-             *  @type function
-             *  @param {object} settings DataTables settings object
-             *  @param {object} json The JSON object request from the server - only
-             *    present if client-side Ajax sourced data is used
-             *
-             *  @dtopt Callbacks
-             *  @name DataTable.defaults.initComplete
-             *
-             *  @example
-             *    $(document).ready( function() {
-             *      $('#example').dataTable( {
-             *        "initComplete": function(settings, json) {
-             *          alert( 'DataTables has finished its initialisation.' );
-             *        }
-             *      } );
-             *    } )
-             */
-            "fnInitComplete": null,
-
-
-            /**
-             * Called at the very start of each table draw and can be used to cancel the
-             * draw by returning false, any other return (including undefined) results in
-             * the full draw occurring).
-             *  @type function
-             *  @param {object} settings DataTables settings object
-             *  @returns {boolean} False will cancel the draw, anything else (including no
-             *    return) will allow it to complete.
-             *
-             *  @dtopt Callbacks
-             *  @name DataTable.defaults.preDrawCallback
-             *
-             *  @example
-             *    $(document).ready( function() {
-             *      $('#example').dataTable( {
-             *        "preDrawCallback": function( settings ) {
-             *          if ( $('#test').val() == 1 ) {
-             *            return false;
-             *          }
-             *        }
-             *      } );
-             *    } );
-             */
-            "fnPreDrawCallback": null,
-
-
-            /**
-             * This function allows you to 'post process' each row after it have been
-             * generated for each table draw, but before it is rendered on screen. This
-             * function might be used for setting the row class name etc.
-             *  @type function
-             *  @param {node} row "TR" element for the current row
-             *  @param {array} data Raw data array for this row
-             *  @param {int} displayIndex The display index for the current table draw
-             *  @param {int} displayIndexFull The index of the data in the full list of
-             *    rows (after filtering)
-             *
-             *  @dtopt Callbacks
-             *  @name DataTable.defaults.rowCallback
-             *
-             *  @example
-             *    $(document).ready( function() {
-             *      $('#example').dataTable( {
-             *        "rowCallback": function( row, data, displayIndex, displayIndexFull ) {
-             *          // Bold the grade for all 'A' grade browsers
-             *          if ( data[4] == "A" ) {
-             *            $('td:eq(4)', row).html( '<b>A</b>' );
-             *          }
-             *        }
-             *      } );
-             *    } );
-             */
-            "fnRowCallback": null,
-
-
-            /**
-             * __Deprecated__ The functionality provided by this parameter has now been
-             * superseded by that provided through `ajax`, which should be used instead.
-             *
-             * This parameter allows you to override the default function which obtains
-             * the data from the server so something more suitable for your application.
-             * For example you could use POST data, or pull information from a Gears or
-             * AIR database.
-             *  @type function
-             *  @member
-             *  @param {string} source HTTP source to obtain the data from (`ajax`)
-             *  @param {array} data A key/value pair object containing the data to send
-             *    to the server
-             *  @param {function} callback to be called on completion of the data get
-             *    process that will draw the data on the page.
-             *  @param {object} settings DataTables settings object
-             *
-             *  @dtopt Callbacks
-             *  @dtopt Server-side
-             *  @name DataTable.defaults.serverData
-             *
-             *  @deprecated 1.10. Please use `ajax` for this functionality now.
-             */
-            "fnServerData": null,
-
-
-            /**
-             * __Deprecated__ The functionality provided by this parameter has now been
-             * superseded by that provided through `ajax`, which should be used instead.
-             *
-             *  It is often useful to send extra data to the server when making an Ajax
-             * request - for example custom filtering information, and this callback
-             * function makes it trivial to send extra information to the server. The
-             * passed in parameter is the data set that has been constructed by
-             * DataTables, and you can add to this or modify it as you require.
-             *  @type function
-             *  @param {array} data Data array (array of objects which are name/value
-             *    pairs) that has been constructed by DataTables and will be sent to the
-             *    server. In the case of Ajax sourced data with server-side processing
-             *    this will be an empty array, for server-side processing there will be a
-             *    significant number of parameters!
-             *  @returns {undefined} Ensure that you modify the data array passed in,
-             *    as this is passed by reference.
-             *
-             *  @dtopt Callbacks
-             *  @dtopt Server-side
-             *  @name DataTable.defaults.serverParams
-             *
-             *  @deprecated 1.10. Please use `ajax` for this functionality now.
-             */
-            "fnServerParams": null,
-
-
-            /**
-             * Load the table state. With this function you can define from where, and how, the
-             * state of a table is loaded. By default DataTables will load from `localStorage`
-             * but you might wish to use a server-side database or cookies.
-             *  @type function
-             *  @member
-             *  @param {object} settings DataTables settings object
-             *  @return {object} The DataTables state object to be loaded
-             *
-             *  @dtopt Callbacks
-             *  @name DataTable.defaults.stateLoadCallback
-             *
-             *  @example
-             *    $(document).ready( function() {
-             *      $('#example').dataTable( {
-             *        "stateSave": true,
-             *        "stateLoadCallback": function (settings) {
-             *          var o;
-             *
-             *          // Send an Ajax request to the server to get the data. Note that
-             *          // this is a synchronous request.
-             *          $.ajax( {
-             *            "url": "/state_load",
-             *            "async": false,
-             *            "dataType": "json",
-             *            "success": function (json) {
-             *              o = json;
-             *            }
-             *          } );
-             *
-             *          return o;
-             *        }
-             *      } );
-             *    } );
-             */
-            "fnStateLoadCallback": function (settings) {
-                try {
-                    return JSON.parse(
-                        (settings.iStateDuration === -1 ? sessionStorage : localStorage).getItem(
-                            'DataTables_' + settings.sInstance + '_' + location.pathname
-                        )
-                    );
-                } catch (e) { }
-            },
-
-
-            /**
-             * Callback which allows modification of the saved state prior to loading that state.
-             * This callback is called when the table is loading state from the stored data, but
-             * prior to the settings object being modified by the saved state. Note that for
-             * plug-in authors, you should use the `stateLoadParams` event to load parameters for
-             * a plug-in.
-             *  @type function
-             *  @param {object} settings DataTables settings object
-             *  @param {object} data The state object that is to be loaded
-             *
-             *  @dtopt Callbacks
-             *  @name DataTable.defaults.stateLoadParams
-             *
-             *  @example
-             *    // Remove a saved filter, so filtering is never loaded
-             *    $(document).ready( function() {
-             *      $('#example').dataTable( {
-             *        "stateSave": true,
-             *        "stateLoadParams": function (settings, data) {
-             *          data.oSearch.sSearch = "";
-             *        }
-             *      } );
-             *    } );
-             *
-             *  @example
-             *    // Disallow state loading by returning false
-             *    $(document).ready( function() {
-             *      $('#example').dataTable( {
-             *        "stateSave": true,
-             *        "stateLoadParams": function (settings, data) {
-             *          return false;
-             *        }
-             *      } );
-             *    } );
-             */
-            "fnStateLoadParams": null,
-
-
-            /**
-             * Callback that is called when the state has been loaded from the state saving method
-             * and the DataTables settings object has been modified as a result of the loaded state.
-             *  @type function
-             *  @param {object} settings DataTables settings object
-             *  @param {object} data The state object that was loaded
-             *
-             *  @dtopt Callbacks
-             *  @name DataTable.defaults.stateLoaded
-             *
-             *  @example
-             *    // Show an alert with the filtering value that was saved
-             *    $(document).ready( function() {
-             *      $('#example').dataTable( {
-             *        "stateSave": true,
-             *        "stateLoaded": function (settings, data) {
-             *          alert( 'Saved filter was: '+data.oSearch.sSearch );
-             *        }
-             *      } );
-             *    } );
-             */
-            "fnStateLoaded": null,
-
-
-            /**
-             * Save the table state. This function allows you to define where and how the state
-             * information for the table is stored By default DataTables will use `localStorage`
-             * but you might wish to use a server-side database or cookies.
-             *  @type function
-             *  @member
-             *  @param {object} settings DataTables settings object
-             *  @param {object} data The state object to be saved
-             *
-             *  @dtopt Callbacks
-             *  @name DataTable.defaults.stateSaveCallback
-             *
-             *  @example
-             *    $(document).ready( function() {
-             *      $('#example').dataTable( {
-             *        "stateSave": true,
-             *        "stateSaveCallback": function (settings, data) {
-             *          // Send an Ajax request to the server with the state object
-             *          $.ajax( {
-             *            "url": "/state_save",
-             *            "data": data,
-             *            "dataType": "json",
-             *            "method": "POST"
-             *            "success": function () {}
-             *          } );
-             *        }
-             *      } );
-             *    } );
-             */
-            "fnStateSaveCallback": function (settings, data) {
-                try {
-                    (settings.iStateDuration === -1 ? sessionStorage : localStorage).setItem(
-                        'DataTables_' + settings.sInstance + '_' + location.pathname,
-                        JSON.stringify(data)
-                    );
-                } catch (e) { }
-            },
-
-
-            /**
-             * Callback which allows modification of the state to be saved. Called when the table
-             * has changed state a new state save is required. This method allows modification of
-             * the state saving object prior to actually doing the save, including addition or
-             * other state properties or modification. Note that for plug-in authors, you should
-             * use the `stateSaveParams` event to save parameters for a plug-in.
-             *  @type function
-             *  @param {object} settings DataTables settings object
-             *  @param {object} data The state object to be saved
-             *
-             *  @dtopt Callbacks
-             *  @name DataTable.defaults.stateSaveParams
-             *
-             *  @example
-             *    // Remove a saved filter, so filtering is never saved
-             *    $(document).ready( function() {
-             *      $('#example').dataTable( {
-             *        "stateSave": true,
-             *        "stateSaveParams": function (settings, data) {
-             *          data.oSearch.sSearch = "";
-             *        }
-             *      } );
-             *    } );
-             */
-            "fnStateSaveParams": null,
-
-
-            /**
-             * Duration for which the saved state information is considered valid. After this period
-             * has elapsed the state will be returned to the default.
-             * Value is given in seconds.
-             *  @type int
-             *  @default 7200 <i>(2 hours)</i>
-             *
-             *  @dtopt Options
-             *  @name DataTable.defaults.stateDuration
-             *
-             *  @example
-             *    $(document).ready( function() {
-             *      $('#example').dataTable( {
-             *        "stateDuration": 60*60*24; // 1 day
-             *      } );
-             *    } )
-             */
-            "iStateDuration": 7200,
-
-
-            /**
-             * When enabled DataTables will not make a request to the server for the first
-             * page draw - rather it will use the data already on the page (no sorting etc
-             * will be applied to it), thus saving on an XHR at load time. `deferLoading`
-             * is used to indicate that deferred loading is required, but it is also used
-             * to tell DataTables how many records there are in the full table (allowing
-             * the information element and pagination to be displayed correctly). In the case
-             * where a filtering is applied to the table on initial load, this can be
-             * indicated by giving the parameter as an array, where the first element is
-             * the number of records available after filtering and the second element is the
-             * number of records without filtering (allowing the table information element
-             * to be shown correctly).
-             *  @type int | array
-             *  @default null
-             *
-             *  @dtopt Options
-             *  @name DataTable.defaults.deferLoading
-             *
-             *  @example
-             *    // 57 records available in the table, no filtering applied
-             *    $(document).ready( function() {
-             *      $('#example').dataTable( {
-             *        "serverSide": true,
-             *        "ajax": "scripts/server_processing.php",
-             *        "deferLoading": 57
-             *      } );
-             *    } );
-             *
-             *  @example
-             *    // 57 records after filtering, 100 without filtering (an initial filter applied)
-             *    $(document).ready( function() {
-             *      $('#example').dataTable( {
-             *        "serverSide": true,
-             *        "ajax": "scripts/server_processing.php",
-             *        "deferLoading": [ 57, 100 ],
-             *        "search": {
-             *          "search": "my_filter"
-             *        }
-             *      } );
-             *    } );
-             */
-            "iDeferLoading": null,
-
-
-            /**
-             * Number of rows to display on a single page when using pagination. If
-             * feature enabled (`lengthChange`) then the end user will be able to override
-             * this to a custom setting using a pop-up menu.
-             *  @type int
-             *  @default 10
-             *
-             *  @dtopt Options
-             *  @name DataTable.defaults.pageLength
-             *
-             *  @example
-             *    $(document).ready( function() {
-             *      $('#example').dataTable( {
-             *        "pageLength": 50
-             *      } );
-             *    } )
-             */
-            "iDisplayLength": 10,
-
-
-            /**
-             * Define the starting point for data display when using DataTables with
-             * pagination. Note that this parameter is the number of records, rather than
-             * the page number, so if you have 10 records per page and want to start on
-             * the third page, it should be "20".
-             *  @type int
-             *  @default 0
-             *
-             *  @dtopt Options
-             *  @name DataTable.defaults.displayStart
-             *
-             *  @example
-             *    $(document).ready( function() {
-             *      $('#example').dataTable( {
-             *        "displayStart": 20
-             *      } );
-             *    } )
-             */
-            "iDisplayStart": 0,
-
-
-            /**
-             * By default DataTables allows keyboard navigation of the table (sorting, paging,
-             * and filtering) by adding a `tabindex` attribute to the required elements. This
-             * allows you to tab through the controls and press the enter key to activate them.
-             * The tabindex is default 0, meaning that the tab follows the flow of the document.
-             * You can overrule this using this parameter if you wish. Use a value of -1 to
-             * disable built-in keyboard navigation.
-             *  @type int
-             *  @default 0
-             *
-             *  @dtopt Options
-             *  @name DataTable.defaults.tabIndex
-             *
-             *  @example
-             *    $(document).ready( function() {
-             *      $('#example').dataTable( {
-             *        "tabIndex": 1
-             *      } );
-             *    } );
-             */
-            "iTabIndex": 0,
-
-
-            /**
-             * Classes that DataTables assigns to the various components and features
-             * that it adds to the HTML table. This allows classes to be configured
-             * during initialisation in addition to through the static
-             * {@link DataTable.ext.oStdClasses} object).
-             *  @namespace
-             *  @name DataTable.defaults.classes
-             */
-            "oClasses": {},
-
-
-            /**
-             * All strings that DataTables uses in the user interface that it creates
-             * are defined in this object, allowing you to modified them individually or
-             * completely replace them all as required.
-             *  @namespace
-             *  @name DataTable.defaults.language
-             */
-            "oLanguage": {
-                /**
-                 * Strings that are used for WAI-ARIA labels and controls only (these are not
-                 * actually visible on the page, but will be read by screenreaders, and thus
-                 * must be internationalised as well).
-                 *  @namespace
-                 *  @name DataTable.defaults.language.aria
-                 */
-                "oAria": {
-                    /**
-                     * ARIA label that is added to the table headers when the column may be
-                     * sorted ascending by activing the column (click or return when focused).
-                     * Note that the column header is prefixed to this string.
-                     *  @type string
-                     *  @default : activate to sort column ascending
-                     *
-                     *  @dtopt Language
-                     *  @name DataTable.defaults.language.aria.sortAscending
-                     *
-                     *  @example
-                     *    $(document).ready( function() {
-                     *      $('#example').dataTable( {
-                     *        "language": {
-                     *          "aria": {
-                     *            "sortAscending": " - click/return to sort ascending"
-                     *          }
-                     *        }
-                     *      } );
-                     *    } );
-                     */
-                    "sSortAscending": ": activate to sort column ascending",
-
-                    /**
-                     * ARIA label that is added to the table headers when the column may be
-                     * sorted descending by activing the column (click or return when focused).
-                     * Note that the column header is prefixed to this string.
-                     *  @type string
-                     *  @default : activate to sort column ascending
-                     *
-                     *  @dtopt Language
-                     *  @name DataTable.defaults.language.aria.sortDescending
-                     *
-                     *  @example
-                     *    $(document).ready( function() {
-                     *      $('#example').dataTable( {
-                     *        "language": {
-                     *          "aria": {
-                     *            "sortDescending": " - click/return to sort descending"
-                     *          }
-                     *        }
-                     *      } );
-                     *    } );
-                     */
-                    "sSortDescending": ": activate to sort column descending"
-                },
-
-                /**
-                 * Pagination string used by DataTables for the built-in pagination
-                 * control types.
-                 *  @namespace
-                 *  @name DataTable.defaults.language.paginate
-                 */
-                "oPaginate": {
-                    /**
-                     * Text to use when using the 'full_numbers' type of pagination for the
-                     * button to take the user to the first page.
-                     *  @type string
-                     *  @default First
-                     *
-                     *  @dtopt Language
-                     *  @name DataTable.defaults.language.paginate.first
-                     *
-                     *  @example
-                     *    $(document).ready( function() {
-                     *      $('#example').dataTable( {
-                     *        "language": {
-                     *          "paginate": {
-                     *            "first": "First page"
-                     *          }
-                     *        }
-                     *      } );
-                     *    } );
-                     */
-                    "sFirst": "First",
-
-
-                    /**
-                     * Text to use when using the 'full_numbers' type of pagination for the
-                     * button to take the user to the last page.
-                     *  @type string
-                     *  @default Last
-                     *
-                     *  @dtopt Language
-                     *  @name DataTable.defaults.language.paginate.last
-                     *
-                     *  @example
-                     *    $(document).ready( function() {
-                     *      $('#example').dataTable( {
-                     *        "language": {
-                     *          "paginate": {
-                     *            "last": "Last page"
-                     *          }
-                     *        }
-                     *      } );
-                     *    } );
-                     */
-                    "sLast": "Last",
-
-
-                    /**
-                     * Text to use for the 'next' pagination button (to take the user to the
-                     * next page).
-                     *  @type string
-                     *  @default Next
-                     *
-                     *  @dtopt Language
-                     *  @name DataTable.defaults.language.paginate.next
-                     *
-                     *  @example
-                     *    $(document).ready( function() {
-                     *      $('#example').dataTable( {
-                     *        "language": {
-                     *          "paginate": {
-                     *            "next": "Next page"
-                     *          }
-                     *        }
-                     *      } );
-                     *    } );
-                     */
-                    "sNext": "Next",
-
-
-                    /**
-                     * Text to use for the 'previous' pagination button (to take the user to
-                     * the previous page).
-                     *  @type string
-                     *  @default Previous
-                     *
-                     *  @dtopt Language
-                     *  @name DataTable.defaults.language.paginate.previous
-                     *
-                     *  @example
-                     *    $(document).ready( function() {
-                     *      $('#example').dataTable( {
-                     *        "language": {
-                     *          "paginate": {
-                     *            "previous": "Previous page"
-                     *          }
-                     *        }
-                     *      } );
-                     *    } );
-                     */
-                    "sPrevious": "Previous"
-                },
-
-                /**
-                 * This string is shown in preference to `zeroRecords` when the table is
-                 * empty of data (regardless of filtering). Note that this is an optional
-                 * parameter - if it is not given, the value of `zeroRecords` will be used
-                 * instead (either the default or given value).
-                 *  @type string
-                 *  @default No data available in table
-                 *
-                 *  @dtopt Language
-                 *  @name DataTable.defaults.language.emptyTable
-                 *
-                 *  @example
-                 *    $(document).ready( function() {
-                 *      $('#example').dataTable( {
-                 *        "language": {
-                 *          "emptyTable": "No data available in table"
-                 *        }
-                 *      } );
-                 *    } );
-                 */
-                "sEmptyTable": "No data available in table",
-
-
-                /**
-                 * This string gives information to the end user about the information
-                 * that is current on display on the page. The following tokens can be
-                 * used in the string and will be dynamically replaced as the table
-                 * display updates. This tokens can be placed anywhere in the string, or
-                 * removed as needed by the language requires:
-                 *
-                 * * `\_START\_` - Display index of the first record on the current page
-                 * * `\_END\_` - Display index of the last record on the current page
-                 * * `\_TOTAL\_` - Number of records in the table after filtering
-                 * * `\_MAX\_` - Number of records in the table without filtering
-                 * * `\_PAGE\_` - Current page number
-                 * * `\_PAGES\_` - Total number of pages of data in the table
-                 *
-                 *  @type string
-                 *  @default Showing _START_ to _END_ of _TOTAL_ entries
-                 *
-                 *  @dtopt Language
-                 *  @name DataTable.defaults.language.info
-                 *
-                 *  @example
-                 *    $(document).ready( function() {
-                 *      $('#example').dataTable( {
-                 *        "language": {
-                 *          "info": "Showing page _PAGE_ of _PAGES_"
-                 *        }
-                 *      } );
-                 *    } );
-                 */
-                "sInfo": "Showing _START_ to _END_ of _TOTAL_ entries",
-
-
-                /**
-                 * Display information string for when the table is empty. Typically the
-                 * format of this string should match `info`.
-                 *  @type string
-                 *  @default Showing 0 to 0 of 0 entries
-                 *
-                 *  @dtopt Language
-                 *  @name DataTable.defaults.language.infoEmpty
-                 *
-                 *  @example
-                 *    $(document).ready( function() {
-                 *      $('#example').dataTable( {
-                 *        "language": {
-                 *          "infoEmpty": "No entries to show"
-                 *        }
-                 *      } );
-                 *    } );
-                 */
-                "sInfoEmpty": "Showing 0 to 0 of 0 entries",
-
-
-                /**
-                 * When a user filters the information in a table, this string is appended
-                 * to the information (`info`) to give an idea of how strong the filtering
-                 * is. The variable _MAX_ is dynamically updated.
-                 *  @type string
-                 *  @default (filtered from _MAX_ total entries)
-                 *
-                 *  @dtopt Language
-                 *  @name DataTable.defaults.language.infoFiltered
-                 *
-                 *  @example
-                 *    $(document).ready( function() {
-                 *      $('#example').dataTable( {
-                 *        "language": {
-                 *          "infoFiltered": " - filtering from _MAX_ records"
-                 *        }
-                 *      } );
-                 *    } );
-                 */
-                "sInfoFiltered": "(filtered from _MAX_ total entries)",
-
-
-                /**
-                 * If can be useful to append extra information to the info string at times,
-                 * and this variable does exactly that. This information will be appended to
-                 * the `info` (`infoEmpty` and `infoFiltered` in whatever combination they are
-                 * being used) at all times.
-                 *  @type string
-                 *  @default <i>Empty string</i>
-                 *
-                 *  @dtopt Language
-                 *  @name DataTable.defaults.language.infoPostFix
-                 *
-                 *  @example
-                 *    $(document).ready( function() {
-                 *      $('#example').dataTable( {
-                 *        "language": {
-                 *          "infoPostFix": "All records shown are derived from real information."
-                 *        }
-                 *      } );
-                 *    } );
-                 */
-                "sInfoPostFix": "",
-
-
-                /**
-                 * This decimal place operator is a little different from the other
-                 * language options since DataTables doesn't output floating point
-                 * numbers, so it won't ever use this for display of a number. Rather,
-                 * what this parameter does is modify the sort methods of the table so
-                 * that numbers which are in a format which has a character other than
-                 * a period (`.`) as a decimal place will be sorted numerically.
-                 *
-                 * Note that numbers with different decimal places cannot be shown in
-                 * the same table and still be sortable, the table must be consistent.
-                 * However, multiple different tables on the page can use different
-                 * decimal place characters.
-                 *  @type string
-                 *  @default 
-                 *
-                 *  @dtopt Language
-                 *  @name DataTable.defaults.language.decimal
-                 *
-                 *  @example
-                 *    $(document).ready( function() {
-                 *      $('#example').dataTable( {
-                 *        "language": {
-                 *          "decimal": ","
-                 *          "thousands": "."
-                 *        }
-                 *      } );
-                 *    } );
-                 */
-                "sDecimal": "",
-
-
-                /**
-                 * DataTables has a build in number formatter (`formatNumber`) which is
-                 * used to format large numbers that are used in the table information.
-                 * By default a comma is used, but this can be trivially changed to any
-                 * character you wish with this parameter.
-                 *  @type string
-                 *  @default ,
-                 *
-                 *  @dtopt Language
-                 *  @name DataTable.defaults.language.thousands
-                 *
-                 *  @example
-                 *    $(document).ready( function() {
-                 *      $('#example').dataTable( {
-                 *        "language": {
-                 *          "thousands": "'"
-                 *        }
-                 *      } );
-                 *    } );
-                 */
-                "sThousands": ",",
-
-
-                /**
-                 * Detail the action that will be taken when the drop down menu for the
-                 * pagination length option is changed. The '_MENU_' variable is replaced
-                 * with a default select list of 10, 25, 50 and 100, and can be replaced
-                 * with a custom select box if required.
-                 *  @type string
-                 *  @default Show _MENU_ entries
-                 *
-                 *  @dtopt Language
-                 *  @name DataTable.defaults.language.lengthMenu
-                 *
-                 *  @example
-                 *    // Language change only
-                 *    $(document).ready( function() {
-                 *      $('#example').dataTable( {
-                 *        "language": {
-                 *          "lengthMenu": "Display _MENU_ records"
-                 *        }
-                 *      } );
-                 *    } );
-                 *
-                 *  @example
-                 *    // Language and options change
-                 *    $(document).ready( function() {
-                 *      $('#example').dataTable( {
-                 *        "language": {
-                 *          "lengthMenu": 'Display <select>'+
-                 *            '<option value="10">10</option>'+
-                 *            '<option value="20">20</option>'+
-                 *            '<option value="30">30</option>'+
-                 *            '<option value="40">40</option>'+
-                 *            '<option value="50">50</option>'+
-                 *            '<option value="-1">All</option>'+
-                 *            '</select> records'
-                 *        }
-                 *      } );
-                 *    } );
-                 */
-                "sLengthMenu": "Show _MENU_ entries",
-
-
-                /**
-                 * When using Ajax sourced data and during the first draw when DataTables is
-                 * gathering the data, this message is shown in an empty row in the table to
-                 * indicate to the end user the the data is being loaded. Note that this
-                 * parameter is not used when loading data by server-side processing, just
-                 * Ajax sourced data with client-side processing.
-                 *  @type string
-                 *  @default Loading...
-                 *
-                 *  @dtopt Language
-                 *  @name DataTable.defaults.language.loadingRecords
-                 *
-                 *  @example
-                 *    $(document).ready( function() {
-                 *      $('#example').dataTable( {
-                 *        "language": {
-                 *          "loadingRecords": "Please wait - loading..."
-                 *        }
-                 *      } );
-                 *    } );
-                 */
-                "sLoadingRecords": "Loading...",
-
-
-                /**
-                 * Text which is displayed when the table is processing a user action
-                 * (usually a sort command or similar).
-                 *  @type string
-                 *  @default Processing...
-                 *
-                 *  @dtopt Language
-                 *  @name DataTable.defaults.language.processing
-                 *
-                 *  @example
-                 *    $(document).ready( function() {
-                 *      $('#example').dataTable( {
-                 *        "language": {
-                 *          "processing": "DataTables is currently busy"
-                 *        }
-                 *      } );
-                 *    } );
-                 */
-                "sProcessing": "Processing...",
-
-
-                /**
-                 * Details the actions that will be taken when the user types into the
-                 * filtering input text box. The variable "_INPUT_", if used in the string,
-                 * is replaced with the HTML text box for the filtering input allowing
-                 * control over where it appears in the string. If "_INPUT_" is not given
-                 * then the input box is appended to the string automatically.
-                 *  @type string
-                 *  @default Search:
-                 *
-                 *  @dtopt Language
-                 *  @name DataTable.defaults.language.search
-                 *
-                 *  @example
-                 *    // Input text box will be appended at the end automatically
-                 *    $(document).ready( function() {
-                 *      $('#example').dataTable( {
-                 *        "language": {
-                 *          "search": "Filter records:"
-                 *        }
-                 *      } );
-                 *    } );
-                 *
-                 *  @example
-                 *    // Specify where the filter should appear
-                 *    $(document).ready( function() {
-                 *      $('#example').dataTable( {
-                 *        "language": {
-                 *          "search": "Apply filter _INPUT_ to table"
-                 *        }
-                 *      } );
-                 *    } );
-                 */
-                "sSearch": "Search:",
-
-
-                /**
-                 * Assign a `placeholder` attribute to the search `input` element
-                 *  @type string
-                 *  @default 
-                 *
-                 *  @dtopt Language
-                 *  @name DataTable.defaults.language.searchPlaceholder
-                 */
-                "sSearchPlaceholder": "",
-
-
-                /**
-                 * All of the language information can be stored in a file on the
-                 * server-side, which DataTables will look up if this parameter is passed.
-                 * It must store the URL of the language file, which is in a JSON format,
-                 * and the object has the same properties as the oLanguage object in the
-                 * initialiser object (i.e. the above parameters). Please refer to one of
-                 * the example language files to see how this works in action.
-                 *  @type string
-                 *  @default <i>Empty string - i.e. disabled</i>
-                 *
-                 *  @dtopt Language
-                 *  @name DataTable.defaults.language.url
-                 *
-                 *  @example
-                 *    $(document).ready( function() {
-                 *      $('#example').dataTable( {
-                 *        "language": {
-                 *          "url": "http://www.sprymedia.co.uk/dataTables/lang.txt"
-                 *        }
-                 *      } );
-                 *    } );
-                 */
-                "sUrl": "",
-
-
-                /**
-                 * Text shown inside the table records when the is no information to be
-                 * displayed after filtering. `emptyTable` is shown when there is simply no
-                 * information in the table at all (regardless of filtering).
-                 *  @type string
-                 *  @default No matching records found
-                 *
-                 *  @dtopt Language
-                 *  @name DataTable.defaults.language.zeroRecords
-                 *
-                 *  @example
-                 *    $(document).ready( function() {
-                 *      $('#example').dataTable( {
-                 *        "language": {
-                 *          "zeroRecords": "No records to display"
-                 *        }
-                 *      } );
-                 *    } );
-                 */
-                "sZeroRecords": "No matching records found"
-            },
-
-
-            /**
-             * This parameter allows you to have define the global filtering state at
-             * initialisation time. As an object the `search` parameter must be
-             * defined, but all other parameters are optional. When `regex` is true,
-             * the search string will be treated as a regular expression, when false
-             * (default) it will be treated as a straight string. When `smart`
-             * DataTables will use it's smart filtering methods (to word match at
-             * any point in the data), when false this will not be done.
-             *  @namespace
-             *  @extends DataTable.models.oSearch
-             *
-             *  @dtopt Options
-             *  @name DataTable.defaults.search
-             *
-             *  @example
-             *    $(document).ready( function() {
-             *      $('#example').dataTable( {
-             *        "search": {"search": "Initial search"}
-             *      } );
-             *    } )
-             */
-            "oSearch": $.extend({}, DataTable.models.oSearch),
-
-
-            /**
-             * __Deprecated__ The functionality provided by this parameter has now been
-             * superseded by that provided through `ajax`, which should be used instead.
-             *
-             * By default DataTables will look for the property `data` (or `aaData` for
-             * compatibility with DataTables 1.9-) when obtaining data from an Ajax
-             * source or for server-side processing - this parameter allows that
-             * property to be changed. You can use Javascript dotted object notation to
-             * get a data source for multiple levels of nesting.
-             *  @type string
-             *  @default data
-             *
-             *  @dtopt Options
-             *  @dtopt Server-side
-             *  @name DataTable.defaults.ajaxDataProp
-             *
-             *  @deprecated 1.10. Please use `ajax` for this functionality now.
-             */
-            "sAjaxDataProp": "data",
-
-
-            /**
-             * __Deprecated__ The functionality provided by this parameter has now been
-             * superseded by that provided through `ajax`, which should be used instead.
-             *
-             * You can instruct DataTables to load data from an external
-             * source using this parameter (use aData if you want to pass data in you
-             * already have). Simply provide a url a JSON object can be obtained from.
-             *  @type string
-             *  @default null
-             *
-             *  @dtopt Options
-             *  @dtopt Server-side
-             *  @name DataTable.defaults.ajaxSource
-             *
-             *  @deprecated 1.10. Please use `ajax` for this functionality now.
-             */
-            "sAjaxSource": null,
-
-
-            /**
-             * This initialisation variable allows you to specify exactly where in the
-             * DOM you want DataTables to inject the various controls it adds to the page
-             * (for example you might want the pagination controls at the top of the
-             * table). DIV elements (with or without a custom class) can also be added to
-             * aid styling. The follow syntax is used:
-             *   <ul>
-             *     <li>The following options are allowed:
-             *       <ul>
-             *         <li>'l' - Length changing</li>
-             *         <li>'f' - Filtering input</li>
-             *         <li>'t' - The table!</li>
-             *         <li>'i' - Information</li>
-             *         <li>'p' - Pagination</li>
-             *         <li>'r' - pRocessing</li>
-             *       </ul>
-             *     </li>
-             *     <li>The following constants are allowed:
-             *       <ul>
-             *         <li>'H' - jQueryUI theme "header" classes ('fg-toolbar ui-widget-header ui-corner-tl ui-corner-tr ui-helper-clearfix')</li>
-             *         <li>'F' - jQueryUI theme "footer" classes ('fg-toolbar ui-widget-header ui-corner-bl ui-corner-br ui-helper-clearfix')</li>
-             *       </ul>
-             *     </li>
-             *     <li>The following syntax is expected:
-             *       <ul>
-             *         <li>'&lt;' and '&gt;' - div elements</li>
-             *         <li>'&lt;"class" and '&gt;' - div with a class</li>
-             *         <li>'&lt;"#id" and '&gt;' - div with an ID</li>
-             *       </ul>
-             *     </li>
-             *     <li>Examples:
-             *       <ul>
-             *         <li>'&lt;"wrapper"flipt&gt;'</li>
-             *         <li>'&lt;lf&lt;t&gt;ip&gt;'</li>
-             *       </ul>
-             *     </li>
-             *   </ul>
-             *  @type string
-             *  @default lfrtip <i>(when `jQueryUI` is false)</i> <b>or</b>
-             *    <"H"lfr>t<"F"ip> <i>(when `jQueryUI` is true)</i>
-             *
-             *  @dtopt Options
-             *  @name DataTable.defaults.dom
-             *
-             *  @example
-             *    $(document).ready( function() {
-             *      $('#example').dataTable( {
-             *        "dom": '&lt;"top"i&gt;rt&lt;"bottom"flp&gt;&lt;"clear"&gt;'
-             *      } );
-             *    } );
-             */
-            "sDom": "lfrtip",
-
-
-            /**
-             * Search delay option. This will throttle full table searches that use the
-             * DataTables provided search input element (it does not effect calls to
-             * `dt-api search()`, providing a delay before the search is made.
-             *  @type integer
-             *  @default 0
-             *
-             *  @dtopt Options
-             *  @name DataTable.defaults.searchDelay
-             *
-             *  @example
-             *    $(document).ready( function() {
-             *      $('#example').dataTable( {
-             *        "searchDelay": 200
-             *      } );
-             *    } )
-             */
-            "searchDelay": null,
-
-
-            /**
-             * DataTables features four different built-in options for the buttons to
-             * display for pagination control:
-             *
-             * * `simple` - 'Previous' and 'Next' buttons only
-             * * 'simple_numbers` - 'Previous' and 'Next' buttons, plus page numbers
-             * * `full` - 'First', 'Previous', 'Next' and 'Last' buttons
-             * * `full_numbers` - 'First', 'Previous', 'Next' and 'Last' buttons, plus
-             *   page numbers
-             *  
-             * Further methods can be added using {@link DataTable.ext.oPagination}.
-             *  @type string
-             *  @default simple_numbers
-             *
-             *  @dtopt Options
-             *  @name DataTable.defaults.pagingType
-             *
-             *  @example
-             *    $(document).ready( function() {
-             *      $('#example').dataTable( {
-             *        "pagingType": "full_numbers"
-             *      } );
-             *    } )
-             */
-            "sPaginationType": "simple_numbers",
-
-
-            /**
-             * Enable horizontal scrolling. When a table is too wide to fit into a
-             * certain layout, or you have a large number of columns in the table, you
-             * can enable x-scrolling to show the table in a viewport, which can be
-             * scrolled. This property can be `true` which will allow the table to
-             * scroll horizontally when needed, or any CSS unit, or a number (in which
-             * case it will be treated as a pixel measurement). Setting as simply `true`
-             * is recommended.
-             *  @type boolean|string
-             *  @default <i>blank string - i.e. disabled</i>
-             *
-             *  @dtopt Features
-             *  @name DataTable.defaults.scrollX
-             *
-             *  @example
-             *    $(document).ready( function() {
-             *      $('#example').dataTable( {
-             *        "scrollX": true,
-             *        "scrollCollapse": true
-             *      } );
-             *    } );
-             */
-            "sScrollX": "",
-
-
-            /**
-             * This property can be used to force a DataTable to use more width than it
-             * might otherwise do when x-scrolling is enabled. For example if you have a
-             * table which requires to be well spaced, this parameter is useful for
-             * "over-sizing" the table, and thus forcing scrolling. This property can by
-             * any CSS unit, or a number (in which case it will be treated as a pixel
-             * measurement).
-             *  @type string
-             *  @default <i>blank string - i.e. disabled</i>
-             *
-             *  @dtopt Options
-             *  @name DataTable.defaults.scrollXInner
-             *
-             *  @example
-             *    $(document).ready( function() {
-             *      $('#example').dataTable( {
-             *        "scrollX": "100%",
-             *        "scrollXInner": "110%"
-             *      } );
-             *    } );
-             */
-            "sScrollXInner": "",
-
-
-            /**
-             * Enable vertical scrolling. Vertical scrolling will constrain the DataTable
-             * to the given height, and enable scrolling for any data which overflows the
-             * current viewport. This can be used as an alternative to paging to display
-             * a lot of data in a small area (although paging and scrolling can both be
-             * enabled at the same time). This property can be any CSS unit, or a number
-             * (in which case it will be treated as a pixel measurement).
-             *  @type string
-             *  @default <i>blank string - i.e. disabled</i>
-             *
-             *  @dtopt Features
-             *  @name DataTable.defaults.scrollY
-             *
-             *  @example
-             *    $(document).ready( function() {
-             *      $('#example').dataTable( {
-             *        "scrollY": "200px",
-             *        "paginate": false
-             *      } );
-             *    } );
-             */
-            "sScrollY": "",
-
-
-            /**
-             * __Deprecated__ The functionality provided by this parameter has now been
-             * superseded by that provided through `ajax`, which should be used instead.
-             *
-             * Set the HTTP method that is used to make the Ajax call for server-side
-             * processing or Ajax sourced data.
-             *  @type string
-             *  @default GET
-             *
-             *  @dtopt Options
-             *  @dtopt Server-side
-             *  @name DataTable.defaults.serverMethod
-             *
-             *  @deprecated 1.10. Please use `ajax` for this functionality now.
-             */
-            "sServerMethod": "GET",
-
-
-            /**
-             * DataTables makes use of renderers when displaying HTML elements for
-             * a table. These renderers can be added or modified by plug-ins to
-             * generate suitable mark-up for a site. For example the Bootstrap
-             * integration plug-in for DataTables uses a paging button renderer to
-             * display pagination buttons in the mark-up required by Bootstrap.
-             *
-             * For further information about the renderers available see
-             * DataTable.ext.renderer
-             *  @type string|object
-             *  @default null
-             *
-             *  @name DataTable.defaults.renderer
-             *
-             */
-            "renderer": null
-        };
-
-        _fnHungarianMap(DataTable.defaults);
-
-
-
-        /*
-         * Developer note - See note in model.defaults.js about the use of Hungarian
-         * notation and camel case.
-         */
-
-        /**
-         * Column options that can be given to DataTables at initialisation time.
-         *  @namespace
-         */
-        DataTable.defaults.column = {
-            /**
-             * Define which column(s) an order will occur on for this column. This
-             * allows a column's ordering to take multiple columns into account when
-             * doing a sort or use the data from a different column. For example first
-             * name / last name columns make sense to do a multi-column sort over the
-             * two columns.
-             *  @type array|int
-             *  @default null <i>Takes the value of the column index automatically</i>
-             *
-             *  @name DataTable.defaults.column.orderData
-             *  @dtopt Columns
-             *
-             *  @example
-             *    // Using `columnDefs`
-             *    $(document).ready( function() {
-             *      $('#example').dataTable( {
-             *        "columnDefs": [
-             *          { "orderData": [ 0, 1 ], "targets": [ 0 ] },
-             *          { "orderData": [ 1, 0 ], "targets": [ 1 ] },
-             *          { "orderData": 2, "targets": [ 2 ] }
-             *        ]
-             *      } );
-             *    } );
-             *
-             *  @example
-             *    // Using `columns`
-             *    $(document).ready( function() {
-             *      $('#example').dataTable( {
-             *        "columns": [
-             *          { "orderData": [ 0, 1 ] },
-             *          { "orderData": [ 1, 0 ] },
-             *          { "orderData": 2 },
-             *          null,
-             *          null
-             *        ]
-             *      } );
-             *    } );
-             */
-            "aDataSort": null,
-            "iDataSort": -1,
-
-
-            /**
-             * You can control the default ordering direction, and even alter the
-             * behaviour of the sort handler (i.e. only allow ascending ordering etc)
-             * using this parameter.
-             *  @type array
-             *  @default [ 'asc', 'desc' ]
-             *
-             *  @name DataTable.defaults.column.orderSequence
-             *  @dtopt Columns
-             *
-             *  @example
-             *    // Using `columnDefs`
-             *    $(document).ready( function() {
-             *      $('#example').dataTable( {
-             *        "columnDefs": [
-             *          { "orderSequence": [ "asc" ], "targets": [ 1 ] },
-             *          { "orderSequence": [ "desc", "asc", "asc" ], "targets": [ 2 ] },
-             *          { "orderSequence": [ "desc" ], "targets": [ 3 ] }
-             *        ]
-             *      } );
-             *    } );
-             *
-             *  @example
-             *    // Using `columns`
-             *    $(document).ready( function() {
-             *      $('#example').dataTable( {
-             *        "columns": [
-             *          null,
-             *          { "orderSequence": [ "asc" ] },
-             *          { "orderSequence": [ "desc", "asc", "asc" ] },
-             *          { "orderSequence": [ "desc" ] },
-             *          null
-             *        ]
-             *      } );
-             *    } );
-             */
-            "asSorting": ['asc', 'desc'],
-
-
-            /**
-             * Enable or disable filtering on the data in this column.
-             *  @type boolean
-             *  @default true
-             *
-             *  @name DataTable.defaults.column.searchable
-             *  @dtopt Columns
-             *
-             *  @example
-             *    // Using `columnDefs`
-             *    $(document).ready( function() {
-             *      $('#example').dataTable( {
-             *        "columnDefs": [
-             *          { "searchable": false, "targets": [ 0 ] }
-             *        ] } );
-             *    } );
-             *
-             *  @example
-             *    // Using `columns`
-             *    $(document).ready( function() {
-             *      $('#example').dataTable( {
-             *        "columns": [
-             *          { "searchable": false },
-             *          null,
-             *          null,
-             *          null,
-             *          null
-             *        ] } );
-             *    } );
-             */
-            "bSearchable": true,
-
-
-            /**
-             * Enable or disable ordering on this column.
-             *  @type boolean
-             *  @default true
-             *
-             *  @name DataTable.defaults.column.orderable
-             *  @dtopt Columns
-             *
-             *  @example
-             *    // Using `columnDefs`
-             *    $(document).ready( function() {
-             *      $('#example').dataTable( {
-             *        "columnDefs": [
-             *          { "orderable": false, "targets": [ 0 ] }
-             *        ] } );
-             *    } );
-             *
-             *  @example
-             *    // Using `columns`
-             *    $(document).ready( function() {
-             *      $('#example').dataTable( {
-             *        "columns": [
-             *          { "orderable": false },
-             *          null,
-             *          null,
-             *          null,
-             *          null
-             *        ] } );
-             *    } );
-             */
-            "bSortable": true,
-
-
-            /**
-             * Enable or disable the display of this column.
-             *  @type boolean
-             *  @default true
-             *
-             *  @name DataTable.defaults.column.visible
-             *  @dtopt Columns
-             *
-             *  @example
-             *    // Using `columnDefs`
-             *    $(document).ready( function() {
-             *      $('#example').dataTable( {
-             *        "columnDefs": [
-             *          { "visible": false, "targets": [ 0 ] }
-             *        ] } );
-             *    } );
-             *
-             *  @example
-             *    // Using `columns`
-             *    $(document).ready( function() {
-             *      $('#example').dataTable( {
-             *        "columns": [
-             *          { "visible": false },
-             *          null,
-             *          null,
-             *          null,
-             *          null
-             *        ] } );
-             *    } );
-             */
-            "bVisible": true,
-
-
-            /**
-             * Developer definable function that is called whenever a cell is created (Ajax source,
-             * etc) or processed for input (DOM source). This can be used as a compliment to mRender
-             * allowing you to modify the DOM element (add background colour for example) when the
-             * element is available.
-             *  @type function
-             *  @param {element} td The TD node that has been created
-             *  @param {*} cellData The Data for the cell
-             *  @param {array|object} rowData The data for the whole row
-             *  @param {int} row The row index for the aoData data store
-             *  @param {int} col The column index for aoColumns
-             *
-             *  @name DataTable.defaults.column.createdCell
-             *  @dtopt Columns
-             *
-             *  @example
-             *    $(document).ready( function() {
-             *      $('#example').dataTable( {
-             *        "columnDefs": [ {
-             *          "targets": [3],
-             *          "createdCell": function (td, cellData, rowData, row, col) {
-             *            if ( cellData == "1.7" ) {
-             *              $(td).css('color', 'blue')
-             *            }
-             *          }
-             *        } ]
-             *      });
-             *    } );
-             */
-            "fnCreatedCell": null,
-
-
-            /**
-             * This parameter has been replaced by `data` in DataTables to ensure naming
-             * consistency. `dataProp` can still be used, as there is backwards
-             * compatibility in DataTables for this option, but it is strongly
-             * recommended that you use `data` in preference to `dataProp`.
-             *  @name DataTable.defaults.column.dataProp
-             */
-
-
-            /**
-             * This property can be used to read data from any data source property,
-             * including deeply nested objects / properties. `data` can be given in a
-             * number of different ways which effect its behaviour:
-             *
-             * * `integer` - treated as an array index for the data source. This is the
-             *   default that DataTables uses (incrementally increased for each column).
-             * * `string` - read an object property from the data source. There are
-             *   three 'special' options that can be used in the string to alter how
-             *   DataTables reads the data from the source object:
-             *    * `.` - Dotted Javascript notation. Just as you use a `.` in
-             *      Javascript to read from nested objects, so to can the options
-             *      specified in `data`. For example: `browser.version` or
-             *      `browser.name`. If your object parameter name contains a period, use
-             *      `\\` to escape it - i.e. `first\\.name`.
-             *    * `[]` - Array notation. DataTables can automatically combine data
-             *      from and array source, joining the data with the characters provided
-             *      between the two brackets. For example: `name[, ]` would provide a
-             *      comma-space separated list from the source array. If no characters
-             *      are provided between the brackets, the original array source is
-             *      returned.
-             *    * `()` - Function notation. Adding `()` to the end of a parameter will
-             *      execute a function of the name given. For example: `browser()` for a
-             *      simple function on the data source, `browser.version()` for a
-             *      function in a nested property or even `browser().version` to get an
-             *      object property if the function called returns an object. Note that
-             *      function notation is recommended for use in `render` rather than
-             *      `data` as it is much simpler to use as a renderer.
-             * * `null` - use the original data source for the row rather than plucking
-             *   data directly from it. This action has effects on two other
-             *   initialisation options:
-             *    * `defaultContent` - When null is given as the `data` option and
-             *      `defaultContent` is specified for the column, the value defined by
-             *      `defaultContent` will be used for the cell.
-             *    * `render` - When null is used for the `data` option and the `render`
-             *      option is specified for the column, the whole data source for the
-             *      row is used for the renderer.
-             * * `function` - the function given will be executed whenever DataTables
-             *   needs to set or get the data for a cell in the column. The function
-             *   takes three parameters:
-             *    * Parameters:
-             *      * `{array|object}` The data source for the row
-             *      * `{string}` The type call data requested - this will be 'set' when
-             *        setting data or 'filter', 'display', 'type', 'sort' or undefined
-             *        when gathering data. Note that when `undefined` is given for the
-             *        type DataTables expects to get the raw data for the object back<
-             *      * `{*}` Data to set when the second parameter is 'set'.
-             *    * Return:
-             *      * The return value from the function is not required when 'set' is
-             *        the type of call, but otherwise the return is what will be used
-             *        for the data requested.
-             *
-             * Note that `data` is a getter and setter option. If you just require
-             * formatting of data for output, you will likely want to use `render` which
-             * is simply a getter and thus simpler to use.
-             *
-             * Note that prior to DataTables 1.9.2 `data` was called `mDataProp`. The
-             * name change reflects the flexibility of this property and is consistent
-             * with the naming of mRender. If 'mDataProp' is given, then it will still
-             * be used by DataTables, as it automatically maps the old name to the new
-             * if required.
-             *
-             *  @type string|int|function|null
-             *  @default null <i>Use automatically calculated column index</i>
-             *
-             *  @name DataTable.defaults.column.data
-             *  @dtopt Columns
-             *
-             *  @example
-             *    // Read table data from objects
-             *    // JSON structure for each row:
-             *    //   {
-             *    //      "engine": {value},
-             *    //      "browser": {value},
-             *    //      "platform": {value},
-             *    //      "version": {value},
-             *    //      "grade": {value}
-             *    //   }
-             *    $(document).ready( function() {
-             *      $('#example').dataTable( {
-             *        "ajaxSource": "sources/objects.txt",
-             *        "columns": [
-             *          { "data": "engine" },
-             *          { "data": "browser" },
-             *          { "data": "platform" },
-             *          { "data": "version" },
-             *          { "data": "grade" }
-             *        ]
-             *      } );
-             *    } );
-             *
-             *  @example
-             *    // Read information from deeply nested objects
-             *    // JSON structure for each row:
-             *    //   {
-             *    //      "engine": {value},
-             *    //      "browser": {value},
-             *    //      "platform": {
-             *    //         "inner": {value}
-             *    //      },
-             *    //      "details": [
-             *    //         {value}, {value}
-             *    //      ]
-             *    //   }
-             *    $(document).ready( function() {
-             *      $('#example').dataTable( {
-             *        "ajaxSource": "sources/deep.txt",
-             *        "columns": [
-             *          { "data": "engine" },
-             *          { "data": "browser" },
-             *          { "data": "platform.inner" },
-             *          { "data": "platform.details.0" },
-             *          { "data": "platform.details.1" }
-             *        ]
-             *      } );
-             *    } );
-             *
-             *  @example
-             *    // Using `data` as a function to provide different information for
-             *    // sorting, filtering and display. In this case, currency (price)
-             *    $(document).ready( function() {
-             *      $('#example').dataTable( {
-             *        "columnDefs": [ {
-             *          "targets": [ 0 ],
-             *          "data": function ( source, type, val ) {
-             *            if (type === 'set') {
-             *              source.price = val;
-             *              // Store the computed dislay and filter values for efficiency
-             *              source.price_display = val=="" ? "" : "$"+numberFormat(val);
-             *              source.price_filter  = val=="" ? "" : "$"+numberFormat(val)+" "+val;
-             *              return;
-             *            }
-             *            else if (type === 'display') {
-             *              return source.price_display;
-             *            }
-             *            else if (type === 'filter') {
-             *              return source.price_filter;
-             *            }
-             *            // 'sort', 'type' and undefined all just use the integer
-             *            return source.price;
-             *          }
-             *        } ]
-             *      } );
-             *    } );
-             *
-             *  @example
-             *    // Using default content
-             *    $(document).ready( function() {
-             *      $('#example').dataTable( {
-             *        "columnDefs": [ {
-             *          "targets": [ 0 ],
-             *          "data": null,
-             *          "defaultContent": "Click to edit"
-             *        } ]
-             *      } );
-             *    } );
-             *
-             *  @example
-             *    // Using array notation - outputting a list from an array
-             *    $(document).ready( function() {
-             *      $('#example').dataTable( {
-             *        "columnDefs": [ {
-             *          "targets": [ 0 ],
-             *          "data": "name[, ]"
-             *        } ]
-             *      } );
-             *    } );
-             *
-             */
-            "mData": null,
-
-
-            /**
-             * This property is the rendering partner to `data` and it is suggested that
-             * when you want to manipulate data for display (including filtering,
-             * sorting etc) without altering the underlying data for the table, use this
-             * property. `render` can be considered to be the the read only companion to
-             * `data` which is read / write (then as such more complex). Like `data`
-             * this option can be given in a number of different ways to effect its
-             * behaviour:
-             *
-             * * `integer` - treated as an array index for the data source. This is the
-             *   default that DataTables uses (incrementally increased for each column).
-             * * `string` - read an object property from the data source. There are
-             *   three 'special' options that can be used in the string to alter how
-             *   DataTables reads the data from the source object:
-             *    * `.` - Dotted Javascript notation. Just as you use a `.` in
-             *      Javascript to read from nested objects, so to can the options
-             *      specified in `data`. For example: `browser.version` or
-             *      `browser.name`. If your object parameter name contains a period, use
-             *      `\\` to escape it - i.e. `first\\.name`.
-             *    * `[]` - Array notation. DataTables can automatically combine data
-             *      from and array source, joining the data with the characters provided
-             *      between the two brackets. For example: `name[, ]` would provide a
-             *      comma-space separated list from the source array. If no characters
-             *      are provided between the brackets, the original array source is
-             *      returned.
-             *    * `()` - Function notation. Adding `()` to the end of a parameter will
-             *      execute a function of the name given. For example: `browser()` for a
-             *      simple function on the data source, `browser.version()` for a
-             *      function in a nested property or even `browser().version` to get an
-             *      object property if the function called returns an object.
-             * * `object` - use different data for the different data types requested by
-             *   DataTables ('filter', 'display', 'type' or 'sort'). The property names
-             *   of the object is the data type the property refers to and the value can
-             *   defined using an integer, string or function using the same rules as
-             *   `render` normally does. Note that an `_` option _must_ be specified.
-             *   This is the default value to use if you haven't specified a value for
-             *   the data type requested by DataTables.
-             * * `function` - the function given will be executed whenever DataTables
-             *   needs to set or get the data for a cell in the column. The function
-             *   takes three parameters:
-             *    * Parameters:
-             *      * {array|object} The data source for the row (based on `data`)
-             *      * {string} The type call data requested - this will be 'filter',
-             *        'display', 'type' or 'sort'.
-             *      * {array|object} The full data source for the row (not based on
-             *        `data`)
-             *    * Return:
-             *      * The return value from the function is what will be used for the
-             *        data requested.
-             *
-             *  @type string|int|function|object|null
-             *  @default null Use the data source value.
-             *
-             *  @name DataTable.defaults.column.render
-             *  @dtopt Columns
-             *
-             *  @example
-             *    // Create a comma separated list from an array of objects
-             *    $(document).ready( function() {
-             *      $('#example').dataTable( {
-             *        "ajaxSource": "sources/deep.txt",
-             *        "columns": [
-             *          { "data": "engine" },
-             *          { "data": "browser" },
-             *          {
-             *            "data": "platform",
-             *            "render": "[, ].name"
-             *          }
-             *        ]
-             *      } );
-             *    } );
-             *
-             *  @example
-             *    // Execute a function to obtain data
-             *    $(document).ready( function() {
-             *      $('#example').dataTable( {
-             *        "columnDefs": [ {
-             *          "targets": [ 0 ],
-             *          "data": null, // Use the full data source object for the renderer's source
-             *          "render": "browserName()"
-             *        } ]
-             *      } );
-             *    } );
-             *
-             *  @example
-             *    // As an object, extracting different data for the different types
-             *    // This would be used with a data source such as:
-             *    //   { "phone": 5552368, "phone_filter": "5552368 555-2368", "phone_display": "555-2368" }
-             *    // Here the `phone` integer is used for sorting and type detection, while `phone_filter`
-             *    // (which has both forms) is used for filtering for if a user inputs either format, while
-             *    // the formatted phone number is the one that is shown in the table.
-             *    $(document).ready( function() {
-             *      $('#example').dataTable( {
-             *        "columnDefs": [ {
-             *          "targets": [ 0 ],
-             *          "data": null, // Use the full data source object for the renderer's source
-             *          "render": {
-             *            "_": "phone",
-             *            "filter": "phone_filter",
-             *            "display": "phone_display"
-             *          }
-             *        } ]
-             *      } );
-             *    } );
-             *
-             *  @example
-             *    // Use as a function to create a link from the data source
-             *    $(document).ready( function() {
-             *      $('#example').dataTable( {
-             *        "columnDefs": [ {
-             *          "targets": [ 0 ],
-             *          "data": "download_link",
-             *          "render": function ( data, type, full ) {
-             *            return '<a href="'+data+'">Download</a>';
-             *          }
-             *        } ]
-             *      } );
-             *    } );
-             */
-            "mRender": null,
-
-
-            /**
-             * Change the cell type created for the column - either TD cells or TH cells. This
-             * can be useful as TH cells have semantic meaning in the table body, allowing them
-             * to act as a header for a row (you may wish to add scope='row' to the TH elements).
-             *  @type string
-             *  @default td
-             *
-             *  @name DataTable.defaults.column.cellType
-             *  @dtopt Columns
-             *
-             *  @example
-             *    // Make the first column use TH cells
-             *    $(document).ready( function() {
-             *      $('#example').dataTable( {
-             *        "columnDefs": [ {
-             *          "targets": [ 0 ],
-             *          "cellType": "th"
-             *        } ]
-             *      } );
-             *    } );
-             */
-            "sCellType": "td",
-
-
-            /**
-             * Class to give to each cell in this column.
-             *  @type string
-             *  @default <i>Empty string</i>
-             *
-             *  @name DataTable.defaults.column.class
-             *  @dtopt Columns
-             *
-             *  @example
-             *    // Using `columnDefs`
-             *    $(document).ready( function() {
-             *      $('#example').dataTable( {
-             *        "columnDefs": [
-             *          { "class": "my_class", "targets": [ 0 ] }
-             *        ]
-             *      } );
-             *    } );
-             *
-             *  @example
-             *    // Using `columns`
-             *    $(document).ready( function() {
-             *      $('#example').dataTable( {
-             *        "columns": [
-             *          { "class": "my_class" },
-             *          null,
-             *          null,
-             *          null,
-             *          null
-             *        ]
-             *      } );
-             *    } );
-             */
-            "sClass": "",
-
-            /**
-             * When DataTables calculates the column widths to assign to each column,
-             * it finds the longest string in each column and then constructs a
-             * temporary table and reads the widths from that. The problem with this
-             * is that "mmm" is much wider then "iiii", but the latter is a longer
-             * string - thus the calculation can go wrong (doing it properly and putting
-             * it into an DOM object and measuring that is horribly(!) slow). Thus as
-             * a "work around" we provide this option. It will append its value to the
-             * text that is found to be the longest string for the column - i.e. padding.
-             * Generally you shouldn't need this!
-             *  @type string
-             *  @default <i>Empty string<i>
-             *
-             *  @name DataTable.defaults.column.contentPadding
-             *  @dtopt Columns
-             *
-             *  @example
-             *    // Using `columns`
-             *    $(document).ready( function() {
-             *      $('#example').dataTable( {
-             *        "columns": [
-             *          null,
-             *          null,
-             *          null,
-             *          {
-             *            "contentPadding": "mmm"
-             *          }
-             *        ]
-             *      } );
-             *    } );
-             */
-            "sContentPadding": "",
-
-
-            /**
-             * Allows a default value to be given for a column's data, and will be used
-             * whenever a null data source is encountered (this can be because `data`
-             * is set to null, or because the data source itself is null).
-             *  @type string
-             *  @default null
-             *
-             *  @name DataTable.defaults.column.defaultContent
-             *  @dtopt Columns
-             *
-             *  @example
-             *    // Using `columnDefs`
-             *    $(document).ready( function() {
-             *      $('#example').dataTable( {
-             *        "columnDefs": [
-             *          {
-             *            "data": null,
-             *            "defaultContent": "Edit",
-             *            "targets": [ -1 ]
-             *          }
-             *        ]
-             *      } );
-             *    } );
-             *
-             *  @example
-             *    // Using `columns`
-             *    $(document).ready( function() {
-             *      $('#example').dataTable( {
-             *        "columns": [
-             *          null,
-             *          null,
-             *          null,
-             *          {
-             *            "data": null,
-             *            "defaultContent": "Edit"
-             *          }
-             *        ]
-             *      } );
-             *    } );
-             */
-            "sDefaultContent": null,
-
-
-            /**
-             * This parameter is only used in DataTables' server-side processing. It can
-             * be exceptionally useful to know what columns are being displayed on the
-             * client side, and to map these to database fields. When defined, the names
-             * also allow DataTables to reorder information from the server if it comes
-             * back in an unexpected order (i.e. if you switch your columns around on the
-             * client-side, your server-side code does not also need updating).
-             *  @type string
-             *  @default <i>Empty string</i>
-             *
-             *  @name DataTable.defaults.column.name
-             *  @dtopt Columns
-             *
-             *  @example
-             *    // Using `columnDefs`
-             *    $(document).ready( function() {
-             *      $('#example').dataTable( {
-             *        "columnDefs": [
-             *          { "name": "engine", "targets": [ 0 ] },
-             *          { "name": "browser", "targets": [ 1 ] },
-             *          { "name": "platform", "targets": [ 2 ] },
-             *          { "name": "version", "targets": [ 3 ] },
-             *          { "name": "grade", "targets": [ 4 ] }
-             *        ]
-             *      } );
-             *    } );
-             *
-             *  @example
-             *    // Using `columns`
-             *    $(document).ready( function() {
-             *      $('#example').dataTable( {
-             *        "columns": [
-             *          { "name": "engine" },
-             *          { "name": "browser" },
-             *          { "name": "platform" },
-             *          { "name": "version" },
-             *          { "name": "grade" }
-             *        ]
-             *      } );
-             *    } );
-             */
-            "sName": "",
-
-
-            /**
-             * Defines a data source type for the ordering which can be used to read
-             * real-time information from the table (updating the internally cached
-             * version) prior to ordering. This allows ordering to occur on user
-             * editable elements such as form inputs.
-             *  @type string
-             *  @default std
-             *
-             *  @name DataTable.defaults.column.orderDataType
-             *  @dtopt Columns
-             *
-             *  @example
-             *    // Using `columnDefs`
-             *    $(document).ready( function() {
-             *      $('#example').dataTable( {
-             *        "columnDefs": [
-             *          { "orderDataType": "dom-text", "targets": [ 2, 3 ] },
-             *          { "type": "numeric", "targets": [ 3 ] },
-             *          { "orderDataType": "dom-select", "targets": [ 4 ] },
-             *          { "orderDataType": "dom-checkbox", "targets": [ 5 ] }
-             *        ]
-             *      } );
-             *    } );
-             *
-             *  @example
-             *    // Using `columns`
-             *    $(document).ready( function() {
-             *      $('#example').dataTable( {
-             *        "columns": [
-             *          null,
-             *          null,
-             *          { "orderDataType": "dom-text" },
-             *          { "orderDataType": "dom-text", "type": "numeric" },
-             *          { "orderDataType": "dom-select" },
-             *          { "orderDataType": "dom-checkbox" }
-             *        ]
-             *      } );
-             *    } );
-             */
-            "sSortDataType": "std",
-
-
-            /**
-             * The title of this column.
-             *  @type string
-             *  @default null <i>Derived from the 'TH' value for this column in the
-             *    original HTML table.</i>
-             *
-             *  @name DataTable.defaults.column.title
-             *  @dtopt Columns
-             *
-             *  @example
-             *    // Using `columnDefs`
-             *    $(document).ready( function() {
-             *      $('#example').dataTable( {
-             *        "columnDefs": [
-             *          { "title": "My column title", "targets": [ 0 ] }
-             *        ]
-             *      } );
-             *    } );
-             *
-             *  @example
-             *    // Using `columns`
-             *    $(document).ready( function() {
-             *      $('#example').dataTable( {
-             *        "columns": [
-             *          { "title": "My column title" },
-             *          null,
-             *          null,
-             *          null,
-             *          null
-             *        ]
-             *      } );
-             *    } );
-             */
-            "sTitle": null,
-
-
-            /**
-             * The type allows you to specify how the data for this column will be
-             * ordered. Four types (string, numeric, date and html (which will strip
-             * HTML tags before ordering)) are currently available. Note that only date
-             * formats understood by Javascript's Date() object will be accepted as type
-             * date. For example: "Mar 26, 2008 5:03 PM". May take the values: 'string',
-             * 'numeric', 'date' or 'html' (by default). Further types can be adding
-             * through plug-ins.
-             *  @type string
-             *  @default null <i>Auto-detected from raw data</i>
-             *
-             *  @name DataTable.defaults.column.type
-             *  @dtopt Columns
-             *
-             *  @example
-             *    // Using `columnDefs`
-             *    $(document).ready( function() {
-             *      $('#example').dataTable( {
-             *        "columnDefs": [
-             *          { "type": "html", "targets": [ 0 ] }
-             *        ]
-             *      } );
-             *    } );
-             *
-             *  @example
-             *    // Using `columns`
-             *    $(document).ready( function() {
-             *      $('#example').dataTable( {
-             *        "columns": [
-             *          { "type": "html" },
-             *          null,
-             *          null,
-             *          null,
-             *          null
-             *        ]
-             *      } );
-             *    } );
-             */
-            "sType": null,
-
-
-            /**
-             * Defining the width of the column, this parameter may take any CSS value
-             * (3em, 20px etc). DataTables applies 'smart' widths to columns which have not
-             * been given a specific width through this interface ensuring that the table
-             * remains readable.
-             *  @type string
-             *  @default null <i>Automatic</i>
-             *
-             *  @name DataTable.defaults.column.width
-             *  @dtopt Columns
-             *
-             *  @example
-             *    // Using `columnDefs`
-             *    $(document).ready( function() {
-             *      $('#example').dataTable( {
-             *        "columnDefs": [
-             *          { "width": "20%", "targets": [ 0 ] }
-             *        ]
-             *      } );
-             *    } );
-             *
-             *  @example
-             *    // Using `columns`
-             *    $(document).ready( function() {
-             *      $('#example').dataTable( {
-             *        "columns": [
-             *          { "width": "20%" },
-             *          null,
-             *          null,
-             *          null,
-             *          null
-             *        ]
-             *      } );
-             *    } );
-             */
-            "sWidth": null
-        };
-
-        _fnHungarianMap(DataTable.defaults.column);
-
-
-
-        /**
-         * DataTables settings object - this holds all the information needed for a
-         * given table, including configuration, data and current application of the
-         * table options. DataTables does not have a single instance for each DataTable
-         * with the settings attached to that instance, but rather instances of the
-         * DataTable "class" are created on-the-fly as needed (typically by a
-         * $().dataTable() call) and the settings object is then applied to that
-         * instance.
-         *
-         * Note that this object is related to {@link DataTable.defaults} but this
-         * one is the internal data store for DataTables's cache of columns. It should
-         * NOT be manipulated outside of DataTables. Any configuration should be done
-         * through the initialisation options.
-         *  @namespace
-         *  @todo Really should attach the settings object to individual instances so we
-         *    don't need to create new instances on each $().dataTable() call (if the
-         *    table already exists). It would also save passing oSettings around and
-         *    into every single function. However, this is a very significant
-         *    architecture change for DataTables and will almost certainly break
-         *    backwards compatibility with older installations. This is something that
-         *    will be done in 2.0.
-         */
-        DataTable.models.oSettings = {
-            /**
-             * Primary features of DataTables and their enablement state.
-             *  @namespace
-             */
-            "oFeatures": {
-
-                /**
-                 * Flag to say if DataTables should automatically try to calculate the
-                 * optimum table and columns widths (true) or not (false).
-                 * Note that this parameter will be set by the initialisation routine. To
-                 * set a default use {@link DataTable.defaults}.
-                 *  @type boolean
-                 */
-                "bAutoWidth": null,
-
-                /**
-                 * Delay the creation of TR and TD elements until they are actually
-                 * needed by a driven page draw. This can give a significant speed
-                 * increase for Ajax source and Javascript source data, but makes no
-                 * difference at all fro DOM and server-side processing tables.
-                 * Note that this parameter will be set by the initialisation routine. To
-                 * set a default use {@link DataTable.defaults}.
-                 *  @type boolean
-                 */
-                "bDeferRender": null,
-
-                /**
-                 * Enable filtering on the table or not. Note that if this is disabled
-                 * then there is no filtering at all on the table, including fnFilter.
-                 * To just remove the filtering input use sDom and remove the 'f' option.
-                 * Note that this parameter will be set by the initialisation routine. To
-                 * set a default use {@link DataTable.defaults}.
-                 *  @type boolean
-                 */
-                "bFilter": null,
-
-                /**
-                 * Table information element (the 'Showing x of y records' div) enable
-                 * flag.
-                 * Note that this parameter will be set by the initialisation routine. To
-                 * set a default use {@link DataTable.defaults}.
-                 *  @type boolean
-                 */
-                "bInfo": null,
-
-                /**
-                 * Present a user control allowing the end user to change the page size
-                 * when pagination is enabled.
-                 * Note that this parameter will be set by the initialisation routine. To
-                 * set a default use {@link DataTable.defaults}.
-                 *  @type boolean
-                 */
-                "bLengthChange": null,
-
-                /**
-                 * Pagination enabled or not. Note that if this is disabled then length
-                 * changing must also be disabled.
-                 * Note that this parameter will be set by the initialisation routine. To
-                 * set a default use {@link DataTable.defaults}.
-                 *  @type boolean
-                 */
-                "bPaginate": null,
-
-                /**
-                 * Processing indicator enable flag whenever DataTables is enacting a
-                 * user request - typically an Ajax request for server-side processing.
-                 * Note that this parameter will be set by the initialisation routine. To
-                 * set a default use {@link DataTable.defaults}.
-                 *  @type boolean
-                 */
-                "bProcessing": null,
-
-                /**
-                 * Server-side processing enabled flag - when enabled DataTables will
-                 * get all data from the server for every draw - there is no filtering,
-                 * sorting or paging done on the client-side.
-                 * Note that this parameter will be set by the initialisation routine. To
-                 * set a default use {@link DataTable.defaults}.
-                 *  @type boolean
-                 */
-                "bServerSide": null,
-
-                /**
-                 * Sorting enablement flag.
-                 * Note that this parameter will be set by the initialisation routine. To
-                 * set a default use {@link DataTable.defaults}.
-                 *  @type boolean
-                 */
-                "bSort": null,
-
-                /**
-                 * Multi-column sorting
-                 * Note that this parameter will be set by the initialisation routine. To
-                 * set a default use {@link DataTable.defaults}.
-                 *  @type boolean
-                 */
-                "bSortMulti": null,
-
-                /**
-                 * Apply a class to the columns which are being sorted to provide a
-                 * visual highlight or not. This can slow things down when enabled since
-                 * there is a lot of DOM interaction.
-                 * Note that this parameter will be set by the initialisation routine. To
-                 * set a default use {@link DataTable.defaults}.
-                 *  @type boolean
-                 */
-                "bSortClasses": null,
-
-                /**
-                 * State saving enablement flag.
-                 * Note that this parameter will be set by the initialisation routine. To
-                 * set a default use {@link DataTable.defaults}.
-                 *  @type boolean
-                 */
-                "bStateSave": null
-            },
-
-
-            /**
-             * Scrolling settings for a table.
-             *  @namespace
-             */
-            "oScroll": {
-                /**
-                 * When the table is shorter in height than sScrollY, collapse the
-                 * table container down to the height of the table (when true).
-                 * Note that this parameter will be set by the initialisation routine. To
-                 * set a default use {@link DataTable.defaults}.
-                 *  @type boolean
-                 */
-                "bCollapse": null,
-
-                /**
-                 * Width of the scrollbar for the web-browser's platform. Calculated
-                 * during table initialisation.
-                 *  @type int
-                 *  @default 0
-                 */
-                "iBarWidth": 0,
-
-                /**
-                 * Viewport width for horizontal scrolling. Horizontal scrolling is
-                 * disabled if an empty string.
-                 * Note that this parameter will be set by the initialisation routine. To
-                 * set a default use {@link DataTable.defaults}.
-                 *  @type string
-                 */
-                "sX": null,
-
-                /**
-                 * Width to expand the table to when using x-scrolling. Typically you
-                 * should not need to use this.
-                 * Note that this parameter will be set by the initialisation routine. To
-                 * set a default use {@link DataTable.defaults}.
-                 *  @type string
-                 *  @deprecated
-                 */
-                "sXInner": null,
-
-                /**
-                 * Viewport height for vertical scrolling. Vertical scrolling is disabled
-                 * if an empty string.
-                 * Note that this parameter will be set by the initialisation routine. To
-                 * set a default use {@link DataTable.defaults}.
-                 *  @type string
-                 */
-                "sY": null
-            },
-
-            /**
-             * Language information for the table.
-             *  @namespace
-             *  @extends DataTable.defaults.oLanguage
-             */
-            "oLanguage": {
-                /**
-                 * Information callback function. See
-                 * {@link DataTable.defaults.fnInfoCallback}
-                 *  @type function
-                 *  @default null
-                 */
-                "fnInfoCallback": null
-            },
-
-            /**
-             * Browser support parameters
-             *  @namespace
-             */
-            "oBrowser": {
-                /**
-                 * Indicate if the browser incorrectly calculates width:100% inside a
-                 * scrolling element (IE6/7)
-                 *  @type boolean
-                 *  @default false
-                 */
-                "bScrollOversize": false,
-
-                /**
-                 * Determine if the vertical scrollbar is on the right or left of the
-                 * scrolling container - needed for rtl language layout, although not
-                 * all browsers move the scrollbar (Safari).
-                 *  @type boolean
-                 *  @default false
-                 */
-                "bScrollbarLeft": false
-            },
-
-
-            "ajax": null,
-
-
-            /**
-             * Array referencing the nodes which are used for the features. The
-             * parameters of this object match what is allowed by sDom - i.e.
-             *   <ul>
-             *     <li>'l' - Length changing</li>
-             *     <li>'f' - Filtering input</li>
-             *     <li>'t' - The table!</li>
-             *     <li>'i' - Information</li>
-             *     <li>'p' - Pagination</li>
-             *     <li>'r' - pRocessing</li>
-             *   </ul>
-             *  @type array
-             *  @default []
-             */
-            "aanFeatures": [],
-
-            /**
-             * Store data information - see {@link DataTable.models.oRow} for detailed
-             * information.
-             *  @type array
-             *  @default []
-             */
-            "aoData": [],
-
-            /**
-             * Array of indexes which are in the current display (after filtering etc)
-             *  @type array
-             *  @default []
-             */
-            "aiDisplay": [],
-
-            /**
-             * Array of indexes for display - no filtering
-             *  @type array
-             *  @default []
-             */
-            "aiDisplayMaster": [],
-
-            /**
-             * Store information about each column that is in use
-             *  @type array
-             *  @default []
-             */
-            "aoColumns": [],
-
-            /**
-             * Store information about the table's header
-             *  @type array
-             *  @default []
-             */
-            "aoHeader": [],
-
-            /**
-             * Store information about the table's footer
-             *  @type array
-             *  @default []
-             */
-            "aoFooter": [],
-
-            /**
-             * Store the applied global search information in case we want to force a
-             * research or compare the old search to a new one.
-             * Note that this parameter will be set by the initialisation routine. To
-             * set a default use {@link DataTable.defaults}.
-             *  @namespace
-             *  @extends DataTable.models.oSearch
-             */
-            "oPreviousSearch": {},
-
-            /**
-             * Store the applied search for each column - see
-             * {@link DataTable.models.oSearch} for the format that is used for the
-             * filtering information for each column.
-             *  @type array
-             *  @default []
-             */
-            "aoPreSearchCols": [],
-
-            /**
-             * Sorting that is applied to the table. Note that the inner arrays are
-             * used in the following manner:
-             * <ul>
-             *   <li>Index 0 - column number</li>
-             *   <li>Index 1 - current sorting direction</li>
-             * </ul>
-             * Note that this parameter will be set by the initialisation routine. To
-             * set a default use {@link DataTable.defaults}.
-             *  @type array
-             *  @todo These inner arrays should really be objects
-             */
-            "aaSorting": null,
-
-            /**
-             * Sorting that is always applied to the table (i.e. prefixed in front of
-             * aaSorting).
-             * Note that this parameter will be set by the initialisation routine. To
-             * set a default use {@link DataTable.defaults}.
-             *  @type array
-             *  @default []
-             */
-            "aaSortingFixed": [],
-
-            /**
-             * Classes to use for the striping of a table.
-             * Note that this parameter will be set by the initialisation routine. To
-             * set a default use {@link DataTable.defaults}.
-             *  @type array
-             *  @default []
-             */
-            "asStripeClasses": null,
-
-            /**
-             * If restoring a table - we should restore its striping classes as well
-             *  @type array
-             *  @default []
-             */
-            "asDestroyStripes": [],
-
-            /**
-             * If restoring a table - we should restore its width
-             *  @type int
-             *  @default 0
-             */
-            "sDestroyWidth": 0,
-
-            /**
-             * Callback functions array for every time a row is inserted (i.e. on a draw).
-             *  @type array
-             *  @default []
-             */
-            "aoRowCallback": [],
-
-            /**
-             * Callback functions for the header on each draw.
-             *  @type array
-             *  @default []
-             */
-            "aoHeaderCallback": [],
-
-            /**
-             * Callback function for the footer on each draw.
-             *  @type array
-             *  @default []
-             */
-            "aoFooterCallback": [],
-
-            /**
-             * Array of callback functions for draw callback functions
-             *  @type array
-             *  @default []
-             */
-            "aoDrawCallback": [],
-
-            /**
-             * Array of callback functions for row created function
-             *  @type array
-             *  @default []
-             */
-            "aoRowCreatedCallback": [],
-
-            /**
-             * Callback functions for just before the table is redrawn. A return of
-             * false will be used to cancel the draw.
-             *  @type array
-             *  @default []
-             */
-            "aoPreDrawCallback": [],
-
-            /**
-             * Callback functions for when the table has been initialised.
-             *  @type array
-             *  @default []
-             */
-            "aoInitComplete": [],
-
-
-            /**
-             * Callbacks for modifying the settings to be stored for state saving, prior to
-             * saving state.
-             *  @type array
-             *  @default []
-             */
-            "aoStateSaveParams": [],
-
-            /**
-             * Callbacks for modifying the settings that have been stored for state saving
-             * prior to using the stored values to restore the state.
-             *  @type array
-             *  @default []
-             */
-            "aoStateLoadParams": [],
-
-            /**
-             * Callbacks for operating on the settings object once the saved state has been
-             * loaded
-             *  @type array
-             *  @default []
-             */
-            "aoStateLoaded": [],
-
-            /**
-             * Cache the table ID for quick access
-             *  @type string
-             *  @default <i>Empty string</i>
-             */
-            "sTableId": "",
-
-            /**
-             * The TABLE node for the main table
-             *  @type node
-             *  @default null
-             */
-            "nTable": null,
-
-            /**
-             * Permanent ref to the thead element
-             *  @type node
-             *  @default null
-             */
-            "nTHead": null,
-
-            /**
-             * Permanent ref to the tfoot element - if it exists
-             *  @type node
-             *  @default null
-             */
-            "nTFoot": null,
-
-            /**
-             * Permanent ref to the tbody element
-             *  @type node
-             *  @default null
-             */
-            "nTBody": null,
-
-            /**
-             * Cache the wrapper node (contains all DataTables controlled elements)
-             *  @type node
-             *  @default null
-             */
-            "nTableWrapper": null,
-
-            /**
-             * Indicate if when using server-side processing the loading of data
-             * should be deferred until the second draw.
-             * Note that this parameter will be set by the initialisation routine. To
-             * set a default use {@link DataTable.defaults}.
-             *  @type boolean
-             *  @default false
-             */
-            "bDeferLoading": false,
-
-            /**
-             * Indicate if all required information has been read in
-             *  @type boolean
-             *  @default false
-             */
-            "bInitialised": false,
-
-            /**
-             * Information about open rows. Each object in the array has the parameters
-             * 'nTr' and 'nParent'
-             *  @type array
-             *  @default []
-             */
-            "aoOpenRows": [],
-
-            /**
-             * Dictate the positioning of DataTables' control elements - see
-             * {@link DataTable.model.oInit.sDom}.
-             * Note that this parameter will be set by the initialisation routine. To
-             * set a default use {@link DataTable.defaults}.
-             *  @type string
-             *  @default null
-             */
-            "sDom": null,
-
-            /**
-             * Search delay (in mS)
-             *  @type integer
-             *  @default null
-             */
-            "searchDelay": null,
-
-            /**
-             * Which type of pagination should be used.
-             * Note that this parameter will be set by the initialisation routine. To
-             * set a default use {@link DataTable.defaults}.
-             *  @type string
-             *  @default two_button
-             */
-            "sPaginationType": "two_button",
-
-            /**
-             * The state duration (for `stateSave`) in seconds.
-             * Note that this parameter will be set by the initialisation routine. To
-             * set a default use {@link DataTable.defaults}.
-             *  @type int
-             *  @default 0
-             */
-            "iStateDuration": 0,
-
-            /**
-             * Array of callback functions for state saving. Each array element is an
-             * object with the following parameters:
-             *   <ul>
-             *     <li>function:fn - function to call. Takes two parameters, oSettings
-             *       and the JSON string to save that has been thus far created. Returns
-             *       a JSON string to be inserted into a json object
-             *       (i.e. '"param": [ 0, 1, 2]')</li>
-             *     <li>string:sName - name of callback</li>
-             *   </ul>
-             *  @type array
-             *  @default []
-             */
-            "aoStateSave": [],
-
-            /**
-             * Array of callback functions for state loading. Each array element is an
-             * object with the following parameters:
-             *   <ul>
-             *     <li>function:fn - function to call. Takes two parameters, oSettings
-             *       and the object stored. May return false to cancel state loading</li>
-             *     <li>string:sName - name of callback</li>
-             *   </ul>
-             *  @type array
-             *  @default []
-             */
-            "aoStateLoad": [],
-
-            /**
-             * State that was saved. Useful for back reference
-             *  @type object
-             *  @default null
-             */
-            "oSavedState": null,
-
-            /**
-             * State that was loaded. Useful for back reference
-             *  @type object
-             *  @default null
-             */
-            "oLoadedState": null,
-
-            /**
-             * Source url for AJAX data for the table.
-             * Note that this parameter will be set by the initialisation routine. To
-             * set a default use {@link DataTable.defaults}.
-             *  @type string
-             *  @default null
-             */
-            "sAjaxSource": null,
-
-            /**
-             * Property from a given object from which to read the table data from. This
-             * can be an empty string (when not server-side processing), in which case
-             * it is  assumed an an array is given directly.
-             * Note that this parameter will be set by the initialisation routine. To
-             * set a default use {@link DataTable.defaults}.
-             *  @type string
-             */
-            "sAjaxDataProp": null,
-
-            /**
-             * Note if draw should be blocked while getting data
-             *  @type boolean
-             *  @default true
-             */
-            "bAjaxDataGet": true,
-
-            /**
-             * The last jQuery XHR object that was used for server-side data gathering.
-             * This can be used for working with the XHR information in one of the
-             * callbacks
-             *  @type object
-             *  @default null
-             */
-            "jqXHR": null,
-
-            /**
-             * JSON returned from the server in the last Ajax request
-             *  @type object
-             *  @default undefined
-             */
-            "json": undefined,
-
-            /**
-             * Data submitted as part of the last Ajax request
-             *  @type object
-             *  @default undefined
-             */
-            "oAjaxData": undefined,
-
-            /**
-             * Function to get the server-side data.
-             * Note that this parameter will be set by the initialisation routine. To
-             * set a default use {@link DataTable.defaults}.
-             *  @type function
-             */
-            "fnServerData": null,
-
-            /**
-             * Functions which are called prior to sending an Ajax request so extra
-             * parameters can easily be sent to the server
-             *  @type array
-             *  @default []
-             */
-            "aoServerParams": [],
-
-            /**
-             * Send the XHR HTTP method - GET or POST (could be PUT or DELETE if
-             * required).
-             * Note that this parameter will be set by the initialisation routine. To
-             * set a default use {@link DataTable.defaults}.
-             *  @type string
-             */
-            "sServerMethod": null,
-
-            /**
-             * Format numbers for display.
-             * Note that this parameter will be set by the initialisation routine. To
-             * set a default use {@link DataTable.defaults}.
-             *  @type function
-             */
-            "fnFormatNumber": null,
-
-            /**
-             * List of options that can be used for the user selectable length menu.
-             * Note that this parameter will be set by the initialisation routine. To
-             * set a default use {@link DataTable.defaults}.
-             *  @type array
-             *  @default []
-             */
-            "aLengthMenu": null,
-
-            /**
-             * Counter for the draws that the table does. Also used as a tracker for
-             * server-side processing
-             *  @type int
-             *  @default 0
-             */
-            "iDraw": 0,
-
-            /**
-             * Indicate if a redraw is being done - useful for Ajax
-             *  @type boolean
-             *  @default false
-             */
-            "bDrawing": false,
-
-            /**
-             * Draw index (iDraw) of the last error when parsing the returned data
-             *  @type int
-             *  @default -1
-             */
-            "iDrawError": -1,
-
-            /**
-             * Paging display length
-             *  @type int
-             *  @default 10
-             */
-            "_iDisplayLength": 10,
-
-            /**
-             * Paging start point - aiDisplay index
-             *  @type int
-             *  @default 0
-             */
-            "_iDisplayStart": 0,
-
-            /**
-             * Server-side processing - number of records in the result set
-             * (i.e. before filtering), Use fnRecordsTotal rather than
-             * this property to get the value of the number of records, regardless of
-             * the server-side processing setting.
-             *  @type int
-             *  @default 0
-             *  @private
-             */
-            "_iRecordsTotal": 0,
-
-            /**
-             * Server-side processing - number of records in the current display set
-             * (i.e. after filtering). Use fnRecordsDisplay rather than
-             * this property to get the value of the number of records, regardless of
-             * the server-side processing setting.
-             *  @type boolean
-             *  @default 0
-             *  @private
-             */
-            "_iRecordsDisplay": 0,
-
-            /**
-             * Flag to indicate if jQuery UI marking and classes should be used.
-             * Note that this parameter will be set by the initialisation routine. To
-             * set a default use {@link DataTable.defaults}.
-             *  @type boolean
-             */
-            "bJUI": null,
-
-            /**
-             * The classes to use for the table
-             *  @type object
-             *  @default {}
-             */
-            "oClasses": {},
-
-            /**
-             * Flag attached to the settings object so you can check in the draw
-             * callback if filtering has been done in the draw. Deprecated in favour of
-             * events.
-             *  @type boolean
-             *  @default false
-             *  @deprecated
-             */
-            "bFiltered": false,
-
-            /**
-             * Flag attached to the settings object so you can check in the draw
-             * callback if sorting has been done in the draw. Deprecated in favour of
-             * events.
-             *  @type boolean
-             *  @default false
-             *  @deprecated
-             */
-            "bSorted": false,
-
-            /**
-             * Indicate that if multiple rows are in the header and there is more than
-             * one unique cell per column, if the top one (true) or bottom one (false)
-             * should be used for sorting / title by DataTables.
-             * Note that this parameter will be set by the initialisation routine. To
-             * set a default use {@link DataTable.defaults}.
-             *  @type boolean
-             */
-            "bSortCellsTop": null,
-
-            /**
-             * Initialisation object that is used for the table
-             *  @type object
-             *  @default null
-             */
-            "oInit": null,
-
-            /**
-             * Destroy callback functions - for plug-ins to attach themselves to the
-             * destroy so they can clean up markup and events.
-             *  @type array
-             *  @default []
-             */
-            "aoDestroyCallback": [],
-
-
-            /**
-             * Get the number of records in the current record set, before filtering
-             *  @type function
-             */
-            "fnRecordsTotal": function () {
-                return _fnDataSource(this) == 'ssp' ?
-                    this._iRecordsTotal * 1 :
-                    this.aiDisplayMaster.length;
-            },
-
-            /**
-             * Get the number of records in the current record set, after filtering
-             *  @type function
-             */
-            "fnRecordsDisplay": function () {
-                return _fnDataSource(this) == 'ssp' ?
-                    this._iRecordsDisplay * 1 :
-                    this.aiDisplay.length;
-            },
-
-            /**
-             * Get the display end point - aiDisplay index
-             *  @type function
-             */
-            "fnDisplayEnd": function () {
-                var
-                    len = this._iDisplayLength,
-                    start = this._iDisplayStart,
-                    calc = start + len,
-                    records = this.aiDisplay.length,
-                    features = this.oFeatures,
-                    paginate = features.bPaginate;
-
-                if (features.bServerSide) {
-                    return paginate === false || len === -1 ?
-                        start + records :
-                        Math.min(start + len, this._iRecordsDisplay);
-                }
-                else {
-                    return !paginate || calc > records || len === -1 ?
-                        records :
-                        calc;
-                }
-            },
-
-            /**
-             * The DataTables object for this table
-             *  @type object
-             *  @default null
-             */
-            "oInstance": null,
-
-            /**
-             * Unique identifier for each instance of the DataTables object. If there
-             * is an ID on the table node, then it takes that value, otherwise an
-             * incrementing internal counter is used.
-             *  @type string
-             *  @default null
-             */
-            "sInstance": null,
-
-            /**
-             * tabindex attribute value that is added to DataTables control elements, allowing
-             * keyboard navigation of the table and its controls.
-             */
-            "iTabIndex": 0,
-
-            /**
-             * DIV container for the footer scrolling table if scrolling
-             */
-            "nScrollHead": null,
-
-            /**
-             * DIV container for the footer scrolling table if scrolling
-             */
-            "nScrollFoot": null,
-
-            /**
-             * Last applied sort
-             *  @type array
-             *  @default []
-             */
-            "aLastSort": [],
-
-            /**
-             * Stored plug-in instances
-             *  @type object
-             *  @default {}
-             */
-            "oPlugins": {}
-        };
-
-        /**
-         * Extension object for DataTables that is used to provide all extension
-         * options.
-         *
-         * Note that the `DataTable.ext` object is available through
-         * `jQuery.fn.dataTable.ext` where it may be accessed and manipulated. It is
-         * also aliased to `jQuery.fn.dataTableExt` for historic reasons.
-         *  @namespace
-         *  @extends DataTable.models.ext
-         */
-
-
-        /**
-         * DataTables extensions
-         * 
-         * This namespace acts as a collection area for plug-ins that can be used to
-         * extend DataTables capabilities. Indeed many of the build in methods
-         * use this method to provide their own capabilities (sorting methods for
-         * example).
-         *
-         * Note that this namespace is aliased to `jQuery.fn.dataTableExt` for legacy
-         * reasons
-         *
-         *  @namespace
-         */
-        DataTable.ext = _ext = {
-            /**
-             * Buttons. For use with the Buttons extension for DataTables. This is
-             * defined here so other extensions can define buttons regardless of load
-             * order. It is _not_ used by DataTables core.
-             *
-             *  @type object
-             *  @default {}
-             */
-            buttons: {},
-
-
-            /**
-             * Element class names
-             *
-             *  @type object
-             *  @default {}
-             */
-            classes: {},
-
-
-            /**
-             * Error reporting.
-             * 
-             * How should DataTables report an error. Can take the value 'alert',
-             * 'throw', 'none' or a function.
-             *
-             *  @type string|function
-             *  @default alert
-             */
-            errMode: "alert",
-
-
-            /**
-             * Feature plug-ins.
-             * 
-             * This is an array of objects which describe the feature plug-ins that are
-             * available to DataTables. These feature plug-ins are then available for
-             * use through the `dom` initialisation option.
-             * 
-             * Each feature plug-in is described by an object which must have the
-             * following properties:
-             * 
-             * * `fnInit` - function that is used to initialise the plug-in,
-             * * `cFeature` - a character so the feature can be enabled by the `dom`
-             *   instillation option. This is case sensitive.
-             *
-             * The `fnInit` function has the following input parameters:
-             *
-             * 1. `{object}` DataTables settings object: see
-             *    {@link DataTable.models.oSettings}
-             *
-             * And the following return is expected:
-             * 
-             * * {node|null} The element which contains your feature. Note that the
-             *   return may also be void if your plug-in does not require to inject any
-             *   DOM elements into DataTables control (`dom`) - for example this might
-             *   be useful when developing a plug-in which allows table control via
-             *   keyboard entry
-             *
-             *  @type array
-             *
-             *  @example
-             *    $.fn.dataTable.ext.features.push( {
-             *      "fnInit": function( oSettings ) {
-             *        return new TableTools( { "oDTSettings": oSettings } );
-             *      },
-             *      "cFeature": "T"
-             *    } );
-             */
-            feature: [],
-
-
-            /**
-             * Row searching.
-             * 
-             * This method of searching is complimentary to the default type based
-             * searching, and a lot more comprehensive as it allows you complete control
-             * over the searching logic. Each element in this array is a function
-             * (parameters described below) that is called for every row in the table,
-             * and your logic decides if it should be included in the searching data set
-             * or not.
-             *
-             * Searching functions have the following input parameters:
-             *
-             * 1. `{object}` DataTables settings object: see
-             *    {@link DataTable.models.oSettings}
-             * 2. `{array|object}` Data for the row to be processed (same as the
-             *    original format that was passed in as the data source, or an array
-             *    from a DOM data source
-             * 3. `{int}` Row index ({@link DataTable.models.oSettings.aoData}), which
-             *    can be useful to retrieve the `TR` element if you need DOM interaction.
-             *
-             * And the following return is expected:
-             *
-             * * {boolean} Include the row in the searched result set (true) or not
-             *   (false)
-             *
-             * Note that as with the main search ability in DataTables, technically this
-             * is "filtering", since it is subtractive. However, for consistency in
-             * naming we call it searching here.
-             *
-             *  @type array
-             *  @default []
-             *
-             *  @example
-             *    // The following example shows custom search being applied to the
-             *    // fourth column (i.e. the data[3] index) based on two input values
-             *    // from the end-user, matching the data in a certain range.
-             *    $.fn.dataTable.ext.search.push(
-             *      function( settings, data, dataIndex ) {
-             *        var min = document.getElementById('min').value * 1;
-             *        var max = document.getElementById('max').value * 1;
-             *        var version = data[3] == "-" ? 0 : data[3]*1;
-             *
-             *        if ( min == "" && max == "" ) {
-             *          return true;
-             *        }
-             *        else if ( min == "" && version < max ) {
-             *          return true;
-             *        }
-             *        else if ( min < version && "" == max ) {
-             *          return true;
-             *        }
-             *        else if ( min < version && version < max ) {
-             *          return true;
-             *        }
-             *        return false;
-             *      }
-             *    );
-             */
-            search: [],
-
-
-            /**
-             * Selector extensions
-             *
-             * The `selector` option can be used to extend the options available for the
-             * selector modifier options (`selector-modifier` object data type) that
-             * each of the three built in selector types offer (row, column and cell +
-             * their plural counterparts). For example the Select extension uses this
-             * mechanism to provide an option to select only rows, columns and cells
-             * that have been marked as selected by the end user (`{selected: true}`),
-             * which can be used in conjunction with the existing built in selector
-             * options.
-             *
-             * Each property is an array to which functions can be pushed. The functions
-             * take three attributes:
-             *
-             * * Settings object for the host table
-             * * Options object (`selector-modifier` object type)
-             * * Array of selected item indexes
-             *
-             * The return is an array of the resulting item indexes after the custom
-             * selector has been applied.
-             *
-             *  @type object
-             */
-            selector: {
-                cell: [],
-                column: [],
-                row: []
-            },
-
-
-            /**
-             * Internal functions, exposed for used in plug-ins.
-             * 
-             * Please note that you should not need to use the internal methods for
-             * anything other than a plug-in (and even then, try to avoid if possible).
-             * The internal function may change between releases.
-             *
-             *  @type object
-             *  @default {}
-             */
-            internal: {},
-
-
-            /**
-             * Legacy configuration options. Enable and disable legacy options that
-             * are available in DataTables.
-             *
-             *  @type object
-             */
-            legacy: {
-                /**
-                 * Enable / disable DataTables 1.9 compatible server-side processing
-                 * requests
-                 *
-                 *  @type boolean
-                 *  @default null
-                 */
-                ajax: null
-            },
-
-
-            /**
-             * Pagination plug-in methods.
-             * 
-             * Each entry in this object is a function and defines which buttons should
-             * be shown by the pagination rendering method that is used for the table:
-             * {@link DataTable.ext.renderer.pageButton}. The renderer addresses how the
-             * buttons are displayed in the document, while the functions here tell it
-             * what buttons to display. This is done by returning an array of button
-             * descriptions (what each button will do).
-             *
-             * Pagination types (the four built in options and any additional plug-in
-             * options defined here) can be used through the `paginationType`
-             * initialisation parameter.
-             *
-             * The functions defined take two parameters:
-             *
-             * 1. `{int} page` The current page index
-             * 2. `{int} pages` The number of pages in the table
-             *
-             * Each function is expected to return an array where each element of the
-             * array can be one of:
-             *
-             * * `first` - Jump to first page when activated
-             * * `last` - Jump to last page when activated
-             * * `previous` - Show previous page when activated
-             * * `next` - Show next page when activated
-             * * `{int}` - Show page of the index given
-             * * `{array}` - A nested array containing the above elements to add a
-             *   containing 'DIV' element (might be useful for styling).
-             *
-             * Note that DataTables v1.9- used this object slightly differently whereby
-             * an object with two functions would be defined for each plug-in. That
-             * ability is still supported by DataTables 1.10+ to provide backwards
-             * compatibility, but this option of use is now decremented and no longer
-             * documented in DataTables 1.10+.
-             *
-             *  @type object
-             *  @default {}
-             *
-             *  @example
-             *    // Show previous, next and current page buttons only
-             *    $.fn.dataTableExt.oPagination.current = function ( page, pages ) {
-             *      return [ 'previous', page, 'next' ];
-             *    };
-             */
-            pager: {},
-
-
-            renderer: {
-                pageButton: {},
-                header: {}
-            },
-
-
-            /**
-             * Ordering plug-ins - custom data source
-             * 
-             * The extension options for ordering of data available here is complimentary
-             * to the default type based ordering that DataTables typically uses. It
-             * allows much greater control over the the data that is being used to
-             * order a column, but is necessarily therefore more complex.
-             * 
-             * This type of ordering is useful if you want to do ordering based on data
-             * live from the DOM (for example the contents of an 'input' element) rather
-             * than just the static string that DataTables knows of.
-             * 
-             * The way these plug-ins work is that you create an array of the values you
-             * wish to be ordering for the column in question and then return that
-             * array. The data in the array much be in the index order of the rows in
-             * the table (not the currently ordering order!). Which order data gathering
-             * function is run here depends on the `dt-init columns.orderDataType`
-             * parameter that is used for the column (if any).
-             *
-             * The functions defined take two parameters:
-             *
-             * 1. `{object}` DataTables settings object: see
-             *    {@link DataTable.models.oSettings}
-             * 2. `{int}` Target column index
-             *
-             * Each function is expected to return an array:
-             *
-             * * `{array}` Data for the column to be ordering upon
-             *
-             *  @type array
-             *
-             *  @example
-             *    // Ordering using `input` node values
-             *    $.fn.dataTable.ext.order['dom-text'] = function  ( settings, col )
-             *    {
-             *      return this.api().column( col, {order:'index'} ).nodes().map( function ( td, i ) {
-             *        return $('input', td).val();
-             *      } );
-             *    }
-             */
-            order: {},
-
-
-            /**
-             * Type based plug-ins.
-             *
-             * Each column in DataTables has a type assigned to it, either by automatic
-             * detection or by direct assignment using the `type` option for the column.
-             * The type of a column will effect how it is ordering and search (plug-ins
-             * can also make use of the column type if required).
-             *
-             * @namespace
-             */
-            type: {
-                /**
-                 * Type detection functions.
-                 *
-                 * The functions defined in this object are used to automatically detect
-                 * a column's type, making initialisation of DataTables super easy, even
-                 * when complex data is in the table.
-                 *
-                 * The functions defined take two parameters:
-                 *
-                 *  1. `{*}` Data from the column cell to be analysed
-                 *  2. `{settings}` DataTables settings object. This can be used to
-                 *     perform context specific type detection - for example detection
-                 *     based on language settings such as using a comma for a decimal
-                 *     place. Generally speaking the options from the settings will not
-                 *     be required
-                 *
-                 * Each function is expected to return:
-                 *
-                 * * `{string|null}` Data type detected, or null if unknown (and thus
-                 *   pass it on to the other type detection functions.
-                 *
-                 *  @type array
-                 *
-                 *  @example
-                 *    // Currency type detection plug-in:
-                 *    $.fn.dataTable.ext.type.detect.push(
-                 *      function ( data, settings ) {
-                 *        // Check the numeric part
-                 *        if ( ! $.isNumeric( data.substring(1) ) ) {
-                 *          return null;
-                 *        }
-                 *
-                 *        // Check prefixed by currency
-                 *        if ( data.charAt(0) == '$' || data.charAt(0) == '&pound;' ) {
-                 *          return 'currency';
-                 *        }
-                 *        return null;
-                 *      }
-                 *    );
-                 */
-                detect: [],
-
-
-                /**
-                 * Type based search formatting.
-                 *
-                 * The type based searching functions can be used to pre-format the
-                 * data to be search on. For example, it can be used to strip HTML
-                 * tags or to de-format telephone numbers for numeric only searching.
-                 *
-                 * Note that is a search is not defined for a column of a given type,
-                 * no search formatting will be performed.
-                 * 
-                 * Pre-processing of searching data plug-ins - When you assign the sType
-                 * for a column (or have it automatically detected for you by DataTables
-                 * or a type detection plug-in), you will typically be using this for
-                 * custom sorting, but it can also be used to provide custom searching
-                 * by allowing you to pre-processing the data and returning the data in
-                 * the format that should be searched upon. This is done by adding
-                 * functions this object with a parameter name which matches the sType
-                 * for that target column. This is the corollary of <i>afnSortData</i>
-                 * for searching data.
-                 *
-                 * The functions defined take a single parameter:
-                 *
-                 *  1. `{*}` Data from the column cell to be prepared for searching
-                 *
-                 * Each function is expected to return:
-                 *
-                 * * `{string|null}` Formatted string that will be used for the searching.
-                 *
-                 *  @type object
-                 *  @default {}
-                 *
-                 *  @example
-                 *    $.fn.dataTable.ext.type.search['title-numeric'] = function ( d ) {
-                 *      return d.replace(/\n/g," ").replace( /<.*?>/g, "" );
-                 *    }
-                 */
-                search: {},
-
-
-                /**
-                 * Type based ordering.
-                 *
-                 * The column type tells DataTables what ordering to apply to the table
-                 * when a column is sorted upon. The order for each type that is defined,
-                 * is defined by the functions available in this object.
-                 *
-                 * Each ordering option can be described by three properties added to
-                 * this object:
-                 *
-                 * * `{type}-pre` - Pre-formatting function
-                 * * `{type}-asc` - Ascending order function
-                 * * `{type}-desc` - Descending order function
-                 *
-                 * All three can be used together, only `{type}-pre` or only
-                 * `{type}-asc` and `{type}-desc` together. It is generally recommended
-                 * that only `{type}-pre` is used, as this provides the optimal
-                 * implementation in terms of speed, although the others are provided
-                 * for compatibility with existing Javascript sort functions.
-                 *
-                 * `{type}-pre`: Functions defined take a single parameter:
-                 *
-                 *  1. `{*}` Data from the column cell to be prepared for ordering
-                 *
-                 * And return:
-                 *
-                 * * `{*}` Data to be sorted upon
-                 *
-                 * `{type}-asc` and `{type}-desc`: Functions are typical Javascript sort
-                 * functions, taking two parameters:
-                 *
-                 *  1. `{*}` Data to compare to the second parameter
-                 *  2. `{*}` Data to compare to the first parameter
-                 *
-                 * And returning:
-                 *
-                 * * `{*}` Ordering match: <0 if first parameter should be sorted lower
-                 *   than the second parameter, ===0 if the two parameters are equal and
-                 *   >0 if the first parameter should be sorted height than the second
-                 *   parameter.
-                 * 
-                 *  @type object
-                 *  @default {}
-                 *
-                 *  @example
-                 *    // Numeric ordering of formatted numbers with a pre-formatter
-                 *    $.extend( $.fn.dataTable.ext.type.order, {
-                 *      "string-pre": function(x) {
-                 *        a = (a === "-" || a === "") ? 0 : a.replace( /[^\d\-\.]/g, "" );
-                 *        return parseFloat( a );
-                 *      }
-                 *    } );
-                 *
-                 *  @example
-                 *    // Case-sensitive string ordering, with no pre-formatting method
-                 *    $.extend( $.fn.dataTable.ext.order, {
-                 *      "string-case-asc": function(x,y) {
-                 *        return ((x < y) ? -1 : ((x > y) ? 1 : 0));
-                 *      },
-                 *      "string-case-desc": function(x,y) {
-                 *        return ((x < y) ? 1 : ((x > y) ? -1 : 0));
-                 *      }
-                 *    } );
-                 */
-                order: {}
-            },
-
-            /**
-             * Unique DataTables instance counter
-             *
-             * @type int
-             * @private
-             */
-            _unique: 0,
-
-
-            //
-            // Depreciated
-            // The following properties are retained for backwards compatiblity only.
-            // The should not be used in new projects and will be removed in a future
-            // version
-            //
-
-            /**
-             * Version check function.
-             *  @type function
-             *  @depreciated Since 1.10
-             */
-            fnVersionCheck: DataTable.fnVersionCheck,
-
-
-            /**
-             * Index for what 'this' index API functions should use
-             *  @type int
-             *  @deprecated Since v1.10
-             */
-            iApiIndex: 0,
-
-
-            /**
-             * jQuery UI class container
-             *  @type object
-             *  @deprecated Since v1.10
-             */
-            oJUIClasses: {},
-
-
-            /**
-             * Software version
-             *  @type string
-             *  @deprecated Since v1.10
-             */
-            sVersion: DataTable.version
-        };
-
-
-        //
-        // Backwards compatibility. Alias to pre 1.10 Hungarian notation counter parts
-        //
-        $.extend(_ext, {
-            afnFiltering: _ext.search,
-            aTypes: _ext.type.detect,
-            ofnSearch: _ext.type.search,
-            oSort: _ext.type.order,
-            afnSortData: _ext.order,
-            aoFeatures: _ext.feature,
-            oApi: _ext.internal,
-            oStdClasses: _ext.classes,
-            oPagination: _ext.pager
-        });
-
-
-        $.extend(DataTable.ext.classes, {
-            "sTable": "dataTable",
-            "sNoFooter": "no-footer",
-
-            /* Paging buttons */
-            "sPageButton": "paginate_button",
-            "sPageButtonActive": "current",
-            "sPageButtonDisabled": "disabled",
-
-            /* Striping classes */
-            "sStripeOdd": "odd",
-            "sStripeEven": "even",
-
-            /* Empty row */
-            "sRowEmpty": "dataTables_empty",
-
-            /* Features */
-            "sWrapper": "dataTables_wrapper",
-            "sFilter": "dataTables_filter",
-            "sInfo": "dataTables_info",
-            "sPaging": "dataTables_paginate paging_", /* Note that the type is postfixed */
-            "sLength": "dataTables_length",
-            "sProcessing": "dataTables_processing",
-
-            /* Sorting */
-            "sSortAsc": "sorting_asc",
-            "sSortDesc": "sorting_desc",
-            "sSortable": "sorting", /* Sortable in both directions */
-            "sSortableAsc": "sorting_asc_disabled",
-            "sSortableDesc": "sorting_desc_disabled",
-            "sSortableNone": "sorting_disabled",
-            "sSortColumn": "sorting_", /* Note that an int is postfixed for the sorting order */
-
-            /* Filtering */
-            "sFilterInput": "",
-
-            /* Page length */
-            "sLengthSelect": "",
-
-            /* Scrolling */
-            "sScrollWrapper": "dataTables_scroll",
-            "sScrollHead": "dataTables_scrollHead",
-            "sScrollHeadInner": "dataTables_scrollHeadInner",
-            "sScrollBody": "dataTables_scrollBody",
-            "sScrollFoot": "dataTables_scrollFoot",
-            "sScrollFootInner": "dataTables_scrollFootInner",
-
-            /* Misc */
-            "sHeaderTH": "",
-            "sFooterTH": "",
-
-            // Deprecated
-            "sSortJUIAsc": "",
-            "sSortJUIDesc": "",
-            "sSortJUI": "",
-            "sSortJUIAscAllowed": "",
-            "sSortJUIDescAllowed": "",
-            "sSortJUIWrapper": "",
-            "sSortIcon": "",
-            "sJUIHeader": "",
-            "sJUIFooter": ""
-        });
-
-
-        (function () {
-
-            // Reused strings for better compression. Closure compiler appears to have a
-            // weird edge case where it is trying to expand strings rather than use the
-            // variable version. This results in about 200 bytes being added, for very
-            // little preference benefit since it this run on script load only.
-            var _empty = '';
-            _empty = '';
-
-            var _stateDefault = _empty + 'ui-state-default';
-            var _sortIcon = _empty + 'css_right ui-icon ui-icon-';
-            var _headerFooter = _empty + 'fg-toolbar ui-toolbar ui-widget-header ui-helper-clearfix';
-
-            $.extend(DataTable.ext.oJUIClasses, DataTable.ext.classes, {
-                /* Full numbers paging buttons */
-                "sPageButton": "fg-button ui-button " + _stateDefault,
-                "sPageButtonActive": "ui-state-disabled",
-                "sPageButtonDisabled": "ui-state-disabled",
-
-                /* Features */
-                "sPaging": "dataTables_paginate fg-buttonset ui-buttonset fg-buttonset-multi " +
-                    "ui-buttonset-multi paging_", /* Note that the type is postfixed */
-
-                /* Sorting */
-                "sSortAsc": _stateDefault + " sorting_asc",
-                "sSortDesc": _stateDefault + " sorting_desc",
-                "sSortable": _stateDefault + " sorting",
-                "sSortableAsc": _stateDefault + " sorting_asc_disabled",
-                "sSortableDesc": _stateDefault + " sorting_desc_disabled",
-                "sSortableNone": _stateDefault + " sorting_disabled",
-                "sSortJUIAsc": _sortIcon + "triangle-1-n",
-                "sSortJUIDesc": _sortIcon + "triangle-1-s",
-                "sSortJUI": _sortIcon + "carat-2-n-s",
-                "sSortJUIAscAllowed": _sortIcon + "carat-1-n",
-                "sSortJUIDescAllowed": _sortIcon + "carat-1-s",
-                "sSortJUIWrapper": "DataTables_sort_wrapper",
-                "sSortIcon": "DataTables_sort_icon",
-
-                /* Scrolling */
-                "sScrollHead": "dataTables_scrollHead " + _stateDefault,
-                "sScrollFoot": "dataTables_scrollFoot " + _stateDefault,
-
-                /* Misc */
-                "sHeaderTH": _stateDefault,
-                "sFooterTH": _stateDefault,
-                "sJUIHeader": _headerFooter + " ui-corner-tl ui-corner-tr",
-                "sJUIFooter": _headerFooter + " ui-corner-bl ui-corner-br"
-            });
-
-        }());
-
-
-
-        var extPagination = DataTable.ext.pager;
-
-        function _numbers(page, pages) {
-            var
-                numbers = [],
-                buttons = extPagination.numbers_length,
-                half = Math.floor(buttons / 2),
-                i = 1;
-
-            if (pages <= buttons) {
-                numbers = _range(0, pages);
-            }
-            else if (page <= half) {
-                numbers = _range(0, buttons - 2);
-                numbers.push('ellipsis');
-                numbers.push(pages - 1);
-            }
-            else if (page >= pages - 1 - half) {
-                numbers = _range(pages - (buttons - 2), pages);
-                numbers.splice(0, 0, 'ellipsis'); // no unshift in ie6
-                numbers.splice(0, 0, 0);
-            }
-            else {
-                numbers = _range(page - half + 2, page + half - 1);
-                numbers.push('ellipsis');
-                numbers.push(pages - 1);
-                numbers.splice(0, 0, 'ellipsis');
-                numbers.splice(0, 0, 0);
-            }
-
-            numbers.DT_el = 'span';
-            return numbers;
-        }
-
-
-        $.extend(extPagination, {
-            simple: function (page, pages) {
-                return ['previous', 'next'];
-            },
-
-            full: function (page, pages) {
-                return ['first', 'previous', 'next', 'last'];
-            },
-
-            simple_numbers: function (page, pages) {
-                return ['previous', _numbers(page, pages), 'next'];
-            },
-
-            full_numbers: function (page, pages) {
-                return ['first', 'previous', _numbers(page, pages), 'next', 'last'];
-            },
-
-            // For testing and plug-ins to use
-            _numbers: _numbers,
-
-            // Number of number buttons (including ellipsis) to show. _Must be odd!_
-            numbers_length: 7
-        });
-
-
-        $.extend(true, DataTable.ext.renderer, {
-            pageButton: {
-                _: function (settings, host, idx, buttons, page, pages) {
-                    var classes = settings.oClasses;
-                    var lang = settings.oLanguage.oPaginate;
-                    var btnDisplay, btnClass, counter = 0;
-
-                    var attach = function (container, buttons) {
-                        var i, ien, node, button;
-                        var clickHandler = function (e) {
-                            _fnPageChange(settings, e.data.action, true);
-                        };
-
-                        for (i = 0, ien = buttons.length ; i < ien ; i++) {
-                            button = buttons[i];
-
-                            if ($.isArray(button)) {
-                                var inner = $('<' + (button.DT_el || 'div') + '/>')
-                                    .appendTo(container);
-                                attach(inner, button);
-                            }
-                            else {
-                                btnDisplay = '';
-                                btnClass = '';
-
-                                switch (button) {
-                                    case 'ellipsis':
-                                        container.append('<span class="ellipsis">&#x2026;</span>');
-                                        break;
-
-                                    case 'first':
-                                        btnDisplay = lang.sFirst;
-                                        btnClass = button + (page > 0 ?
-                                            '' : ' ' + classes.sPageButtonDisabled);
-                                        break;
-
-                                    case 'previous':
-                                        btnDisplay = lang.sPrevious;
-                                        btnClass = button + (page > 0 ?
-                                            '' : ' ' + classes.sPageButtonDisabled);
-                                        break;
-
-                                    case 'next':
-                                        btnDisplay = lang.sNext;
-                                        btnClass = button + (page < pages - 1 ?
-                                            '' : ' ' + classes.sPageButtonDisabled);
-                                        break;
-
-                                    case 'last':
-                                        btnDisplay = lang.sLast;
-                                        btnClass = button + (page < pages - 1 ?
-                                            '' : ' ' + classes.sPageButtonDisabled);
-                                        break;
-
-                                    default:
-                                        btnDisplay = button + 1;
-                                        btnClass = page === button ?
-                                            classes.sPageButtonActive : '';
-                                        break;
-                                }
-
-                                if (btnDisplay) {
-                                    node = $('<a>', {
-                                        'class': classes.sPageButton + ' ' + btnClass,
-                                        'aria-controls': settings.sTableId,
-                                        'data-dt-idx': counter,
-                                        'tabindex': settings.iTabIndex,
-                                        'id': idx === 0 && typeof button === 'string' ?
-											settings.sTableId + '_' + button :
-											null
-                                    })
-                                        .html(btnDisplay)
-                                        .appendTo(container);
-
-                                    _fnBindAction(
-                                        node, { action: button }, clickHandler
-                                    );
-
-                                    counter++;
-                                }
-                            }
-                        }
-                    };
-
-                    // IE9 throws an 'unknown error' if document.activeElement is used
-                    // inside an iframe or frame. Try / catch the error. Not good for
-                    // accessibility, but neither are frames.
-                    var activeEl;
-
-                    try {
-                        // Because this approach is destroying and recreating the paging
-                        // elements, focus is lost on the select button which is bad for
-                        // accessibility. So we want to restore focus once the draw has
-                        // completed
-                        activeEl = $(document.activeElement).data('dt-idx');
-                    }
-                    catch (e) { }
-
-                    attach($(host).empty(), buttons);
-
-                    if (activeEl) {
-                        $(host).find('[data-dt-idx=' + activeEl + ']').focus();
-                    }
-                }
-            }
-        });
-
-
-
-        // Built in type detection. See model.ext.aTypes for information about
-        // what is required from this methods.
-        $.extend(DataTable.ext.type.detect, [
-            // Plain numbers - first since V8 detects some plain numbers as dates
-            // e.g. Date.parse('55') (but not all, e.g. Date.parse('22')...).
-            function (d, settings) {
-                var decimal = settings.oLanguage.sDecimal;
-                return _isNumber(d, decimal) ? 'num' + decimal : null;
-            },
-
-            // Dates (only those recognised by the browser's Date.parse)
-            function (d, settings) {
-                // V8 will remove any unknown characters at the start and end of the
-                // expression, leading to false matches such as `$245.12` or `10%` being
-                // a valid date. See forum thread 18941 for detail.
-                if (d && !(d instanceof Date) && (!_re_date_start.test(d) || !_re_date_end.test(d))) {
-                    return null;
-                }
-                var parsed = Date.parse(d);
-                return (parsed !== null && !isNaN(parsed)) || _empty(d) ? 'date' : null;
-            },
-
-            // Formatted numbers
-            function (d, settings) {
-                var decimal = settings.oLanguage.sDecimal;
-                return _isNumber(d, decimal, true) ? 'num-fmt' + decimal : null;
-            },
-
-            // HTML numeric
-            function (d, settings) {
-                var decimal = settings.oLanguage.sDecimal;
-                return _htmlNumeric(d, decimal) ? 'html-num' + decimal : null;
-            },
-
-            // HTML numeric, formatted
-            function (d, settings) {
-                var decimal = settings.oLanguage.sDecimal;
-                return _htmlNumeric(d, decimal, true) ? 'html-num-fmt' + decimal : null;
-            },
-
-            // HTML (this is strict checking - there must be html)
-            function (d, settings) {
-                return _empty(d) || (typeof d === 'string' && d.indexOf('<') !== -1) ?
-                    'html' : null;
-            }
-        ]);
-
-
-
-        // Filter formatting functions. See model.ext.ofnSearch for information about
-        // what is required from these methods.
-        // 
-        // Note that additional search methods are added for the html numbers and
-        // html formatted numbers by `_addNumericSort()` when we know what the decimal
-        // place is
-
-
-        $.extend(DataTable.ext.type.search, {
-            html: function (data) {
-                return _empty(data) ?
-                    data :
-                    typeof data === 'string' ?
-                        data
-                            .replace(_re_new_lines, " ")
-                            .replace(_re_html, "") :
-                        '';
-            },
-
-            string: function (data) {
-                return _empty(data) ?
-                    data :
-                    typeof data === 'string' ?
-                        data.replace(_re_new_lines, " ") :
-                        data;
-            }
-        });
-
-
-
-        var __numericReplace = function (d, decimalPlace, re1, re2) {
-            if (d !== 0 && (!d || d === '-')) {
-                return -Infinity;
-            }
-
-            // If a decimal place other than `.` is used, it needs to be given to the
-            // function so we can detect it and replace with a `.` which is the only
-            // decimal place Javascript recognises - it is not locale aware.
-            if (decimalPlace) {
-                d = _numToDecimal(d, decimalPlace);
-            }
-
-            if (d.replace) {
-                if (re1) {
-                    d = d.replace(re1, '');
-                }
-
-                if (re2) {
-                    d = d.replace(re2, '');
-                }
-            }
-
-            return d * 1;
-        };
-
-
-        // Add the numeric 'deformatting' functions for sorting and search. This is done
-        // in a function to provide an easy ability for the language options to add
-        // additional methods if a non-period decimal place is used.
-        function _addNumericSort(decimalPlace) {
-            $.each(
-                {
-                    // Plain numbers
-                    "num": function (d) {
-                        return __numericReplace(d, decimalPlace);
-                    },
-
-                    // Formatted numbers
-                    "num-fmt": function (d) {
-                        return __numericReplace(d, decimalPlace, _re_formatted_numeric);
-                    },
-
-                    // HTML numeric
-                    "html-num": function (d) {
-                        return __numericReplace(d, decimalPlace, _re_html);
-                    },
-
-                    // HTML numeric, formatted
-                    "html-num-fmt": function (d) {
-                        return __numericReplace(d, decimalPlace, _re_html, _re_formatted_numeric);
-                    }
-                },
-                function (key, fn) {
-                    // Add the ordering method
-                    _ext.type.order[key + decimalPlace + '-pre'] = fn;
-
-                    // For HTML types add a search formatter that will strip the HTML
-                    if (key.match(/^html\-/)) {
-                        _ext.type.search[key + decimalPlace] = _ext.type.search.html;
-                    }
-                }
-            );
-        }
-
-
-        // Default sort methods
-        $.extend(_ext.type.order, {
-            // Dates
-            "date-pre": function (d) {
-                return Date.parse(d) || 0;
-            },
-
-            // html
-            "html-pre": function (a) {
-                return _empty(a) ?
-                    '' :
-                    a.replace ?
-                        a.replace(/<.*?>/g, "").toLowerCase() :
-                        a + '';
-            },
-
-            // string
-            "string-pre": function (a) {
-                // This is a little complex, but faster than always calling toString,
-                // http://jsperf.com/tostring-v-check
-                return _empty(a) ?
-                    '' :
-                    typeof a === 'string' ?
-                        a.toLowerCase() :
-                        !a.toString ?
-                            '' :
-                            a.toString();
-            },
-
-            // string-asc and -desc are retained only for compatibility with the old
-            // sort methods
-            "string-asc": function (x, y) {
-                return ((x < y) ? -1 : ((x > y) ? 1 : 0));
-            },
-
-            "string-desc": function (x, y) {
-                return ((x < y) ? 1 : ((x > y) ? -1 : 0));
-            }
-        });
-
-
-        // Numeric sorting types - order doesn't matter here
-        _addNumericSort('');
-
-
-        $.extend(true, DataTable.ext.renderer, {
-            header: {
-                _: function (settings, cell, column, classes) {
-                    // No additional mark-up required
-                    // Attach a sort listener to update on sort - note that using the
-                    // `DT` namespace will allow the event to be removed automatically
-                    // on destroy, while the `dt` namespaced event is the one we are
-                    // listening for
-                    $(settings.nTable).on('order.dt.DT', function (e, ctx, sorting, columns) {
-                        if (settings !== ctx) { // need to check this this is the host
-                            return;               // table, not a nested one
-                        }
-
-                        var colIdx = column.idx;
-
-                        cell
-                            .removeClass(
-                                column.sSortingClass + ' ' +
-                                classes.sSortAsc + ' ' +
-                                classes.sSortDesc
-                            )
-                            .addClass(columns[colIdx] == 'asc' ?
-                                classes.sSortAsc : columns[colIdx] == 'desc' ?
-                                    classes.sSortDesc :
-                                    column.sSortingClass
-                            );
-                    });
-                },
-
-                jqueryui: function (settings, cell, column, classes) {
-                    $('<div/>')
-                        .addClass(classes.sSortJUIWrapper)
-                        .append(cell.contents())
-                        .append($('<span/>')
-                            .addClass(classes.sSortIcon + ' ' + column.sSortingClassJUI)
-                        )
-                        .appendTo(cell);
-
-                    // Attach a sort listener to update on sort
-                    $(settings.nTable).on('order.dt.DT', function (e, ctx, sorting, columns) {
-                        if (settings !== ctx) {
-                            return;
-                        }
-
-                        var colIdx = column.idx;
-
-                        cell
-                            .removeClass(classes.sSortAsc + " " + classes.sSortDesc)
-                            .addClass(columns[colIdx] == 'asc' ?
-                                classes.sSortAsc : columns[colIdx] == 'desc' ?
-                                    classes.sSortDesc :
-                                    column.sSortingClass
-                            );
-
-                        cell
-                            .find('span.' + classes.sSortIcon)
-                            .removeClass(
-                                classes.sSortJUIAsc + " " +
-                                classes.sSortJUIDesc + " " +
-                                classes.sSortJUI + " " +
-                                classes.sSortJUIAscAllowed + " " +
-                                classes.sSortJUIDescAllowed
-                            )
-                            .addClass(columns[colIdx] == 'asc' ?
-                                classes.sSortJUIAsc : columns[colIdx] == 'desc' ?
-                                    classes.sSortJUIDesc :
-                                    column.sSortingClassJUI
-                            );
-                    });
-                }
-            }
-        });
-
-        /*
-         * Public helper functions. These aren't used internally by DataTables, or
-         * called by any of the options passed into DataTables, but they can be used
-         * externally by developers working with DataTables. They are helper functions
-         * to make working with DataTables a little bit easier.
-         */
-
-        /**
-         * Helpers for `columns.render`.
-         *
-         * The options defined here can be used with the `columns.render` initialisation
-         * option to provide a display renderer. The following functions are defined:
-         *
-         * * `number` - Will format numeric data (defined by `columns.data`) for
-         *   display, retaining the original unformatted data for sorting and filtering.
-         *   It takes 4 parameters:
-         *   * `string` - Thousands grouping separator
-         *   * `string` - Decimal point indicator
-         *   * `integer` - Number of decimal points to show
-         *   * `string` (optional) - Prefix.
-         *
-         * @example
-         *   // Column definition using the number renderer
-         *   {
-         *     data: "salary",
-         *     render: $.fn.dataTable.render.number( '\'', '.', 0, '$' )
-         *   }
-         *
-         * @namespace
-         */
-        DataTable.render = {
-            number: function (thousands, decimal, precision, prefix) {
-                return {
-                    display: function (d) {
-                        if (typeof d !== 'number' && typeof d !== 'string') {
-                            return d;
-                        }
-
-                        var negative = d < 0 ? '-' : '';
-                        d = Math.abs(parseFloat(d));
-
-                        var intPart = parseInt(d, 10);
-                        var floatPart = precision ?
-                            decimal + (d - intPart).toFixed(precision).substring(2) :
-                            '';
-
-                        return negative + (prefix || '') +
-                            intPart.toString().replace(
-                                /\B(?=(\d{3})+(?!\d))/g, thousands
-                            ) +
-                            floatPart;
-                    }
-                };
-            }
-        };
-
-
-        /*
-         * This is really a good bit rubbish this method of exposing the internal methods
-         * publicly... - To be fixed in 2.0 using methods on the prototype
-         */
-
-
-        /**
-         * Create a wrapper function for exporting an internal functions to an external API.
-         *  @param {string} fn API function name
-         *  @returns {function} wrapped function
-         *  @memberof DataTable#internal
-         */
-        function _fnExternApiFunc(fn) {
-            return function () {
-                var args = [_fnSettingsFromNode(this[DataTable.ext.iApiIndex])].concat(
-                    Array.prototype.slice.call(arguments)
-                );
-                return DataTable.ext.internal[fn].apply(this, args);
-            };
-        }
-
-
-        /**
-         * Reference to internal functions for use by plug-in developers. Note that
-         * these methods are references to internal functions and are considered to be
-         * private. If you use these methods, be aware that they are liable to change
-         * between versions.
-         *  @namespace
-         */
-        $.extend(DataTable.ext.internal, {
-            _fnExternApiFunc: _fnExternApiFunc,
-            _fnBuildAjax: _fnBuildAjax,
-            _fnAjaxUpdate: _fnAjaxUpdate,
-            _fnAjaxParameters: _fnAjaxParameters,
-            _fnAjaxUpdateDraw: _fnAjaxUpdateDraw,
-            _fnAjaxDataSrc: _fnAjaxDataSrc,
-            _fnAddColumn: _fnAddColumn,
-            _fnColumnOptions: _fnColumnOptions,
-            _fnAdjustColumnSizing: _fnAdjustColumnSizing,
-            _fnVisibleToColumnIndex: _fnVisibleToColumnIndex,
-            _fnColumnIndexToVisible: _fnColumnIndexToVisible,
-            _fnVisbleColumns: _fnVisbleColumns,
-            _fnGetColumns: _fnGetColumns,
-            _fnColumnTypes: _fnColumnTypes,
-            _fnApplyColumnDefs: _fnApplyColumnDefs,
-            _fnHungarianMap: _fnHungarianMap,
-            _fnCamelToHungarian: _fnCamelToHungarian,
-            _fnLanguageCompat: _fnLanguageCompat,
-            _fnBrowserDetect: _fnBrowserDetect,
-            _fnAddData: _fnAddData,
-            _fnAddTr: _fnAddTr,
-            _fnNodeToDataIndex: _fnNodeToDataIndex,
-            _fnNodeToColumnIndex: _fnNodeToColumnIndex,
-            _fnGetCellData: _fnGetCellData,
-            _fnSetCellData: _fnSetCellData,
-            _fnSplitObjNotation: _fnSplitObjNotation,
-            _fnGetObjectDataFn: _fnGetObjectDataFn,
-            _fnSetObjectDataFn: _fnSetObjectDataFn,
-            _fnGetDataMaster: _fnGetDataMaster,
-            _fnClearTable: _fnClearTable,
-            _fnDeleteIndex: _fnDeleteIndex,
-            _fnInvalidate: _fnInvalidate,
-            _fnGetRowElements: _fnGetRowElements,
-            _fnCreateTr: _fnCreateTr,
-            _fnBuildHead: _fnBuildHead,
-            _fnDrawHead: _fnDrawHead,
-            _fnDraw: _fnDraw,
-            _fnReDraw: _fnReDraw,
-            _fnAddOptionsHtml: _fnAddOptionsHtml,
-            _fnDetectHeader: _fnDetectHeader,
-            _fnGetUniqueThs: _fnGetUniqueThs,
-            _fnFeatureHtmlFilter: _fnFeatureHtmlFilter,
-            _fnFilterComplete: _fnFilterComplete,
-            _fnFilterCustom: _fnFilterCustom,
-            _fnFilterColumn: _fnFilterColumn,
-            _fnFilter: _fnFilter,
-            _fnFilterCreateSearch: _fnFilterCreateSearch,
-            _fnEscapeRegex: _fnEscapeRegex,
-            _fnFilterData: _fnFilterData,
-            _fnFeatureHtmlInfo: _fnFeatureHtmlInfo,
-            _fnUpdateInfo: _fnUpdateInfo,
-            _fnInfoMacros: _fnInfoMacros,
-            _fnInitialise: _fnInitialise,
-            _fnInitComplete: _fnInitComplete,
-            _fnLengthChange: _fnLengthChange,
-            _fnFeatureHtmlLength: _fnFeatureHtmlLength,
-            _fnFeatureHtmlPaginate: _fnFeatureHtmlPaginate,
-            _fnPageChange: _fnPageChange,
-            _fnFeatureHtmlProcessing: _fnFeatureHtmlProcessing,
-            _fnProcessingDisplay: _fnProcessingDisplay,
-            _fnFeatureHtmlTable: _fnFeatureHtmlTable,
-            _fnScrollDraw: _fnScrollDraw,
-            _fnApplyToChildren: _fnApplyToChildren,
-            _fnCalculateColumnWidths: _fnCalculateColumnWidths,
-            _fnThrottle: _fnThrottle,
-            _fnConvertToWidth: _fnConvertToWidth,
-            _fnScrollingWidthAdjust: _fnScrollingWidthAdjust,
-            _fnGetWidestNode: _fnGetWidestNode,
-            _fnGetMaxLenString: _fnGetMaxLenString,
-            _fnStringToCss: _fnStringToCss,
-            _fnScrollBarWidth: _fnScrollBarWidth,
-            _fnSortFlatten: _fnSortFlatten,
-            _fnSort: _fnSort,
-            _fnSortAria: _fnSortAria,
-            _fnSortListener: _fnSortListener,
-            _fnSortAttachListener: _fnSortAttachListener,
-            _fnSortingClasses: _fnSortingClasses,
-            _fnSortData: _fnSortData,
-            _fnSaveState: _fnSaveState,
-            _fnLoadState: _fnLoadState,
-            _fnSettingsFromNode: _fnSettingsFromNode,
-            _fnLog: _fnLog,
-            _fnMap: _fnMap,
-            _fnBindAction: _fnBindAction,
-            _fnCallbackReg: _fnCallbackReg,
-            _fnCallbackFire: _fnCallbackFire,
-            _fnLengthOverflow: _fnLengthOverflow,
-            _fnRenderer: _fnRenderer,
-            _fnDataSource: _fnDataSource,
-            _fnRowAttributes: _fnRowAttributes,
-            _fnCalculateEnd: function () { } // Used by a lot of plug-ins, but redundant
-            // in 1.10, so this dead-end function is
-            // added to prevent errors
-        });
-
-
-        // jQuery access
-        $.fn.dataTable = DataTable;
-
-        // Legacy aliases
-        $.fn.dataTableSettings = DataTable.settings;
-        $.fn.dataTableExt = DataTable.ext;
-
-        // With a capital `D` we return a DataTables API instance rather than a
-        // jQuery object
-        $.fn.DataTable = function (opts) {
-            return $(this).dataTable(opts).api();
-        };
-
-        // All properties that are available to $.fn.dataTable should also be
-        // available on $.fn.DataTable
-        $.each(DataTable, function (prop, val) {
-            $.fn.DataTable[prop] = val;
-        });
-
-
-        // Information about events fired by DataTables - for documentation.
-        /**
-         * Draw event, fired whenever the table is redrawn on the page, at the same
-         * point as fnDrawCallback. This may be useful for binding events or
-         * performing calculations when the table is altered at all.
-         *  @name DataTable#draw.dt
-         *  @event
-         *  @param {event} e jQuery event object
-         *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}
-         */
-
-        /**
-         * Search event, fired when the searching applied to the table (using the
-         * built-in global search, or column filters) is altered.
-         *  @name DataTable#search.dt
-         *  @event
-         *  @param {event} e jQuery event object
-         *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}
-         */
-
-        /**
-         * Page change event, fired when the paging of the table is altered.
-         *  @name DataTable#page.dt
-         *  @event
-         *  @param {event} e jQuery event object
-         *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}
-         */
-
-        /**
-         * Order event, fired when the ordering applied to the table is altered.
-         *  @name DataTable#order.dt
-         *  @event
-         *  @param {event} e jQuery event object
-         *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}
-         */
-
-        /**
-         * DataTables initialisation complete event, fired when the table is fully
-         * drawn, including Ajax data loaded, if Ajax data is required.
-         *  @name DataTable#init.dt
-         *  @event
-         *  @param {event} e jQuery event object
-         *  @param {object} oSettings DataTables settings object
-         *  @param {object} json The JSON object request from the server - only
-         *    present if client-side Ajax sourced data is used</li></ol>
-         */
-
-        /**
-         * State save event, fired when the table has changed state a new state save
-         * is required. This event allows modification of the state saving object
-         * prior to actually doing the save, including addition or other state
-         * properties (for plug-ins) or modification of a DataTables core property.
-         *  @name DataTable#stateSaveParams.dt
-         *  @event
-         *  @param {event} e jQuery event object
-         *  @param {object} oSettings DataTables settings object
-         *  @param {object} json The state information to be saved
-         */
-
-        /**
-         * State load event, fired when the table is loading state from the stored
-         * data, but prior to the settings object being modified by the saved state
-         * - allowing modification of the saved state is required or loading of
-         * state for a plug-in.
-         *  @name DataTable#stateLoadParams.dt
-         *  @event
-         *  @param {event} e jQuery event object
-         *  @param {object} oSettings DataTables settings object
-         *  @param {object} json The saved state information
-         */
-
-        /**
-         * State loaded event, fired when state has been loaded from stored data and
-         * the settings object has been modified by the loaded data.
-         *  @name DataTable#stateLoaded.dt
-         *  @event
-         *  @param {event} e jQuery event object
-         *  @param {object} oSettings DataTables settings object
-         *  @param {object} json The saved state information
-         */
-
-        /**
-         * Processing event, fired when DataTables is doing some kind of processing
-         * (be it, order, searcg or anything else). It can be used to indicate to
-         * the end user that there is something happening, or that something has
-         * finished.
-         *  @name DataTable#processing.dt
-         *  @event
-         *  @param {event} e jQuery event object
-         *  @param {object} oSettings DataTables settings object
-         *  @param {boolean} bShow Flag for if DataTables is doing processing or not
-         */
-
-        /**
-         * Ajax (XHR) event, fired whenever an Ajax request is completed from a
-         * request to made to the server for new data. This event is called before
-         * DataTables processed the returned data, so it can also be used to pre-
-         * process the data returned from the server, if needed.
-         *
-         * Note that this trigger is called in `fnServerData`, if you override
-         * `fnServerData` and which to use this event, you need to trigger it in you
-         * success function.
-         *  @name DataTable#xhr.dt
-         *  @event
-         *  @param {event} e jQuery event object
-         *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}
-         *  @param {object} json JSON returned from the server
-         *
-         *  @example
-         *     // Use a custom property returned from the server in another DOM element
-         *     $('#table').dataTable().on('xhr.dt', function (e, settings, json) {
-         *       $('#status').html( json.status );
-         *     } );
-         *
-         *  @example
-         *     // Pre-process the data returned from the server
-         *     $('#table').dataTable().on('xhr.dt', function (e, settings, json) {
-         *       for ( var i=0, ien=json.aaData.length ; i<ien ; i++ ) {
-         *         json.aaData[i].sum = json.aaData[i].one + json.aaData[i].two;
-         *       }
-         *       // Note no return - manipulate the data directly in the JSON object.
-         *     } );
-         */
-
-        /**
-         * Destroy event, fired when the DataTable is destroyed by calling fnDestroy
-         * or passing the bDestroy:true parameter in the initialisation object. This
-         * can be used to remove bound events, added DOM nodes, etc.
-         *  @name DataTable#destroy.dt
-         *  @event
-         *  @param {event} e jQuery event object
-         *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}
-         */
-
-        /**
-         * Page length change event, fired when number of records to show on each
-         * page (the length) is changed.
-         *  @name DataTable#length.dt
-         *  @event
-         *  @param {event} e jQuery event object
-         *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}
-         *  @param {integer} len New length
-         */
-
-        /**
-         * Column sizing has changed.
-         *  @name DataTable#column-sizing.dt
-         *  @event
-         *  @param {event} e jQuery event object
-         *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}
-         */
-
-        /**
-         * Column visibility has changed.
-         *  @name DataTable#column-visibility.dt
-         *  @event
-         *  @param {event} e jQuery event object
-         *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}
-         *  @param {int} column Column index
-         *  @param {bool} vis `false` if column now hidden, or `true` if visible
-         */
-
-        return $.fn.dataTable;
-    }));
-
-}(window, document));
diff --git a/src/Jackett/Content/bootstrap-notify.js b/src/Jackett/Content/libs/bootstrap-notify.js
similarity index 100%
rename from src/Jackett/Content/bootstrap-notify.js
rename to src/Jackett/Content/libs/bootstrap-notify.js
diff --git a/src/Jackett/Content/libs/handlebars.min.js b/src/Jackett/Content/libs/handlebars.min.js
new file mode 100644
index 0000000000000000000000000000000000000000..150df8a433e577868224d9bdc977615ce07a46a9
--- /dev/null
+++ b/src/Jackett/Content/libs/handlebars.min.js
@@ -0,0 +1,29 @@
+/*!
+
+ handlebars v3.0.3
+
+Copyright (C) 2011-2014 by Yehuda Katz
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+@license
+*/
+!function(a,b){"object"==typeof exports&&"object"==typeof module?module.exports=b():"function"==typeof define&&define.amd?define(b):"object"==typeof exports?exports.Handlebars=b():a.Handlebars=b()}(this,function(){return function(a){function b(d){if(c[d])return c[d].exports;var e=c[d]={exports:{},id:d,loaded:!1};return a[d].call(e.exports,e,e.exports,b),e.loaded=!0,e.exports}var c={};return b.m=a,b.c=c,b.p="",b(0)}([function(a,b,c){"use strict";function d(){var a=r();return a.compile=function(b,c){return k.compile(b,c,a)},a.precompile=function(b,c){return k.precompile(b,c,a)},a.AST=i["default"],a.Compiler=k.Compiler,a.JavaScriptCompiler=m["default"],a.Parser=j.parser,a.parse=j.parse,a}var e=c(8)["default"];b.__esModule=!0;var f=c(1),g=e(f),h=c(2),i=e(h),j=c(3),k=c(4),l=c(5),m=e(l),n=c(6),o=e(n),p=c(7),q=e(p),r=g["default"].create,s=d();s.create=d,q["default"](s),s.Visitor=o["default"],s["default"]=s,b["default"]=s,a.exports=b["default"]},function(a,b,c){"use strict";function d(){var a=new g.HandlebarsEnvironment;return m.extend(a,g),a.SafeString=i["default"],a.Exception=k["default"],a.Utils=m,a.escapeExpression=m.escapeExpression,a.VM=o,a.template=function(b){return o.template(b,a)},a}var e=c(8)["default"];b.__esModule=!0;var f=c(9),g=e(f),h=c(10),i=e(h),j=c(11),k=e(j),l=c(12),m=e(l),n=c(13),o=e(n),p=c(7),q=e(p),r=d();r.create=d,q["default"](r),r["default"]=r,b["default"]=r,a.exports=b["default"]},function(a,b){"use strict";b.__esModule=!0;var c={Program:function(a,b,c,d){this.loc=d,this.type="Program",this.body=a,this.blockParams=b,this.strip=c},MustacheStatement:function(a,b,c,d,e,f){this.loc=f,this.type="MustacheStatement",this.path=a,this.params=b||[],this.hash=c,this.escaped=d,this.strip=e},BlockStatement:function(a,b,c,d,e,f,g,h,i){this.loc=i,this.type="BlockStatement",this.path=a,this.params=b||[],this.hash=c,this.program=d,this.inverse=e,this.openStrip=f,this.inverseStrip=g,this.closeStrip=h},PartialStatement:function(a,b,c,d,e){this.loc=e,this.type="PartialStatement",this.name=a,this.params=b||[],this.hash=c,this.indent="",this.strip=d},ContentStatement:function(a,b){this.loc=b,this.type="ContentStatement",this.original=this.value=a},CommentStatement:function(a,b,c){this.loc=c,this.type="CommentStatement",this.value=a,this.strip=b},SubExpression:function(a,b,c,d){this.loc=d,this.type="SubExpression",this.path=a,this.params=b||[],this.hash=c},PathExpression:function(a,b,c,d,e){this.loc=e,this.type="PathExpression",this.data=a,this.original=d,this.parts=c,this.depth=b},StringLiteral:function(a,b){this.loc=b,this.type="StringLiteral",this.original=this.value=a},NumberLiteral:function(a,b){this.loc=b,this.type="NumberLiteral",this.original=this.value=Number(a)},BooleanLiteral:function(a,b){this.loc=b,this.type="BooleanLiteral",this.original=this.value="true"===a},UndefinedLiteral:function(a){this.loc=a,this.type="UndefinedLiteral",this.original=this.value=void 0},NullLiteral:function(a){this.loc=a,this.type="NullLiteral",this.original=this.value=null},Hash:function(a,b){this.loc=b,this.type="Hash",this.pairs=a},HashPair:function(a,b,c){this.loc=c,this.type="HashPair",this.key=a,this.value=b},helpers:{helperExpression:function(a){return!("SubExpression"!==a.type&&!a.params.length&&!a.hash)},scopedId:function(a){return/^\.|this\b/.test(a.original)},simpleId:function(a){return 1===a.parts.length&&!c.helpers.scopedId(a)&&!a.depth}}};b["default"]=c,a.exports=b["default"]},function(a,b,c){"use strict";function d(a,b){if("Program"===a.type)return a;g["default"].yy=o,o.locInfo=function(a){return new o.SourceLocation(b&&b.srcName,a)};var c=new k["default"];return c.accept(g["default"].parse(a))}var e=c(8)["default"];b.__esModule=!0,b.parse=d;var f=c(14),g=e(f),h=c(2),i=e(h),j=c(15),k=e(j),l=c(16),m=e(l),n=c(12);b.parser=g["default"];var o={};n.extend(o,m,i["default"])},function(a,b,c){"use strict";function d(){}function e(a,b,c){if(null==a||"string"!=typeof a&&"Program"!==a.type)throw new k["default"]("You must pass a string or Handlebars AST to Handlebars.precompile. You passed "+a);b=b||{},"data"in b||(b.data=!0),b.compat&&(b.useDepths=!0);var d=c.parse(a,b),e=(new c.Compiler).compile(d,b);return(new c.JavaScriptCompiler).compile(e,b)}function f(a,b,c){function d(){var b=c.parse(a,f),d=(new c.Compiler).compile(b,f),e=(new c.JavaScriptCompiler).compile(d,f,void 0,!0);return c.template(e)}function e(a,b){return g||(g=d()),g.call(this,a,b)}var f=void 0===arguments[1]?{}:arguments[1];if(null==a||"string"!=typeof a&&"Program"!==a.type)throw new k["default"]("You must pass a string or Handlebars AST to Handlebars.compile. You passed "+a);"data"in f||(f.data=!0),f.compat&&(f.useDepths=!0);var g=void 0;return e._setup=function(a){return g||(g=d()),g._setup(a)},e._child=function(a,b,c,e){return g||(g=d()),g._child(a,b,c,e)},e}function g(a,b){if(a===b)return!0;if(l.isArray(a)&&l.isArray(b)&&a.length===b.length){for(var c=0;c<a.length;c++)if(!g(a[c],b[c]))return!1;return!0}}function h(a){if(!a.path.parts){var b=a.path;a.path=new n["default"].PathExpression(!1,0,[b.original+""],b.original+"",b.loc)}}var i=c(8)["default"];b.__esModule=!0,b.Compiler=d,b.precompile=e,b.compile=f;var j=c(11),k=i(j),l=c(12),m=c(2),n=i(m),o=[].slice;d.prototype={compiler:d,equals:function(a){var b=this.opcodes.length;if(a.opcodes.length!==b)return!1;for(var c=0;b>c;c++){var d=this.opcodes[c],e=a.opcodes[c];if(d.opcode!==e.opcode||!g(d.args,e.args))return!1}b=this.children.length;for(var c=0;b>c;c++)if(!this.children[c].equals(a.children[c]))return!1;return!0},guid:0,compile:function(a,b){this.sourceNode=[],this.opcodes=[],this.children=[],this.options=b,this.stringParams=b.stringParams,this.trackIds=b.trackIds,b.blockParams=b.blockParams||[];var c=b.knownHelpers;if(b.knownHelpers={helperMissing:!0,blockHelperMissing:!0,each:!0,"if":!0,unless:!0,"with":!0,log:!0,lookup:!0},c)for(var d in c)d in c&&(b.knownHelpers[d]=c[d]);return this.accept(a)},compileProgram:function(a){var b=new this.compiler,c=b.compile(a,this.options),d=this.guid++;return this.usePartial=this.usePartial||c.usePartial,this.children[d]=c,this.useDepths=this.useDepths||c.useDepths,d},accept:function(a){this.sourceNode.unshift(a);var b=this[a.type](a);return this.sourceNode.shift(),b},Program:function(a){this.options.blockParams.unshift(a.blockParams);for(var b=a.body,c=b.length,d=0;c>d;d++)this.accept(b[d]);return this.options.blockParams.shift(),this.isSimple=1===c,this.blockParams=a.blockParams?a.blockParams.length:0,this},BlockStatement:function(a){h(a);var b=a.program,c=a.inverse;b=b&&this.compileProgram(b),c=c&&this.compileProgram(c);var d=this.classifySexpr(a);"helper"===d?this.helperSexpr(a,b,c):"simple"===d?(this.simpleSexpr(a),this.opcode("pushProgram",b),this.opcode("pushProgram",c),this.opcode("emptyHash"),this.opcode("blockValue",a.path.original)):(this.ambiguousSexpr(a,b,c),this.opcode("pushProgram",b),this.opcode("pushProgram",c),this.opcode("emptyHash"),this.opcode("ambiguousBlockValue")),this.opcode("append")},PartialStatement:function(a){this.usePartial=!0;var b=a.params;if(b.length>1)throw new k["default"]("Unsupported number of partial arguments: "+b.length,a);b.length||b.push({type:"PathExpression",parts:[],depth:0});var c=a.name.original,d="SubExpression"===a.name.type;d&&this.accept(a.name),this.setupFullMustacheParams(a,void 0,void 0,!0);var e=a.indent||"";this.options.preventIndent&&e&&(this.opcode("appendContent",e),e=""),this.opcode("invokePartial",d,c,e),this.opcode("append")},MustacheStatement:function(a){this.SubExpression(a),this.opcode(a.escaped&&!this.options.noEscape?"appendEscaped":"append")},ContentStatement:function(a){a.value&&this.opcode("appendContent",a.value)},CommentStatement:function(){},SubExpression:function(a){h(a);var b=this.classifySexpr(a);"simple"===b?this.simpleSexpr(a):"helper"===b?this.helperSexpr(a):this.ambiguousSexpr(a)},ambiguousSexpr:function(a,b,c){var d=a.path,e=d.parts[0],f=null!=b||null!=c;this.opcode("getContext",d.depth),this.opcode("pushProgram",b),this.opcode("pushProgram",c),this.accept(d),this.opcode("invokeAmbiguous",e,f)},simpleSexpr:function(a){this.accept(a.path),this.opcode("resolvePossibleLambda")},helperSexpr:function(a,b,c){var d=this.setupFullMustacheParams(a,b,c),e=a.path,f=e.parts[0];if(this.options.knownHelpers[f])this.opcode("invokeKnownHelper",d.length,f);else{if(this.options.knownHelpersOnly)throw new k["default"]("You specified knownHelpersOnly, but used the unknown helper "+f,a);e.falsy=!0,this.accept(e),this.opcode("invokeHelper",d.length,e.original,n["default"].helpers.simpleId(e))}},PathExpression:function(a){this.addDepth(a.depth),this.opcode("getContext",a.depth);var b=a.parts[0],c=n["default"].helpers.scopedId(a),d=!a.depth&&!c&&this.blockParamIndex(b);d?this.opcode("lookupBlockParam",d,a.parts):b?a.data?(this.options.data=!0,this.opcode("lookupData",a.depth,a.parts)):this.opcode("lookupOnContext",a.parts,a.falsy,c):this.opcode("pushContext")},StringLiteral:function(a){this.opcode("pushString",a.value)},NumberLiteral:function(a){this.opcode("pushLiteral",a.value)},BooleanLiteral:function(a){this.opcode("pushLiteral",a.value)},UndefinedLiteral:function(){this.opcode("pushLiteral","undefined")},NullLiteral:function(){this.opcode("pushLiteral","null")},Hash:function(a){var b=a.pairs,c=0,d=b.length;for(this.opcode("pushHash");d>c;c++)this.pushParam(b[c].value);for(;c--;)this.opcode("assignToHash",b[c].key);this.opcode("popHash")},opcode:function(a){this.opcodes.push({opcode:a,args:o.call(arguments,1),loc:this.sourceNode[0].loc})},addDepth:function(a){a&&(this.useDepths=!0)},classifySexpr:function(a){var b=n["default"].helpers.simpleId(a.path),c=b&&!!this.blockParamIndex(a.path.parts[0]),d=!c&&n["default"].helpers.helperExpression(a),e=!c&&(d||b);if(e&&!d){var f=a.path.parts[0],g=this.options;g.knownHelpers[f]?d=!0:g.knownHelpersOnly&&(e=!1)}return d?"helper":e?"ambiguous":"simple"},pushParams:function(a){for(var b=0,c=a.length;c>b;b++)this.pushParam(a[b])},pushParam:function(a){var b=null!=a.value?a.value:a.original||"";if(this.stringParams)b.replace&&(b=b.replace(/^(\.?\.\/)*/g,"").replace(/\//g,".")),a.depth&&this.addDepth(a.depth),this.opcode("getContext",a.depth||0),this.opcode("pushStringParam",b,a.type),"SubExpression"===a.type&&this.accept(a);else{if(this.trackIds){var c=void 0;if(!a.parts||n["default"].helpers.scopedId(a)||a.depth||(c=this.blockParamIndex(a.parts[0])),c){var d=a.parts.slice(1).join(".");this.opcode("pushId","BlockParam",c,d)}else b=a.original||b,b.replace&&(b=b.replace(/^\.\//g,"").replace(/^\.$/g,"")),this.opcode("pushId",a.type,b)}this.accept(a)}},setupFullMustacheParams:function(a,b,c,d){var e=a.params;return this.pushParams(e),this.opcode("pushProgram",b),this.opcode("pushProgram",c),a.hash?this.accept(a.hash):this.opcode("emptyHash",d),e},blockParamIndex:function(a){for(var b=0,c=this.options.blockParams.length;c>b;b++){var d=this.options.blockParams[b],e=d&&l.indexOf(d,a);if(d&&e>=0)return[b,e]}}}},function(a,b,c){"use strict";function d(a){this.value=a}function e(){}function f(a,b,c,d){var e=b.popStack(),f=0,g=c.length;for(a&&g--;g>f;f++)e=b.nameLookup(e,c[f],d);return a?[b.aliasable("this.strict"),"(",e,", ",b.quotedString(c[f]),")"]:e}var g=c(8)["default"];b.__esModule=!0;var h=c(9),i=c(11),j=g(i),k=c(12),l=c(17),m=g(l);e.prototype={nameLookup:function(a,b){return e.isValidJavaScriptVariableName(b)?[a,".",b]:[a,"['",b,"']"]},depthedLookup:function(a){return[this.aliasable("this.lookup"),'(depths, "',a,'")']},compilerInfo:function(){var a=h.COMPILER_REVISION,b=h.REVISION_CHANGES[a];return[a,b]},appendToBuffer:function(a,b,c){return k.isArray(a)||(a=[a]),a=this.source.wrap(a,b),this.environment.isSimple?["return ",a,";"]:c?["buffer += ",a,";"]:(a.appendToBuffer=!0,a)},initializeBuffer:function(){return this.quotedString("")},compile:function(a,b,c,d){this.environment=a,this.options=b,this.stringParams=this.options.stringParams,this.trackIds=this.options.trackIds,this.precompile=!d,this.name=this.environment.name,this.isChild=!!c,this.context=c||{programs:[],environments:[]},this.preamble(),this.stackSlot=0,this.stackVars=[],this.aliases={},this.registers={list:[]},this.hashes=[],this.compileStack=[],this.inlineStack=[],this.blockParams=[],this.compileChildren(a,b),this.useDepths=this.useDepths||a.useDepths||this.options.compat,this.useBlockParams=this.useBlockParams||a.useBlockParams;var e=a.opcodes,f=void 0,g=void 0,h=void 0,i=void 0;for(h=0,i=e.length;i>h;h++)f=e[h],this.source.currentLocation=f.loc,g=g||f.loc,this[f.opcode].apply(this,f.args);if(this.source.currentLocation=g,this.pushSource(""),this.stackSlot||this.inlineStack.length||this.compileStack.length)throw new j["default"]("Compile completed with content left on stack");var k=this.createFunctionContext(d);if(this.isChild)return k;var l={compiler:this.compilerInfo(),main:k},m=this.context.programs;for(h=0,i=m.length;i>h;h++)m[h]&&(l[h]=m[h]);return this.environment.usePartial&&(l.usePartial=!0),this.options.data&&(l.useData=!0),this.useDepths&&(l.useDepths=!0),this.useBlockParams&&(l.useBlockParams=!0),this.options.compat&&(l.compat=!0),d?l.compilerOptions=this.options:(l.compiler=JSON.stringify(l.compiler),this.source.currentLocation={start:{line:1,column:0}},l=this.objectLiteral(l),b.srcName?(l=l.toStringWithSourceMap({file:b.destName}),l.map=l.map&&l.map.toString()):l=l.toString()),l},preamble:function(){this.lastContext=0,this.source=new m["default"](this.options.srcName)},createFunctionContext:function(a){var b="",c=this.stackVars.concat(this.registers.list);c.length>0&&(b+=", "+c.join(", "));var d=0;for(var e in this.aliases){var f=this.aliases[e];this.aliases.hasOwnProperty(e)&&f.children&&f.referenceCount>1&&(b+=", alias"+ ++d+"="+e,f.children[0]="alias"+d)}var g=["depth0","helpers","partials","data"];(this.useBlockParams||this.useDepths)&&g.push("blockParams"),this.useDepths&&g.push("depths");var h=this.mergeSource(b);return a?(g.push(h),Function.apply(this,g)):this.source.wrap(["function(",g.join(","),") {\n  ",h,"}"])},mergeSource:function(a){var b=this.environment.isSimple,c=!this.forceBuffer,d=void 0,e=void 0,f=void 0,g=void 0;return this.source.each(function(a){a.appendToBuffer?(f?a.prepend("  + "):f=a,g=a):(f&&(e?f.prepend("buffer += "):d=!0,g.add(";"),f=g=void 0),e=!0,b||(c=!1))}),c?f?(f.prepend("return "),g.add(";")):e||this.source.push('return "";'):(a+=", buffer = "+(d?"":this.initializeBuffer()),f?(f.prepend("return buffer + "),g.add(";")):this.source.push("return buffer;")),a&&this.source.prepend("var "+a.substring(2)+(d?"":";\n")),this.source.merge()},blockValue:function(a){var b=this.aliasable("helpers.blockHelperMissing"),c=[this.contextName(0)];this.setupHelperArgs(a,0,c);var d=this.popStack();c.splice(1,0,d),this.push(this.source.functionCall(b,"call",c))},ambiguousBlockValue:function(){var a=this.aliasable("helpers.blockHelperMissing"),b=[this.contextName(0)];this.setupHelperArgs("",0,b,!0),this.flushInline();var c=this.topStack();b.splice(1,0,c),this.pushSource(["if (!",this.lastHelper,") { ",c," = ",this.source.functionCall(a,"call",b),"}"])},appendContent:function(a){this.pendingContent?a=this.pendingContent+a:this.pendingLocation=this.source.currentLocation,this.pendingContent=a},append:function(){if(this.isInline())this.replaceStack(function(a){return[" != null ? ",a,' : ""']}),this.pushSource(this.appendToBuffer(this.popStack()));else{var a=this.popStack();this.pushSource(["if (",a," != null) { ",this.appendToBuffer(a,void 0,!0)," }"]),this.environment.isSimple&&this.pushSource(["else { ",this.appendToBuffer("''",void 0,!0)," }"])}},appendEscaped:function(){this.pushSource(this.appendToBuffer([this.aliasable("this.escapeExpression"),"(",this.popStack(),")"]))},getContext:function(a){this.lastContext=a},pushContext:function(){this.pushStackLiteral(this.contextName(this.lastContext))},lookupOnContext:function(a,b,c){var d=0;c||!this.options.compat||this.lastContext?this.pushContext():this.push(this.depthedLookup(a[d++])),this.resolvePath("context",a,d,b)},lookupBlockParam:function(a,b){this.useBlockParams=!0,this.push(["blockParams[",a[0],"][",a[1],"]"]),this.resolvePath("context",b,1)},lookupData:function(a,b){this.pushStackLiteral(a?"this.data(data, "+a+")":"data"),this.resolvePath("data",b,0,!0)},resolvePath:function(a,b,c,d){var e=this;if(this.options.strict||this.options.assumeObjects)return void this.push(f(this.options.strict,this,b,a));for(var g=b.length;g>c;c++)this.replaceStack(function(f){var g=e.nameLookup(f,b[c],a);return d?[" && ",g]:[" != null ? ",g," : ",f]})},resolvePossibleLambda:function(){this.push([this.aliasable("this.lambda"),"(",this.popStack(),", ",this.contextName(0),")"])},pushStringParam:function(a,b){this.pushContext(),this.pushString(b),"SubExpression"!==b&&("string"==typeof a?this.pushString(a):this.pushStackLiteral(a))},emptyHash:function(a){this.trackIds&&this.push("{}"),this.stringParams&&(this.push("{}"),this.push("{}")),this.pushStackLiteral(a?"undefined":"{}")},pushHash:function(){this.hash&&this.hashes.push(this.hash),this.hash={values:[],types:[],contexts:[],ids:[]}},popHash:function(){var a=this.hash;this.hash=this.hashes.pop(),this.trackIds&&this.push(this.objectLiteral(a.ids)),this.stringParams&&(this.push(this.objectLiteral(a.contexts)),this.push(this.objectLiteral(a.types))),this.push(this.objectLiteral(a.values))},pushString:function(a){this.pushStackLiteral(this.quotedString(a))},pushLiteral:function(a){this.pushStackLiteral(a)},pushProgram:function(a){this.pushStackLiteral(null!=a?this.programExpression(a):null)},invokeHelper:function(a,b,c){var d=this.popStack(),e=this.setupHelper(a,b),f=c?[e.name," || "]:"",g=["("].concat(f,d);this.options.strict||g.push(" || ",this.aliasable("helpers.helperMissing")),g.push(")"),this.push(this.source.functionCall(g,"call",e.callParams))},invokeKnownHelper:function(a,b){var c=this.setupHelper(a,b);this.push(this.source.functionCall(c.name,"call",c.callParams))},invokeAmbiguous:function(a,b){this.useRegister("helper");var c=this.popStack();this.emptyHash();var d=this.setupHelper(0,a,b),e=this.lastHelper=this.nameLookup("helpers",a,"helper"),f=["(","(helper = ",e," || ",c,")"];this.options.strict||(f[0]="(helper = ",f.push(" != null ? helper : ",this.aliasable("helpers.helperMissing"))),this.push(["(",f,d.paramsInit?["),(",d.paramsInit]:[],"),","(typeof helper === ",this.aliasable('"function"')," ? ",this.source.functionCall("helper","call",d.callParams)," : helper))"])},invokePartial:function(a,b,c){var d=[],e=this.setupParams(b,1,d,!1);a&&(b=this.popStack(),delete e.name),c&&(e.indent=JSON.stringify(c)),e.helpers="helpers",e.partials="partials",d.unshift(a?b:this.nameLookup("partials",b,"partial")),this.options.compat&&(e.depths="depths"),e=this.objectLiteral(e),d.push(e),this.push(this.source.functionCall("this.invokePartial","",d))},assignToHash:function(a){var b=this.popStack(),c=void 0,d=void 0,e=void 0;this.trackIds&&(e=this.popStack()),this.stringParams&&(d=this.popStack(),c=this.popStack());var f=this.hash;c&&(f.contexts[a]=c),d&&(f.types[a]=d),e&&(f.ids[a]=e),f.values[a]=b},pushId:function(a,b,c){"BlockParam"===a?this.pushStackLiteral("blockParams["+b[0]+"].path["+b[1]+"]"+(c?" + "+JSON.stringify("."+c):"")):"PathExpression"===a?this.pushString(b):this.pushStackLiteral("SubExpression"===a?"true":"null")},compiler:e,compileChildren:function(a,b){for(var c=a.children,d=void 0,e=void 0,f=0,g=c.length;g>f;f++){d=c[f],e=new this.compiler;var h=this.matchExistingProgram(d);null==h?(this.context.programs.push(""),h=this.context.programs.length,d.index=h,d.name="program"+h,this.context.programs[h]=e.compile(d,b,this.context,!this.precompile),this.context.environments[h]=d,this.useDepths=this.useDepths||e.useDepths,this.useBlockParams=this.useBlockParams||e.useBlockParams):(d.index=h,d.name="program"+h,this.useDepths=this.useDepths||d.useDepths,this.useBlockParams=this.useBlockParams||d.useBlockParams)}},matchExistingProgram:function(a){for(var b=0,c=this.context.environments.length;c>b;b++){var d=this.context.environments[b];if(d&&d.equals(a))return b}},programExpression:function(a){var b=this.environment.children[a],c=[b.index,"data",b.blockParams];return(this.useBlockParams||this.useDepths)&&c.push("blockParams"),this.useDepths&&c.push("depths"),"this.program("+c.join(", ")+")"},useRegister:function(a){this.registers[a]||(this.registers[a]=!0,this.registers.list.push(a))},push:function(a){return a instanceof d||(a=this.source.wrap(a)),this.inlineStack.push(a),a},pushStackLiteral:function(a){this.push(new d(a))},pushSource:function(a){this.pendingContent&&(this.source.push(this.appendToBuffer(this.source.quotedString(this.pendingContent),this.pendingLocation)),this.pendingContent=void 0),a&&this.source.push(a)},replaceStack:function(a){var b=["("],c=void 0,e=void 0,f=void 0;if(!this.isInline())throw new j["default"]("replaceStack on non-inline");var g=this.popStack(!0);if(g instanceof d)c=[g.value],b=["(",c],f=!0;else{e=!0;var h=this.incrStack();b=["((",this.push(h)," = ",g,")"],c=this.topStack()}var i=a.call(this,c);f||this.popStack(),e&&this.stackSlot--,this.push(b.concat(i,")"))},incrStack:function(){return this.stackSlot++,this.stackSlot>this.stackVars.length&&this.stackVars.push("stack"+this.stackSlot),this.topStackName()},topStackName:function(){return"stack"+this.stackSlot},flushInline:function(){var a=this.inlineStack;this.inlineStack=[];for(var b=0,c=a.length;c>b;b++){var e=a[b];if(e instanceof d)this.compileStack.push(e);else{var f=this.incrStack();this.pushSource([f," = ",e,";"]),this.compileStack.push(f)}}},isInline:function(){return this.inlineStack.length},popStack:function(a){var b=this.isInline(),c=(b?this.inlineStack:this.compileStack).pop();if(!a&&c instanceof d)return c.value;if(!b){if(!this.stackSlot)throw new j["default"]("Invalid stack pop");this.stackSlot--}return c},topStack:function(){var a=this.isInline()?this.inlineStack:this.compileStack,b=a[a.length-1];return b instanceof d?b.value:b},contextName:function(a){return this.useDepths&&a?"depths["+a+"]":"depth"+a},quotedString:function(a){return this.source.quotedString(a)},objectLiteral:function(a){return this.source.objectLiteral(a)},aliasable:function(a){var b=this.aliases[a];return b?(b.referenceCount++,b):(b=this.aliases[a]=this.source.wrap(a),b.aliasable=!0,b.referenceCount=1,b)},setupHelper:function(a,b,c){var d=[],e=this.setupHelperArgs(b,a,d,c),f=this.nameLookup("helpers",b,"helper");return{params:d,paramsInit:e,name:f,callParams:[this.contextName(0)].concat(d)}},setupParams:function(a,b,c){var d={},e=[],f=[],g=[],h=void 0;d.name=this.quotedString(a),d.hash=this.popStack(),this.trackIds&&(d.hashIds=this.popStack()),this.stringParams&&(d.hashTypes=this.popStack(),d.hashContexts=this.popStack());var i=this.popStack(),j=this.popStack();(j||i)&&(d.fn=j||"this.noop",d.inverse=i||"this.noop");for(var k=b;k--;)h=this.popStack(),c[k]=h,this.trackIds&&(g[k]=this.popStack()),this.stringParams&&(f[k]=this.popStack(),e[k]=this.popStack());return this.trackIds&&(d.ids=this.source.generateArray(g)),this.stringParams&&(d.types=this.source.generateArray(f),d.contexts=this.source.generateArray(e)),this.options.data&&(d.data="data"),this.useBlockParams&&(d.blockParams="blockParams"),d},setupHelperArgs:function(a,b,c,d){var e=this.setupParams(a,b,c,!0);return e=this.objectLiteral(e),d?(this.useRegister("options"),c.push("options"),["options=",e]):(c.push(e),"")}},function(){for(var a="break else new var case finally return void catch for switch while continue function this with default if throw delete in try do instanceof typeof abstract enum int short boolean export interface static byte extends long super char final native synchronized class float package throws const goto private transient debugger implements protected volatile double import public let yield await null true false".split(" "),b=e.RESERVED_WORDS={},c=0,d=a.length;d>c;c++)b[a[c]]=!0}(),e.isValidJavaScriptVariableName=function(a){return!e.RESERVED_WORDS[a]&&/^[a-zA-Z_$][0-9a-zA-Z_$]*$/.test(a)},b["default"]=e,a.exports=b["default"]},function(a,b,c){"use strict";function d(){this.parents=[]}var e=c(8)["default"];b.__esModule=!0;var f=c(11),g=e(f),h=c(2),i=e(h);d.prototype={constructor:d,mutating:!1,acceptKey:function(a,b){var c=this.accept(a[b]);if(this.mutating){if(c&&(!c.type||!i["default"][c.type]))throw new g["default"]('Unexpected node type "'+c.type+'" found when accepting '+b+" on "+a.type);a[b]=c}},acceptRequired:function(a,b){if(this.acceptKey(a,b),!a[b])throw new g["default"](a.type+" requires "+b)},acceptArray:function(a){for(var b=0,c=a.length;c>b;b++)this.acceptKey(a,b),a[b]||(a.splice(b,1),b--,c--)},accept:function(a){if(a){this.current&&this.parents.unshift(this.current),this.current=a;var b=this[a.type](a);return this.current=this.parents.shift(),!this.mutating||b?b:b!==!1?a:void 0}},Program:function(a){this.acceptArray(a.body)},MustacheStatement:function(a){this.acceptRequired(a,"path"),this.acceptArray(a.params),this.acceptKey(a,"hash")},BlockStatement:function(a){this.acceptRequired(a,"path"),this.acceptArray(a.params),this.acceptKey(a,"hash"),this.acceptKey(a,"program"),this.acceptKey(a,"inverse")},PartialStatement:function(a){this.acceptRequired(a,"name"),this.acceptArray(a.params),this.acceptKey(a,"hash")},ContentStatement:function(){},CommentStatement:function(){},SubExpression:function(a){this.acceptRequired(a,"path"),this.acceptArray(a.params),this.acceptKey(a,"hash")},PathExpression:function(){},StringLiteral:function(){},NumberLiteral:function(){},BooleanLiteral:function(){},UndefinedLiteral:function(){},NullLiteral:function(){},Hash:function(a){this.acceptArray(a.pairs)},HashPair:function(a){this.acceptRequired(a,"value")}},b["default"]=d,a.exports=b["default"]},function(a,b){(function(c){"use strict";b.__esModule=!0,b["default"]=function(a){var b="undefined"!=typeof c?c:window,d=b.Handlebars;a.noConflict=function(){b.Handlebars===a&&(b.Handlebars=d)}},a.exports=b["default"]}).call(b,function(){return this}())},function(a,b){"use strict";b["default"]=function(a){return a&&a.__esModule?a:{"default":a}},b.__esModule=!0},function(a,b,c){"use strict";function d(a,b){this.helpers=a||{},this.partials=b||{},e(this)}function e(a){a.registerHelper("helperMissing",function(){if(1===arguments.length)return void 0;throw new k["default"]('Missing helper: "'+arguments[arguments.length-1].name+'"')}),a.registerHelper("blockHelperMissing",function(b,c){var d=c.inverse,e=c.fn;if(b===!0)return e(this);if(b===!1||null==b)return d(this);if(o(b))return b.length>0?(c.ids&&(c.ids=[c.name]),a.helpers.each(b,c)):d(this);if(c.data&&c.ids){var g=f(c.data);g.contextPath=i.appendContextPath(c.data.contextPath,c.name),c={data:g}}return e(b,c)}),a.registerHelper("each",function(a,b){function c(b,c,e){j&&(j.key=b,j.index=c,j.first=0===c,j.last=!!e,l&&(j.contextPath=l+b)),h+=d(a[b],{data:j,blockParams:i.blockParams([a[b],b],[l+b,null])})}if(!b)throw new k["default"]("Must pass iterator to #each");var d=b.fn,e=b.inverse,g=0,h="",j=void 0,l=void 0;if(b.data&&b.ids&&(l=i.appendContextPath(b.data.contextPath,b.ids[0])+"."),p(a)&&(a=a.call(this)),b.data&&(j=f(b.data)),a&&"object"==typeof a)if(o(a))for(var m=a.length;m>g;g++)c(g,g,g===a.length-1);else{var n=void 0;for(var q in a)a.hasOwnProperty(q)&&(n&&c(n,g-1),n=q,g++);n&&c(n,g-1,!0)}return 0===g&&(h=e(this)),h}),a.registerHelper("if",function(a,b){return p(a)&&(a=a.call(this)),!b.hash.includeZero&&!a||i.isEmpty(a)?b.inverse(this):b.fn(this)}),a.registerHelper("unless",function(b,c){return a.helpers["if"].call(this,b,{fn:c.inverse,inverse:c.fn,hash:c.hash})}),a.registerHelper("with",function(a,b){p(a)&&(a=a.call(this));var c=b.fn;if(i.isEmpty(a))return b.inverse(this);if(b.data&&b.ids){var d=f(b.data);d.contextPath=i.appendContextPath(b.data.contextPath,b.ids[0]),b={data:d}}return c(a,b)}),a.registerHelper("log",function(b,c){var d=c.data&&null!=c.data.level?parseInt(c.data.level,10):1;a.log(d,b)}),a.registerHelper("lookup",function(a,b){return a&&a[b]})}function f(a){var b=i.extend({},a);return b._parent=a,b}var g=c(8)["default"];b.__esModule=!0,b.HandlebarsEnvironment=d,b.createFrame=f;var h=c(12),i=g(h),j=c(11),k=g(j),l="3.0.1";b.VERSION=l;var m=6;b.COMPILER_REVISION=m;var n={1:"<= 1.0.rc.2",2:"== 1.0.0-rc.3",3:"== 1.0.0-rc.4",4:"== 1.x.x",5:"== 2.0.0-alpha.x",6:">= 2.0.0-beta.1"};b.REVISION_CHANGES=n;var o=i.isArray,p=i.isFunction,q=i.toString,r="[object Object]";d.prototype={constructor:d,logger:s,log:t,registerHelper:function(a,b){if(q.call(a)===r){if(b)throw new k["default"]("Arg not supported with multiple helpers");i.extend(this.helpers,a)}else this.helpers[a]=b},unregisterHelper:function(a){delete this.helpers[a]},registerPartial:function(a,b){if(q.call(a)===r)i.extend(this.partials,a);else{if("undefined"==typeof b)throw new k["default"]("Attempting to register a partial as undefined");this.partials[a]=b}},unregisterPartial:function(a){delete this.partials[a]}};var s={methodMap:{0:"debug",1:"info",2:"warn",3:"error"},DEBUG:0,INFO:1,WARN:2,ERROR:3,level:1,log:function(a,b){if("undefined"!=typeof console&&s.level<=a){var c=s.methodMap[a];(console[c]||console.log).call(console,b)}}};b.logger=s;var t=s.log;b.log=t},function(a,b){"use strict";function c(a){this.string=a}b.__esModule=!0,c.prototype.toString=c.prototype.toHTML=function(){return""+this.string},b["default"]=c,a.exports=b["default"]},function(a,b){"use strict";function c(a,b){var e=b&&b.loc,f=void 0,g=void 0;e&&(f=e.start.line,g=e.start.column,a+=" - "+f+":"+g);for(var h=Error.prototype.constructor.call(this,a),i=0;i<d.length;i++)this[d[i]]=h[d[i]];Error.captureStackTrace&&Error.captureStackTrace(this,c),e&&(this.lineNumber=f,this.column=g)}b.__esModule=!0;var d=["description","fileName","lineNumber","message","name","number","stack"];c.prototype=new Error,b["default"]=c,a.exports=b["default"]},function(a,b){"use strict";function c(a){return j[a]}function d(a){for(var b=1;b<arguments.length;b++)for(var c in arguments[b])Object.prototype.hasOwnProperty.call(arguments[b],c)&&(a[c]=arguments[b][c]);return a}function e(a,b){for(var c=0,d=a.length;d>c;c++)if(a[c]===b)return c;return-1}function f(a){if("string"!=typeof a){if(a&&a.toHTML)return a.toHTML();if(null==a)return"";if(!a)return a+"";a=""+a}return l.test(a)?a.replace(k,c):a}function g(a){return a||0===a?o(a)&&0===a.length?!0:!1:!0}function h(a,b){return a.path=b,a}function i(a,b){return(a?a+".":"")+b}b.__esModule=!0,b.extend=d,b.indexOf=e,b.escapeExpression=f,b.isEmpty=g,b.blockParams=h,b.appendContextPath=i;var j={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#x27;","`":"&#x60;"},k=/[&<>"'`]/g,l=/[&<>"'`]/,m=Object.prototype.toString;b.toString=m;var n=function(a){return"function"==typeof a};n(/x/)&&(b.isFunction=n=function(a){return"function"==typeof a&&"[object Function]"===m.call(a)});var n;b.isFunction=n;var o=Array.isArray||function(a){return a&&"object"==typeof a?"[object Array]"===m.call(a):!1};b.isArray=o},function(a,b,c){"use strict";function d(a){var b=a&&a[0]||1,c=p.COMPILER_REVISION;if(b!==c){if(c>b){var d=p.REVISION_CHANGES[c],e=p.REVISION_CHANGES[b];throw new o["default"]("Template was precompiled with an older version of Handlebars than the current runtime. Please update your precompiler to a newer version ("+d+") or downgrade your runtime to an older version ("+e+").")}throw new o["default"]("Template was precompiled with a newer version of Handlebars than the current runtime. Please update your runtime to a newer version ("+a[1]+").")}}function e(a,b){function c(c,d,e){e.hash&&(d=m.extend({},d,e.hash)),c=b.VM.resolvePartial.call(this,c,d,e);var f=b.VM.invokePartial.call(this,c,d,e);if(null==f&&b.compile&&(e.partials[e.name]=b.compile(c,a.compilerOptions,b),f=e.partials[e.name](d,e)),null!=f){if(e.indent){for(var g=f.split("\n"),h=0,i=g.length;i>h&&(g[h]||h+1!==i);h++)g[h]=e.indent+g[h];f=g.join("\n")}return f}throw new o["default"]("The partial "+e.name+" could not be compiled when running in runtime-only mode")}function d(b){var c=void 0===arguments[1]?{}:arguments[1],f=c.data;
+d._setup(c),!c.partial&&a.useData&&(f=j(b,f));var g=void 0,h=a.useBlockParams?[]:void 0;return a.useDepths&&(g=c.depths?[b].concat(c.depths):[b]),a.main.call(e,b,e.helpers,e.partials,f,h,g)}if(!b)throw new o["default"]("No environment passed to template");if(!a||!a.main)throw new o["default"]("Unknown template object: "+typeof a);b.VM.checkRevision(a.compiler);var e={strict:function(a,b){if(!(b in a))throw new o["default"]('"'+b+'" not defined in '+a);return a[b]},lookup:function(a,b){for(var c=a.length,d=0;c>d;d++)if(a[d]&&null!=a[d][b])return a[d][b]},lambda:function(a,b){return"function"==typeof a?a.call(b):a},escapeExpression:m.escapeExpression,invokePartial:c,fn:function(b){return a[b]},programs:[],program:function(a,b,c,d,e){var g=this.programs[a],h=this.fn(a);return b||e||d||c?g=f(this,a,h,b,c,d,e):g||(g=this.programs[a]=f(this,a,h)),g},data:function(a,b){for(;a&&b--;)a=a._parent;return a},merge:function(a,b){var c=a||b;return a&&b&&a!==b&&(c=m.extend({},b,a)),c},noop:b.VM.noop,compilerInfo:a.compiler};return d.isTop=!0,d._setup=function(c){c.partial?(e.helpers=c.helpers,e.partials=c.partials):(e.helpers=e.merge(c.helpers,b.helpers),a.usePartial&&(e.partials=e.merge(c.partials,b.partials)))},d._child=function(b,c,d,g){if(a.useBlockParams&&!d)throw new o["default"]("must pass block params");if(a.useDepths&&!g)throw new o["default"]("must pass parent depths");return f(e,b,a[b],c,0,d,g)},d}function f(a,b,c,d,e,f,g){function h(b){var e=void 0===arguments[1]?{}:arguments[1];return c.call(a,b,a.helpers,a.partials,e.data||d,f&&[e.blockParams].concat(f),g&&[b].concat(g))}return h.program=b,h.depth=g?g.length:0,h.blockParams=e||0,h}function g(a,b,c){return a?a.call||c.name||(c.name=a,a=c.partials[a]):a=c.partials[c.name],a}function h(a,b,c){if(c.partial=!0,void 0===a)throw new o["default"]("The partial "+c.name+" could not be found");return a instanceof Function?a(b,c):void 0}function i(){return""}function j(a,b){return b&&"root"in b||(b=b?p.createFrame(b):{},b.root=a),b}var k=c(8)["default"];b.__esModule=!0,b.checkRevision=d,b.template=e,b.wrapProgram=f,b.resolvePartial=g,b.invokePartial=h,b.noop=i;var l=c(12),m=k(l),n=c(11),o=k(n),p=c(9)},function(a,b){"use strict";b.__esModule=!0;var c=function(){function a(){this.yy={}}var b={trace:function(){},yy:{},symbols_:{error:2,root:3,program:4,EOF:5,program_repetition0:6,statement:7,mustache:8,block:9,rawBlock:10,partial:11,content:12,COMMENT:13,CONTENT:14,openRawBlock:15,END_RAW_BLOCK:16,OPEN_RAW_BLOCK:17,helperName:18,openRawBlock_repetition0:19,openRawBlock_option0:20,CLOSE_RAW_BLOCK:21,openBlock:22,block_option0:23,closeBlock:24,openInverse:25,block_option1:26,OPEN_BLOCK:27,openBlock_repetition0:28,openBlock_option0:29,openBlock_option1:30,CLOSE:31,OPEN_INVERSE:32,openInverse_repetition0:33,openInverse_option0:34,openInverse_option1:35,openInverseChain:36,OPEN_INVERSE_CHAIN:37,openInverseChain_repetition0:38,openInverseChain_option0:39,openInverseChain_option1:40,inverseAndProgram:41,INVERSE:42,inverseChain:43,inverseChain_option0:44,OPEN_ENDBLOCK:45,OPEN:46,mustache_repetition0:47,mustache_option0:48,OPEN_UNESCAPED:49,mustache_repetition1:50,mustache_option1:51,CLOSE_UNESCAPED:52,OPEN_PARTIAL:53,partialName:54,partial_repetition0:55,partial_option0:56,param:57,sexpr:58,OPEN_SEXPR:59,sexpr_repetition0:60,sexpr_option0:61,CLOSE_SEXPR:62,hash:63,hash_repetition_plus0:64,hashSegment:65,ID:66,EQUALS:67,blockParams:68,OPEN_BLOCK_PARAMS:69,blockParams_repetition_plus0:70,CLOSE_BLOCK_PARAMS:71,path:72,dataName:73,STRING:74,NUMBER:75,BOOLEAN:76,UNDEFINED:77,NULL:78,DATA:79,pathSegments:80,SEP:81,$accept:0,$end:1},terminals_:{2:"error",5:"EOF",13:"COMMENT",14:"CONTENT",16:"END_RAW_BLOCK",17:"OPEN_RAW_BLOCK",21:"CLOSE_RAW_BLOCK",27:"OPEN_BLOCK",31:"CLOSE",32:"OPEN_INVERSE",37:"OPEN_INVERSE_CHAIN",42:"INVERSE",45:"OPEN_ENDBLOCK",46:"OPEN",49:"OPEN_UNESCAPED",52:"CLOSE_UNESCAPED",53:"OPEN_PARTIAL",59:"OPEN_SEXPR",62:"CLOSE_SEXPR",66:"ID",67:"EQUALS",69:"OPEN_BLOCK_PARAMS",71:"CLOSE_BLOCK_PARAMS",74:"STRING",75:"NUMBER",76:"BOOLEAN",77:"UNDEFINED",78:"NULL",79:"DATA",81:"SEP"},productions_:[0,[3,2],[4,1],[7,1],[7,1],[7,1],[7,1],[7,1],[7,1],[12,1],[10,3],[15,5],[9,4],[9,4],[22,6],[25,6],[36,6],[41,2],[43,3],[43,1],[24,3],[8,5],[8,5],[11,5],[57,1],[57,1],[58,5],[63,1],[65,3],[68,3],[18,1],[18,1],[18,1],[18,1],[18,1],[18,1],[18,1],[54,1],[54,1],[73,2],[72,1],[80,3],[80,1],[6,0],[6,2],[19,0],[19,2],[20,0],[20,1],[23,0],[23,1],[26,0],[26,1],[28,0],[28,2],[29,0],[29,1],[30,0],[30,1],[33,0],[33,2],[34,0],[34,1],[35,0],[35,1],[38,0],[38,2],[39,0],[39,1],[40,0],[40,1],[44,0],[44,1],[47,0],[47,2],[48,0],[48,1],[50,0],[50,2],[51,0],[51,1],[55,0],[55,2],[56,0],[56,1],[60,0],[60,2],[61,0],[61,1],[64,1],[64,2],[70,1],[70,2]],performAction:function(a,b,c,d,e,f){var g=f.length-1;switch(e){case 1:return f[g-1];case 2:this.$=new d.Program(f[g],null,{},d.locInfo(this._$));break;case 3:this.$=f[g];break;case 4:this.$=f[g];break;case 5:this.$=f[g];break;case 6:this.$=f[g];break;case 7:this.$=f[g];break;case 8:this.$=new d.CommentStatement(d.stripComment(f[g]),d.stripFlags(f[g],f[g]),d.locInfo(this._$));break;case 9:this.$=new d.ContentStatement(f[g],d.locInfo(this._$));break;case 10:this.$=d.prepareRawBlock(f[g-2],f[g-1],f[g],this._$);break;case 11:this.$={path:f[g-3],params:f[g-2],hash:f[g-1]};break;case 12:this.$=d.prepareBlock(f[g-3],f[g-2],f[g-1],f[g],!1,this._$);break;case 13:this.$=d.prepareBlock(f[g-3],f[g-2],f[g-1],f[g],!0,this._$);break;case 14:this.$={path:f[g-4],params:f[g-3],hash:f[g-2],blockParams:f[g-1],strip:d.stripFlags(f[g-5],f[g])};break;case 15:this.$={path:f[g-4],params:f[g-3],hash:f[g-2],blockParams:f[g-1],strip:d.stripFlags(f[g-5],f[g])};break;case 16:this.$={path:f[g-4],params:f[g-3],hash:f[g-2],blockParams:f[g-1],strip:d.stripFlags(f[g-5],f[g])};break;case 17:this.$={strip:d.stripFlags(f[g-1],f[g-1]),program:f[g]};break;case 18:var h=d.prepareBlock(f[g-2],f[g-1],f[g],f[g],!1,this._$),i=new d.Program([h],null,{},d.locInfo(this._$));i.chained=!0,this.$={strip:f[g-2].strip,program:i,chain:!0};break;case 19:this.$=f[g];break;case 20:this.$={path:f[g-1],strip:d.stripFlags(f[g-2],f[g])};break;case 21:this.$=d.prepareMustache(f[g-3],f[g-2],f[g-1],f[g-4],d.stripFlags(f[g-4],f[g]),this._$);break;case 22:this.$=d.prepareMustache(f[g-3],f[g-2],f[g-1],f[g-4],d.stripFlags(f[g-4],f[g]),this._$);break;case 23:this.$=new d.PartialStatement(f[g-3],f[g-2],f[g-1],d.stripFlags(f[g-4],f[g]),d.locInfo(this._$));break;case 24:this.$=f[g];break;case 25:this.$=f[g];break;case 26:this.$=new d.SubExpression(f[g-3],f[g-2],f[g-1],d.locInfo(this._$));break;case 27:this.$=new d.Hash(f[g],d.locInfo(this._$));break;case 28:this.$=new d.HashPair(d.id(f[g-2]),f[g],d.locInfo(this._$));break;case 29:this.$=d.id(f[g-1]);break;case 30:this.$=f[g];break;case 31:this.$=f[g];break;case 32:this.$=new d.StringLiteral(f[g],d.locInfo(this._$));break;case 33:this.$=new d.NumberLiteral(f[g],d.locInfo(this._$));break;case 34:this.$=new d.BooleanLiteral(f[g],d.locInfo(this._$));break;case 35:this.$=new d.UndefinedLiteral(d.locInfo(this._$));break;case 36:this.$=new d.NullLiteral(d.locInfo(this._$));break;case 37:this.$=f[g];break;case 38:this.$=f[g];break;case 39:this.$=d.preparePath(!0,f[g],this._$);break;case 40:this.$=d.preparePath(!1,f[g],this._$);break;case 41:f[g-2].push({part:d.id(f[g]),original:f[g],separator:f[g-1]}),this.$=f[g-2];break;case 42:this.$=[{part:d.id(f[g]),original:f[g]}];break;case 43:this.$=[];break;case 44:f[g-1].push(f[g]);break;case 45:this.$=[];break;case 46:f[g-1].push(f[g]);break;case 53:this.$=[];break;case 54:f[g-1].push(f[g]);break;case 59:this.$=[];break;case 60:f[g-1].push(f[g]);break;case 65:this.$=[];break;case 66:f[g-1].push(f[g]);break;case 73:this.$=[];break;case 74:f[g-1].push(f[g]);break;case 77:this.$=[];break;case 78:f[g-1].push(f[g]);break;case 81:this.$=[];break;case 82:f[g-1].push(f[g]);break;case 85:this.$=[];break;case 86:f[g-1].push(f[g]);break;case 89:this.$=[f[g]];break;case 90:f[g-1].push(f[g]);break;case 91:this.$=[f[g]];break;case 92:f[g-1].push(f[g])}},table:[{3:1,4:2,5:[2,43],6:3,13:[2,43],14:[2,43],17:[2,43],27:[2,43],32:[2,43],46:[2,43],49:[2,43],53:[2,43]},{1:[3]},{5:[1,4]},{5:[2,2],7:5,8:6,9:7,10:8,11:9,12:10,13:[1,11],14:[1,18],15:16,17:[1,21],22:14,25:15,27:[1,19],32:[1,20],37:[2,2],42:[2,2],45:[2,2],46:[1,12],49:[1,13],53:[1,17]},{1:[2,1]},{5:[2,44],13:[2,44],14:[2,44],17:[2,44],27:[2,44],32:[2,44],37:[2,44],42:[2,44],45:[2,44],46:[2,44],49:[2,44],53:[2,44]},{5:[2,3],13:[2,3],14:[2,3],17:[2,3],27:[2,3],32:[2,3],37:[2,3],42:[2,3],45:[2,3],46:[2,3],49:[2,3],53:[2,3]},{5:[2,4],13:[2,4],14:[2,4],17:[2,4],27:[2,4],32:[2,4],37:[2,4],42:[2,4],45:[2,4],46:[2,4],49:[2,4],53:[2,4]},{5:[2,5],13:[2,5],14:[2,5],17:[2,5],27:[2,5],32:[2,5],37:[2,5],42:[2,5],45:[2,5],46:[2,5],49:[2,5],53:[2,5]},{5:[2,6],13:[2,6],14:[2,6],17:[2,6],27:[2,6],32:[2,6],37:[2,6],42:[2,6],45:[2,6],46:[2,6],49:[2,6],53:[2,6]},{5:[2,7],13:[2,7],14:[2,7],17:[2,7],27:[2,7],32:[2,7],37:[2,7],42:[2,7],45:[2,7],46:[2,7],49:[2,7],53:[2,7]},{5:[2,8],13:[2,8],14:[2,8],17:[2,8],27:[2,8],32:[2,8],37:[2,8],42:[2,8],45:[2,8],46:[2,8],49:[2,8],53:[2,8]},{18:22,66:[1,32],72:23,73:24,74:[1,25],75:[1,26],76:[1,27],77:[1,28],78:[1,29],79:[1,31],80:30},{18:33,66:[1,32],72:23,73:24,74:[1,25],75:[1,26],76:[1,27],77:[1,28],78:[1,29],79:[1,31],80:30},{4:34,6:3,13:[2,43],14:[2,43],17:[2,43],27:[2,43],32:[2,43],37:[2,43],42:[2,43],45:[2,43],46:[2,43],49:[2,43],53:[2,43]},{4:35,6:3,13:[2,43],14:[2,43],17:[2,43],27:[2,43],32:[2,43],42:[2,43],45:[2,43],46:[2,43],49:[2,43],53:[2,43]},{12:36,14:[1,18]},{18:38,54:37,58:39,59:[1,40],66:[1,32],72:23,73:24,74:[1,25],75:[1,26],76:[1,27],77:[1,28],78:[1,29],79:[1,31],80:30},{5:[2,9],13:[2,9],14:[2,9],16:[2,9],17:[2,9],27:[2,9],32:[2,9],37:[2,9],42:[2,9],45:[2,9],46:[2,9],49:[2,9],53:[2,9]},{18:41,66:[1,32],72:23,73:24,74:[1,25],75:[1,26],76:[1,27],77:[1,28],78:[1,29],79:[1,31],80:30},{18:42,66:[1,32],72:23,73:24,74:[1,25],75:[1,26],76:[1,27],77:[1,28],78:[1,29],79:[1,31],80:30},{18:43,66:[1,32],72:23,73:24,74:[1,25],75:[1,26],76:[1,27],77:[1,28],78:[1,29],79:[1,31],80:30},{31:[2,73],47:44,59:[2,73],66:[2,73],74:[2,73],75:[2,73],76:[2,73],77:[2,73],78:[2,73],79:[2,73]},{21:[2,30],31:[2,30],52:[2,30],59:[2,30],62:[2,30],66:[2,30],69:[2,30],74:[2,30],75:[2,30],76:[2,30],77:[2,30],78:[2,30],79:[2,30]},{21:[2,31],31:[2,31],52:[2,31],59:[2,31],62:[2,31],66:[2,31],69:[2,31],74:[2,31],75:[2,31],76:[2,31],77:[2,31],78:[2,31],79:[2,31]},{21:[2,32],31:[2,32],52:[2,32],59:[2,32],62:[2,32],66:[2,32],69:[2,32],74:[2,32],75:[2,32],76:[2,32],77:[2,32],78:[2,32],79:[2,32]},{21:[2,33],31:[2,33],52:[2,33],59:[2,33],62:[2,33],66:[2,33],69:[2,33],74:[2,33],75:[2,33],76:[2,33],77:[2,33],78:[2,33],79:[2,33]},{21:[2,34],31:[2,34],52:[2,34],59:[2,34],62:[2,34],66:[2,34],69:[2,34],74:[2,34],75:[2,34],76:[2,34],77:[2,34],78:[2,34],79:[2,34]},{21:[2,35],31:[2,35],52:[2,35],59:[2,35],62:[2,35],66:[2,35],69:[2,35],74:[2,35],75:[2,35],76:[2,35],77:[2,35],78:[2,35],79:[2,35]},{21:[2,36],31:[2,36],52:[2,36],59:[2,36],62:[2,36],66:[2,36],69:[2,36],74:[2,36],75:[2,36],76:[2,36],77:[2,36],78:[2,36],79:[2,36]},{21:[2,40],31:[2,40],52:[2,40],59:[2,40],62:[2,40],66:[2,40],69:[2,40],74:[2,40],75:[2,40],76:[2,40],77:[2,40],78:[2,40],79:[2,40],81:[1,45]},{66:[1,32],80:46},{21:[2,42],31:[2,42],52:[2,42],59:[2,42],62:[2,42],66:[2,42],69:[2,42],74:[2,42],75:[2,42],76:[2,42],77:[2,42],78:[2,42],79:[2,42],81:[2,42]},{50:47,52:[2,77],59:[2,77],66:[2,77],74:[2,77],75:[2,77],76:[2,77],77:[2,77],78:[2,77],79:[2,77]},{23:48,36:50,37:[1,52],41:51,42:[1,53],43:49,45:[2,49]},{26:54,41:55,42:[1,53],45:[2,51]},{16:[1,56]},{31:[2,81],55:57,59:[2,81],66:[2,81],74:[2,81],75:[2,81],76:[2,81],77:[2,81],78:[2,81],79:[2,81]},{31:[2,37],59:[2,37],66:[2,37],74:[2,37],75:[2,37],76:[2,37],77:[2,37],78:[2,37],79:[2,37]},{31:[2,38],59:[2,38],66:[2,38],74:[2,38],75:[2,38],76:[2,38],77:[2,38],78:[2,38],79:[2,38]},{18:58,66:[1,32],72:23,73:24,74:[1,25],75:[1,26],76:[1,27],77:[1,28],78:[1,29],79:[1,31],80:30},{28:59,31:[2,53],59:[2,53],66:[2,53],69:[2,53],74:[2,53],75:[2,53],76:[2,53],77:[2,53],78:[2,53],79:[2,53]},{31:[2,59],33:60,59:[2,59],66:[2,59],69:[2,59],74:[2,59],75:[2,59],76:[2,59],77:[2,59],78:[2,59],79:[2,59]},{19:61,21:[2,45],59:[2,45],66:[2,45],74:[2,45],75:[2,45],76:[2,45],77:[2,45],78:[2,45],79:[2,45]},{18:65,31:[2,75],48:62,57:63,58:66,59:[1,40],63:64,64:67,65:68,66:[1,69],72:23,73:24,74:[1,25],75:[1,26],76:[1,27],77:[1,28],78:[1,29],79:[1,31],80:30},{66:[1,70]},{21:[2,39],31:[2,39],52:[2,39],59:[2,39],62:[2,39],66:[2,39],69:[2,39],74:[2,39],75:[2,39],76:[2,39],77:[2,39],78:[2,39],79:[2,39],81:[1,45]},{18:65,51:71,52:[2,79],57:72,58:66,59:[1,40],63:73,64:67,65:68,66:[1,69],72:23,73:24,74:[1,25],75:[1,26],76:[1,27],77:[1,28],78:[1,29],79:[1,31],80:30},{24:74,45:[1,75]},{45:[2,50]},{4:76,6:3,13:[2,43],14:[2,43],17:[2,43],27:[2,43],32:[2,43],37:[2,43],42:[2,43],45:[2,43],46:[2,43],49:[2,43],53:[2,43]},{45:[2,19]},{18:77,66:[1,32],72:23,73:24,74:[1,25],75:[1,26],76:[1,27],77:[1,28],78:[1,29],79:[1,31],80:30},{4:78,6:3,13:[2,43],14:[2,43],17:[2,43],27:[2,43],32:[2,43],45:[2,43],46:[2,43],49:[2,43],53:[2,43]},{24:79,45:[1,75]},{45:[2,52]},{5:[2,10],13:[2,10],14:[2,10],17:[2,10],27:[2,10],32:[2,10],37:[2,10],42:[2,10],45:[2,10],46:[2,10],49:[2,10],53:[2,10]},{18:65,31:[2,83],56:80,57:81,58:66,59:[1,40],63:82,64:67,65:68,66:[1,69],72:23,73:24,74:[1,25],75:[1,26],76:[1,27],77:[1,28],78:[1,29],79:[1,31],80:30},{59:[2,85],60:83,62:[2,85],66:[2,85],74:[2,85],75:[2,85],76:[2,85],77:[2,85],78:[2,85],79:[2,85]},{18:65,29:84,31:[2,55],57:85,58:66,59:[1,40],63:86,64:67,65:68,66:[1,69],69:[2,55],72:23,73:24,74:[1,25],75:[1,26],76:[1,27],77:[1,28],78:[1,29],79:[1,31],80:30},{18:65,31:[2,61],34:87,57:88,58:66,59:[1,40],63:89,64:67,65:68,66:[1,69],69:[2,61],72:23,73:24,74:[1,25],75:[1,26],76:[1,27],77:[1,28],78:[1,29],79:[1,31],80:30},{18:65,20:90,21:[2,47],57:91,58:66,59:[1,40],63:92,64:67,65:68,66:[1,69],72:23,73:24,74:[1,25],75:[1,26],76:[1,27],77:[1,28],78:[1,29],79:[1,31],80:30},{31:[1,93]},{31:[2,74],59:[2,74],66:[2,74],74:[2,74],75:[2,74],76:[2,74],77:[2,74],78:[2,74],79:[2,74]},{31:[2,76]},{21:[2,24],31:[2,24],52:[2,24],59:[2,24],62:[2,24],66:[2,24],69:[2,24],74:[2,24],75:[2,24],76:[2,24],77:[2,24],78:[2,24],79:[2,24]},{21:[2,25],31:[2,25],52:[2,25],59:[2,25],62:[2,25],66:[2,25],69:[2,25],74:[2,25],75:[2,25],76:[2,25],77:[2,25],78:[2,25],79:[2,25]},{21:[2,27],31:[2,27],52:[2,27],62:[2,27],65:94,66:[1,95],69:[2,27]},{21:[2,89],31:[2,89],52:[2,89],62:[2,89],66:[2,89],69:[2,89]},{21:[2,42],31:[2,42],52:[2,42],59:[2,42],62:[2,42],66:[2,42],67:[1,96],69:[2,42],74:[2,42],75:[2,42],76:[2,42],77:[2,42],78:[2,42],79:[2,42],81:[2,42]},{21:[2,41],31:[2,41],52:[2,41],59:[2,41],62:[2,41],66:[2,41],69:[2,41],74:[2,41],75:[2,41],76:[2,41],77:[2,41],78:[2,41],79:[2,41],81:[2,41]},{52:[1,97]},{52:[2,78],59:[2,78],66:[2,78],74:[2,78],75:[2,78],76:[2,78],77:[2,78],78:[2,78],79:[2,78]},{52:[2,80]},{5:[2,12],13:[2,12],14:[2,12],17:[2,12],27:[2,12],32:[2,12],37:[2,12],42:[2,12],45:[2,12],46:[2,12],49:[2,12],53:[2,12]},{18:98,66:[1,32],72:23,73:24,74:[1,25],75:[1,26],76:[1,27],77:[1,28],78:[1,29],79:[1,31],80:30},{36:50,37:[1,52],41:51,42:[1,53],43:100,44:99,45:[2,71]},{31:[2,65],38:101,59:[2,65],66:[2,65],69:[2,65],74:[2,65],75:[2,65],76:[2,65],77:[2,65],78:[2,65],79:[2,65]},{45:[2,17]},{5:[2,13],13:[2,13],14:[2,13],17:[2,13],27:[2,13],32:[2,13],37:[2,13],42:[2,13],45:[2,13],46:[2,13],49:[2,13],53:[2,13]},{31:[1,102]},{31:[2,82],59:[2,82],66:[2,82],74:[2,82],75:[2,82],76:[2,82],77:[2,82],78:[2,82],79:[2,82]},{31:[2,84]},{18:65,57:104,58:66,59:[1,40],61:103,62:[2,87],63:105,64:67,65:68,66:[1,69],72:23,73:24,74:[1,25],75:[1,26],76:[1,27],77:[1,28],78:[1,29],79:[1,31],80:30},{30:106,31:[2,57],68:107,69:[1,108]},{31:[2,54],59:[2,54],66:[2,54],69:[2,54],74:[2,54],75:[2,54],76:[2,54],77:[2,54],78:[2,54],79:[2,54]},{31:[2,56],69:[2,56]},{31:[2,63],35:109,68:110,69:[1,108]},{31:[2,60],59:[2,60],66:[2,60],69:[2,60],74:[2,60],75:[2,60],76:[2,60],77:[2,60],78:[2,60],79:[2,60]},{31:[2,62],69:[2,62]},{21:[1,111]},{21:[2,46],59:[2,46],66:[2,46],74:[2,46],75:[2,46],76:[2,46],77:[2,46],78:[2,46],79:[2,46]},{21:[2,48]},{5:[2,21],13:[2,21],14:[2,21],17:[2,21],27:[2,21],32:[2,21],37:[2,21],42:[2,21],45:[2,21],46:[2,21],49:[2,21],53:[2,21]},{21:[2,90],31:[2,90],52:[2,90],62:[2,90],66:[2,90],69:[2,90]},{67:[1,96]},{18:65,57:112,58:66,59:[1,40],66:[1,32],72:23,73:24,74:[1,25],75:[1,26],76:[1,27],77:[1,28],78:[1,29],79:[1,31],80:30},{5:[2,22],13:[2,22],14:[2,22],17:[2,22],27:[2,22],32:[2,22],37:[2,22],42:[2,22],45:[2,22],46:[2,22],49:[2,22],53:[2,22]},{31:[1,113]},{45:[2,18]},{45:[2,72]},{18:65,31:[2,67],39:114,57:115,58:66,59:[1,40],63:116,64:67,65:68,66:[1,69],69:[2,67],72:23,73:24,74:[1,25],75:[1,26],76:[1,27],77:[1,28],78:[1,29],79:[1,31],80:30},{5:[2,23],13:[2,23],14:[2,23],17:[2,23],27:[2,23],32:[2,23],37:[2,23],42:[2,23],45:[2,23],46:[2,23],49:[2,23],53:[2,23]},{62:[1,117]},{59:[2,86],62:[2,86],66:[2,86],74:[2,86],75:[2,86],76:[2,86],77:[2,86],78:[2,86],79:[2,86]},{62:[2,88]},{31:[1,118]},{31:[2,58]},{66:[1,120],70:119},{31:[1,121]},{31:[2,64]},{14:[2,11]},{21:[2,28],31:[2,28],52:[2,28],62:[2,28],66:[2,28],69:[2,28]},{5:[2,20],13:[2,20],14:[2,20],17:[2,20],27:[2,20],32:[2,20],37:[2,20],42:[2,20],45:[2,20],46:[2,20],49:[2,20],53:[2,20]},{31:[2,69],40:122,68:123,69:[1,108]},{31:[2,66],59:[2,66],66:[2,66],69:[2,66],74:[2,66],75:[2,66],76:[2,66],77:[2,66],78:[2,66],79:[2,66]},{31:[2,68],69:[2,68]},{21:[2,26],31:[2,26],52:[2,26],59:[2,26],62:[2,26],66:[2,26],69:[2,26],74:[2,26],75:[2,26],76:[2,26],77:[2,26],78:[2,26],79:[2,26]},{13:[2,14],14:[2,14],17:[2,14],27:[2,14],32:[2,14],37:[2,14],42:[2,14],45:[2,14],46:[2,14],49:[2,14],53:[2,14]},{66:[1,125],71:[1,124]},{66:[2,91],71:[2,91]},{13:[2,15],14:[2,15],17:[2,15],27:[2,15],32:[2,15],42:[2,15],45:[2,15],46:[2,15],49:[2,15],53:[2,15]},{31:[1,126]},{31:[2,70]},{31:[2,29]},{66:[2,92],71:[2,92]},{13:[2,16],14:[2,16],17:[2,16],27:[2,16],32:[2,16],37:[2,16],42:[2,16],45:[2,16],46:[2,16],49:[2,16],53:[2,16]}],defaultActions:{4:[2,1],49:[2,50],51:[2,19],55:[2,52],64:[2,76],73:[2,80],78:[2,17],82:[2,84],92:[2,48],99:[2,18],100:[2,72],105:[2,88],107:[2,58],110:[2,64],111:[2,11],123:[2,70],124:[2,29]},parseError:function(a){throw new Error(a)},parse:function(a){function b(){var a;return a=c.lexer.lex()||1,"number"!=typeof a&&(a=c.symbols_[a]||a),a}var c=this,d=[0],e=[null],f=[],g=this.table,h="",i=0,j=0,k=0;this.lexer.setInput(a),this.lexer.yy=this.yy,this.yy.lexer=this.lexer,this.yy.parser=this,"undefined"==typeof this.lexer.yylloc&&(this.lexer.yylloc={});var l=this.lexer.yylloc;f.push(l);var m=this.lexer.options&&this.lexer.options.ranges;"function"==typeof this.yy.parseError&&(this.parseError=this.yy.parseError);for(var n,o,p,q,r,s,t,u,v,w={};;){if(p=d[d.length-1],this.defaultActions[p]?q=this.defaultActions[p]:((null===n||"undefined"==typeof n)&&(n=b()),q=g[p]&&g[p][n]),"undefined"==typeof q||!q.length||!q[0]){var x="";if(!k){v=[];for(s in g[p])this.terminals_[s]&&s>2&&v.push("'"+this.terminals_[s]+"'");x=this.lexer.showPosition?"Parse error on line "+(i+1)+":\n"+this.lexer.showPosition()+"\nExpecting "+v.join(", ")+", got '"+(this.terminals_[n]||n)+"'":"Parse error on line "+(i+1)+": Unexpected "+(1==n?"end of input":"'"+(this.terminals_[n]||n)+"'"),this.parseError(x,{text:this.lexer.match,token:this.terminals_[n]||n,line:this.lexer.yylineno,loc:l,expected:v})}}if(q[0]instanceof Array&&q.length>1)throw new Error("Parse Error: multiple actions possible at state: "+p+", token: "+n);switch(q[0]){case 1:d.push(n),e.push(this.lexer.yytext),f.push(this.lexer.yylloc),d.push(q[1]),n=null,o?(n=o,o=null):(j=this.lexer.yyleng,h=this.lexer.yytext,i=this.lexer.yylineno,l=this.lexer.yylloc,k>0&&k--);break;case 2:if(t=this.productions_[q[1]][1],w.$=e[e.length-t],w._$={first_line:f[f.length-(t||1)].first_line,last_line:f[f.length-1].last_line,first_column:f[f.length-(t||1)].first_column,last_column:f[f.length-1].last_column},m&&(w._$.range=[f[f.length-(t||1)].range[0],f[f.length-1].range[1]]),r=this.performAction.call(w,h,j,i,this.yy,q[1],e,f),"undefined"!=typeof r)return r;t&&(d=d.slice(0,-1*t*2),e=e.slice(0,-1*t),f=f.slice(0,-1*t)),d.push(this.productions_[q[1]][0]),e.push(w.$),f.push(w._$),u=g[d[d.length-2]][d[d.length-1]],d.push(u);break;case 3:return!0}}return!0}},c=function(){var a={EOF:1,parseError:function(a,b){if(!this.yy.parser)throw new Error(a);this.yy.parser.parseError(a,b)},setInput:function(a){return this._input=a,this._more=this._less=this.done=!1,this.yylineno=this.yyleng=0,this.yytext=this.matched=this.match="",this.conditionStack=["INITIAL"],this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0},this.options.ranges&&(this.yylloc.range=[0,0]),this.offset=0,this},input:function(){var a=this._input[0];this.yytext+=a,this.yyleng++,this.offset++,this.match+=a,this.matched+=a;var b=a.match(/(?:\r\n?|\n).*/g);return b?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),a},unput:function(a){var b=a.length,c=a.split(/(?:\r\n?|\n)/g);this._input=a+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-b-1),this.offset-=b;var d=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1),this.matched=this.matched.substr(0,this.matched.length-1),c.length-1&&(this.yylineno-=c.length-1);var e=this.yylloc.range;return this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:c?(c.length===d.length?this.yylloc.first_column:0)+d[d.length-c.length].length-c[0].length:this.yylloc.first_column-b},this.options.ranges&&(this.yylloc.range=[e[0],e[0]+this.yyleng-b]),this},more:function(){return this._more=!0,this},less:function(a){this.unput(this.match.slice(a))},pastInput:function(){var a=this.matched.substr(0,this.matched.length-this.match.length);return(a.length>20?"...":"")+a.substr(-20).replace(/\n/g,"")},upcomingInput:function(){var a=this.match;return a.length<20&&(a+=this._input.substr(0,20-a.length)),(a.substr(0,20)+(a.length>20?"...":"")).replace(/\n/g,"")},showPosition:function(){var a=this.pastInput(),b=new Array(a.length+1).join("-");return a+this.upcomingInput()+"\n"+b+"^"},next:function(){if(this.done)return this.EOF;this._input||(this.done=!0);var a,b,c,d,e;this._more||(this.yytext="",this.match="");for(var f=this._currentRules(),g=0;g<f.length&&(c=this._input.match(this.rules[f[g]]),!c||b&&!(c[0].length>b[0].length)||(b=c,d=g,this.options.flex));g++);return b?(e=b[0].match(/(?:\r\n?|\n).*/g),e&&(this.yylineno+=e.length),this.yylloc={first_line:this.yylloc.last_line,last_line:this.yylineno+1,first_column:this.yylloc.last_column,last_column:e?e[e.length-1].length-e[e.length-1].match(/\r?\n?/)[0].length:this.yylloc.last_column+b[0].length},this.yytext+=b[0],this.match+=b[0],this.matches=b,this.yyleng=this.yytext.length,this.options.ranges&&(this.yylloc.range=[this.offset,this.offset+=this.yyleng]),this._more=!1,this._input=this._input.slice(b[0].length),this.matched+=b[0],a=this.performAction.call(this,this.yy,this,f[d],this.conditionStack[this.conditionStack.length-1]),this.done&&this._input&&(this.done=!1),a?a:void 0):""===this._input?this.EOF:this.parseError("Lexical error on line "+(this.yylineno+1)+". Unrecognized text.\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})},lex:function(){var a=this.next();return"undefined"!=typeof a?a:this.lex()},begin:function(a){this.conditionStack.push(a)},popState:function(){return this.conditionStack.pop()},_currentRules:function(){return this.conditions[this.conditionStack[this.conditionStack.length-1]].rules},topState:function(){return this.conditionStack[this.conditionStack.length-2]},pushState:function(a){this.begin(a)}};return a.options={},a.performAction=function(a,b,c,d){function e(a,c){return b.yytext=b.yytext.substr(a,b.yyleng-c)}switch(c){case 0:if("\\\\"===b.yytext.slice(-2)?(e(0,1),this.begin("mu")):"\\"===b.yytext.slice(-1)?(e(0,1),this.begin("emu")):this.begin("mu"),b.yytext)return 14;break;case 1:return 14;case 2:return this.popState(),14;case 3:return b.yytext=b.yytext.substr(5,b.yyleng-9),this.popState(),16;case 4:return 14;case 5:return this.popState(),13;case 6:return 59;case 7:return 62;case 8:return 17;case 9:return this.popState(),this.begin("raw"),21;case 10:return 53;case 11:return 27;case 12:return 45;case 13:return this.popState(),42;case 14:return this.popState(),42;case 15:return 32;case 16:return 37;case 17:return 49;case 18:return 46;case 19:this.unput(b.yytext),this.popState(),this.begin("com");break;case 20:return this.popState(),13;case 21:return 46;case 22:return 67;case 23:return 66;case 24:return 66;case 25:return 81;case 26:break;case 27:return this.popState(),52;case 28:return this.popState(),31;case 29:return b.yytext=e(1,2).replace(/\\"/g,'"'),74;case 30:return b.yytext=e(1,2).replace(/\\'/g,"'"),74;case 31:return 79;case 32:return 76;case 33:return 76;case 34:return 77;case 35:return 78;case 36:return 75;case 37:return 69;case 38:return 71;case 39:return 66;case 40:return 66;case 41:return"INVALID";case 42:return 5}},a.rules=[/^(?:[^\x00]*?(?=(\{\{)))/,/^(?:[^\x00]+)/,/^(?:[^\x00]{2,}?(?=(\{\{|\\\{\{|\\\\\{\{|$)))/,/^(?:\{\{\{\{\/[^\s!"#%-,\.\/;->@\[-\^`\{-~]+(?=[=}\s\/.])\}\}\}\})/,/^(?:[^\x00]*?(?=(\{\{\{\{\/)))/,/^(?:[\s\S]*?--(~)?\}\})/,/^(?:\()/,/^(?:\))/,/^(?:\{\{\{\{)/,/^(?:\}\}\}\})/,/^(?:\{\{(~)?>)/,/^(?:\{\{(~)?#)/,/^(?:\{\{(~)?\/)/,/^(?:\{\{(~)?\^\s*(~)?\}\})/,/^(?:\{\{(~)?\s*else\s*(~)?\}\})/,/^(?:\{\{(~)?\^)/,/^(?:\{\{(~)?\s*else\b)/,/^(?:\{\{(~)?\{)/,/^(?:\{\{(~)?&)/,/^(?:\{\{(~)?!--)/,/^(?:\{\{(~)?![\s\S]*?\}\})/,/^(?:\{\{(~)?)/,/^(?:=)/,/^(?:\.\.)/,/^(?:\.(?=([=~}\s\/.)|])))/,/^(?:[\/.])/,/^(?:\s+)/,/^(?:\}(~)?\}\})/,/^(?:(~)?\}\})/,/^(?:"(\\["]|[^"])*")/,/^(?:'(\\[']|[^'])*')/,/^(?:@)/,/^(?:true(?=([~}\s)])))/,/^(?:false(?=([~}\s)])))/,/^(?:undefined(?=([~}\s)])))/,/^(?:null(?=([~}\s)])))/,/^(?:-?[0-9]+(?:\.[0-9]+)?(?=([~}\s)])))/,/^(?:as\s+\|)/,/^(?:\|)/,/^(?:([^\s!"#%-,\.\/;->@\[-\^`\{-~]+(?=([=~}\s\/.)|]))))/,/^(?:\[[^\]]*\])/,/^(?:.)/,/^(?:$)/],a.conditions={mu:{rules:[6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42],inclusive:!1},emu:{rules:[2],inclusive:!1},com:{rules:[5],inclusive:!1},raw:{rules:[3,4],inclusive:!1},INITIAL:{rules:[0,1,42],inclusive:!0}},a}();return b.lexer=c,a.prototype=b,b.Parser=a,new a}();b["default"]=c,a.exports=b["default"]},function(a,b,c){"use strict";function d(){}function e(a,b,c){void 0===b&&(b=a.length);var d=a[b-1],e=a[b-2];return d?"ContentStatement"===d.type?(e||!c?/\r?\n\s*?$/:/(^|\r?\n)\s*?$/).test(d.original):void 0:c}function f(a,b,c){void 0===b&&(b=-1);var d=a[b+1],e=a[b+2];return d?"ContentStatement"===d.type?(e||!c?/^\s*?\r?\n/:/^\s*?(\r?\n|$)/).test(d.original):void 0:c}function g(a,b,c){var d=a[null==b?0:b+1];if(d&&"ContentStatement"===d.type&&(c||!d.rightStripped)){var e=d.value;d.value=d.value.replace(c?/^\s+/:/^[ \t]*\r?\n?/,""),d.rightStripped=d.value!==e}}function h(a,b,c){var d=a[null==b?a.length-1:b-1];if(d&&"ContentStatement"===d.type&&(c||!d.leftStripped)){var e=d.value;return d.value=d.value.replace(c?/\s+$/:/[ \t]+$/,""),d.leftStripped=d.value!==e,d.leftStripped}}var i=c(8)["default"];b.__esModule=!0;var j=c(6),k=i(j);d.prototype=new k["default"],d.prototype.Program=function(a){var b=!this.isRootSeen;this.isRootSeen=!0;for(var c=a.body,d=0,i=c.length;i>d;d++){var j=c[d],k=this.accept(j);if(k){var l=e(c,d,b),m=f(c,d,b),n=k.openStandalone&&l,o=k.closeStandalone&&m,p=k.inlineStandalone&&l&&m;k.close&&g(c,d,!0),k.open&&h(c,d,!0),p&&(g(c,d),h(c,d)&&"PartialStatement"===j.type&&(j.indent=/([ \t]+$)/.exec(c[d-1].original)[1])),n&&(g((j.program||j.inverse).body),h(c,d)),o&&(g(c,d),h((j.inverse||j.program).body))}}return a},d.prototype.BlockStatement=function(a){this.accept(a.program),this.accept(a.inverse);var b=a.program||a.inverse,c=a.program&&a.inverse,d=c,i=c;if(c&&c.chained)for(d=c.body[0].program;i.chained;)i=i.body[i.body.length-1].program;var j={open:a.openStrip.open,close:a.closeStrip.close,openStandalone:f(b.body),closeStandalone:e((d||b).body)};if(a.openStrip.close&&g(b.body,null,!0),c){var k=a.inverseStrip;k.open&&h(b.body,null,!0),k.close&&g(d.body,null,!0),a.closeStrip.open&&h(i.body,null,!0),e(b.body)&&f(d.body)&&(h(b.body),g(d.body))}else a.closeStrip.open&&h(b.body,null,!0);return j},d.prototype.MustacheStatement=function(a){return a.strip},d.prototype.PartialStatement=d.prototype.CommentStatement=function(a){var b=a.strip||{};return{inlineStandalone:!0,open:b.open,close:b.close}},b["default"]=d,a.exports=b["default"]},function(a,b,c){"use strict";function d(a,b){this.source=a,this.start={line:b.first_line,column:b.first_column},this.end={line:b.last_line,column:b.last_column}}function e(a){return/^\[.*\]$/.test(a)?a.substr(1,a.length-2):a}function f(a,b){return{open:"~"===a.charAt(2),close:"~"===b.charAt(b.length-3)}}function g(a){return a.replace(/^\{\{~?\!-?-?/,"").replace(/-?-?~?\}\}$/,"")}function h(a,b,c){c=this.locInfo(c);for(var d=a?"@":"",e=[],f=0,g="",h=0,i=b.length;i>h;h++){var j=b[h].part,k=b[h].original!==j;if(d+=(b[h].separator||"")+j,k||".."!==j&&"."!==j&&"this"!==j)e.push(j);else{if(e.length>0)throw new n["default"]("Invalid path: "+d,{loc:c});".."===j&&(f++,g+="../")}}return new this.PathExpression(a,f,e,d,c)}function i(a,b,c,d,e,f){var g=d.charAt(3)||d.charAt(2),h="{"!==g&&"&"!==g;return new this.MustacheStatement(a,b,c,h,e,this.locInfo(f))}function j(a,b,c,d){if(a.path.original!==c){var e={loc:a.path.loc};throw new n["default"](a.path.original+" doesn't match "+c,e)}d=this.locInfo(d);var f=new this.Program([b],null,{},d);return new this.BlockStatement(a.path,a.params,a.hash,f,void 0,{},{},{},d)}function k(a,b,c,d,e,f){if(d&&d.path&&a.path.original!==d.path.original){var g={loc:a.path.loc};throw new n["default"](a.path.original+" doesn't match "+d.path.original,g)}b.blockParams=a.blockParams;var h=void 0,i=void 0;return c&&(c.chain&&(c.program.body[0].closeStrip=d.strip),i=c.strip,h=c.program),e&&(e=h,h=b,b=e),new this.BlockStatement(a.path,a.params,a.hash,b,h,a.strip,i,d&&d.strip,this.locInfo(f))}var l=c(8)["default"];b.__esModule=!0,b.SourceLocation=d,b.id=e,b.stripFlags=f,b.stripComment=g,b.preparePath=h,b.prepareMustache=i,b.prepareRawBlock=j,b.prepareBlock=k;var m=c(11),n=l(m)},function(a,b,c){"use strict";function d(a,b,c){if(f.isArray(a)){for(var d=[],e=0,g=a.length;g>e;e++)d.push(b.wrap(a[e],c));return d}return"boolean"==typeof a||"number"==typeof a?a+"":a}function e(a){this.srcFile=a,this.source=[]}b.__esModule=!0;var f=c(12),g=void 0;try{}catch(h){}g||(g=function(a,b,c,d){this.src="",d&&this.add(d)},g.prototype={add:function(a){f.isArray(a)&&(a=a.join("")),this.src+=a},prepend:function(a){f.isArray(a)&&(a=a.join("")),this.src=a+this.src},toStringWithSourceMap:function(){return{code:this.toString()}},toString:function(){return this.src}}),e.prototype={prepend:function(a,b){this.source.unshift(this.wrap(a,b))},push:function(a,b){this.source.push(this.wrap(a,b))},merge:function(){var a=this.empty();return this.each(function(b){a.add(["  ",b,"\n"])}),a},each:function(a){for(var b=0,c=this.source.length;c>b;b++)a(this.source[b])},empty:function(){var a=void 0===arguments[0]?this.currentLocation||{start:{}}:arguments[0];return new g(a.start.line,a.start.column,this.srcFile)},wrap:function(a){var b=void 0===arguments[1]?this.currentLocation||{start:{}}:arguments[1];return a instanceof g?a:(a=d(a,this,b),new g(b.start.line,b.start.column,this.srcFile,a))},functionCall:function(a,b,c){return c=this.generateList(c),this.wrap([a,b?"."+b+"(":"(",c,")"])},quotedString:function(a){return'"'+(a+"").replace(/\\/g,"\\\\").replace(/"/g,'\\"').replace(/\n/g,"\\n").replace(/\r/g,"\\r").replace(/\u2028/g,"\\u2028").replace(/\u2029/g,"\\u2029")+'"'},objectLiteral:function(a){var b=[];for(var c in a)if(a.hasOwnProperty(c)){var e=d(a[c],this);"undefined"!==e&&b.push([this.quotedString(c),":",e])
+}var f=this.generateList(b);return f.prepend("{"),f.add("}"),f},generateList:function(a,b){for(var c=this.empty(b),e=0,f=a.length;f>e;e++)e&&c.add(","),c.add(d(a[e],this,b));return c},generateArray:function(a,b){var c=this.generateList(a,b);return c.prepend("["),c.add("]"),c}},b["default"]=e,a.exports=b["default"]}])});
\ No newline at end of file
diff --git a/src/Jackett/Content/libs/handlebarsmoment.js b/src/Jackett/Content/libs/handlebarsmoment.js
new file mode 100644
index 0000000000000000000000000000000000000000..0bf9f5fd13bd4d2548af1317e2af89064c9bd67b
--- /dev/null
+++ b/src/Jackett/Content/libs/handlebarsmoment.js
@@ -0,0 +1,33 @@
+
+Handlebars.registerHelper('dateFormat', function (context, block) {
+    if (window.moment) {
+        var f = block.hash.format || "MMM DD, YYYY hh:mm:ss A";
+        return moment(context).format(f); //had to remove Date(context)
+    } else {
+        return context;   //  moment plugin not available. return data as is.
+    };
+});
+
+Handlebars.registerHelper('jacketTimespan', function (context, block) {
+    var now = moment();
+    var from = moment(context);
+    var timeSpan = moment.duration(now.diff(from));
+
+    var minutes = timeSpan.asMinutes();
+    if (minutes < 120) {
+        return Math.round(minutes) + 'm ago';
+    }
+
+    var hours = timeSpan.asHours();
+    if (hours < 48) {
+        return Math.round(hours) + 'h ago';
+    }
+    
+    var days = timeSpan.asDays();
+    if (days < 365) {
+        return Math.round(days) + 'd ago';
+    }
+
+    var years = timeSpan.asYears();
+    return Math.round(years) + 'y ago';
+});
\ No newline at end of file
diff --git a/src/Jackett/Content/libs/jquery.dataTables.min.js b/src/Jackett/Content/libs/jquery.dataTables.min.js
new file mode 100644
index 0000000000000000000000000000000000000000..85dd817e132579887fb2785f6cdaeba5b1998dd1
--- /dev/null
+++ b/src/Jackett/Content/libs/jquery.dataTables.min.js
@@ -0,0 +1,160 @@
+/*! DataTables 1.10.7
+ * ©2008-2015 SpryMedia Ltd - datatables.net/license
+ */
+(function(Ea,Q,k){var P=function(h){function W(a){var b,c,e={};h.each(a,function(d){if((b=d.match(/^([^A-Z]+?)([A-Z])/))&&-1!=="a aa ai ao as b fn i m o s ".indexOf(b[1]+" "))c=d.replace(b[0],b[2].toLowerCase()),e[c]=d,"o"===b[1]&&W(a[d])});a._hungarianMap=e}function H(a,b,c){a._hungarianMap||W(a);var e;h.each(b,function(d){e=a._hungarianMap[d];if(e!==k&&(c||b[e]===k))"o"===e.charAt(0)?(b[e]||(b[e]={}),h.extend(!0,b[e],b[d]),H(a[e],b[e],c)):b[e]=b[d]})}function P(a){var b=m.defaults.oLanguage,c=a.sZeroRecords;
+!a.sEmptyTable&&(c&&"No data available in table"===b.sEmptyTable)&&E(a,a,"sZeroRecords","sEmptyTable");!a.sLoadingRecords&&(c&&"Loading..."===b.sLoadingRecords)&&E(a,a,"sZeroRecords","sLoadingRecords");a.sInfoThousands&&(a.sThousands=a.sInfoThousands);(a=a.sDecimal)&&db(a)}function eb(a){A(a,"ordering","bSort");A(a,"orderMulti","bSortMulti");A(a,"orderClasses","bSortClasses");A(a,"orderCellsTop","bSortCellsTop");A(a,"order","aaSorting");A(a,"orderFixed","aaSortingFixed");A(a,"paging","bPaginate");
+A(a,"pagingType","sPaginationType");A(a,"pageLength","iDisplayLength");A(a,"searching","bFilter");if(a=a.aoSearchCols)for(var b=0,c=a.length;b<c;b++)a[b]&&H(m.models.oSearch,a[b])}function fb(a){A(a,"orderable","bSortable");A(a,"orderData","aDataSort");A(a,"orderSequence","asSorting");A(a,"orderDataType","sortDataType");var b=a.aDataSort;b&&!h.isArray(b)&&(a.aDataSort=[b])}function gb(a){var a=a.oBrowser,b=h("<div/>").css({position:"absolute",top:0,left:0,height:1,width:1,overflow:"hidden"}).append(h("<div/>").css({position:"absolute",
+top:1,left:1,width:100,overflow:"scroll"}).append(h('<div class="test"/>').css({width:"100%",height:10}))).appendTo("body"),c=b.find(".test");a.bScrollOversize=100===c[0].offsetWidth;a.bScrollbarLeft=1!==Math.round(c.offset().left);b.remove()}function hb(a,b,c,e,d,f){var g,j=!1;c!==k&&(g=c,j=!0);for(;e!==d;)a.hasOwnProperty(e)&&(g=j?b(g,a[e],e,a):a[e],j=!0,e+=f);return g}function Fa(a,b){var c=m.defaults.column,e=a.aoColumns.length,c=h.extend({},m.models.oColumn,c,{nTh:b?b:Q.createElement("th"),sTitle:c.sTitle?
+c.sTitle:b?b.innerHTML:"",aDataSort:c.aDataSort?c.aDataSort:[e],mData:c.mData?c.mData:e,idx:e});a.aoColumns.push(c);c=a.aoPreSearchCols;c[e]=h.extend({},m.models.oSearch,c[e]);ka(a,e,h(b).data())}function ka(a,b,c){var b=a.aoColumns[b],e=a.oClasses,d=h(b.nTh);if(!b.sWidthOrig){b.sWidthOrig=d.attr("width")||null;var f=(d.attr("style")||"").match(/width:\s*(\d+[pxem%]+)/);f&&(b.sWidthOrig=f[1])}c!==k&&null!==c&&(fb(c),H(m.defaults.column,c),c.mDataProp!==k&&!c.mData&&(c.mData=c.mDataProp),c.sType&&
+(b._sManualType=c.sType),c.className&&!c.sClass&&(c.sClass=c.className),h.extend(b,c),E(b,c,"sWidth","sWidthOrig"),c.iDataSort!==k&&(b.aDataSort=[c.iDataSort]),E(b,c,"aDataSort"));var g=b.mData,j=R(g),i=b.mRender?R(b.mRender):null,c=function(a){return"string"===typeof a&&-1!==a.indexOf("@")};b._bAttrSrc=h.isPlainObject(g)&&(c(g.sort)||c(g.type)||c(g.filter));b.fnGetData=function(a,b,c){var e=j(a,b,k,c);return i&&b?i(e,b,a,c):e};b.fnSetData=function(a,b,c){return S(g)(a,b,c)};"number"!==typeof g&&
+(a._rowReadObject=!0);a.oFeatures.bSort||(b.bSortable=!1,d.addClass(e.sSortableNone));a=-1!==h.inArray("asc",b.asSorting);c=-1!==h.inArray("desc",b.asSorting);!b.bSortable||!a&&!c?(b.sSortingClass=e.sSortableNone,b.sSortingClassJUI=""):a&&!c?(b.sSortingClass=e.sSortableAsc,b.sSortingClassJUI=e.sSortJUIAscAllowed):!a&&c?(b.sSortingClass=e.sSortableDesc,b.sSortingClassJUI=e.sSortJUIDescAllowed):(b.sSortingClass=e.sSortable,b.sSortingClassJUI=e.sSortJUI)}function X(a){if(!1!==a.oFeatures.bAutoWidth){var b=
+a.aoColumns;Ga(a);for(var c=0,e=b.length;c<e;c++)b[c].nTh.style.width=b[c].sWidth}b=a.oScroll;(""!==b.sY||""!==b.sX)&&Y(a);w(a,null,"column-sizing",[a])}function la(a,b){var c=Z(a,"bVisible");return"number"===typeof c[b]?c[b]:null}function $(a,b){var c=Z(a,"bVisible"),c=h.inArray(b,c);return-1!==c?c:null}function aa(a){return Z(a,"bVisible").length}function Z(a,b){var c=[];h.map(a.aoColumns,function(a,d){a[b]&&c.push(d)});return c}function Ha(a){var b=a.aoColumns,c=a.aoData,e=m.ext.type.detect,d,
+f,g,j,i,h,l,q,n;d=0;for(f=b.length;d<f;d++)if(l=b[d],n=[],!l.sType&&l._sManualType)l.sType=l._sManualType;else if(!l.sType){g=0;for(j=e.length;g<j;g++){i=0;for(h=c.length;i<h;i++){n[i]===k&&(n[i]=x(a,i,d,"type"));q=e[g](n[i],a);if(!q&&g!==e.length-1)break;if("html"===q)break}if(q){l.sType=q;break}}l.sType||(l.sType="string")}}function ib(a,b,c,e){var d,f,g,j,i,o,l=a.aoColumns;if(b)for(d=b.length-1;0<=d;d--){o=b[d];var q=o.targets!==k?o.targets:o.aTargets;h.isArray(q)||(q=[q]);f=0;for(g=q.length;f<
+g;f++)if("number"===typeof q[f]&&0<=q[f]){for(;l.length<=q[f];)Fa(a);e(q[f],o)}else if("number"===typeof q[f]&&0>q[f])e(l.length+q[f],o);else if("string"===typeof q[f]){j=0;for(i=l.length;j<i;j++)("_all"==q[f]||h(l[j].nTh).hasClass(q[f]))&&e(j,o)}}if(c){d=0;for(a=c.length;d<a;d++)e(d,c[d])}}function K(a,b,c,e){var d=a.aoData.length,f=h.extend(!0,{},m.models.oRow,{src:c?"dom":"data"});f._aData=b;a.aoData.push(f);for(var b=a.aoColumns,f=0,g=b.length;f<g;f++)c&&Ia(a,d,f,x(a,d,f)),b[f].sType=null;a.aiDisplayMaster.push(d);
+(c||!a.oFeatures.bDeferRender)&&Ja(a,d,c,e);return d}function ma(a,b){var c;b instanceof h||(b=h(b));return b.map(function(b,d){c=na(a,d);return K(a,c.data,d,c.cells)})}function x(a,b,c,e){var d=a.iDraw,f=a.aoColumns[c],g=a.aoData[b]._aData,j=f.sDefaultContent,c=f.fnGetData(g,e,{settings:a,row:b,col:c});if(c===k)return a.iDrawError!=d&&null===j&&(I(a,0,"Requested unknown parameter "+("function"==typeof f.mData?"{function}":"'"+f.mData+"'")+" for row "+b,4),a.iDrawError=d),j;if((c===g||null===c)&&
+null!==j)c=j;else if("function"===typeof c)return c.call(g);return null===c&&"display"==e?"":c}function Ia(a,b,c,e){a.aoColumns[c].fnSetData(a.aoData[b]._aData,e,{settings:a,row:b,col:c})}function Ka(a){return h.map(a.match(/(\\.|[^\.])+/g),function(a){return a.replace(/\\./g,".")})}function R(a){if(h.isPlainObject(a)){var b={};h.each(a,function(a,c){c&&(b[a]=R(c))});return function(a,c,f,g){var j=b[c]||b._;return j!==k?j(a,c,f,g):a}}if(null===a)return function(a){return a};if("function"===typeof a)return function(b,
+c,f,g){return a(b,c,f,g)};if("string"===typeof a&&(-1!==a.indexOf(".")||-1!==a.indexOf("[")||-1!==a.indexOf("("))){var c=function(a,b,f){var g,j;if(""!==f){j=Ka(f);for(var i=0,h=j.length;i<h;i++){f=j[i].match(ba);g=j[i].match(T);if(f){j[i]=j[i].replace(ba,"");""!==j[i]&&(a=a[j[i]]);g=[];j.splice(0,i+1);j=j.join(".");i=0;for(h=a.length;i<h;i++)g.push(c(a[i],b,j));a=f[0].substring(1,f[0].length-1);a=""===a?g:g.join(a);break}else if(g){j[i]=j[i].replace(T,"");a=a[j[i]]();continue}if(null===a||a[j[i]]===
+k)return k;a=a[j[i]]}}return a};return function(b,d){return c(b,d,a)}}return function(b){return b[a]}}function S(a){if(h.isPlainObject(a))return S(a._);if(null===a)return function(){};if("function"===typeof a)return function(b,e,d){a(b,"set",e,d)};if("string"===typeof a&&(-1!==a.indexOf(".")||-1!==a.indexOf("[")||-1!==a.indexOf("("))){var b=function(a,e,d){var d=Ka(d),f;f=d[d.length-1];for(var g,j,i=0,h=d.length-1;i<h;i++){g=d[i].match(ba);j=d[i].match(T);if(g){d[i]=d[i].replace(ba,"");a[d[i]]=[];
+f=d.slice();f.splice(0,i+1);g=f.join(".");j=0;for(h=e.length;j<h;j++)f={},b(f,e[j],g),a[d[i]].push(f);return}j&&(d[i]=d[i].replace(T,""),a=a[d[i]](e));if(null===a[d[i]]||a[d[i]]===k)a[d[i]]={};a=a[d[i]]}if(f.match(T))a[f.replace(T,"")](e);else a[f.replace(ba,"")]=e};return function(c,e){return b(c,e,a)}}return function(b,e){b[a]=e}}function La(a){return D(a.aoData,"_aData")}function oa(a){a.aoData.length=0;a.aiDisplayMaster.length=0;a.aiDisplay.length=0}function pa(a,b,c){for(var e=-1,d=0,f=a.length;d<
+f;d++)a[d]==b?e=d:a[d]>b&&a[d]--; -1!=e&&c===k&&a.splice(e,1)}function ca(a,b,c,e){var d=a.aoData[b],f,g=function(c,f){for(;c.childNodes.length;)c.removeChild(c.firstChild);c.innerHTML=x(a,b,f,"display")};if("dom"===c||(!c||"auto"===c)&&"dom"===d.src)d._aData=na(a,d,e,e===k?k:d._aData).data;else{var j=d.anCells;if(j)if(e!==k)g(j[e],e);else{c=0;for(f=j.length;c<f;c++)g(j[c],c)}}d._aSortData=null;d._aFilterData=null;g=a.aoColumns;if(e!==k)g[e].sType=null;else{c=0;for(f=g.length;c<f;c++)g[c].sType=null;
+Ma(d)}}function na(a,b,c,e){var d=[],f=b.firstChild,g,j=0,i,o=a.aoColumns,l=a._rowReadObject,e=e||l?{}:[],q=function(a,b){if("string"===typeof a){var c=a.indexOf("@");-1!==c&&(c=a.substring(c+1),S(a)(e,b.getAttribute(c)))}},a=function(a){if(c===k||c===j)g=o[j],i=h.trim(a.innerHTML),g&&g._bAttrSrc?(S(g.mData._)(e,i),q(g.mData.sort,a),q(g.mData.type,a),q(g.mData.filter,a)):l?(g._setter||(g._setter=S(g.mData)),g._setter(e,i)):e[j]=i;j++};if(f)for(;f;){b=f.nodeName.toUpperCase();if("TD"==b||"TH"==b)a(f),
+d.push(f);f=f.nextSibling}else{d=b.anCells;f=0;for(b=d.length;f<b;f++)a(d[f])}return{data:e,cells:d}}function Ja(a,b,c,e){var d=a.aoData[b],f=d._aData,g=[],j,i,h,l,q;if(null===d.nTr){j=c||Q.createElement("tr");d.nTr=j;d.anCells=g;j._DT_RowIndex=b;Ma(d);l=0;for(q=a.aoColumns.length;l<q;l++){h=a.aoColumns[l];i=c?e[l]:Q.createElement(h.sCellType);g.push(i);if(!c||h.mRender||h.mData!==l)i.innerHTML=x(a,b,l,"display");h.sClass&&(i.className+=" "+h.sClass);h.bVisible&&!c?j.appendChild(i):!h.bVisible&&c&&
+i.parentNode.removeChild(i);h.fnCreatedCell&&h.fnCreatedCell.call(a.oInstance,i,x(a,b,l),f,b,l)}w(a,"aoRowCreatedCallback",null,[j,f,b])}d.nTr.setAttribute("role","row")}function Ma(a){var b=a.nTr,c=a._aData;if(b){c.DT_RowId&&(b.id=c.DT_RowId);if(c.DT_RowClass){var e=c.DT_RowClass.split(" ");a.__rowc=a.__rowc?Na(a.__rowc.concat(e)):e;h(b).removeClass(a.__rowc.join(" ")).addClass(c.DT_RowClass)}c.DT_RowAttr&&h(b).attr(c.DT_RowAttr);c.DT_RowData&&h(b).data(c.DT_RowData)}}function jb(a){var b,c,e,d,
+f,g=a.nTHead,j=a.nTFoot,i=0===h("th, td",g).length,o=a.oClasses,l=a.aoColumns;i&&(d=h("<tr/>").appendTo(g));b=0;for(c=l.length;b<c;b++)f=l[b],e=h(f.nTh).addClass(f.sClass),i&&e.appendTo(d),a.oFeatures.bSort&&(e.addClass(f.sSortingClass),!1!==f.bSortable&&(e.attr("tabindex",a.iTabIndex).attr("aria-controls",a.sTableId),Oa(a,f.nTh,b))),f.sTitle!=e.html()&&e.html(f.sTitle),Pa(a,"header")(a,e,f,o);i&&da(a.aoHeader,g);h(g).find(">tr").attr("role","row");h(g).find(">tr>th, >tr>td").addClass(o.sHeaderTH);
+h(j).find(">tr>th, >tr>td").addClass(o.sFooterTH);if(null!==j){a=a.aoFooter[0];b=0;for(c=a.length;b<c;b++)f=l[b],f.nTf=a[b].cell,f.sClass&&h(f.nTf).addClass(f.sClass)}}function ea(a,b,c){var e,d,f,g=[],j=[],i=a.aoColumns.length,o;if(b){c===k&&(c=!1);e=0;for(d=b.length;e<d;e++){g[e]=b[e].slice();g[e].nTr=b[e].nTr;for(f=i-1;0<=f;f--)!a.aoColumns[f].bVisible&&!c&&g[e].splice(f,1);j.push([])}e=0;for(d=g.length;e<d;e++){if(a=g[e].nTr)for(;f=a.firstChild;)a.removeChild(f);f=0;for(b=g[e].length;f<b;f++)if(o=
+i=1,j[e][f]===k){a.appendChild(g[e][f].cell);for(j[e][f]=1;g[e+i]!==k&&g[e][f].cell==g[e+i][f].cell;)j[e+i][f]=1,i++;for(;g[e][f+o]!==k&&g[e][f].cell==g[e][f+o].cell;){for(c=0;c<i;c++)j[e+c][f+o]=1;o++}h(g[e][f].cell).attr("rowspan",i).attr("colspan",o)}}}}function M(a){var b=w(a,"aoPreDrawCallback","preDraw",[a]);if(-1!==h.inArray(!1,b))C(a,!1);else{var b=[],c=0,e=a.asStripeClasses,d=e.length,f=a.oLanguage,g=a.iInitDisplayStart,j="ssp"==B(a),i=a.aiDisplay;a.bDrawing=!0;g!==k&&-1!==g&&(a._iDisplayStart=
+j?g:g>=a.fnRecordsDisplay()?0:g,a.iInitDisplayStart=-1);var g=a._iDisplayStart,o=a.fnDisplayEnd();if(a.bDeferLoading)a.bDeferLoading=!1,a.iDraw++,C(a,!1);else if(j){if(!a.bDestroying&&!kb(a))return}else a.iDraw++;if(0!==i.length){f=j?a.aoData.length:o;for(j=j?0:g;j<f;j++){var l=i[j],q=a.aoData[l];null===q.nTr&&Ja(a,l);l=q.nTr;if(0!==d){var n=e[c%d];q._sRowStripe!=n&&(h(l).removeClass(q._sRowStripe).addClass(n),q._sRowStripe=n)}w(a,"aoRowCallback",null,[l,q._aData,c,j]);b.push(l);c++}}else c=f.sZeroRecords,
+1==a.iDraw&&"ajax"==B(a)?c=f.sLoadingRecords:f.sEmptyTable&&0===a.fnRecordsTotal()&&(c=f.sEmptyTable),b[0]=h("<tr/>",{"class":d?e[0]:""}).append(h("<td />",{valign:"top",colSpan:aa(a),"class":a.oClasses.sRowEmpty}).html(c))[0];w(a,"aoHeaderCallback","header",[h(a.nTHead).children("tr")[0],La(a),g,o,i]);w(a,"aoFooterCallback","footer",[h(a.nTFoot).children("tr")[0],La(a),g,o,i]);e=h(a.nTBody);e.children().detach();e.append(h(b));w(a,"aoDrawCallback","draw",[a]);a.bSorted=!1;a.bFiltered=!1;a.bDrawing=
+!1}}function N(a,b){var c=a.oFeatures,e=c.bFilter;c.bSort&&lb(a);e?fa(a,a.oPreviousSearch):a.aiDisplay=a.aiDisplayMaster.slice();!0!==b&&(a._iDisplayStart=0);a._drawHold=b;M(a);a._drawHold=!1}function mb(a){var b=a.oClasses,c=h(a.nTable),c=h("<div/>").insertBefore(c),e=a.oFeatures,d=h("<div/>",{id:a.sTableId+"_wrapper","class":b.sWrapper+(a.nTFoot?"":" "+b.sNoFooter)});a.nHolding=c[0];a.nTableWrapper=d[0];a.nTableReinsertBefore=a.nTable.nextSibling;for(var f=a.sDom.split(""),g,j,i,o,l,q,n=0;n<f.length;n++){g=
+null;j=f[n];if("<"==j){i=h("<div/>")[0];o=f[n+1];if("'"==o||'"'==o){l="";for(q=2;f[n+q]!=o;)l+=f[n+q],q++;"H"==l?l=b.sJUIHeader:"F"==l&&(l=b.sJUIFooter);-1!=l.indexOf(".")?(o=l.split("."),i.id=o[0].substr(1,o[0].length-1),i.className=o[1]):"#"==l.charAt(0)?i.id=l.substr(1,l.length-1):i.className=l;n+=q}d.append(i);d=h(i)}else if(">"==j)d=d.parent();else if("l"==j&&e.bPaginate&&e.bLengthChange)g=nb(a);else if("f"==j&&e.bFilter)g=ob(a);else if("r"==j&&e.bProcessing)g=pb(a);else if("t"==j)g=qb(a);else if("i"==
+j&&e.bInfo)g=rb(a);else if("p"==j&&e.bPaginate)g=sb(a);else if(0!==m.ext.feature.length){i=m.ext.feature;q=0;for(o=i.length;q<o;q++)if(j==i[q].cFeature){g=i[q].fnInit(a);break}}g&&(i=a.aanFeatures,i[j]||(i[j]=[]),i[j].push(g),d.append(g))}c.replaceWith(d)}function da(a,b){var c=h(b).children("tr"),e,d,f,g,j,i,o,l,q,n;a.splice(0,a.length);f=0;for(i=c.length;f<i;f++)a.push([]);f=0;for(i=c.length;f<i;f++){e=c[f];for(d=e.firstChild;d;){if("TD"==d.nodeName.toUpperCase()||"TH"==d.nodeName.toUpperCase()){l=
+1*d.getAttribute("colspan");q=1*d.getAttribute("rowspan");l=!l||0===l||1===l?1:l;q=!q||0===q||1===q?1:q;g=0;for(j=a[f];j[g];)g++;o=g;n=1===l?!0:!1;for(j=0;j<l;j++)for(g=0;g<q;g++)a[f+g][o+j]={cell:d,unique:n},a[f+g].nTr=e}d=d.nextSibling}}}function qa(a,b,c){var e=[];c||(c=a.aoHeader,b&&(c=[],da(c,b)));for(var b=0,d=c.length;b<d;b++)for(var f=0,g=c[b].length;f<g;f++)if(c[b][f].unique&&(!e[f]||!a.bSortCellsTop))e[f]=c[b][f].cell;return e}function ra(a,b,c){w(a,"aoServerParams","serverParams",[b]);
+if(b&&h.isArray(b)){var e={},d=/(.*?)\[\]$/;h.each(b,function(a,b){var c=b.name.match(d);c?(c=c[0],e[c]||(e[c]=[]),e[c].push(b.value)):e[b.name]=b.value});b=e}var f,g=a.ajax,j=a.oInstance,i=function(b){w(a,null,"xhr",[a,b,a.jqXHR]);c(b)};if(h.isPlainObject(g)&&g.data){f=g.data;var o=h.isFunction(f)?f(b,a):f,b=h.isFunction(f)&&o?o:h.extend(!0,b,o);delete g.data}o={data:b,success:function(b){var c=b.error||b.sError;c&&I(a,0,c);a.json=b;i(b)},dataType:"json",cache:!1,type:a.sServerMethod,error:function(b,
+c){var f=w(a,null,"xhr",[a,null,a.jqXHR]);-1===h.inArray(!0,f)&&("parsererror"==c?I(a,0,"Invalid JSON response",1):4===b.readyState&&I(a,0,"Ajax error",7));C(a,!1)}};a.oAjaxData=b;w(a,null,"preXhr",[a,b]);a.fnServerData?a.fnServerData.call(j,a.sAjaxSource,h.map(b,function(a,b){return{name:b,value:a}}),i,a):a.sAjaxSource||"string"===typeof g?a.jqXHR=h.ajax(h.extend(o,{url:g||a.sAjaxSource})):h.isFunction(g)?a.jqXHR=g.call(j,b,i,a):(a.jqXHR=h.ajax(h.extend(o,g)),g.data=f)}function kb(a){return a.bAjaxDataGet?
+(a.iDraw++,C(a,!0),ra(a,tb(a),function(b){ub(a,b)}),!1):!0}function tb(a){var b=a.aoColumns,c=b.length,e=a.oFeatures,d=a.oPreviousSearch,f=a.aoPreSearchCols,g,j=[],i,o,l,q=U(a);g=a._iDisplayStart;i=!1!==e.bPaginate?a._iDisplayLength:-1;var n=function(a,b){j.push({name:a,value:b})};n("sEcho",a.iDraw);n("iColumns",c);n("sColumns",D(b,"sName").join(","));n("iDisplayStart",g);n("iDisplayLength",i);var k={draw:a.iDraw,columns:[],order:[],start:g,length:i,search:{value:d.sSearch,regex:d.bRegex}};for(g=
+0;g<c;g++)o=b[g],l=f[g],i="function"==typeof o.mData?"function":o.mData,k.columns.push({data:i,name:o.sName,searchable:o.bSearchable,orderable:o.bSortable,search:{value:l.sSearch,regex:l.bRegex}}),n("mDataProp_"+g,i),e.bFilter&&(n("sSearch_"+g,l.sSearch),n("bRegex_"+g,l.bRegex),n("bSearchable_"+g,o.bSearchable)),e.bSort&&n("bSortable_"+g,o.bSortable);e.bFilter&&(n("sSearch",d.sSearch),n("bRegex",d.bRegex));e.bSort&&(h.each(q,function(a,b){k.order.push({column:b.col,dir:b.dir});n("iSortCol_"+a,b.col);
+n("sSortDir_"+a,b.dir)}),n("iSortingCols",q.length));b=m.ext.legacy.ajax;return null===b?a.sAjaxSource?j:k:b?j:k}function ub(a,b){var c=sa(a,b),e=b.sEcho!==k?b.sEcho:b.draw,d=b.iTotalRecords!==k?b.iTotalRecords:b.recordsTotal,f=b.iTotalDisplayRecords!==k?b.iTotalDisplayRecords:b.recordsFiltered;if(e){if(1*e<a.iDraw)return;a.iDraw=1*e}oa(a);a._iRecordsTotal=parseInt(d,10);a._iRecordsDisplay=parseInt(f,10);e=0;for(d=c.length;e<d;e++)K(a,c[e]);a.aiDisplay=a.aiDisplayMaster.slice();a.bAjaxDataGet=!1;
+M(a);a._bInitComplete||ta(a,b);a.bAjaxDataGet=!0;C(a,!1)}function sa(a,b){var c=h.isPlainObject(a.ajax)&&a.ajax.dataSrc!==k?a.ajax.dataSrc:a.sAjaxDataProp;return"data"===c?b.aaData||b[c]:""!==c?R(c)(b):b}function ob(a){var b=a.oClasses,c=a.sTableId,e=a.oLanguage,d=a.oPreviousSearch,f=a.aanFeatures,g='<input type="search" class="'+b.sFilterInput+'"/>',j=e.sSearch,j=j.match(/_INPUT_/)?j.replace("_INPUT_",g):j+g,b=h("<div/>",{id:!f.f?c+"_filter":null,"class":b.sFilter}).append(h("<label/>").append(j)),
+f=function(){var b=!this.value?"":this.value;b!=d.sSearch&&(fa(a,{sSearch:b,bRegex:d.bRegex,bSmart:d.bSmart,bCaseInsensitive:d.bCaseInsensitive}),a._iDisplayStart=0,M(a))},g=null!==a.searchDelay?a.searchDelay:"ssp"===B(a)?400:0,i=h("input",b).val(d.sSearch).attr("placeholder",e.sSearchPlaceholder).bind("keyup.DT search.DT input.DT paste.DT cut.DT",g?ua(f,g):f).bind("keypress.DT",function(a){if(13==a.keyCode)return!1}).attr("aria-controls",c);h(a.nTable).on("search.dt.DT",function(b,c){if(a===c)try{i[0]!==
+Q.activeElement&&i.val(d.sSearch)}catch(f){}});return b[0]}function fa(a,b,c){var e=a.oPreviousSearch,d=a.aoPreSearchCols,f=function(a){e.sSearch=a.sSearch;e.bRegex=a.bRegex;e.bSmart=a.bSmart;e.bCaseInsensitive=a.bCaseInsensitive};Ha(a);if("ssp"!=B(a)){vb(a,b.sSearch,c,b.bEscapeRegex!==k?!b.bEscapeRegex:b.bRegex,b.bSmart,b.bCaseInsensitive);f(b);for(b=0;b<d.length;b++)wb(a,d[b].sSearch,b,d[b].bEscapeRegex!==k?!d[b].bEscapeRegex:d[b].bRegex,d[b].bSmart,d[b].bCaseInsensitive);xb(a)}else f(b);a.bFiltered=
+!0;w(a,null,"search",[a])}function xb(a){for(var b=m.ext.search,c=a.aiDisplay,e,d,f=0,g=b.length;f<g;f++){for(var j=[],i=0,h=c.length;i<h;i++)d=c[i],e=a.aoData[d],b[f](a,e._aFilterData,d,e._aData,i)&&j.push(d);c.length=0;c.push.apply(c,j)}}function wb(a,b,c,e,d,f){if(""!==b)for(var g=a.aiDisplay,e=Qa(b,e,d,f),d=g.length-1;0<=d;d--)b=a.aoData[g[d]]._aFilterData[c],e.test(b)||g.splice(d,1)}function vb(a,b,c,e,d,f){var e=Qa(b,e,d,f),d=a.oPreviousSearch.sSearch,f=a.aiDisplayMaster,g;0!==m.ext.search.length&&
+(c=!0);g=yb(a);if(0>=b.length)a.aiDisplay=f.slice();else{if(g||c||d.length>b.length||0!==b.indexOf(d)||a.bSorted)a.aiDisplay=f.slice();b=a.aiDisplay;for(c=b.length-1;0<=c;c--)e.test(a.aoData[b[c]]._sFilterRow)||b.splice(c,1)}}function Qa(a,b,c,e){a=b?a:va(a);c&&(a="^(?=.*?"+h.map(a.match(/"[^"]+"|[^ ]+/g)||[""],function(a){if('"'===a.charAt(0))var b=a.match(/^"(.*)"$/),a=b?b[1]:a;return a.replace('"',"")}).join(")(?=.*?")+").*$");return RegExp(a,e?"i":"")}function va(a){return a.replace(Yb,"\\$1")}
+function yb(a){var b=a.aoColumns,c,e,d,f,g,j,i,h,l=m.ext.type.search;c=!1;e=0;for(f=a.aoData.length;e<f;e++)if(h=a.aoData[e],!h._aFilterData){j=[];d=0;for(g=b.length;d<g;d++)c=b[d],c.bSearchable?(i=x(a,e,d,"filter"),l[c.sType]&&(i=l[c.sType](i)),null===i&&(i=""),"string"!==typeof i&&i.toString&&(i=i.toString())):i="",i.indexOf&&-1!==i.indexOf("&")&&(wa.innerHTML=i,i=Zb?wa.textContent:wa.innerText),i.replace&&(i=i.replace(/[\r\n]/g,"")),j.push(i);h._aFilterData=j;h._sFilterRow=j.join("  ");c=!0}return c}
+function zb(a){return{search:a.sSearch,smart:a.bSmart,regex:a.bRegex,caseInsensitive:a.bCaseInsensitive}}function Ab(a){return{sSearch:a.search,bSmart:a.smart,bRegex:a.regex,bCaseInsensitive:a.caseInsensitive}}function rb(a){var b=a.sTableId,c=a.aanFeatures.i,e=h("<div/>",{"class":a.oClasses.sInfo,id:!c?b+"_info":null});c||(a.aoDrawCallback.push({fn:Bb,sName:"information"}),e.attr("role","status").attr("aria-live","polite"),h(a.nTable).attr("aria-describedby",b+"_info"));return e[0]}function Bb(a){var b=
+a.aanFeatures.i;if(0!==b.length){var c=a.oLanguage,e=a._iDisplayStart+1,d=a.fnDisplayEnd(),f=a.fnRecordsTotal(),g=a.fnRecordsDisplay(),j=g?c.sInfo:c.sInfoEmpty;g!==f&&(j+=" "+c.sInfoFiltered);j+=c.sInfoPostFix;j=Cb(a,j);c=c.fnInfoCallback;null!==c&&(j=c.call(a.oInstance,a,e,d,f,g,j));h(b).html(j)}}function Cb(a,b){var c=a.fnFormatNumber,e=a._iDisplayStart+1,d=a._iDisplayLength,f=a.fnRecordsDisplay(),g=-1===d;return b.replace(/_START_/g,c.call(a,e)).replace(/_END_/g,c.call(a,a.fnDisplayEnd())).replace(/_MAX_/g,
+c.call(a,a.fnRecordsTotal())).replace(/_TOTAL_/g,c.call(a,f)).replace(/_PAGE_/g,c.call(a,g?1:Math.ceil(e/d))).replace(/_PAGES_/g,c.call(a,g?1:Math.ceil(f/d)))}function ga(a){var b,c,e=a.iInitDisplayStart,d=a.aoColumns,f;c=a.oFeatures;if(a.bInitialised){mb(a);jb(a);ea(a,a.aoHeader);ea(a,a.aoFooter);C(a,!0);c.bAutoWidth&&Ga(a);b=0;for(c=d.length;b<c;b++)f=d[b],f.sWidth&&(f.nTh.style.width=s(f.sWidth));N(a);d=B(a);"ssp"!=d&&("ajax"==d?ra(a,[],function(c){var f=sa(a,c);for(b=0;b<f.length;b++)K(a,f[b]);
+a.iInitDisplayStart=e;N(a);C(a,!1);ta(a,c)},a):(C(a,!1),ta(a)))}else setTimeout(function(){ga(a)},200)}function ta(a,b){a._bInitComplete=!0;b&&X(a);w(a,"aoInitComplete","init",[a,b])}function Ra(a,b){var c=parseInt(b,10);a._iDisplayLength=c;Sa(a);w(a,null,"length",[a,c])}function nb(a){for(var b=a.oClasses,c=a.sTableId,e=a.aLengthMenu,d=h.isArray(e[0]),f=d?e[0]:e,e=d?e[1]:e,d=h("<select/>",{name:c+"_length","aria-controls":c,"class":b.sLengthSelect}),g=0,j=f.length;g<j;g++)d[0][g]=new Option(e[g],
+f[g]);var i=h("<div><label/></div>").addClass(b.sLength);a.aanFeatures.l||(i[0].id=c+"_length");i.children().append(a.oLanguage.sLengthMenu.replace("_MENU_",d[0].outerHTML));h("select",i).val(a._iDisplayLength).bind("change.DT",function(){Ra(a,h(this).val());M(a)});h(a.nTable).bind("length.dt.DT",function(b,c,f){a===c&&h("select",i).val(f)});return i[0]}function sb(a){var b=a.sPaginationType,c=m.ext.pager[b],e="function"===typeof c,d=function(a){M(a)},b=h("<div/>").addClass(a.oClasses.sPaging+b)[0],
+f=a.aanFeatures;e||c.fnInit(a,b,d);f.p||(b.id=a.sTableId+"_paginate",a.aoDrawCallback.push({fn:function(a){if(e){var b=a._iDisplayStart,i=a._iDisplayLength,h=a.fnRecordsDisplay(),l=-1===i,b=l?0:Math.ceil(b/i),i=l?1:Math.ceil(h/i),h=c(b,i),q,l=0;for(q=f.p.length;l<q;l++)Pa(a,"pageButton")(a,f.p[l],l,h,b,i)}else c.fnUpdate(a,d)},sName:"pagination"}));return b}function Ta(a,b,c){var e=a._iDisplayStart,d=a._iDisplayLength,f=a.fnRecordsDisplay();0===f||-1===d?e=0:"number"===typeof b?(e=b*d,e>f&&(e=0)):
+"first"==b?e=0:"previous"==b?(e=0<=d?e-d:0,0>e&&(e=0)):"next"==b?e+d<f&&(e+=d):"last"==b?e=Math.floor((f-1)/d)*d:I(a,0,"Unknown paging action: "+b,5);b=a._iDisplayStart!==e;a._iDisplayStart=e;b&&(w(a,null,"page",[a]),c&&M(a));return b}function pb(a){return h("<div/>",{id:!a.aanFeatures.r?a.sTableId+"_processing":null,"class":a.oClasses.sProcessing}).html(a.oLanguage.sProcessing).insertBefore(a.nTable)[0]}function C(a,b){a.oFeatures.bProcessing&&h(a.aanFeatures.r).css("display",b?"block":"none");w(a,
+null,"processing",[a,b])}function qb(a){var b=h(a.nTable);b.attr("role","grid");var c=a.oScroll;if(""===c.sX&&""===c.sY)return a.nTable;var e=c.sX,d=c.sY,f=a.oClasses,g=b.children("caption"),j=g.length?g[0]._captionSide:null,i=h(b[0].cloneNode(!1)),o=h(b[0].cloneNode(!1)),l=b.children("tfoot");c.sX&&"100%"===b.attr("width")&&b.removeAttr("width");l.length||(l=null);c=h("<div/>",{"class":f.sScrollWrapper}).append(h("<div/>",{"class":f.sScrollHead}).css({overflow:"hidden",position:"relative",border:0,
+width:e?!e?null:s(e):"100%"}).append(h("<div/>",{"class":f.sScrollHeadInner}).css({"box-sizing":"content-box",width:c.sXInner||"100%"}).append(i.removeAttr("id").css("margin-left",0).append("top"===j?g:null).append(b.children("thead"))))).append(h("<div/>",{"class":f.sScrollBody}).css({overflow:"auto",height:!d?null:s(d),width:!e?null:s(e)}).append(b));l&&c.append(h("<div/>",{"class":f.sScrollFoot}).css({overflow:"hidden",border:0,width:e?!e?null:s(e):"100%"}).append(h("<div/>",{"class":f.sScrollFootInner}).append(o.removeAttr("id").css("margin-left",
+0).append("bottom"===j?g:null).append(b.children("tfoot")))));var b=c.children(),q=b[0],f=b[1],n=l?b[2]:null;if(e)h(f).on("scroll.DT",function(){var a=this.scrollLeft;q.scrollLeft=a;l&&(n.scrollLeft=a)});a.nScrollHead=q;a.nScrollBody=f;a.nScrollFoot=n;a.aoDrawCallback.push({fn:Y,sName:"scrolling"});return c[0]}function Y(a){var b=a.oScroll,c=b.sX,e=b.sXInner,d=b.sY,f=b.iBarWidth,g=h(a.nScrollHead),j=g[0].style,i=g.children("div"),o=i[0].style,l=i.children("table"),i=a.nScrollBody,q=h(i),n=i.style,
+k=h(a.nScrollFoot).children("div"),p=k.children("table"),m=h(a.nTHead),r=h(a.nTable),t=r[0],O=t.style,L=a.nTFoot?h(a.nTFoot):null,ha=a.oBrowser,w=ha.bScrollOversize,v,u,y,x,z,A=[],B=[],C=[],D,E=function(a){a=a.style;a.paddingTop="0";a.paddingBottom="0";a.borderTopWidth="0";a.borderBottomWidth="0";a.height=0};r.children("thead, tfoot").remove();z=m.clone().prependTo(r);v=m.find("tr");y=z.find("tr");z.find("th, td").removeAttr("tabindex");L&&(x=L.clone().prependTo(r),u=L.find("tr"),x=x.find("tr"));
+c||(n.width="100%",g[0].style.width="100%");h.each(qa(a,z),function(b,c){D=la(a,b);c.style.width=a.aoColumns[D].sWidth});L&&G(function(a){a.style.width=""},x);b.bCollapse&&""!==d&&(n.height=q[0].offsetHeight+m[0].offsetHeight+"px");g=r.outerWidth();if(""===c){if(O.width="100%",w&&(r.find("tbody").height()>i.offsetHeight||"scroll"==q.css("overflow-y")))O.width=s(r.outerWidth()-f)}else""!==e?O.width=s(e):g==q.width()&&q.height()<r.height()?(O.width=s(g-f),r.outerWidth()>g-f&&(O.width=s(g))):O.width=
+s(g);g=r.outerWidth();G(E,y);G(function(a){C.push(a.innerHTML);A.push(s(h(a).css("width")))},y);G(function(a,b){a.style.width=A[b]},v);h(y).height(0);L&&(G(E,x),G(function(a){B.push(s(h(a).css("width")))},x),G(function(a,b){a.style.width=B[b]},u),h(x).height(0));G(function(a,b){a.innerHTML='<div class="dataTables_sizing" style="height:0;overflow:hidden;">'+C[b]+"</div>";a.style.width=A[b]},y);L&&G(function(a,b){a.innerHTML="";a.style.width=B[b]},x);if(r.outerWidth()<g){u=i.scrollHeight>i.offsetHeight||
+"scroll"==q.css("overflow-y")?g+f:g;if(w&&(i.scrollHeight>i.offsetHeight||"scroll"==q.css("overflow-y")))O.width=s(u-f);(""===c||""!==e)&&I(a,1,"Possible column misalignment",6)}else u="100%";n.width=s(u);j.width=s(u);L&&(a.nScrollFoot.style.width=s(u));!d&&w&&(n.height=s(t.offsetHeight+f));d&&b.bCollapse&&(n.height=s(d),b=c&&t.offsetWidth>i.offsetWidth?f:0,t.offsetHeight<i.offsetHeight&&(n.height=s(t.offsetHeight+b)));b=r.outerWidth();l[0].style.width=s(b);o.width=s(b);l=r.height()>i.clientHeight||
+"scroll"==q.css("overflow-y");ha="padding"+(ha.bScrollbarLeft?"Left":"Right");o[ha]=l?f+"px":"0px";L&&(p[0].style.width=s(b),k[0].style.width=s(b),k[0].style[ha]=l?f+"px":"0px");q.scroll();if((a.bSorted||a.bFiltered)&&!a._drawHold)i.scrollTop=0}function G(a,b,c){for(var e=0,d=0,f=b.length,g,j;d<f;){g=b[d].firstChild;for(j=c?c[d].firstChild:null;g;)1===g.nodeType&&(c?a(g,j,e):a(g,e),e++),g=g.nextSibling,j=c?j.nextSibling:null;d++}}function Ga(a){var b=a.nTable,c=a.aoColumns,e=a.oScroll,d=e.sY,f=e.sX,
+g=e.sXInner,j=c.length,e=Z(a,"bVisible"),i=h("th",a.nTHead),o=b.getAttribute("width"),l=b.parentNode,k=!1,n,m;(n=b.style.width)&&-1!==n.indexOf("%")&&(o=n);for(n=0;n<e.length;n++)m=c[e[n]],null!==m.sWidth&&(m.sWidth=Db(m.sWidthOrig,l),k=!0);if(!k&&!f&&!d&&j==aa(a)&&j==i.length)for(n=0;n<j;n++)c[n].sWidth=s(i.eq(n).width());else{j=h(b).clone().css("visibility","hidden").removeAttr("id");j.find("tbody tr").remove();var p=h("<tr/>").appendTo(j.find("tbody"));j.find("tfoot th, tfoot td").css("width",
+"");i=qa(a,j.find("thead")[0]);for(n=0;n<e.length;n++)m=c[e[n]],i[n].style.width=null!==m.sWidthOrig&&""!==m.sWidthOrig?s(m.sWidthOrig):"";if(a.aoData.length)for(n=0;n<e.length;n++)k=e[n],m=c[k],h(Eb(a,k)).clone(!1).append(m.sContentPadding).appendTo(p);j.appendTo(l);f&&g?j.width(g):f?(j.css("width","auto"),j.width()<l.offsetWidth&&j.width(l.offsetWidth)):d?j.width(l.offsetWidth):o&&j.width(o);Fb(a,j[0]);if(f){for(n=g=0;n<e.length;n++)m=c[e[n]],d=h(i[n]).outerWidth(),g+=null===m.sWidthOrig?d:parseInt(m.sWidth,
+10)+d-h(i[n]).width();j.width(s(g));b.style.width=s(g)}for(n=0;n<e.length;n++)if(m=c[e[n]],d=h(i[n]).width())m.sWidth=s(d);b.style.width=s(j.css("width"));j.remove()}o&&(b.style.width=s(o));if((o||f)&&!a._reszEvt)b=function(){h(Ea).bind("resize.DT-"+a.sInstance,ua(function(){X(a)}))},a.oBrowser.bScrollOversize?setTimeout(b,1E3):b(),a._reszEvt=!0}function ua(a,b){var c=b!==k?b:200,e,d;return function(){var b=this,g=+new Date,j=arguments;e&&g<e+c?(clearTimeout(d),d=setTimeout(function(){e=k;a.apply(b,
+j)},c)):(e=g,a.apply(b,j))}}function Db(a,b){if(!a)return 0;var c=h("<div/>").css("width",s(a)).appendTo(b||Q.body),e=c[0].offsetWidth;c.remove();return e}function Fb(a,b){var c=a.oScroll;if(c.sX||c.sY)c=!c.sX?c.iBarWidth:0,b.style.width=s(h(b).outerWidth()-c)}function Eb(a,b){var c=Gb(a,b);if(0>c)return null;var e=a.aoData[c];return!e.nTr?h("<td/>").html(x(a,c,b,"display"))[0]:e.anCells[b]}function Gb(a,b){for(var c,e=-1,d=-1,f=0,g=a.aoData.length;f<g;f++)c=x(a,f,b,"display")+"",c=c.replace($b,""),
+c.length>e&&(e=c.length,d=f);return d}function s(a){return null===a?"0px":"number"==typeof a?0>a?"0px":a+"px":a.match(/\d$/)?a+"px":a}function Hb(){var a=m.__scrollbarWidth;if(a===k){var b=h("<p/>").css({position:"absolute",top:0,left:0,width:"100%",height:150,padding:0,overflow:"scroll",visibility:"hidden"}).appendTo("body"),a=b[0].offsetWidth-b[0].clientWidth;m.__scrollbarWidth=a;b.remove()}return a}function U(a){var b,c,e=[],d=a.aoColumns,f,g,j,i;b=a.aaSortingFixed;c=h.isPlainObject(b);var o=[];
+f=function(a){a.length&&!h.isArray(a[0])?o.push(a):o.push.apply(o,a)};h.isArray(b)&&f(b);c&&b.pre&&f(b.pre);f(a.aaSorting);c&&b.post&&f(b.post);for(a=0;a<o.length;a++){i=o[a][0];f=d[i].aDataSort;b=0;for(c=f.length;b<c;b++)g=f[b],j=d[g].sType||"string",o[a]._idx===k&&(o[a]._idx=h.inArray(o[a][1],d[g].asSorting)),e.push({src:i,col:g,dir:o[a][1],index:o[a]._idx,type:j,formatter:m.ext.type.order[j+"-pre"]})}return e}function lb(a){var b,c,e=[],d=m.ext.type.order,f=a.aoData,g=0,j,i=a.aiDisplayMaster,h;
+Ha(a);h=U(a);b=0;for(c=h.length;b<c;b++)j=h[b],j.formatter&&g++,Ib(a,j.col);if("ssp"!=B(a)&&0!==h.length){b=0;for(c=i.length;b<c;b++)e[i[b]]=b;g===h.length?i.sort(function(a,b){var c,d,g,j,i=h.length,k=f[a]._aSortData,m=f[b]._aSortData;for(g=0;g<i;g++)if(j=h[g],c=k[j.col],d=m[j.col],c=c<d?-1:c>d?1:0,0!==c)return"asc"===j.dir?c:-c;c=e[a];d=e[b];return c<d?-1:c>d?1:0}):i.sort(function(a,b){var c,g,j,i,k=h.length,m=f[a]._aSortData,r=f[b]._aSortData;for(j=0;j<k;j++)if(i=h[j],c=m[i.col],g=r[i.col],i=d[i.type+
+"-"+i.dir]||d["string-"+i.dir],c=i(c,g),0!==c)return c;c=e[a];g=e[b];return c<g?-1:c>g?1:0})}a.bSorted=!0}function Jb(a){for(var b,c,e=a.aoColumns,d=U(a),a=a.oLanguage.oAria,f=0,g=e.length;f<g;f++){c=e[f];var j=c.asSorting;b=c.sTitle.replace(/<.*?>/g,"");var i=c.nTh;i.removeAttribute("aria-sort");c.bSortable&&(0<d.length&&d[0].col==f?(i.setAttribute("aria-sort","asc"==d[0].dir?"ascending":"descending"),c=j[d[0].index+1]||j[0]):c=j[0],b+="asc"===c?a.sSortAscending:a.sSortDescending);i.setAttribute("aria-label",
+b)}}function Ua(a,b,c,e){var d=a.aaSorting,f=a.aoColumns[b].asSorting,g=function(a,b){var c=a._idx;c===k&&(c=h.inArray(a[1],f));return c+1<f.length?c+1:b?null:0};"number"===typeof d[0]&&(d=a.aaSorting=[d]);c&&a.oFeatures.bSortMulti?(c=h.inArray(b,D(d,"0")),-1!==c?(b=g(d[c],!0),null===b&&1===d.length&&(b=0),null===b?d.splice(c,1):(d[c][1]=f[b],d[c]._idx=b)):(d.push([b,f[0],0]),d[d.length-1]._idx=0)):d.length&&d[0][0]==b?(b=g(d[0]),d.length=1,d[0][1]=f[b],d[0]._idx=b):(d.length=0,d.push([b,f[0]]),d[0]._idx=
+0);N(a);"function"==typeof e&&e(a)}function Oa(a,b,c,e){var d=a.aoColumns[c];Va(b,{},function(b){!1!==d.bSortable&&(a.oFeatures.bProcessing?(C(a,!0),setTimeout(function(){Ua(a,c,b.shiftKey,e);"ssp"!==B(a)&&C(a,!1)},0)):Ua(a,c,b.shiftKey,e))})}function xa(a){var b=a.aLastSort,c=a.oClasses.sSortColumn,e=U(a),d=a.oFeatures,f,g;if(d.bSort&&d.bSortClasses){d=0;for(f=b.length;d<f;d++)g=b[d].src,h(D(a.aoData,"anCells",g)).removeClass(c+(2>d?d+1:3));d=0;for(f=e.length;d<f;d++)g=e[d].src,h(D(a.aoData,"anCells",
+g)).addClass(c+(2>d?d+1:3))}a.aLastSort=e}function Ib(a,b){var c=a.aoColumns[b],e=m.ext.order[c.sSortDataType],d;e&&(d=e.call(a.oInstance,a,b,$(a,b)));for(var f,g=m.ext.type.order[c.sType+"-pre"],j=0,i=a.aoData.length;j<i;j++)if(c=a.aoData[j],c._aSortData||(c._aSortData=[]),!c._aSortData[b]||e)f=e?d[j]:x(a,j,b,"sort"),c._aSortData[b]=g?g(f):f}function ya(a){if(a.oFeatures.bStateSave&&!a.bDestroying){var b={time:+new Date,start:a._iDisplayStart,length:a._iDisplayLength,order:h.extend(!0,[],a.aaSorting),
+search:zb(a.oPreviousSearch),columns:h.map(a.aoColumns,function(b,e){return{visible:b.bVisible,search:zb(a.aoPreSearchCols[e])}})};w(a,"aoStateSaveParams","stateSaveParams",[a,b]);a.oSavedState=b;a.fnStateSaveCallback.call(a.oInstance,a,b)}}function Kb(a){var b,c,e=a.aoColumns;if(a.oFeatures.bStateSave){var d=a.fnStateLoadCallback.call(a.oInstance,a);if(d&&d.time&&(b=w(a,"aoStateLoadParams","stateLoadParams",[a,d]),-1===h.inArray(!1,b)&&(b=a.iStateDuration,!(0<b&&d.time<+new Date-1E3*b)&&e.length===
+d.columns.length))){a.oLoadedState=h.extend(!0,{},d);d.start!==k&&(a._iDisplayStart=d.start,a.iInitDisplayStart=d.start);d.length!==k&&(a._iDisplayLength=d.length);d.order!==k&&(a.aaSorting=[],h.each(d.order,function(b,c){a.aaSorting.push(c[0]>=e.length?[0,c[1]]:c)}));d.search!==k&&h.extend(a.oPreviousSearch,Ab(d.search));b=0;for(c=d.columns.length;b<c;b++){var f=d.columns[b];f.visible!==k&&(e[b].bVisible=f.visible);f.search!==k&&h.extend(a.aoPreSearchCols[b],Ab(f.search))}w(a,"aoStateLoaded","stateLoaded",
+[a,d])}}}function za(a){var b=m.settings,a=h.inArray(a,D(b,"nTable"));return-1!==a?b[a]:null}function I(a,b,c,e){c="DataTables warning: "+(null!==a?"table id="+a.sTableId+" - ":"")+c;e&&(c+=". For more information about this error, please see http://datatables.net/tn/"+e);if(b)Ea.console&&console.log&&console.log(c);else if(b=m.ext,b=b.sErrMode||b.errMode,w(a,null,"error",[a,e,c]),"alert"==b)alert(c);else{if("throw"==b)throw Error(c);"function"==typeof b&&b(a,e,c)}}function E(a,b,c,e){h.isArray(c)?
+h.each(c,function(c,f){h.isArray(f)?E(a,b,f[0],f[1]):E(a,b,f)}):(e===k&&(e=c),b[c]!==k&&(a[e]=b[c]))}function Lb(a,b,c){var e,d;for(d in b)b.hasOwnProperty(d)&&(e=b[d],h.isPlainObject(e)?(h.isPlainObject(a[d])||(a[d]={}),h.extend(!0,a[d],e)):a[d]=c&&"data"!==d&&"aaData"!==d&&h.isArray(e)?e.slice():e);return a}function Va(a,b,c){h(a).bind("click.DT",b,function(b){a.blur();c(b)}).bind("keypress.DT",b,function(a){13===a.which&&(a.preventDefault(),c(a))}).bind("selectstart.DT",function(){return!1})}function z(a,
+b,c,e){c&&a[b].push({fn:c,sName:e})}function w(a,b,c,e){var d=[];b&&(d=h.map(a[b].slice().reverse(),function(b){return b.fn.apply(a.oInstance,e)}));null!==c&&(b=h.Event(c+".dt"),h(a.nTable).trigger(b,e),d.push(b.result));return d}function Sa(a){var b=a._iDisplayStart,c=a.fnDisplayEnd(),e=a._iDisplayLength;b>=c&&(b=c-e);b-=b%e;if(-1===e||0>b)b=0;a._iDisplayStart=b}function Pa(a,b){var c=a.renderer,e=m.ext.renderer[b];return h.isPlainObject(c)&&c[b]?e[c[b]]||e._:"string"===typeof c?e[c]||e._:e._}function B(a){return a.oFeatures.bServerSide?
+"ssp":a.ajax||a.sAjaxSource?"ajax":"dom"}function Wa(a,b){var c=[],c=Mb.numbers_length,e=Math.floor(c/2);b<=c?c=V(0,b):a<=e?(c=V(0,c-2),c.push("ellipsis"),c.push(b-1)):(a>=b-1-e?c=V(b-(c-2),b):(c=V(a-e+2,a+e-1),c.push("ellipsis"),c.push(b-1)),c.splice(0,0,"ellipsis"),c.splice(0,0,0));c.DT_el="span";return c}function db(a){h.each({num:function(b){return Aa(b,a)},"num-fmt":function(b){return Aa(b,a,Xa)},"html-num":function(b){return Aa(b,a,Ba)},"html-num-fmt":function(b){return Aa(b,a,Ba,Xa)}},function(b,
+c){u.type.order[b+a+"-pre"]=c;b.match(/^html\-/)&&(u.type.search[b+a]=u.type.search.html)})}function Nb(a){return function(){var b=[za(this[m.ext.iApiIndex])].concat(Array.prototype.slice.call(arguments));return m.ext.internal[a].apply(this,b)}}var m,u,t,r,v,Ya={},Ob=/[\r\n]/g,Ba=/<.*?>/g,ac=/^[\w\+\-]/,bc=/[\w\+\-]$/,Yb=RegExp("(\\/|\\.|\\*|\\+|\\?|\\||\\(|\\)|\\[|\\]|\\{|\\}|\\\\|\\$|\\^|\\-)","g"),Xa=/[',$\u00a3\u20ac\u00a5%\u2009\u202F\u20BD\u20a9\u20BArfk]/gi,J=function(a){return!a||!0===a||
+"-"===a?!0:!1},Pb=function(a){var b=parseInt(a,10);return!isNaN(b)&&isFinite(a)?b:null},Qb=function(a,b){Ya[b]||(Ya[b]=RegExp(va(b),"g"));return"string"===typeof a&&"."!==b?a.replace(/\./g,"").replace(Ya[b],"."):a},Za=function(a,b,c){var e="string"===typeof a;if(J(a))return!0;b&&e&&(a=Qb(a,b));c&&e&&(a=a.replace(Xa,""));return!isNaN(parseFloat(a))&&isFinite(a)},Rb=function(a,b,c){return J(a)?!0:!(J(a)||"string"===typeof a)?null:Za(a.replace(Ba,""),b,c)?!0:null},D=function(a,b,c){var e=[],d=0,f=a.length;
+if(c!==k)for(;d<f;d++)a[d]&&a[d][b]&&e.push(a[d][b][c]);else for(;d<f;d++)a[d]&&e.push(a[d][b]);return e},ia=function(a,b,c,e){var d=[],f=0,g=b.length;if(e!==k)for(;f<g;f++)a[b[f]][c]&&d.push(a[b[f]][c][e]);else for(;f<g;f++)d.push(a[b[f]][c]);return d},V=function(a,b){var c=[],e;b===k?(b=0,e=a):(e=b,b=a);for(var d=b;d<e;d++)c.push(d);return c},Sb=function(a){for(var b=[],c=0,e=a.length;c<e;c++)a[c]&&b.push(a[c]);return b},Na=function(a){var b=[],c,e,d=a.length,f,g=0;e=0;a:for(;e<d;e++){c=a[e];for(f=
+0;f<g;f++)if(b[f]===c)continue a;b.push(c);g++}return b},A=function(a,b,c){a[b]!==k&&(a[c]=a[b])},ba=/\[.*?\]$/,T=/\(\)$/,wa=h("<div>")[0],Zb=wa.textContent!==k,$b=/<.*?>/g;m=function(a){this.$=function(a,b){return this.api(!0).$(a,b)};this._=function(a,b){return this.api(!0).rows(a,b).data()};this.api=function(a){return a?new t(za(this[u.iApiIndex])):new t(this)};this.fnAddData=function(a,b){var c=this.api(!0),e=h.isArray(a)&&(h.isArray(a[0])||h.isPlainObject(a[0]))?c.rows.add(a):c.row.add(a);(b===
+k||b)&&c.draw();return e.flatten().toArray()};this.fnAdjustColumnSizing=function(a){var b=this.api(!0).columns.adjust(),c=b.settings()[0],e=c.oScroll;a===k||a?b.draw(!1):(""!==e.sX||""!==e.sY)&&Y(c)};this.fnClearTable=function(a){var b=this.api(!0).clear();(a===k||a)&&b.draw()};this.fnClose=function(a){this.api(!0).row(a).child.hide()};this.fnDeleteRow=function(a,b,c){var e=this.api(!0),a=e.rows(a),d=a.settings()[0],h=d.aoData[a[0][0]];a.remove();b&&b.call(this,d,h);(c===k||c)&&e.draw();return h};
+this.fnDestroy=function(a){this.api(!0).destroy(a)};this.fnDraw=function(a){this.api(!0).draw(a)};this.fnFilter=function(a,b,c,e,d,h){d=this.api(!0);null===b||b===k?d.search(a,c,e,h):d.column(b).search(a,c,e,h);d.draw()};this.fnGetData=function(a,b){var c=this.api(!0);if(a!==k){var e=a.nodeName?a.nodeName.toLowerCase():"";return b!==k||"td"==e||"th"==e?c.cell(a,b).data():c.row(a).data()||null}return c.data().toArray()};this.fnGetNodes=function(a){var b=this.api(!0);return a!==k?b.row(a).node():b.rows().nodes().flatten().toArray()};
+this.fnGetPosition=function(a){var b=this.api(!0),c=a.nodeName.toUpperCase();return"TR"==c?b.row(a).index():"TD"==c||"TH"==c?(a=b.cell(a).index(),[a.row,a.columnVisible,a.column]):null};this.fnIsOpen=function(a){return this.api(!0).row(a).child.isShown()};this.fnOpen=function(a,b,c){return this.api(!0).row(a).child(b,c).show().child()[0]};this.fnPageChange=function(a,b){var c=this.api(!0).page(a);(b===k||b)&&c.draw(!1)};this.fnSetColumnVis=function(a,b,c){a=this.api(!0).column(a).visible(b);(c===
+k||c)&&a.columns.adjust().draw()};this.fnSettings=function(){return za(this[u.iApiIndex])};this.fnSort=function(a){this.api(!0).order(a).draw()};this.fnSortListener=function(a,b,c){this.api(!0).order.listener(a,b,c)};this.fnUpdate=function(a,b,c,e,d){var h=this.api(!0);c===k||null===c?h.row(b).data(a):h.cell(b,c).data(a);(d===k||d)&&h.columns.adjust();(e===k||e)&&h.draw();return 0};this.fnVersionCheck=u.fnVersionCheck;var b=this,c=a===k,e=this.length;c&&(a={});this.oApi=this.internal=u.internal;for(var d in m.ext.internal)d&&
+(this[d]=Nb(d));this.each(function(){var d={},d=1<e?Lb(d,a,!0):a,g=0,j,i=this.getAttribute("id"),o=!1,l=m.defaults,q=h(this);if("table"!=this.nodeName.toLowerCase())I(null,0,"Non-table node initialisation ("+this.nodeName+")",2);else{eb(l);fb(l.column);H(l,l,!0);H(l.column,l.column,!0);H(l,h.extend(d,q.data()));var n=m.settings,g=0;for(j=n.length;g<j;g++){var r=n[g];if(r.nTable==this||r.nTHead.parentNode==this||r.nTFoot&&r.nTFoot.parentNode==this){g=d.bRetrieve!==k?d.bRetrieve:l.bRetrieve;if(c||g)return r.oInstance;
+if(d.bDestroy!==k?d.bDestroy:l.bDestroy){r.oInstance.fnDestroy();break}else{I(r,0,"Cannot reinitialise DataTable",3);return}}if(r.sTableId==this.id){n.splice(g,1);break}}if(null===i||""===i)this.id=i="DataTables_Table_"+m.ext._unique++;var p=h.extend(!0,{},m.models.oSettings,{sDestroyWidth:q[0].style.width,sInstance:i,sTableId:i});p.nTable=this;p.oApi=b.internal;p.oInit=d;n.push(p);p.oInstance=1===b.length?b:q.dataTable();eb(d);d.oLanguage&&P(d.oLanguage);d.aLengthMenu&&!d.iDisplayLength&&(d.iDisplayLength=
+h.isArray(d.aLengthMenu[0])?d.aLengthMenu[0][0]:d.aLengthMenu[0]);d=Lb(h.extend(!0,{},l),d);E(p.oFeatures,d,"bPaginate bLengthChange bFilter bSort bSortMulti bInfo bProcessing bAutoWidth bSortClasses bServerSide bDeferRender".split(" "));E(p,d,["asStripeClasses","ajax","fnServerData","fnFormatNumber","sServerMethod","aaSorting","aaSortingFixed","aLengthMenu","sPaginationType","sAjaxSource","sAjaxDataProp","iStateDuration","sDom","bSortCellsTop","iTabIndex","fnStateLoadCallback","fnStateSaveCallback",
+"renderer","searchDelay",["iCookieDuration","iStateDuration"],["oSearch","oPreviousSearch"],["aoSearchCols","aoPreSearchCols"],["iDisplayLength","_iDisplayLength"],["bJQueryUI","bJUI"]]);E(p.oScroll,d,[["sScrollX","sX"],["sScrollXInner","sXInner"],["sScrollY","sY"],["bScrollCollapse","bCollapse"]]);E(p.oLanguage,d,"fnInfoCallback");z(p,"aoDrawCallback",d.fnDrawCallback,"user");z(p,"aoServerParams",d.fnServerParams,"user");z(p,"aoStateSaveParams",d.fnStateSaveParams,"user");z(p,"aoStateLoadParams",
+d.fnStateLoadParams,"user");z(p,"aoStateLoaded",d.fnStateLoaded,"user");z(p,"aoRowCallback",d.fnRowCallback,"user");z(p,"aoRowCreatedCallback",d.fnCreatedRow,"user");z(p,"aoHeaderCallback",d.fnHeaderCallback,"user");z(p,"aoFooterCallback",d.fnFooterCallback,"user");z(p,"aoInitComplete",d.fnInitComplete,"user");z(p,"aoPreDrawCallback",d.fnPreDrawCallback,"user");i=p.oClasses;d.bJQueryUI?(h.extend(i,m.ext.oJUIClasses,d.oClasses),d.sDom===l.sDom&&"lfrtip"===l.sDom&&(p.sDom='<"H"lfr>t<"F"ip>'),p.renderer)?
+h.isPlainObject(p.renderer)&&!p.renderer.header&&(p.renderer.header="jqueryui"):p.renderer="jqueryui":h.extend(i,m.ext.classes,d.oClasses);q.addClass(i.sTable);if(""!==p.oScroll.sX||""!==p.oScroll.sY)p.oScroll.iBarWidth=Hb();!0===p.oScroll.sX&&(p.oScroll.sX="100%");p.iInitDisplayStart===k&&(p.iInitDisplayStart=d.iDisplayStart,p._iDisplayStart=d.iDisplayStart);null!==d.iDeferLoading&&(p.bDeferLoading=!0,g=h.isArray(d.iDeferLoading),p._iRecordsDisplay=g?d.iDeferLoading[0]:d.iDeferLoading,p._iRecordsTotal=
+g?d.iDeferLoading[1]:d.iDeferLoading);var t=p.oLanguage;h.extend(!0,t,d.oLanguage);""!==t.sUrl&&(h.ajax({dataType:"json",url:t.sUrl,success:function(a){P(a);H(l.oLanguage,a);h.extend(true,t,a);ga(p)},error:function(){ga(p)}}),o=!0);null===d.asStripeClasses&&(p.asStripeClasses=[i.sStripeOdd,i.sStripeEven]);var g=p.asStripeClasses,s=q.children("tbody").find("tr").eq(0);-1!==h.inArray(!0,h.map(g,function(a){return s.hasClass(a)}))&&(h("tbody tr",this).removeClass(g.join(" ")),p.asDestroyStripes=g.slice());
+n=[];g=this.getElementsByTagName("thead");0!==g.length&&(da(p.aoHeader,g[0]),n=qa(p));if(null===d.aoColumns){r=[];g=0;for(j=n.length;g<j;g++)r.push(null)}else r=d.aoColumns;g=0;for(j=r.length;g<j;g++)Fa(p,n?n[g]:null);ib(p,d.aoColumnDefs,r,function(a,b){ka(p,a,b)});if(s.length){var u=function(a,b){return a.getAttribute("data-"+b)!==null?b:null};h.each(na(p,s[0]).cells,function(a,b){var c=p.aoColumns[a];if(c.mData===a){var d=u(b,"sort")||u(b,"order"),e=u(b,"filter")||u(b,"search");if(d!==null||e!==
+null){c.mData={_:a+".display",sort:d!==null?a+".@data-"+d:k,type:d!==null?a+".@data-"+d:k,filter:e!==null?a+".@data-"+e:k};ka(p,a)}}})}var v=p.oFeatures;d.bStateSave&&(v.bStateSave=!0,Kb(p,d),z(p,"aoDrawCallback",ya,"state_save"));if(d.aaSorting===k){n=p.aaSorting;g=0;for(j=n.length;g<j;g++)n[g][1]=p.aoColumns[g].asSorting[0]}xa(p);v.bSort&&z(p,"aoDrawCallback",function(){if(p.bSorted){var a=U(p),b={};h.each(a,function(a,c){b[c.src]=c.dir});w(p,null,"order",[p,a,b]);Jb(p)}});z(p,"aoDrawCallback",
+function(){(p.bSorted||B(p)==="ssp"||v.bDeferRender)&&xa(p)},"sc");gb(p);g=q.children("caption").each(function(){this._captionSide=q.css("caption-side")});j=q.children("thead");0===j.length&&(j=h("<thead/>").appendTo(this));p.nTHead=j[0];j=q.children("tbody");0===j.length&&(j=h("<tbody/>").appendTo(this));p.nTBody=j[0];j=q.children("tfoot");if(0===j.length&&0<g.length&&(""!==p.oScroll.sX||""!==p.oScroll.sY))j=h("<tfoot/>").appendTo(this);0===j.length||0===j.children().length?q.addClass(i.sNoFooter):
+0<j.length&&(p.nTFoot=j[0],da(p.aoFooter,p.nTFoot));if(d.aaData)for(g=0;g<d.aaData.length;g++)K(p,d.aaData[g]);else(p.bDeferLoading||"dom"==B(p))&&ma(p,h(p.nTBody).children("tr"));p.aiDisplay=p.aiDisplayMaster.slice();p.bInitialised=!0;!1===o&&ga(p)}});b=null;return this};var Tb=[],y=Array.prototype,cc=function(a){var b,c,e=m.settings,d=h.map(e,function(a){return a.nTable});if(a){if(a.nTable&&a.oApi)return[a];if(a.nodeName&&"table"===a.nodeName.toLowerCase())return b=h.inArray(a,d),-1!==b?[e[b]]:
+null;if(a&&"function"===typeof a.settings)return a.settings().toArray();"string"===typeof a?c=h(a):a instanceof h&&(c=a)}else return[];if(c)return c.map(function(){b=h.inArray(this,d);return-1!==b?e[b]:null}).toArray()};t=function(a,b){if(!(this instanceof t))return new t(a,b);var c=[],e=function(a){(a=cc(a))&&c.push.apply(c,a)};if(h.isArray(a))for(var d=0,f=a.length;d<f;d++)e(a[d]);else e(a);this.context=Na(c);b&&this.push.apply(this,b.toArray?b.toArray():b);this.selector={rows:null,cols:null,opts:null};
+t.extend(this,this,Tb)};m.Api=t;t.prototype={any:function(){return 0!==this.flatten().length},concat:y.concat,context:[],each:function(a){for(var b=0,c=this.length;b<c;b++)a.call(this,this[b],b,this);return this},eq:function(a){var b=this.context;return b.length>a?new t(b[a],this[a]):null},filter:function(a){var b=[];if(y.filter)b=y.filter.call(this,a,this);else for(var c=0,e=this.length;c<e;c++)a.call(this,this[c],c,this)&&b.push(this[c]);return new t(this.context,b)},flatten:function(){var a=[];
+return new t(this.context,a.concat.apply(a,this.toArray()))},join:y.join,indexOf:y.indexOf||function(a,b){for(var c=b||0,e=this.length;c<e;c++)if(this[c]===a)return c;return-1},iterator:function(a,b,c,e){var d=[],f,g,h,i,o,l=this.context,q,n,m=this.selector;"string"===typeof a&&(e=c,c=b,b=a,a=!1);g=0;for(h=l.length;g<h;g++){var p=new t(l[g]);if("table"===b)f=c.call(p,l[g],g),f!==k&&d.push(f);else if("columns"===b||"rows"===b)f=c.call(p,l[g],this[g],g),f!==k&&d.push(f);else if("column"===b||"column-rows"===
+b||"row"===b||"cell"===b){n=this[g];"column-rows"===b&&(q=Ca(l[g],m.opts));i=0;for(o=n.length;i<o;i++)f=n[i],f="cell"===b?c.call(p,l[g],f.row,f.column,g,i):c.call(p,l[g],f,g,i,q),f!==k&&d.push(f)}}return d.length||e?(a=new t(l,a?d.concat.apply([],d):d),b=a.selector,b.rows=m.rows,b.cols=m.cols,b.opts=m.opts,a):this},lastIndexOf:y.lastIndexOf||function(a,b){return this.indexOf.apply(this.toArray.reverse(),arguments)},length:0,map:function(a){var b=[];if(y.map)b=y.map.call(this,a,this);else for(var c=
+0,e=this.length;c<e;c++)b.push(a.call(this,this[c],c));return new t(this.context,b)},pluck:function(a){return this.map(function(b){return b[a]})},pop:y.pop,push:y.push,reduce:y.reduce||function(a,b){return hb(this,a,b,0,this.length,1)},reduceRight:y.reduceRight||function(a,b){return hb(this,a,b,this.length-1,-1,-1)},reverse:y.reverse,selector:null,shift:y.shift,sort:y.sort,splice:y.splice,toArray:function(){return y.slice.call(this)},to$:function(){return h(this)},toJQuery:function(){return h(this)},
+unique:function(){return new t(this.context,Na(this))},unshift:y.unshift};t.extend=function(a,b,c){if(c.length&&b&&(b instanceof t||b.__dt_wrapper)){var e,d,f,g=function(a,b,c){return function(){var d=b.apply(a,arguments);t.extend(d,d,c.methodExt);return d}};e=0;for(d=c.length;e<d;e++)f=c[e],b[f.name]="function"===typeof f.val?g(a,f.val,f):h.isPlainObject(f.val)?{}:f.val,b[f.name].__dt_wrapper=!0,t.extend(a,b[f.name],f.propExt)}};t.register=r=function(a,b){if(h.isArray(a))for(var c=0,e=a.length;c<
+e;c++)t.register(a[c],b);else for(var d=a.split("."),f=Tb,g,j,c=0,e=d.length;c<e;c++){g=(j=-1!==d[c].indexOf("()"))?d[c].replace("()",""):d[c];var i;a:{i=0;for(var o=f.length;i<o;i++)if(f[i].name===g){i=f[i];break a}i=null}i||(i={name:g,val:{},methodExt:[],propExt:[]},f.push(i));c===e-1?i.val=b:f=j?i.methodExt:i.propExt}};t.registerPlural=v=function(a,b,c){t.register(a,c);t.register(b,function(){var a=c.apply(this,arguments);return a===this?this:a instanceof t?a.length?h.isArray(a[0])?new t(a.context,
+a[0]):a[0]:k:a})};r("tables()",function(a){var b;if(a){b=t;var c=this.context;if("number"===typeof a)a=[c[a]];else var e=h.map(c,function(a){return a.nTable}),a=h(e).filter(a).map(function(){var a=h.inArray(this,e);return c[a]}).toArray();b=new b(a)}else b=this;return b});r("table()",function(a){var a=this.tables(a),b=a.context;return b.length?new t(b[0]):a});v("tables().nodes()","table().node()",function(){return this.iterator("table",function(a){return a.nTable},1)});v("tables().body()","table().body()",
+function(){return this.iterator("table",function(a){return a.nTBody},1)});v("tables().header()","table().header()",function(){return this.iterator("table",function(a){return a.nTHead},1)});v("tables().footer()","table().footer()",function(){return this.iterator("table",function(a){return a.nTFoot},1)});v("tables().containers()","table().container()",function(){return this.iterator("table",function(a){return a.nTableWrapper},1)});r("draw()",function(a){return this.iterator("table",function(b){N(b,
+!1===a)})});r("page()",function(a){return a===k?this.page.info().page:this.iterator("table",function(b){Ta(b,a)})});r("page.info()",function(){if(0===this.context.length)return k;var a=this.context[0],b=a._iDisplayStart,c=a._iDisplayLength,e=a.fnRecordsDisplay(),d=-1===c;return{page:d?0:Math.floor(b/c),pages:d?1:Math.ceil(e/c),start:b,end:a.fnDisplayEnd(),length:c,recordsTotal:a.fnRecordsTotal(),recordsDisplay:e}});r("page.len()",function(a){return a===k?0!==this.context.length?this.context[0]._iDisplayLength:
+k:this.iterator("table",function(b){Ra(b,a)})});var Ub=function(a,b,c){if(c){var e=new t(a);e.one("draw",function(){c(e.ajax.json())})}"ssp"==B(a)?N(a,b):(C(a,!0),ra(a,[],function(c){oa(a);for(var c=sa(a,c),e=0,g=c.length;e<g;e++)K(a,c[e]);N(a,b);C(a,!1)}))};r("ajax.json()",function(){var a=this.context;if(0<a.length)return a[0].json});r("ajax.params()",function(){var a=this.context;if(0<a.length)return a[0].oAjaxData});r("ajax.reload()",function(a,b){return this.iterator("table",function(c){Ub(c,
+!1===b,a)})});r("ajax.url()",function(a){var b=this.context;if(a===k){if(0===b.length)return k;b=b[0];return b.ajax?h.isPlainObject(b.ajax)?b.ajax.url:b.ajax:b.sAjaxSource}return this.iterator("table",function(b){h.isPlainObject(b.ajax)?b.ajax.url=a:b.ajax=a})});r("ajax.url().load()",function(a,b){return this.iterator("table",function(c){Ub(c,!1===b,a)})});var $a=function(a,b,c,e,d){var f=[],g,j,i,o,l,q;i=typeof b;if(!b||"string"===i||"function"===i||b.length===k)b=[b];i=0;for(o=b.length;i<o;i++){j=
+b[i]&&b[i].split?b[i].split(","):[b[i]];l=0;for(q=j.length;l<q;l++)(g=c("string"===typeof j[l]?h.trim(j[l]):j[l]))&&g.length&&f.push.apply(f,g)}a=u.selector[a];if(a.length){i=0;for(o=a.length;i<o;i++)f=a[i](e,d,f)}return f},ab=function(a){a||(a={});a.filter&&a.search===k&&(a.search=a.filter);return h.extend({search:"none",order:"current",page:"all"},a)},bb=function(a){for(var b=0,c=a.length;b<c;b++)if(0<a[b].length)return a[0]=a[b],a[0].length=1,a.length=1,a.context=[a.context[b]],a;a.length=0;return a},
+Ca=function(a,b){var c,e,d,f=[],g=a.aiDisplay;c=a.aiDisplayMaster;var j=b.search;e=b.order;d=b.page;if("ssp"==B(a))return"removed"===j?[]:V(0,c.length);if("current"==d){c=a._iDisplayStart;for(e=a.fnDisplayEnd();c<e;c++)f.push(g[c])}else if("current"==e||"applied"==e)f="none"==j?c.slice():"applied"==j?g.slice():h.map(c,function(a){return-1===h.inArray(a,g)?a:null});else if("index"==e||"original"==e){c=0;for(e=a.aoData.length;c<e;c++)"none"==j?f.push(c):(d=h.inArray(c,g),(-1===d&&"removed"==j||0<=d&&
+"applied"==j)&&f.push(c))}return f};r("rows()",function(a,b){a===k?a="":h.isPlainObject(a)&&(b=a,a="");var b=ab(b),c=this.iterator("table",function(c){var d=b;return $a("row",a,function(a){var b=Pb(a);if(b!==null&&!d)return[b];var j=Ca(c,d);if(b!==null&&h.inArray(b,j)!==-1)return[b];if(!a)return j;if(typeof a==="function")return h.map(j,function(b){var d=c.aoData[b];return a(b,d._aData,d.nTr)?b:null});b=Sb(ia(c.aoData,j,"nTr"));return a.nodeName&&h.inArray(a,b)!==-1?[a._DT_RowIndex]:h(b).filter(a).map(function(){return this._DT_RowIndex}).toArray()},
+c,d)},1);c.selector.rows=a;c.selector.opts=b;return c});r("rows().nodes()",function(){return this.iterator("row",function(a,b){return a.aoData[b].nTr||k},1)});r("rows().data()",function(){return this.iterator(!0,"rows",function(a,b){return ia(a.aoData,b,"_aData")},1)});v("rows().cache()","row().cache()",function(a){return this.iterator("row",function(b,c){var e=b.aoData[c];return"search"===a?e._aFilterData:e._aSortData},1)});v("rows().invalidate()","row().invalidate()",function(a){return this.iterator("row",
+function(b,c){ca(b,c,a)})});v("rows().indexes()","row().index()",function(){return this.iterator("row",function(a,b){return b},1)});v("rows().remove()","row().remove()",function(){var a=this;return this.iterator("row",function(b,c,e){var d=b.aoData;d.splice(c,1);for(var f=0,g=d.length;f<g;f++)null!==d[f].nTr&&(d[f].nTr._DT_RowIndex=f);h.inArray(c,b.aiDisplay);pa(b.aiDisplayMaster,c);pa(b.aiDisplay,c);pa(a[e],c,!1);Sa(b)})});r("rows.add()",function(a){var b=this.iterator("table",function(b){var c,
+f,g,h=[];f=0;for(g=a.length;f<g;f++)c=a[f],c.nodeName&&"TR"===c.nodeName.toUpperCase()?h.push(ma(b,c)[0]):h.push(K(b,c));return h},1),c=this.rows(-1);c.pop();c.push.apply(c,b.toArray());return c});r("row()",function(a,b){return bb(this.rows(a,b))});r("row().data()",function(a){var b=this.context;if(a===k)return b.length&&this.length?b[0].aoData[this[0]]._aData:k;b[0].aoData[this[0]]._aData=a;ca(b[0],this[0],"data");return this});r("row().node()",function(){var a=this.context;return a.length&&this.length?
+a[0].aoData[this[0]].nTr||null:null});r("row.add()",function(a){a instanceof h&&a.length&&(a=a[0]);var b=this.iterator("table",function(b){return a.nodeName&&"TR"===a.nodeName.toUpperCase()?ma(b,a)[0]:K(b,a)});return this.row(b[0])});var cb=function(a,b){var c=a.context;c.length&&(c=c[0].aoData[b!==k?b:a[0]],c._details&&(c._details.remove(),c._detailsShow=k,c._details=k))},Vb=function(a,b){var c=a.context;if(c.length&&a.length){var e=c[0].aoData[a[0]];if(e._details){(e._detailsShow=b)?e._details.insertAfter(e.nTr):
+e._details.detach();var d=c[0],f=new t(d),g=d.aoData;f.off("draw.dt.DT_details column-visibility.dt.DT_details destroy.dt.DT_details");0<D(g,"_details").length&&(f.on("draw.dt.DT_details",function(a,b){d===b&&f.rows({page:"current"}).eq(0).each(function(a){a=g[a];a._detailsShow&&a._details.insertAfter(a.nTr)})}),f.on("column-visibility.dt.DT_details",function(a,b){if(d===b)for(var c,e=aa(b),f=0,h=g.length;f<h;f++)c=g[f],c._details&&c._details.children("td[colspan]").attr("colspan",e)}),f.on("destroy.dt.DT_details",
+function(a,b){if(d===b)for(var c=0,e=g.length;c<e;c++)g[c]._details&&cb(f,c)}))}}};r("row().child()",function(a,b){var c=this.context;if(a===k)return c.length&&this.length?c[0].aoData[this[0]]._details:k;if(!0===a)this.child.show();else if(!1===a)cb(this);else if(c.length&&this.length){var e=c[0],c=c[0].aoData[this[0]],d=[],f=function(a,b){if(h.isArray(a)||a instanceof h)for(var c=0,k=a.length;c<k;c++)f(a[c],b);else a.nodeName&&"tr"===a.nodeName.toLowerCase()?d.push(a):(c=h("<tr><td/></tr>").addClass(b),
+h("td",c).addClass(b).html(a)[0].colSpan=aa(e),d.push(c[0]))};f(a,b);c._details&&c._details.remove();c._details=h(d);c._detailsShow&&c._details.insertAfter(c.nTr)}return this});r(["row().child.show()","row().child().show()"],function(){Vb(this,!0);return this});r(["row().child.hide()","row().child().hide()"],function(){Vb(this,!1);return this});r(["row().child.remove()","row().child().remove()"],function(){cb(this);return this});r("row().child.isShown()",function(){var a=this.context;return a.length&&
+this.length?a[0].aoData[this[0]]._detailsShow||!1:!1});var dc=/^(.+):(name|visIdx|visible)$/,Wb=function(a,b,c,e,d){for(var c=[],e=0,f=d.length;e<f;e++)c.push(x(a,d[e],b));return c};r("columns()",function(a,b){a===k?a="":h.isPlainObject(a)&&(b=a,a="");var b=ab(b),c=this.iterator("table",function(c){var d=a,f=b,g=c.aoColumns,j=D(g,"sName"),i=D(g,"nTh");return $a("column",d,function(a){var b=Pb(a);if(a==="")return V(g.length);if(b!==null)return[b>=0?b:g.length+b];if(typeof a==="function"){var d=Ca(c,
+f);return h.map(g,function(b,f){return a(f,Wb(c,f,0,0,d),i[f])?f:null})}var k=typeof a==="string"?a.match(dc):"";if(k)switch(k[2]){case "visIdx":case "visible":b=parseInt(k[1],10);if(b<0){var m=h.map(g,function(a,b){return a.bVisible?b:null});return[m[m.length+b]]}return[la(c,b)];case "name":return h.map(j,function(a,b){return a===k[1]?b:null})}else return h(i).filter(a).map(function(){return h.inArray(this,i)}).toArray()},c,f)},1);c.selector.cols=a;c.selector.opts=b;return c});v("columns().header()",
+"column().header()",function(){return this.iterator("column",function(a,b){return a.aoColumns[b].nTh},1)});v("columns().footer()","column().footer()",function(){return this.iterator("column",function(a,b){return a.aoColumns[b].nTf},1)});v("columns().data()","column().data()",function(){return this.iterator("column-rows",Wb,1)});v("columns().dataSrc()","column().dataSrc()",function(){return this.iterator("column",function(a,b){return a.aoColumns[b].mData},1)});v("columns().cache()","column().cache()",
+function(a){return this.iterator("column-rows",function(b,c,e,d,f){return ia(b.aoData,f,"search"===a?"_aFilterData":"_aSortData",c)},1)});v("columns().nodes()","column().nodes()",function(){return this.iterator("column-rows",function(a,b,c,e,d){return ia(a.aoData,d,"anCells",b)},1)});v("columns().visible()","column().visible()",function(a,b){return this.iterator("column",function(c,e){if(a===k)return c.aoColumns[e].bVisible;var d=c.aoColumns,f=d[e],g=c.aoData,j,i,m;if(a!==k&&f.bVisible!==a){if(a){var l=
+h.inArray(!0,D(d,"bVisible"),e+1);j=0;for(i=g.length;j<i;j++)m=g[j].nTr,d=g[j].anCells,m&&m.insertBefore(d[e],d[l]||null)}else h(D(c.aoData,"anCells",e)).detach();f.bVisible=a;ea(c,c.aoHeader);ea(c,c.aoFooter);if(b===k||b)X(c),(c.oScroll.sX||c.oScroll.sY)&&Y(c);w(c,null,"column-visibility",[c,e,a]);ya(c)}})});v("columns().indexes()","column().index()",function(a){return this.iterator("column",function(b,c){return"visible"===a?$(b,c):c},1)});r("columns.adjust()",function(){return this.iterator("table",
+function(a){X(a)},1)});r("column.index()",function(a,b){if(0!==this.context.length){var c=this.context[0];if("fromVisible"===a||"toData"===a)return la(c,b);if("fromData"===a||"toVisible"===a)return $(c,b)}});r("column()",function(a,b){return bb(this.columns(a,b))});r("cells()",function(a,b,c){h.isPlainObject(a)&&(a.row===k?(c=a,a=null):(c=b,b=null));h.isPlainObject(b)&&(c=b,b=null);if(null===b||b===k)return this.iterator("table",function(b){var d=a,e=ab(c),f=b.aoData,g=Ca(b,e),i=Sb(ia(f,g,"anCells")),
+j=h([].concat.apply([],i)),l,m=b.aoColumns.length,o,r,t,s,u,v;return $a("cell",d,function(a){var c=typeof a==="function";if(a===null||a===k||c){o=[];r=0;for(t=g.length;r<t;r++){l=g[r];for(s=0;s<m;s++){u={row:l,column:s};if(c){v=b.aoData[l];a(u,x(b,l,s),v.anCells?v.anCells[s]:null)&&o.push(u)}else o.push(u)}}return o}return h.isPlainObject(a)?[a]:j.filter(a).map(function(a,b){l=b.parentNode._DT_RowIndex;return{row:l,column:h.inArray(b,f[l].anCells)}}).toArray()},b,e)});var e=this.columns(b,c),d=this.rows(a,
+c),f,g,j,i,m,l=this.iterator("table",function(a,b){f=[];g=0;for(j=d[b].length;g<j;g++){i=0;for(m=e[b].length;i<m;i++)f.push({row:d[b][g],column:e[b][i]})}return f},1);h.extend(l.selector,{cols:b,rows:a,opts:c});return l});v("cells().nodes()","cell().node()",function(){return this.iterator("cell",function(a,b,c){return(a=a.aoData[b].anCells)?a[c]:k},1)});r("cells().data()",function(){return this.iterator("cell",function(a,b,c){return x(a,b,c)},1)});v("cells().cache()","cell().cache()",function(a){a=
+"search"===a?"_aFilterData":"_aSortData";return this.iterator("cell",function(b,c,e){return b.aoData[c][a][e]},1)});v("cells().render()","cell().render()",function(a){return this.iterator("cell",function(b,c,e){return x(b,c,e,a)},1)});v("cells().indexes()","cell().index()",function(){return this.iterator("cell",function(a,b,c){return{row:b,column:c,columnVisible:$(a,c)}},1)});v("cells().invalidate()","cell().invalidate()",function(a){return this.iterator("cell",function(b,c,e){ca(b,c,a,e)})});r("cell()",
+function(a,b,c){return bb(this.cells(a,b,c))});r("cell().data()",function(a){var b=this.context,c=this[0];if(a===k)return b.length&&c.length?x(b[0],c[0].row,c[0].column):k;Ia(b[0],c[0].row,c[0].column,a);ca(b[0],c[0].row,"data",c[0].column);return this});r("order()",function(a,b){var c=this.context;if(a===k)return 0!==c.length?c[0].aaSorting:k;"number"===typeof a?a=[[a,b]]:h.isArray(a[0])||(a=Array.prototype.slice.call(arguments));return this.iterator("table",function(b){b.aaSorting=a.slice()})});
+r("order.listener()",function(a,b,c){return this.iterator("table",function(e){Oa(e,a,b,c)})});r(["columns().order()","column().order()"],function(a){var b=this;return this.iterator("table",function(c,e){var d=[];h.each(b[e],function(b,c){d.push([c,a])});c.aaSorting=d})});r("search()",function(a,b,c,e){var d=this.context;return a===k?0!==d.length?d[0].oPreviousSearch.sSearch:k:this.iterator("table",function(d){d.oFeatures.bFilter&&fa(d,h.extend({},d.oPreviousSearch,{sSearch:a+"",bRegex:null===b?!1:
+b,bSmart:null===c?!0:c,bCaseInsensitive:null===e?!0:e}),1)})});v("columns().search()","column().search()",function(a,b,c,e){return this.iterator("column",function(d,f){var g=d.aoPreSearchCols;if(a===k)return g[f].sSearch;d.oFeatures.bFilter&&(h.extend(g[f],{sSearch:a+"",bRegex:null===b?!1:b,bSmart:null===c?!0:c,bCaseInsensitive:null===e?!0:e}),fa(d,d.oPreviousSearch,1))})});r("state()",function(){return this.context.length?this.context[0].oSavedState:null});r("state.clear()",function(){return this.iterator("table",
+function(a){a.fnStateSaveCallback.call(a.oInstance,a,{})})});r("state.loaded()",function(){return this.context.length?this.context[0].oLoadedState:null});r("state.save()",function(){return this.iterator("table",function(a){ya(a)})});m.versionCheck=m.fnVersionCheck=function(a){for(var b=m.version.split("."),a=a.split("."),c,e,d=0,f=a.length;d<f;d++)if(c=parseInt(b[d],10)||0,e=parseInt(a[d],10)||0,c!==e)return c>e;return!0};m.isDataTable=m.fnIsDataTable=function(a){var b=h(a).get(0),c=!1;h.each(m.settings,
+function(a,d){var f=d.nScrollHead?h("table",d.nScrollHead)[0]:null,g=d.nScrollFoot?h("table",d.nScrollFoot)[0]:null;if(d.nTable===b||f===b||g===b)c=!0});return c};m.tables=m.fnTables=function(a){return h.map(m.settings,function(b){if(!a||a&&h(b.nTable).is(":visible"))return b.nTable})};m.util={throttle:ua,escapeRegex:va};m.camelToHungarian=H;r("$()",function(a,b){var c=this.rows(b).nodes(),c=h(c);return h([].concat(c.filter(a).toArray(),c.find(a).toArray()))});h.each(["on","one","off"],function(a,
+b){r(b+"()",function(){var a=Array.prototype.slice.call(arguments);a[0].match(/\.dt\b/)||(a[0]+=".dt");var e=h(this.tables().nodes());e[b].apply(e,a);return this})});r("clear()",function(){return this.iterator("table",function(a){oa(a)})});r("settings()",function(){return new t(this.context,this.context)});r("init()",function(){var a=this.context;return a.length?a[0].oInit:null});r("data()",function(){return this.iterator("table",function(a){return D(a.aoData,"_aData")}).flatten()});r("destroy()",
+function(a){a=a||!1;return this.iterator("table",function(b){var c=b.nTableWrapper.parentNode,e=b.oClasses,d=b.nTable,f=b.nTBody,g=b.nTHead,j=b.nTFoot,i=h(d),f=h(f),k=h(b.nTableWrapper),l=h.map(b.aoData,function(a){return a.nTr}),q;b.bDestroying=!0;w(b,"aoDestroyCallback","destroy",[b]);a||(new t(b)).columns().visible(!0);k.unbind(".DT").find(":not(tbody *)").unbind(".DT");h(Ea).unbind(".DT-"+b.sInstance);d!=g.parentNode&&(i.children("thead").detach(),i.append(g));j&&d!=j.parentNode&&(i.children("tfoot").detach(),
+i.append(j));i.detach();k.detach();b.aaSorting=[];b.aaSortingFixed=[];xa(b);h(l).removeClass(b.asStripeClasses.join(" "));h("th, td",g).removeClass(e.sSortable+" "+e.sSortableAsc+" "+e.sSortableDesc+" "+e.sSortableNone);b.bJUI&&(h("th span."+e.sSortIcon+", td span."+e.sSortIcon,g).detach(),h("th, td",g).each(function(){var a=h("div."+e.sSortJUIWrapper,this);h(this).append(a.contents());a.detach()}));!a&&c&&c.insertBefore(d,b.nTableReinsertBefore);f.children().detach();f.append(l);i.css("width",b.sDestroyWidth).removeClass(e.sTable);
+(q=b.asDestroyStripes.length)&&f.children().each(function(a){h(this).addClass(b.asDestroyStripes[a%q])});c=h.inArray(b,m.settings);-1!==c&&m.settings.splice(c,1)})});h.each(["column","row","cell"],function(a,b){r(b+"s().every()",function(a){return this.iterator(b,function(e,d,f){a.call((new t(e))[b](d,f))})})});r("i18n()",function(a,b,c){var e=this.context[0],a=R(a)(e.oLanguage);a===k&&(a=b);c!==k&&h.isPlainObject(a)&&(a=a[c]!==k?a[c]:a._);return a.replace("%d",c)});m.version="1.10.7";m.settings=
+[];m.models={};m.models.oSearch={bCaseInsensitive:!0,sSearch:"",bRegex:!1,bSmart:!0};m.models.oRow={nTr:null,anCells:null,_aData:[],_aSortData:null,_aFilterData:null,_sFilterRow:null,_sRowStripe:"",src:null};m.models.oColumn={idx:null,aDataSort:null,asSorting:null,bSearchable:null,bSortable:null,bVisible:null,_sManualType:null,_bAttrSrc:!1,fnCreatedCell:null,fnGetData:null,fnSetData:null,mData:null,mRender:null,nTh:null,nTf:null,sClass:null,sContentPadding:null,sDefaultContent:null,sName:null,sSortDataType:"std",
+sSortingClass:null,sSortingClassJUI:null,sTitle:null,sType:null,sWidth:null,sWidthOrig:null};m.defaults={aaData:null,aaSorting:[[0,"asc"]],aaSortingFixed:[],ajax:null,aLengthMenu:[10,25,50,100],aoColumns:null,aoColumnDefs:null,aoSearchCols:[],asStripeClasses:null,bAutoWidth:!0,bDeferRender:!1,bDestroy:!1,bFilter:!0,bInfo:!0,bJQueryUI:!1,bLengthChange:!0,bPaginate:!0,bProcessing:!1,bRetrieve:!1,bScrollCollapse:!1,bServerSide:!1,bSort:!0,bSortMulti:!0,bSortCellsTop:!1,bSortClasses:!0,bStateSave:!1,
+fnCreatedRow:null,fnDrawCallback:null,fnFooterCallback:null,fnFormatNumber:function(a){return a.toString().replace(/\B(?=(\d{3})+(?!\d))/g,this.oLanguage.sThousands)},fnHeaderCallback:null,fnInfoCallback:null,fnInitComplete:null,fnPreDrawCallback:null,fnRowCallback:null,fnServerData:null,fnServerParams:null,fnStateLoadCallback:function(a){try{return JSON.parse((-1===a.iStateDuration?sessionStorage:localStorage).getItem("DataTables_"+a.sInstance+"_"+location.pathname))}catch(b){}},fnStateLoadParams:null,
+fnStateLoaded:null,fnStateSaveCallback:function(a,b){try{(-1===a.iStateDuration?sessionStorage:localStorage).setItem("DataTables_"+a.sInstance+"_"+location.pathname,JSON.stringify(b))}catch(c){}},fnStateSaveParams:null,iStateDuration:7200,iDeferLoading:null,iDisplayLength:10,iDisplayStart:0,iTabIndex:0,oClasses:{},oLanguage:{oAria:{sSortAscending:": activate to sort column ascending",sSortDescending:": activate to sort column descending"},oPaginate:{sFirst:"First",sLast:"Last",sNext:"Next",sPrevious:"Previous"},
+sEmptyTable:"No data available in table",sInfo:"Showing _START_ to _END_ of _TOTAL_ entries",sInfoEmpty:"Showing 0 to 0 of 0 entries",sInfoFiltered:"(filtered from _MAX_ total entries)",sInfoPostFix:"",sDecimal:"",sThousands:",",sLengthMenu:"Show _MENU_ entries",sLoadingRecords:"Loading...",sProcessing:"Processing...",sSearch:"Search:",sSearchPlaceholder:"",sUrl:"",sZeroRecords:"No matching records found"},oSearch:h.extend({},m.models.oSearch),sAjaxDataProp:"data",sAjaxSource:null,sDom:"lfrtip",searchDelay:null,
+sPaginationType:"simple_numbers",sScrollX:"",sScrollXInner:"",sScrollY:"",sServerMethod:"GET",renderer:null};W(m.defaults);m.defaults.column={aDataSort:null,iDataSort:-1,asSorting:["asc","desc"],bSearchable:!0,bSortable:!0,bVisible:!0,fnCreatedCell:null,mData:null,mRender:null,sCellType:"td",sClass:"",sContentPadding:"",sDefaultContent:null,sName:"",sSortDataType:"std",sTitle:null,sType:null,sWidth:null};W(m.defaults.column);m.models.oSettings={oFeatures:{bAutoWidth:null,bDeferRender:null,bFilter:null,
+bInfo:null,bLengthChange:null,bPaginate:null,bProcessing:null,bServerSide:null,bSort:null,bSortMulti:null,bSortClasses:null,bStateSave:null},oScroll:{bCollapse:null,iBarWidth:0,sX:null,sXInner:null,sY:null},oLanguage:{fnInfoCallback:null},oBrowser:{bScrollOversize:!1,bScrollbarLeft:!1},ajax:null,aanFeatures:[],aoData:[],aiDisplay:[],aiDisplayMaster:[],aoColumns:[],aoHeader:[],aoFooter:[],oPreviousSearch:{},aoPreSearchCols:[],aaSorting:null,aaSortingFixed:[],asStripeClasses:null,asDestroyStripes:[],
+sDestroyWidth:0,aoRowCallback:[],aoHeaderCallback:[],aoFooterCallback:[],aoDrawCallback:[],aoRowCreatedCallback:[],aoPreDrawCallback:[],aoInitComplete:[],aoStateSaveParams:[],aoStateLoadParams:[],aoStateLoaded:[],sTableId:"",nTable:null,nTHead:null,nTFoot:null,nTBody:null,nTableWrapper:null,bDeferLoading:!1,bInitialised:!1,aoOpenRows:[],sDom:null,searchDelay:null,sPaginationType:"two_button",iStateDuration:0,aoStateSave:[],aoStateLoad:[],oSavedState:null,oLoadedState:null,sAjaxSource:null,sAjaxDataProp:null,
+bAjaxDataGet:!0,jqXHR:null,json:k,oAjaxData:k,fnServerData:null,aoServerParams:[],sServerMethod:null,fnFormatNumber:null,aLengthMenu:null,iDraw:0,bDrawing:!1,iDrawError:-1,_iDisplayLength:10,_iDisplayStart:0,_iRecordsTotal:0,_iRecordsDisplay:0,bJUI:null,oClasses:{},bFiltered:!1,bSorted:!1,bSortCellsTop:null,oInit:null,aoDestroyCallback:[],fnRecordsTotal:function(){return"ssp"==B(this)?1*this._iRecordsTotal:this.aiDisplayMaster.length},fnRecordsDisplay:function(){return"ssp"==B(this)?1*this._iRecordsDisplay:
+this.aiDisplay.length},fnDisplayEnd:function(){var a=this._iDisplayLength,b=this._iDisplayStart,c=b+a,e=this.aiDisplay.length,d=this.oFeatures,f=d.bPaginate;return d.bServerSide?!1===f||-1===a?b+e:Math.min(b+a,this._iRecordsDisplay):!f||c>e||-1===a?e:c},oInstance:null,sInstance:null,iTabIndex:0,nScrollHead:null,nScrollFoot:null,aLastSort:[],oPlugins:{}};m.ext=u={buttons:{},classes:{},errMode:"alert",feature:[],search:[],selector:{cell:[],column:[],row:[]},internal:{},legacy:{ajax:null},pager:{},renderer:{pageButton:{},
+header:{}},order:{},type:{detect:[],search:{},order:{}},_unique:0,fnVersionCheck:m.fnVersionCheck,iApiIndex:0,oJUIClasses:{},sVersion:m.version};h.extend(u,{afnFiltering:u.search,aTypes:u.type.detect,ofnSearch:u.type.search,oSort:u.type.order,afnSortData:u.order,aoFeatures:u.feature,oApi:u.internal,oStdClasses:u.classes,oPagination:u.pager});h.extend(m.ext.classes,{sTable:"dataTable",sNoFooter:"no-footer",sPageButton:"paginate_button",sPageButtonActive:"current",sPageButtonDisabled:"disabled",sStripeOdd:"odd",
+sStripeEven:"even",sRowEmpty:"dataTables_empty",sWrapper:"dataTables_wrapper",sFilter:"dataTables_filter",sInfo:"dataTables_info",sPaging:"dataTables_paginate paging_",sLength:"dataTables_length",sProcessing:"dataTables_processing",sSortAsc:"sorting_asc",sSortDesc:"sorting_desc",sSortable:"sorting",sSortableAsc:"sorting_asc_disabled",sSortableDesc:"sorting_desc_disabled",sSortableNone:"sorting_disabled",sSortColumn:"sorting_",sFilterInput:"",sLengthSelect:"",sScrollWrapper:"dataTables_scroll",sScrollHead:"dataTables_scrollHead",
+sScrollHeadInner:"dataTables_scrollHeadInner",sScrollBody:"dataTables_scrollBody",sScrollFoot:"dataTables_scrollFoot",sScrollFootInner:"dataTables_scrollFootInner",sHeaderTH:"",sFooterTH:"",sSortJUIAsc:"",sSortJUIDesc:"",sSortJUI:"",sSortJUIAscAllowed:"",sSortJUIDescAllowed:"",sSortJUIWrapper:"",sSortIcon:"",sJUIHeader:"",sJUIFooter:""});var Da="",Da="",F=Da+"ui-state-default",ja=Da+"css_right ui-icon ui-icon-",Xb=Da+"fg-toolbar ui-toolbar ui-widget-header ui-helper-clearfix";h.extend(m.ext.oJUIClasses,
+m.ext.classes,{sPageButton:"fg-button ui-button "+F,sPageButtonActive:"ui-state-disabled",sPageButtonDisabled:"ui-state-disabled",sPaging:"dataTables_paginate fg-buttonset ui-buttonset fg-buttonset-multi ui-buttonset-multi paging_",sSortAsc:F+" sorting_asc",sSortDesc:F+" sorting_desc",sSortable:F+" sorting",sSortableAsc:F+" sorting_asc_disabled",sSortableDesc:F+" sorting_desc_disabled",sSortableNone:F+" sorting_disabled",sSortJUIAsc:ja+"triangle-1-n",sSortJUIDesc:ja+"triangle-1-s",sSortJUI:ja+"carat-2-n-s",
+sSortJUIAscAllowed:ja+"carat-1-n",sSortJUIDescAllowed:ja+"carat-1-s",sSortJUIWrapper:"DataTables_sort_wrapper",sSortIcon:"DataTables_sort_icon",sScrollHead:"dataTables_scrollHead "+F,sScrollFoot:"dataTables_scrollFoot "+F,sHeaderTH:F,sFooterTH:F,sJUIHeader:Xb+" ui-corner-tl ui-corner-tr",sJUIFooter:Xb+" ui-corner-bl ui-corner-br"});var Mb=m.ext.pager;h.extend(Mb,{simple:function(){return["previous","next"]},full:function(){return["first","previous","next","last"]},simple_numbers:function(a,b){return["previous",
+Wa(a,b),"next"]},full_numbers:function(a,b){return["first","previous",Wa(a,b),"next","last"]},_numbers:Wa,numbers_length:7});h.extend(!0,m.ext.renderer,{pageButton:{_:function(a,b,c,e,d,f){var g=a.oClasses,j=a.oLanguage.oPaginate,i,k,l=0,m=function(b,e){var n,r,t,s,u=function(b){Ta(a,b.data.action,true)};n=0;for(r=e.length;n<r;n++){s=e[n];if(h.isArray(s)){t=h("<"+(s.DT_el||"div")+"/>").appendTo(b);m(t,s)}else{k=i="";switch(s){case "ellipsis":b.append('<span class="ellipsis">&#x2026;</span>');break;
+case "first":i=j.sFirst;k=s+(d>0?"":" "+g.sPageButtonDisabled);break;case "previous":i=j.sPrevious;k=s+(d>0?"":" "+g.sPageButtonDisabled);break;case "next":i=j.sNext;k=s+(d<f-1?"":" "+g.sPageButtonDisabled);break;case "last":i=j.sLast;k=s+(d<f-1?"":" "+g.sPageButtonDisabled);break;default:i=s+1;k=d===s?g.sPageButtonActive:""}if(i){t=h("<a>",{"class":g.sPageButton+" "+k,"aria-controls":a.sTableId,"data-dt-idx":l,tabindex:a.iTabIndex,id:c===0&&typeof s==="string"?a.sTableId+"_"+s:null}).html(i).appendTo(b);
+Va(t,{action:s},u);l++}}}},n;try{n=h(Q.activeElement).data("dt-idx")}catch(r){}m(h(b).empty(),e);n&&h(b).find("[data-dt-idx="+n+"]").focus()}}});h.extend(m.ext.type.detect,[function(a,b){var c=b.oLanguage.sDecimal;return Za(a,c)?"num"+c:null},function(a){if(a&&!(a instanceof Date)&&(!ac.test(a)||!bc.test(a)))return null;var b=Date.parse(a);return null!==b&&!isNaN(b)||J(a)?"date":null},function(a,b){var c=b.oLanguage.sDecimal;return Za(a,c,!0)?"num-fmt"+c:null},function(a,b){var c=b.oLanguage.sDecimal;
+return Rb(a,c)?"html-num"+c:null},function(a,b){var c=b.oLanguage.sDecimal;return Rb(a,c,!0)?"html-num-fmt"+c:null},function(a){return J(a)||"string"===typeof a&&-1!==a.indexOf("<")?"html":null}]);h.extend(m.ext.type.search,{html:function(a){return J(a)?a:"string"===typeof a?a.replace(Ob," ").replace(Ba,""):""},string:function(a){return J(a)?a:"string"===typeof a?a.replace(Ob," "):a}});var Aa=function(a,b,c,e){if(0!==a&&(!a||"-"===a))return-Infinity;b&&(a=Qb(a,b));a.replace&&(c&&(a=a.replace(c,"")),
+e&&(a=a.replace(e,"")));return 1*a};h.extend(u.type.order,{"date-pre":function(a){return Date.parse(a)||0},"html-pre":function(a){return J(a)?"":a.replace?a.replace(/<.*?>/g,"").toLowerCase():a+""},"string-pre":function(a){return J(a)?"":"string"===typeof a?a.toLowerCase():!a.toString?"":a.toString()},"string-asc":function(a,b){return a<b?-1:a>b?1:0},"string-desc":function(a,b){return a<b?1:a>b?-1:0}});db("");h.extend(!0,m.ext.renderer,{header:{_:function(a,b,c,e){h(a.nTable).on("order.dt.DT",function(d,
+f,g,h){if(a===f){d=c.idx;b.removeClass(c.sSortingClass+" "+e.sSortAsc+" "+e.sSortDesc).addClass(h[d]=="asc"?e.sSortAsc:h[d]=="desc"?e.sSortDesc:c.sSortingClass)}})},jqueryui:function(a,b,c,e){h("<div/>").addClass(e.sSortJUIWrapper).append(b.contents()).append(h("<span/>").addClass(e.sSortIcon+" "+c.sSortingClassJUI)).appendTo(b);h(a.nTable).on("order.dt.DT",function(d,f,g,h){if(a===f){d=c.idx;b.removeClass(e.sSortAsc+" "+e.sSortDesc).addClass(h[d]=="asc"?e.sSortAsc:h[d]=="desc"?e.sSortDesc:c.sSortingClass);
+b.find("span."+e.sSortIcon).removeClass(e.sSortJUIAsc+" "+e.sSortJUIDesc+" "+e.sSortJUI+" "+e.sSortJUIAscAllowed+" "+e.sSortJUIDescAllowed).addClass(h[d]=="asc"?e.sSortJUIAsc:h[d]=="desc"?e.sSortJUIDesc:c.sSortingClassJUI)}})}}});m.render={number:function(a,b,c,e){return{display:function(d){if("number"!==typeof d&&"string"!==typeof d)return d;var f=0>d?"-":"",d=Math.abs(parseFloat(d)),g=parseInt(d,10),d=c?b+(d-g).toFixed(c).substring(2):"";return f+(e||"")+g.toString().replace(/\B(?=(\d{3})+(?!\d))/g,
+a)+d}}}};h.extend(m.ext.internal,{_fnExternApiFunc:Nb,_fnBuildAjax:ra,_fnAjaxUpdate:kb,_fnAjaxParameters:tb,_fnAjaxUpdateDraw:ub,_fnAjaxDataSrc:sa,_fnAddColumn:Fa,_fnColumnOptions:ka,_fnAdjustColumnSizing:X,_fnVisibleToColumnIndex:la,_fnColumnIndexToVisible:$,_fnVisbleColumns:aa,_fnGetColumns:Z,_fnColumnTypes:Ha,_fnApplyColumnDefs:ib,_fnHungarianMap:W,_fnCamelToHungarian:H,_fnLanguageCompat:P,_fnBrowserDetect:gb,_fnAddData:K,_fnAddTr:ma,_fnNodeToDataIndex:function(a,b){return b._DT_RowIndex!==k?b._DT_RowIndex:
+null},_fnNodeToColumnIndex:function(a,b,c){return h.inArray(c,a.aoData[b].anCells)},_fnGetCellData:x,_fnSetCellData:Ia,_fnSplitObjNotation:Ka,_fnGetObjectDataFn:R,_fnSetObjectDataFn:S,_fnGetDataMaster:La,_fnClearTable:oa,_fnDeleteIndex:pa,_fnInvalidate:ca,_fnGetRowElements:na,_fnCreateTr:Ja,_fnBuildHead:jb,_fnDrawHead:ea,_fnDraw:M,_fnReDraw:N,_fnAddOptionsHtml:mb,_fnDetectHeader:da,_fnGetUniqueThs:qa,_fnFeatureHtmlFilter:ob,_fnFilterComplete:fa,_fnFilterCustom:xb,_fnFilterColumn:wb,_fnFilter:vb,_fnFilterCreateSearch:Qa,
+_fnEscapeRegex:va,_fnFilterData:yb,_fnFeatureHtmlInfo:rb,_fnUpdateInfo:Bb,_fnInfoMacros:Cb,_fnInitialise:ga,_fnInitComplete:ta,_fnLengthChange:Ra,_fnFeatureHtmlLength:nb,_fnFeatureHtmlPaginate:sb,_fnPageChange:Ta,_fnFeatureHtmlProcessing:pb,_fnProcessingDisplay:C,_fnFeatureHtmlTable:qb,_fnScrollDraw:Y,_fnApplyToChildren:G,_fnCalculateColumnWidths:Ga,_fnThrottle:ua,_fnConvertToWidth:Db,_fnScrollingWidthAdjust:Fb,_fnGetWidestNode:Eb,_fnGetMaxLenString:Gb,_fnStringToCss:s,_fnScrollBarWidth:Hb,_fnSortFlatten:U,
+_fnSort:lb,_fnSortAria:Jb,_fnSortListener:Ua,_fnSortAttachListener:Oa,_fnSortingClasses:xa,_fnSortData:Ib,_fnSaveState:ya,_fnLoadState:Kb,_fnSettingsFromNode:za,_fnLog:I,_fnMap:E,_fnBindAction:Va,_fnCallbackReg:z,_fnCallbackFire:w,_fnLengthOverflow:Sa,_fnRenderer:Pa,_fnDataSource:B,_fnRowAttributes:Ma,_fnCalculateEnd:function(){}});h.fn.dataTable=m;h.fn.dataTableSettings=m.settings;h.fn.dataTableExt=m.ext;h.fn.DataTable=function(a){return h(this).dataTable(a).api()};h.each(m,function(a,b){h.fn.DataTable[a]=
+b});return h.fn.dataTable};"function"===typeof define&&define.amd?define("datatables",["jquery"],P):"object"===typeof exports?module.exports=P(require("jquery")):jQuery&&!jQuery.fn.dataTable&&P(jQuery)})(window,document);
diff --git a/src/Jackett/Content/libs/jquery.min.js b/src/Jackett/Content/libs/jquery.min.js
new file mode 100644
index 0000000000000000000000000000000000000000..49990d6e14503798f142dcb0d5b23cb0c8f80244
--- /dev/null
+++ b/src/Jackett/Content/libs/jquery.min.js
@@ -0,0 +1,4 @@
+/*! 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 id='"+u+"'></a><select id='"+u+"-\f]' msallowcapture=''><option selected=''></option></select>",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;++d<b;)a.push(d);return a})}},d.pseudos.nth=d.pseudos.eq;for(b in{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})d.pseudos[b]=ma(b);for(b in{submit:!0,reset:!0})d.pseudos[b]=na(b);function qa(){}qa.prototype=d.filters=d.pseudos,d.setFilters=new qa,g=ga.tokenize=function(a,b){var c,e,f,g,h,i,j,k=z[a+" "];if(k)return b?0:k.slice(0);h=a,i=[],j=d.preFilter;while(h){(!c||(e=S.exec(h)))&&(e&&(h=h.slice(e[0].length)||h),i.push(f=[])),c=!1,(e=T.exec(h))&&(c=e.shift(),f.push({value:c,type:e[0].replace(R," ")}),h=h.slice(c.length));for(g in d.filter)!(e=X[g].exec(h))||j[g]&&!(e=j[g](e))||(c=e.shift(),f.push({value:c,type:g,matches:e}),h=h.slice(c.length));if(!c)break}return b?h.length:h?ga.error(a):z(a,i).slice(0)};function ra(a){for(var b=0,c=a.length,d="";c>b;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 href='#'></a>","#"===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="<input/>",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.length<c?n.queue(this[0],a):void 0===b?this:this.each(function(){var c=n.queue(this,a,b);n._queueHooks(this,a),"fx"===a&&"inprogress"!==c[0]&&n.dequeue(this,a)})},dequeue:function(a){return this.each(function(){n.dequeue(this,a)})},clearQueue:function(a){return this.queue(a||"fx",[])},promise:function(a,b){var c,d=1,e=n.Deferred(),f=this,g=this.length,h=function(){--d||e.resolveWith(f,[f])};"string"!=typeof a&&(b=a,a=void 0),a=a||"fx";while(g--)c=L.get(f[g],a+"queueHooks"),c&&c.empty&&(d++,c.empty.add(h));return h(),e.promise(b)}});var Q=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,R=["Top","Right","Bottom","Left"],S=function(a,b){return a=b||a,"none"===n.css(a,"display")||!n.contains(a.ownerDocument,a)},T=/^(?:checkbox|radio)$/i;!function(){var a=l.createDocumentFragment(),b=a.appendChild(l.createElement("div")),c=l.createElement("input");c.setAttribute("type","radio"),c.setAttribute("checked","checked"),c.setAttribute("name","t"),b.appendChild(c),k.checkClone=b.cloneNode(!0).cloneNode(!0).lastChild.checked,b.innerHTML="<textarea>x</textarea>",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<b.length&&g.push({elem:this,handlers:b.slice(h)}),g},props:"altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(a,b){return null==a.which&&(a.which=null!=b.charCode?b.charCode:b.keyCode),a}},mouseHooks:{props:"button buttons clientX clientY offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(a,b){var c,d,e,f=b.button;return null==a.pageX&&null!=b.clientX&&(c=a.target.ownerDocument||l,d=c.documentElement,e=c.body,a.pageX=b.clientX+(d&&d.scrollLeft||e&&e.scrollLeft||0)-(d&&d.clientLeft||e&&e.clientLeft||0),a.pageY=b.clientY+(d&&d.scrollTop||e&&e.scrollTop||0)-(d&&d.clientTop||e&&e.clientTop||0)),a.which||void 0===f||(a.which=1&f?1:2&f?3:4&f?2:0),a}},fix:function(a){if(a[n.expando])return a;var b,c,d,e=a.type,f=a,g=this.fixHooks[e];g||(this.fixHooks[e]=g=W.test(e)?this.mouseHooks:V.test(e)?this.keyHooks:{}),d=g.props?this.props.concat(g.props):this.props,a=new n.Event(f),b=d.length;while(b--)c=d[b],a[c]=f[c];return a.target||(a.target=l),3===a.target.nodeType&&(a.target=a.target.parentNode),g.filter?g.filter(a,f):a},special:{load:{noBubble:!0},focus:{trigger:function(){return this!==_()&&this.focus?(this.focus(),!1):void 0},delegateType:"focusin"},blur:{trigger:function(){return this===_()&&this.blur?(this.blur(),!1):void 0},delegateType:"focusout"},click:{trigger:function(){return"checkbox"===this.type&&this.click&&n.nodeName(this,"input")?(this.click(),!1):void 0},_default:function(a){return n.nodeName(a.target,"a")}},beforeunload:{postDispatch:function(a){void 0!==a.result&&a.originalEvent&&(a.originalEvent.returnValue=a.result)}}},simulate:function(a,b,c,d){var e=n.extend(new n.Event,c,{type:a,isSimulated:!0,originalEvent:{}});d?n.event.trigger(e,null,b):n.event.dispatch.call(b,e),e.isDefaultPrevented()&&c.preventDefault()}},n.removeEvent=function(a,b,c){a.removeEventListener&&a.removeEventListener(b,c,!1)},n.Event=function(a,b){return this instanceof n.Event?(a&&a.type?(this.originalEvent=a,this.type=a.type,this.isDefaultPrevented=a.defaultPrevented||void 0===a.defaultPrevented&&a.returnValue===!1?Z:$):this.type=a,b&&n.extend(this,b),this.timeStamp=a&&a.timeStamp||n.now(),void(this[n.expando]=!0)):new n.Event(a,b)},n.Event.prototype={isDefaultPrevented:$,isPropagationStopped:$,isImmediatePropagationStopped:$,preventDefault:function(){var a=this.originalEvent;this.isDefaultPrevented=Z,a&&a.preventDefault&&a.preventDefault()},stopPropagation:function(){var a=this.originalEvent;this.isPropagationStopped=Z,a&&a.stopPropagation&&a.stopPropagation()},stopImmediatePropagation:function(){var a=this.originalEvent;this.isImmediatePropagationStopped=Z,a&&a.stopImmediatePropagation&&a.stopImmediatePropagation(),this.stopPropagation()}},n.each({mouseenter:"mouseover",mouseleave:"mouseout",pointerenter:"pointerover",pointerleave:"pointerout"},function(a,b){n.event.special[a]={delegateType:b,bindType:b,handle:function(a){var c,d=this,e=a.relatedTarget,f=a.handleObj;return(!e||e!==d&&!n.contains(d,e))&&(a.type=f.origType,c=f.handler.apply(this,arguments),a.type=b),c}}}),k.focusinBubbles||n.each({focus:"focusin",blur:"focusout"},function(a,b){var c=function(a){n.event.simulate(b,a.target,n.event.fix(a),!0)};n.event.special[b]={setup:function(){var d=this.ownerDocument||this,e=L.access(d,b);e||d.addEventListener(a,c,!0),L.access(d,b,(e||0)+1)},teardown:function(){var d=this.ownerDocument||this,e=L.access(d,b)-1;e?L.access(d,b,e):(d.removeEventListener(a,c,!0),L.remove(d,b))}}}),n.fn.extend({on:function(a,b,c,d,e){var f,g;if("object"==typeof a){"string"!=typeof b&&(c=c||b,b=void 0);for(g in a)this.on(g,b,c,a[g],e);return this}if(null==c&&null==d?(d=b,c=b=void 0):null==d&&("string"==typeof b?(d=c,c=void 0):(d=c,c=b,b=void 0)),d===!1)d=$;else if(!d)return this;return 1===e&&(f=d,d=function(a){return n().off(a),f.apply(this,arguments)},d.guid=f.guid||(f.guid=n.guid++)),this.each(function(){n.event.add(this,a,d,c,b)})},one:function(a,b,c,d){return this.on(a,b,c,d,1)},off:function(a,b,c){var d,e;if(a&&a.preventDefault&&a.handleObj)return d=a.handleObj,n(a.delegateTarget).off(d.namespace?d.origType+"."+d.namespace:d.origType,d.selector,d.handler),this;if("object"==typeof a){for(e in a)this.off(e,b,a[e]);return this}return(b===!1||"function"==typeof b)&&(c=b,b=void 0),c===!1&&(c=$),this.each(function(){n.event.remove(this,a,c,b)})},trigger:function(a,b){return this.each(function(){n.event.trigger(a,b,this)})},triggerHandler:function(a,b){var c=this[0];return c?n.event.trigger(a,b,c,!0):void 0}});var aa=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/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*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g,ia={option:[1,"<select multiple='multiple'>","</select>"],thead:[1,"<table>","</table>"],col:[2,"<table><colgroup>","</colgroup></table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],_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></$2>")+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></$2>");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("<iframe frameborder='0' width='0' height='0'/>")).appendTo(b.documentElement),b=qa[0].contentDocument,b.write(),b.close(),c=sa(a,b),qa.detach()),ra[a]=c),c}var ua=/^margin/,va=new RegExp("^("+Q+")(?!px)[a-z%]+$","i"),wa=function(b){return b.ownerDocument.defaultView.opener?b.ownerDocument.defaultView.getComputedStyle(b,null):a.getComputedStyle(b,null)};function xa(a,b,c){var d,e,f,g,h=a.style;return c=c||wa(a),c&&(g=c.getPropertyValue(b)||c[b]),c&&(""!==g||n.contains(a.ownerDocument,a)||(g=n.style(a,b)),va.test(g)&&ua.test(b)&&(d=h.width,e=h.minWidth,f=h.maxWidth,h.minWidth=h.maxWidth=h.width=g,g=c.width,h.width=d,h.minWidth=e,h.maxWidth=f)),void 0!==g?g+"":g}function ya(a,b){return{get:function(){return a()?void delete this.get:(this.get=b).apply(this,arguments)}}}!function(){var b,c,d=l.documentElement,e=l.createElement("div"),f=l.createElement("div");if(f.style){f.style.backgroundClip="content-box",f.cloneNode(!0).style.backgroundClip="",k.clearCloneStyle="content-box"===f.style.backgroundClip,e.style.cssText="border:0;width:0;height:0;top:0;left:-9999px;margin-top:1px;position:absolute",e.appendChild(f);function g(){f.style.cssText="-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;display:block;margin-top:1%;top:1%;border:1px;padding:1px;width:4px;position:absolute",f.innerHTML="",d.appendChild(e);var g=a.getComputedStyle(f,null);b="1%"!==g.top,c="4px"===g.width,d.removeChild(e)}a.getComputedStyle&&n.extend(k,{pixelPosition:function(){return g(),b},boxSizingReliable:function(){return null==c&&g(),c},reliableMarginRight:function(){var b,c=f.appendChild(l.createElement("div"));return c.style.cssText=f.style.cssText="-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;display:block;margin:0;border:0;padding:0",c.style.marginRight=c.style.width="0",f.style.width="1px",d.appendChild(e),b=!parseFloat(a.getComputedStyle(c,null).marginRight),d.removeChild(e),f.removeChild(c),b}})}}(),n.swap=function(a,b,c,d){var e,f,g={};for(f in b)g[f]=a.style[f],a.style[f]=b[f];e=c.apply(a,d||[]);for(f in b)a.style[f]=g[f];return e};var za=/^(none|table(?!-c[ea]).+)/,Aa=new RegExp("^("+Q+")(.*)$","i"),Ba=new RegExp("^([+-])=("+Q+")","i"),Ca={position:"absolute",visibility:"hidden",display:"block"},Da={letterSpacing:"0",fontWeight:"400"},Ea=["Webkit","O","Moz","ms"];function Fa(a,b){if(b in a)return b;var c=b[0].toUpperCase()+b.slice(1),d=b,e=Ea.length;while(e--)if(b=Ea[e]+c,b in a)return b;return d}function Ga(a,b,c){var d=Aa.exec(b);return d?Math.max(0,d[1]-(c||0))+(d[2]||"px"):b}function Ha(a,b,c,d,e){for(var f=c===(d?"border":"content")?4:"width"===b?1:0,g=0;4>f;f+=2)"margin"===c&&(g+=n.css(a,c+R[f],!0,e)),d?("content"===c&&(g-=n.css(a,"padding"+R[f],!0,e)),"margin"!==c&&(g-=n.css(a,"border"+R[f]+"Width",!0,e))):(g+=n.css(a,"padding"+R[f],!0,e),"padding"!==c&&(g+=n.css(a,"border"+R[f]+"Width",!0,e)));return g}function Ia(a,b,c){var d=!0,e="width"===b?a.offsetWidth:a.offsetHeight,f=wa(a),g="border-box"===n.css(a,"boxSizing",!1,f);if(0>=e||null==e){if(e=xa(a,b,f),(0>e||null==e)&&(e=a.style[b]),va.test(e))return e;d=g&&(k.boxSizingReliable()||e===a.style[b]),e=parseFloat(e)||0}return e+Ha(a,b,c||(g?"border":"content"),d,f)+"px"}function Ja(a,b){for(var c,d,e,f=[],g=0,h=a.length;h>g;g++)d=a[g],d.style&&(f[g]=L.get(d,"olddisplay"),c=d.style.display,b?(f[g]||"none"!==c||(d.style.display=""),""===d.style.display&&S(d)&&(f[g]=L.access(d,"olddisplay",ta(d.nodeName)))):(e=S(d),"none"===c&&e||L.set(d,"olddisplay",e?c:n.css(d,"display"))));for(g=0;h>g;g++)d=a[g],d.style&&(b&&"none"!==d.style.display&&""!==d.style.display||(d.style.display=b?f[g]||"":"none"));return a}n.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=xa(a,"opacity");return""===c?"1":c}}}},cssNumber:{columnCount:!0,fillOpacity:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":"cssFloat"},style:function(a,b,c,d){if(a&&3!==a.nodeType&&8!==a.nodeType&&a.style){var e,f,g,h=n.camelCase(b),i=a.style;return b=n.cssProps[h]||(n.cssProps[h]=Fa(i,h)),g=n.cssHooks[b]||n.cssHooks[h],void 0===c?g&&"get"in g&&void 0!==(e=g.get(a,!1,d))?e:i[b]:(f=typeof c,"string"===f&&(e=Ba.exec(c))&&(c=(e[1]+1)*e[2]+parseFloat(n.css(a,b)),f="number"),null!=c&&c===c&&("number"!==f||n.cssNumber[h]||(c+="px"),k.clearCloneStyle||""!==c||0!==b.indexOf("background")||(i[b]="inherit"),g&&"set"in g&&void 0===(c=g.set(a,c,d))||(i[b]=c)),void 0)}},css:function(a,b,c,d){var e,f,g,h=n.camelCase(b);return b=n.cssProps[h]||(n.cssProps[h]=Fa(a.style,h)),g=n.cssHooks[b]||n.cssHooks[h],g&&"get"in g&&(e=g.get(a,!0,c)),void 0===e&&(e=xa(a,b,d)),"normal"===e&&b in Da&&(e=Da[b]),""===c||c?(f=parseFloat(e),c===!0||n.isNumeric(f)?f||0:e):e}}),n.each(["height","width"],function(a,b){n.cssHooks[b]={get:function(a,c,d){return c?za.test(n.css(a,"display"))&&0===a.offsetWidth?n.swap(a,Ca,function(){return Ia(a,b,d)}):Ia(a,b,d):void 0},set:function(a,c,d){var e=d&&wa(a);return Ga(a,c,d?Ha(a,b,d,"border-box"===n.css(a,"boxSizing",!1,e),e):0)}}}),n.cssHooks.marginRight=ya(k.reliableMarginRight,function(a,b){return b?n.swap(a,{display:"inline-block"},xa,[a,"marginRight"]):void 0}),n.each({margin:"",padding:"",border:"Width"},function(a,b){n.cssHooks[a+b]={expand:function(c){for(var d=0,e={},f="string"==typeof c?c.split(" "):[c];4>d;d++)e[a+R[d]+b]=f[d]||f[d-2]||f[0];return e}},ua.test(a)||(n.cssHooks[a+b].set=Ga)}),n.fn.extend({css:function(a,b){return J(this,function(a,b,c){var d,e,f={},g=0;if(n.isArray(b)){for(d=wa(a),e=b.length;e>g;g++)f[b[g]]=n.css(a,b[g],!1,d);return f}return void 0!==c?n.style(a,b,c):n.css(a,b)},a,b,arguments.length>1)},show:function(){return Ja(this,!0)},hide:function(){return Ja(this)},toggle:function(a){return"boolean"==typeof a?a?this.show():this.hide():this.each(function(){S(this)?n(this).show():n(this).hide()})}});function Ka(a,b,c,d,e){return new Ka.prototype.init(a,b,c,d,e)}n.Tween=Ka,Ka.prototype={constructor:Ka,init:function(a,b,c,d,e,f){this.elem=a,this.prop=c,this.easing=e||"swing",this.options=b,this.start=this.now=this.cur(),this.end=d,this.unit=f||(n.cssNumber[c]?"":"px")},cur:function(){var a=Ka.propHooks[this.prop];return a&&a.get?a.get(this):Ka.propHooks._default.get(this)},run:function(a){var b,c=Ka.propHooks[this.prop];return this.options.duration?this.pos=b=n.easing[this.easing](a,this.options.duration*a,0,1,this.options.duration):this.pos=b=a,this.now=(this.end-this.start)*b+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),c&&c.set?c.set(this):Ka.propHooks._default.set(this),this}},Ka.prototype.init.prototype=Ka.prototype,Ka.propHooks={_default:{get:function(a){var b;return null==a.elem[a.prop]||a.elem.style&&null!=a.elem.style[a.prop]?(b=n.css(a.elem,a.prop,""),b&&"auto"!==b?b:0):a.elem[a.prop]},set:function(a){n.fx.step[a.prop]?n.fx.step[a.prop](a):a.elem.style&&(null!=a.elem.style[n.cssProps[a.prop]]||n.cssHooks[a.prop])?n.style(a.elem,a.prop,a.now+a.unit):a.elem[a.prop]=a.now}}},Ka.propHooks.scrollTop=Ka.propHooks.scrollLeft={set:function(a){a.elem.nodeType&&a.elem.parentNode&&(a.elem[a.prop]=a.now)}},n.easing={linear:function(a){return a},swing:function(a){return.5-Math.cos(a*Math.PI)/2}},n.fx=Ka.prototype.init,n.fx.step={};var La,Ma,Na=/^(?:toggle|show|hide)$/,Oa=new RegExp("^(?:([+-])=|)("+Q+")([a-z%]*)$","i"),Pa=/queueHooks$/,Qa=[Va],Ra={"*":[function(a,b){var c=this.createTween(a,b),d=c.cur(),e=Oa.exec(b),f=e&&e[3]||(n.cssNumber[a]?"":"px"),g=(n.cssNumber[a]||"px"!==f&&+d)&&Oa.exec(n.css(c.elem,a)),h=1,i=20;if(g&&g[3]!==f){f=f||g[3],e=e||[],g=+d||1;do h=h||".5",g/=h,n.style(c.elem,a,g+f);while(h!==(h=c.cur()/d)&&1!==h&&--i)}return e&&(g=c.start=+g||+d||0,c.unit=f,c.end=e[1]?g+(e[1]+1)*e[2]:+e[2]),c}]};function Sa(){return setTimeout(function(){La=void 0}),La=n.now()}function Ta(a,b){var c,d=0,e={height:a};for(b=b?1:0;4>d;d+=2-b)c=R[d],e["margin"+c]=e["padding"+c]=a;return b&&(e.opacity=e.width=a),e}function Ua(a,b,c){for(var d,e=(Ra[b]||[]).concat(Ra["*"]),f=0,g=e.length;g>f;f++)if(d=e[f].call(c,b,a))return d}function Va(a,b,c){var d,e,f,g,h,i,j,k,l=this,m={},o=a.style,p=a.nodeType&&S(a),q=L.get(a,"fxshow");c.queue||(h=n._queueHooks(a,"fx"),null==h.unqueued&&(h.unqueued=0,i=h.empty.fire,h.empty.fire=function(){h.unqueued||i()}),h.unqueued++,l.always(function(){l.always(function(){h.unqueued--,n.queue(a,"fx").length||h.empty.fire()})})),1===a.nodeType&&("height"in b||"width"in b)&&(c.overflow=[o.overflow,o.overflowX,o.overflowY],j=n.css(a,"display"),k="none"===j?L.get(a,"olddisplay")||ta(a.nodeName):j,"inline"===k&&"none"===n.css(a,"float")&&(o.display="inline-block")),c.overflow&&(o.overflow="hidden",l.always(function(){o.overflow=c.overflow[0],o.overflowX=c.overflow[1],o.overflowY=c.overflow[2]}));for(d in b)if(e=b[d],Na.exec(e)){if(delete b[d],f=f||"toggle"===e,e===(p?"hide":"show")){if("show"!==e||!q||void 0===q[d])continue;p=!0}m[d]=q&&q[d]||n.style(a,d)}else j=void 0;if(n.isEmptyObject(m))"inline"===("none"===j?ta(a.nodeName):j)&&(o.display=j);else{q?"hidden"in q&&(p=q.hidden):q=L.access(a,"fxshow",{}),f&&(q.hidden=!p),p?n(a).show():l.done(function(){n(a).hide()}),l.done(function(){var b;L.remove(a,"fxshow");for(b in m)n.style(a,b,m[b])});for(d in m)g=Ua(p?q[d]:0,d,l),d in q||(q[d]=g.start,p&&(g.end=g.start,g.start="width"===d||"height"===d?1:0))}}function Wa(a,b){var c,d,e,f,g;for(c in a)if(d=n.camelCase(c),e=b[d],f=a[c],n.isArray(f)&&(e=f[1],f=a[c]=f[0]),c!==d&&(a[d]=f,delete a[c]),g=n.cssHooks[d],g&&"expand"in g){f=g.expand(f),delete a[d];for(c in f)c in a||(a[c]=f[c],b[c]=e)}else b[d]=e}function Xa(a,b,c){var d,e,f=0,g=Qa.length,h=n.Deferred().always(function(){delete i.elem}),i=function(){if(e)return!1;for(var b=La||Sa(),c=Math.max(0,j.startTime+j.duration-b),d=c/j.duration||0,f=1-d,g=0,i=j.tweens.length;i>g;g++)j.tweens[g].run(f);return h.notifyWith(a,[j,f,c]),1>f&&i?c:(h.resolveWith(a,[j]),!1)},j=h.promise({elem:a,props:n.extend({},b),opts:n.extend(!0,{specialEasing:{}},c),originalProperties:b,originalOptions:c,startTime:La||Sa(),duration:c.duration,tweens:[],createTween:function(b,c){var d=n.Tween(a,j.opts,b,c,j.opts.specialEasing[b]||j.opts.easing);return j.tweens.push(d),d},stop:function(b){var c=0,d=b?j.tweens.length:0;if(e)return this;for(e=!0;d>c;c++)j.tweens[c].run(1);return b?h.resolveWith(a,[j,b]):h.rejectWith(a,[j,b]),this}}),k=j.props;for(Wa(k,j.opts.specialEasing);g>f;f++)if(d=Qa[f].call(j,a,k,j.opts))return d;return n.map(k,Ua,j),n.isFunction(j.opts.start)&&j.opts.start.call(a,j),n.fx.timer(n.extend(i,{elem:a,anim:j,queue:j.opts.queue})),j.progress(j.opts.progress).done(j.opts.done,j.opts.complete).fail(j.opts.fail).always(j.opts.always)}n.Animation=n.extend(Xa,{tweener:function(a,b){n.isFunction(a)?(b=a,a=["*"]):a=a.split(" ");for(var c,d=0,e=a.length;e>d;d++)c=a[d],Ra[c]=Ra[c]||[],Ra[c].unshift(b)},prefilter:function(a,b){b?Qa.unshift(a):Qa.push(a)}}),n.speed=function(a,b,c){var d=a&&"object"==typeof a?n.extend({},a):{complete:c||!c&&b||n.isFunction(a)&&a,duration:a,easing:c&&b||b&&!n.isFunction(b)&&b};return d.duration=n.fx.off?0:"number"==typeof d.duration?d.duration:d.duration in n.fx.speeds?n.fx.speeds[d.duration]:n.fx.speeds._default,(null==d.queue||d.queue===!0)&&(d.queue="fx"),d.old=d.complete,d.complete=function(){n.isFunction(d.old)&&d.old.call(this),d.queue&&n.dequeue(this,d.queue)},d},n.fn.extend({fadeTo:function(a,b,c,d){return this.filter(S).css("opacity",0).show().end().animate({opacity:b},a,c,d)},animate:function(a,b,c,d){var e=n.isEmptyObject(a),f=n.speed(b,c,d),g=function(){var b=Xa(this,n.extend({},a),f);(e||L.get(this,"finish"))&&b.stop(!0)};return g.finish=g,e||f.queue===!1?this.each(g):this.queue(f.queue,g)},stop:function(a,b,c){var d=function(a){var b=a.stop;delete a.stop,b(c)};return"string"!=typeof a&&(c=b,b=a,a=void 0),b&&a!==!1&&this.queue(a||"fx",[]),this.each(function(){var b=!0,e=null!=a&&a+"queueHooks",f=n.timers,g=L.get(this);if(e)g[e]&&g[e].stop&&d(g[e]);else for(e in g)g[e]&&g[e].stop&&Pa.test(e)&&d(g[e]);for(e=f.length;e--;)f[e].elem!==this||null!=a&&f[e].queue!==a||(f[e].anim.stop(c),b=!1,f.splice(e,1));(b||!c)&&n.dequeue(this,a)})},finish:function(a){return a!==!1&&(a=a||"fx"),this.each(function(){var b,c=L.get(this),d=c[a+"queue"],e=c[a+"queueHooks"],f=n.timers,g=d?d.length:0;for(c.finish=!0,n.queue(this,a,[]),e&&e.stop&&e.stop.call(this,!0),b=f.length;b--;)f[b].elem===this&&f[b].queue===a&&(f[b].anim.stop(!0),f.splice(b,1));for(b=0;g>b;b++)d[b]&&d[b].finish&&d[b].finish.call(this);delete c.finish})}}),n.each(["toggle","show","hide"],function(a,b){var c=n.fn[b];n.fn[b]=function(a,d,e){return null==a||"boolean"==typeof a?c.apply(this,arguments):this.animate(Ta(b,!0),a,d,e)}}),n.each({slideDown:Ta("show"),slideUp:Ta("hide"),slideToggle:Ta("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){n.fn[a]=function(a,c,d){return this.animate(b,a,c,d)}}),n.timers=[],n.fx.tick=function(){var a,b=0,c=n.timers;for(La=n.now();b<c.length;b++)a=c[b],a()||c[b]!==a||c.splice(b--,1);c.length||n.fx.stop(),La=void 0},n.fx.timer=function(a){n.timers.push(a),a()?n.fx.start():n.timers.pop()},n.fx.interval=13,n.fx.start=function(){Ma||(Ma=setInterval(n.fx.tick,n.fx.interval))},n.fx.stop=function(){clearInterval(Ma),Ma=null},n.fx.speeds={slow:600,fast:200,_default:400},n.fn.delay=function(a,b){return a=n.fx?n.fx.speeds[a]||a:a,b=b||"fx",this.queue(b,function(b,c){var d=setTimeout(b,a);c.stop=function(){clearTimeout(d)}})},function(){var a=l.createElement("input"),b=l.createElement("select"),c=b.appendChild(l.createElement("option"));a.type="checkbox",k.checkOn=""!==a.value,k.optSelected=c.selected,b.disabled=!0,k.optDisabled=!c.disabled,a=l.createElement("input"),a.value="t",a.type="radio",k.radioValue="t"===a.value}();var Ya,Za,$a=n.expr.attrHandle;n.fn.extend({attr:function(a,b){return J(this,n.attr,a,b,arguments.length>1)},removeAttr:function(a){return this.each(function(){n.removeAttr(this,a)})}}),n.extend({attr:function(a,b,c){var d,e,f=a.nodeType;if(a&&3!==f&&8!==f&&2!==f)return typeof a.getAttribute===U?n.prop(a,b,c):(1===f&&n.isXMLDoc(a)||(b=b.toLowerCase(),d=n.attrHooks[b]||(n.expr.match.bool.test(b)?Za:Ya)),
+void 0===c?d&&"get"in d&&null!==(e=d.get(a,b))?e:(e=n.find.attr(a,b),null==e?void 0:e):null!==c?d&&"set"in d&&void 0!==(e=d.set(a,c,b))?e:(a.setAttribute(b,c+""),c):void n.removeAttr(a,b))},removeAttr:function(a,b){var c,d,e=0,f=b&&b.match(E);if(f&&1===a.nodeType)while(c=f[e++])d=n.propFix[c]||c,n.expr.match.bool.test(c)&&(a[d]=!1),a.removeAttribute(c)},attrHooks:{type:{set:function(a,b){if(!k.radioValue&&"radio"===b&&n.nodeName(a,"input")){var c=a.value;return a.setAttribute("type",b),c&&(a.value=c),b}}}}}),Za={set:function(a,b,c){return b===!1?n.removeAttr(a,c):a.setAttribute(c,c),c}},n.each(n.expr.match.bool.source.match(/\w+/g),function(a,b){var c=$a[b]||n.find.attr;$a[b]=function(a,b,d){var e,f;return d||(f=$a[b],$a[b]=e,e=null!=c(a,b,d)?b.toLowerCase():null,$a[b]=f),e}});var _a=/^(?:input|select|textarea|button)$/i;n.fn.extend({prop:function(a,b){return J(this,n.prop,a,b,arguments.length>1)},removeProp:function(a){return this.each(function(){delete this[n.propFix[a]||a]})}}),n.extend({propFix:{"for":"htmlFor","class":"className"},prop:function(a,b,c){var d,e,f,g=a.nodeType;if(a&&3!==g&&8!==g&&2!==g)return f=1!==g||!n.isXMLDoc(a),f&&(b=n.propFix[b]||b,e=n.propHooks[b]),void 0!==c?e&&"set"in e&&void 0!==(d=e.set(a,c,b))?d:a[b]=c:e&&"get"in e&&null!==(d=e.get(a,b))?d:a[b]},propHooks:{tabIndex:{get:function(a){return a.hasAttribute("tabindex")||_a.test(a.nodeName)||a.href?a.tabIndex:-1}}}}),k.optSelected||(n.propHooks.selected={get:function(a){var b=a.parentNode;return b&&b.parentNode&&b.parentNode.selectedIndex,null}}),n.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){n.propFix[this.toLowerCase()]=this});var ab=/[\t\r\n\f]/g;n.fn.extend({addClass:function(a){var b,c,d,e,f,g,h="string"==typeof a&&a,i=0,j=this.length;if(n.isFunction(a))return this.each(function(b){n(this).addClass(a.call(this,b,this.className))});if(h)for(b=(a||"").match(E)||[];j>i;i++)if(c=this[i],d=1===c.nodeType&&(c.className?(" "+c.className+" ").replace(ab," "):" ")){f=0;while(e=b[f++])d.indexOf(" "+e+" ")<0&&(d+=e+" ");g=n.trim(d),c.className!==g&&(c.className=g)}return this},removeClass:function(a){var b,c,d,e,f,g,h=0===arguments.length||"string"==typeof a&&a,i=0,j=this.length;if(n.isFunction(a))return this.each(function(b){n(this).removeClass(a.call(this,b,this.className))});if(h)for(b=(a||"").match(E)||[];j>i;i++)if(c=this[i],d=1===c.nodeType&&(c.className?(" "+c.className+" ").replace(ab," "):"")){f=0;while(e=b[f++])while(d.indexOf(" "+e+" ")>=0)d=d.replace(" "+e+" "," ");g=a?n.trim(d):"",c.className!==g&&(c.className=g)}return this},toggleClass:function(a,b){var c=typeof a;return"boolean"==typeof b&&"string"===c?b?this.addClass(a):this.removeClass(a):this.each(n.isFunction(a)?function(c){n(this).toggleClass(a.call(this,c,this.className,b),b)}:function(){if("string"===c){var b,d=0,e=n(this),f=a.match(E)||[];while(b=f[d++])e.hasClass(b)?e.removeClass(b):e.addClass(b)}else(c===U||"boolean"===c)&&(this.className&&L.set(this,"__className__",this.className),this.className=this.className||a===!1?"":L.get(this,"__className__")||"")})},hasClass:function(a){for(var b=" "+a+" ",c=0,d=this.length;d>c;c++)if(1===this[c].nodeType&&(" "+this[c].className+" ").replace(ab," ").indexOf(b)>=0)return!0;return!1}});var bb=/\r/g;n.fn.extend({val:function(a){var b,c,d,e=this[0];{if(arguments.length)return d=n.isFunction(a),this.each(function(c){var e;1===this.nodeType&&(e=d?a.call(this,c,n(this).val()):a,null==e?e="":"number"==typeof e?e+="":n.isArray(e)&&(e=n.map(e,function(a){return null==a?"":a+""})),b=n.valHooks[this.type]||n.valHooks[this.nodeName.toLowerCase()],b&&"set"in b&&void 0!==b.set(this,e,"value")||(this.value=e))});if(e)return b=n.valHooks[e.type]||n.valHooks[e.nodeName.toLowerCase()],b&&"get"in b&&void 0!==(c=b.get(e,"value"))?c:(c=e.value,"string"==typeof c?c.replace(bb,""):null==c?"":c)}}}),n.extend({valHooks:{option:{get:function(a){var b=n.find.attr(a,"value");return null!=b?b:n.trim(n.text(a))}},select:{get:function(a){for(var b,c,d=a.options,e=a.selectedIndex,f="select-one"===a.type||0>e,g=f?null:[],h=f?e+1:d.length,i=0>e?h:f?e:0;h>i;i++)if(c=d[i],!(!c.selected&&i!==e||(k.optDisabled?c.disabled:null!==c.getAttribute("disabled"))||c.parentNode.disabled&&n.nodeName(c.parentNode,"optgroup"))){if(b=n(c).val(),f)return b;g.push(b)}return g},set:function(a,b){var c,d,e=a.options,f=n.makeArray(b),g=e.length;while(g--)d=e[g],(d.selected=n.inArray(d.value,f)>=0)&&(c=!0);return c||(a.selectedIndex=-1),f}}}}),n.each(["radio","checkbox"],function(){n.valHooks[this]={set:function(a,b){return n.isArray(b)?a.checked=n.inArray(n(a).val(),b)>=0:void 0}},k.checkOn||(n.valHooks[this].get=function(a){return null===a.getAttribute("value")?"on":a.value})}),n.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu".split(" "),function(a,b){n.fn[b]=function(a,c){return arguments.length>0?this.on(b,null,a,c):this.trigger(b)}}),n.fn.extend({hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)},bind:function(a,b,c){return this.on(a,null,b,c)},unbind:function(a,b){return this.off(a,null,b)},delegate:function(a,b,c,d){return this.on(b,a,c,d)},undelegate:function(a,b,c){return 1===arguments.length?this.off(a,"**"):this.off(b,a||"**",c)}});var cb=n.now(),db=/\?/;n.parseJSON=function(a){return JSON.parse(a+"")},n.parseXML=function(a){var b,c;if(!a||"string"!=typeof a)return null;try{c=new DOMParser,b=c.parseFromString(a,"text/xml")}catch(d){b=void 0}return(!b||b.getElementsByTagName("parsererror").length)&&n.error("Invalid XML: "+a),b};var eb=/#.*$/,fb=/([?&])_=[^&]*/,gb=/^(.*?):[ \t]*([^\r\n]*)$/gm,hb=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,ib=/^(?:GET|HEAD)$/,jb=/^\/\//,kb=/^([\w.+-]+:)(?:\/\/(?:[^\/?#]*@|)([^\/?#:]*)(?::(\d+)|)|)/,lb={},mb={},nb="*/".concat("*"),ob=a.location.href,pb=kb.exec(ob.toLowerCase())||[];function qb(a){return function(b,c){"string"!=typeof b&&(c=b,b="*");var d,e=0,f=b.toLowerCase().match(E)||[];if(n.isFunction(c))while(d=f[e++])"+"===d[0]?(d=d.slice(1)||"*",(a[d]=a[d]||[]).unshift(c)):(a[d]=a[d]||[]).push(c)}}function rb(a,b,c,d){var e={},f=a===mb;function g(h){var i;return e[h]=!0,n.each(a[h]||[],function(a,h){var j=h(b,c,d);return"string"!=typeof j||f||e[j]?f?!(i=j):void 0:(b.dataTypes.unshift(j),g(j),!1)}),i}return g(b.dataTypes[0])||!e["*"]&&g("*")}function sb(a,b){var c,d,e=n.ajaxSettings.flatOptions||{};for(c in b)void 0!==b[c]&&((e[c]?a:d||(d={}))[c]=b[c]);return d&&n.extend(!0,a,d),a}function tb(a,b,c){var d,e,f,g,h=a.contents,i=a.dataTypes;while("*"===i[0])i.shift(),void 0===d&&(d=a.mimeType||b.getResponseHeader("Content-Type"));if(d)for(e in h)if(h[e]&&h[e].test(d)){i.unshift(e);break}if(i[0]in c)f=i[0];else{for(e in c){if(!i[0]||a.converters[e+" "+i[0]]){f=e;break}g||(g=e)}f=f||g}return f?(f!==i[0]&&i.unshift(f),c[f]):void 0}function ub(a,b,c,d){var e,f,g,h,i,j={},k=a.dataTypes.slice();if(k[1])for(g in a.converters)j[g.toLowerCase()]=a.converters[g];f=k.shift();while(f)if(a.responseFields[f]&&(c[a.responseFields[f]]=b),!i&&d&&a.dataFilter&&(b=a.dataFilter(b,a.dataType)),i=f,f=k.shift())if("*"===f)f=i;else if("*"!==i&&i!==f){if(g=j[i+" "+f]||j["* "+f],!g)for(e in j)if(h=e.split(" "),h[1]===f&&(g=j[i+" "+h[0]]||j["* "+h[0]])){g===!0?g=j[e]:j[e]!==!0&&(f=h[0],k.unshift(h[1]));break}if(g!==!0)if(g&&a["throws"])b=g(b);else try{b=g(b)}catch(l){return{state:"parsererror",error:g?l:"No conversion from "+i+" to "+f}}}return{state:"success",data:b}}n.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:ob,type:"GET",isLocal:hb.test(pb[1]),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":nb,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":n.parseJSON,"text xml":n.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(a,b){return b?sb(sb(a,n.ajaxSettings),b):sb(n.ajaxSettings,a)},ajaxPrefilter:qb(lb),ajaxTransport:qb(mb),ajax:function(a,b){"object"==typeof a&&(b=a,a=void 0),b=b||{};var c,d,e,f,g,h,i,j,k=n.ajaxSetup({},b),l=k.context||k,m=k.context&&(l.nodeType||l.jquery)?n(l):n.event,o=n.Deferred(),p=n.Callbacks("once memory"),q=k.statusCode||{},r={},s={},t=0,u="canceled",v={readyState:0,getResponseHeader:function(a){var b;if(2===t){if(!f){f={};while(b=gb.exec(e))f[b[1].toLowerCase()]=b[2]}b=f[a.toLowerCase()]}return null==b?null:b},getAllResponseHeaders:function(){return 2===t?e:null},setRequestHeader:function(a,b){var c=a.toLowerCase();return t||(a=s[c]=s[c]||a,r[a]=b),this},overrideMimeType:function(a){return t||(k.mimeType=a),this},statusCode:function(a){var b;if(a)if(2>t)for(b in a)q[b]=[q[b],a[b]];else v.always(a[v.status]);return this},abort:function(a){var b=a||u;return c&&c.abort(b),x(0,b),this}};if(o.promise(v).complete=p.add,v.success=v.done,v.error=v.fail,k.url=((a||k.url||ob)+"").replace(eb,"").replace(jb,pb[1]+"//"),k.type=b.method||b.type||k.method||k.type,k.dataTypes=n.trim(k.dataType||"*").toLowerCase().match(E)||[""],null==k.crossDomain&&(h=kb.exec(k.url.toLowerCase()),k.crossDomain=!(!h||h[1]===pb[1]&&h[2]===pb[2]&&(h[3]||("http:"===h[1]?"80":"443"))===(pb[3]||("http:"===pb[1]?"80":"443")))),k.data&&k.processData&&"string"!=typeof k.data&&(k.data=n.param(k.data,k.traditional)),rb(lb,k,b,v),2===t)return v;i=n.event&&k.global,i&&0===n.active++&&n.event.trigger("ajaxStart"),k.type=k.type.toUpperCase(),k.hasContent=!ib.test(k.type),d=k.url,k.hasContent||(k.data&&(d=k.url+=(db.test(d)?"&":"?")+k.data,delete k.data),k.cache===!1&&(k.url=fb.test(d)?d.replace(fb,"$1_="+cb++):d+(db.test(d)?"&":"?")+"_="+cb++)),k.ifModified&&(n.lastModified[d]&&v.setRequestHeader("If-Modified-Since",n.lastModified[d]),n.etag[d]&&v.setRequestHeader("If-None-Match",n.etag[d])),(k.data&&k.hasContent&&k.contentType!==!1||b.contentType)&&v.setRequestHeader("Content-Type",k.contentType),v.setRequestHeader("Accept",k.dataTypes[0]&&k.accepts[k.dataTypes[0]]?k.accepts[k.dataTypes[0]]+("*"!==k.dataTypes[0]?", "+nb+"; q=0.01":""):k.accepts["*"]);for(j in k.headers)v.setRequestHeader(j,k.headers[j]);if(k.beforeSend&&(k.beforeSend.call(l,v,k)===!1||2===t))return v.abort();u="abort";for(j in{success:1,error:1,complete:1})v[j](k[j]);if(c=rb(mb,k,b,v)){v.readyState=1,i&&m.trigger("ajaxSend",[v,k]),k.async&&k.timeout>0&&(g=setTimeout(function(){v.abort("timeout")},k.timeout));try{t=1,c.send(r,x)}catch(w){if(!(2>t))throw w;x(-1,w)}}else x(-1,"No Transport");function x(a,b,f,h){var j,r,s,u,w,x=b;2!==t&&(t=2,g&&clearTimeout(g),c=void 0,e=h||"",v.readyState=a>0?4:0,j=a>=200&&300>a||304===a,f&&(u=tb(k,v,f)),u=ub(k,u,v,j),j?(k.ifModified&&(w=v.getResponseHeader("Last-Modified"),w&&(n.lastModified[d]=w),w=v.getResponseHeader("etag"),w&&(n.etag[d]=w)),204===a||"HEAD"===k.type?x="nocontent":304===a?x="notmodified":(x=u.state,r=u.data,s=u.error,j=!s)):(s=x,(a||!x)&&(x="error",0>a&&(a=0))),v.status=a,v.statusText=(b||x)+"",j?o.resolveWith(l,[r,x,v]):o.rejectWith(l,[v,x,s]),v.statusCode(q),q=void 0,i&&m.trigger(j?"ajaxSuccess":"ajaxError",[v,k,j?r:s]),p.fireWith(l,[v,x]),i&&(m.trigger("ajaxComplete",[v,k]),--n.active||n.event.trigger("ajaxStop")))}return v},getJSON:function(a,b,c){return n.get(a,b,c,"json")},getScript:function(a,b){return n.get(a,void 0,b,"script")}}),n.each(["get","post"],function(a,b){n[b]=function(a,c,d,e){return n.isFunction(c)&&(e=e||d,d=c,c=void 0),n.ajax({url:a,type:b,dataType:e,data:c,success:d})}}),n._evalUrl=function(a){return n.ajax({url:a,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0})},n.fn.extend({wrapAll:function(a){var b;return n.isFunction(a)?this.each(function(b){n(this).wrapAll(a.call(this,b))}):(this[0]&&(b=n(a,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstElementChild)a=a.firstElementChild;return a}).append(this)),this)},wrapInner:function(a){return this.each(n.isFunction(a)?function(b){n(this).wrapInner(a.call(this,b))}:function(){var b=n(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=n.isFunction(a);return this.each(function(c){n(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(){return this.parent().each(function(){n.nodeName(this,"body")||n(this).replaceWith(this.childNodes)}).end()}}),n.expr.filters.hidden=function(a){return a.offsetWidth<=0&&a.offsetHeight<=0},n.expr.filters.visible=function(a){return!n.expr.filters.hidden(a)};var vb=/%20/g,wb=/\[\]$/,xb=/\r?\n/g,yb=/^(?:submit|button|image|reset|file)$/i,zb=/^(?:input|select|textarea|keygen)/i;function Ab(a,b,c,d){var e;if(n.isArray(b))n.each(b,function(b,e){c||wb.test(a)?d(a,e):Ab(a+"["+("object"==typeof e?b:"")+"]",e,c,d)});else if(c||"object"!==n.type(b))d(a,b);else for(e in b)Ab(a+"["+e+"]",b[e],c,d)}n.param=function(a,b){var c,d=[],e=function(a,b){b=n.isFunction(b)?b():null==b?"":b,d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};if(void 0===b&&(b=n.ajaxSettings&&n.ajaxSettings.traditional),n.isArray(a)||a.jquery&&!n.isPlainObject(a))n.each(a,function(){e(this.name,this.value)});else for(c in a)Ab(c,a[c],b,e);return d.join("&").replace(vb,"+")},n.fn.extend({serialize:function(){return n.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var a=n.prop(this,"elements");return a?n.makeArray(a):this}).filter(function(){var a=this.type;return this.name&&!n(this).is(":disabled")&&zb.test(this.nodeName)&&!yb.test(a)&&(this.checked||!T.test(a))}).map(function(a,b){var c=n(this).val();return null==c?null:n.isArray(c)?n.map(c,function(a){return{name:b.name,value:a.replace(xb,"\r\n")}}):{name:b.name,value:c.replace(xb,"\r\n")}}).get()}}),n.ajaxSettings.xhr=function(){try{return new XMLHttpRequest}catch(a){}};var Bb=0,Cb={},Db={0:200,1223:204},Eb=n.ajaxSettings.xhr();a.attachEvent&&a.attachEvent("onunload",function(){for(var a in Cb)Cb[a]()}),k.cors=!!Eb&&"withCredentials"in Eb,k.ajax=Eb=!!Eb,n.ajaxTransport(function(a){var b;return k.cors||Eb&&!a.crossDomain?{send:function(c,d){var e,f=a.xhr(),g=++Bb;if(f.open(a.type,a.url,a.async,a.username,a.password),a.xhrFields)for(e in a.xhrFields)f[e]=a.xhrFields[e];a.mimeType&&f.overrideMimeType&&f.overrideMimeType(a.mimeType),a.crossDomain||c["X-Requested-With"]||(c["X-Requested-With"]="XMLHttpRequest");for(e in c)f.setRequestHeader(e,c[e]);b=function(a){return function(){b&&(delete Cb[g],b=f.onload=f.onerror=null,"abort"===a?f.abort():"error"===a?d(f.status,f.statusText):d(Db[f.status]||f.status,f.statusText,"string"==typeof f.responseText?{text:f.responseText}:void 0,f.getAllResponseHeaders()))}},f.onload=b(),f.onerror=b("error"),b=Cb[g]=b("abort");try{f.send(a.hasContent&&a.data||null)}catch(h){if(b)throw h}},abort:function(){b&&b()}}:void 0}),n.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/(?:java|ecma)script/},converters:{"text script":function(a){return n.globalEval(a),a}}}),n.ajaxPrefilter("script",function(a){void 0===a.cache&&(a.cache=!1),a.crossDomain&&(a.type="GET")}),n.ajaxTransport("script",function(a){if(a.crossDomain){var b,c;return{send:function(d,e){b=n("<script>").prop({async:!0,charset:a.scriptCharset,src:a.url}).on("load error",c=function(a){b.remove(),c=null,a&&e("error"===a.type?404:200,a.type)}),l.head.appendChild(b[0])},abort:function(){c&&c()}}}});var Fb=[],Gb=/(=)\?(?=&|$)|\?\?/;n.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var a=Fb.pop()||n.expando+"_"+cb++;return this[a]=!0,a}}),n.ajaxPrefilter("json jsonp",function(b,c,d){var e,f,g,h=b.jsonp!==!1&&(Gb.test(b.url)?"url":"string"==typeof b.data&&!(b.contentType||"").indexOf("application/x-www-form-urlencoded")&&Gb.test(b.data)&&"data");return h||"jsonp"===b.dataTypes[0]?(e=b.jsonpCallback=n.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,h?b[h]=b[h].replace(Gb,"$1"+e):b.jsonp!==!1&&(b.url+=(db.test(b.url)?"&":"?")+b.jsonp+"="+e),b.converters["script json"]=function(){return g||n.error(e+" was not called"),g[0]},b.dataTypes[0]="json",f=a[e],a[e]=function(){g=arguments},d.always(function(){a[e]=f,b[e]&&(b.jsonpCallback=c.jsonpCallback,Fb.push(e)),g&&n.isFunction(f)&&f(g[0]),g=f=void 0}),"script"):void 0}),n.parseHTML=function(a,b,c){if(!a||"string"!=typeof a)return null;"boolean"==typeof b&&(c=b,b=!1),b=b||l;var d=v.exec(a),e=!c&&[];return d?[b.createElement(d[1])]:(d=n.buildFragment([a],b,e),e&&e.length&&n(e).remove(),n.merge([],d.childNodes))};var Hb=n.fn.load;n.fn.load=function(a,b,c){if("string"!=typeof a&&Hb)return Hb.apply(this,arguments);var d,e,f,g=this,h=a.indexOf(" ");return h>=0&&(d=n.trim(a.slice(h)),a=a.slice(0,h)),n.isFunction(b)?(c=b,b=void 0):b&&"object"==typeof b&&(e="POST"),g.length>0&&n.ajax({url:a,type:e,dataType:"html",data:b}).done(function(a){f=arguments,g.html(d?n("<div>").append(n.parseHTML(a)).find(d):a)}).complete(c&&function(a,b){g.each(c,f||[a.responseText,b,a])}),this},n.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(a,b){n.fn[b]=function(a){return this.on(b,a)}}),n.expr.filters.animated=function(a){return n.grep(n.timers,function(b){return a===b.elem}).length};var Ib=a.document.documentElement;function Jb(a){return n.isWindow(a)?a:9===a.nodeType&&a.defaultView}n.offset={setOffset:function(a,b,c){var d,e,f,g,h,i,j,k=n.css(a,"position"),l=n(a),m={};"static"===k&&(a.style.position="relative"),h=l.offset(),f=n.css(a,"top"),i=n.css(a,"left"),j=("absolute"===k||"fixed"===k)&&(f+i).indexOf("auto")>-1,j?(d=l.position(),g=d.top,e=d.left):(g=parseFloat(f)||0,e=parseFloat(i)||0),n.isFunction(b)&&(b=b.call(a,c,h)),null!=b.top&&(m.top=b.top-h.top+g),null!=b.left&&(m.left=b.left-h.left+e),"using"in b?b.using.call(a,m):l.css(m)}},n.fn.extend({offset:function(a){if(arguments.length)return void 0===a?this:this.each(function(b){n.offset.setOffset(this,a,b)});var b,c,d=this[0],e={top:0,left:0},f=d&&d.ownerDocument;if(f)return b=f.documentElement,n.contains(b,d)?(typeof d.getBoundingClientRect!==U&&(e=d.getBoundingClientRect()),c=Jb(f),{top:e.top+c.pageYOffset-b.clientTop,left:e.left+c.pageXOffset-b.clientLeft}):e},position:function(){if(this[0]){var a,b,c=this[0],d={top:0,left:0};return"fixed"===n.css(c,"position")?b=c.getBoundingClientRect():(a=this.offsetParent(),b=this.offset(),n.nodeName(a[0],"html")||(d=a.offset()),d.top+=n.css(a[0],"borderTopWidth",!0),d.left+=n.css(a[0],"borderLeftWidth",!0)),{top:b.top-d.top-n.css(c,"marginTop",!0),left:b.left-d.left-n.css(c,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||Ib;while(a&&!n.nodeName(a,"html")&&"static"===n.css(a,"position"))a=a.offsetParent;return a||Ib})}}),n.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(b,c){var d="pageYOffset"===c;n.fn[b]=function(e){return J(this,function(b,e,f){var g=Jb(b);return void 0===f?g?g[c]:b[e]:void(g?g.scrollTo(d?a.pageXOffset:f,d?f:a.pageYOffset):b[e]=f)},b,e,arguments.length,null)}}),n.each(["top","left"],function(a,b){n.cssHooks[b]=ya(k.pixelPosition,function(a,c){return c?(c=xa(a,b),va.test(c)?n(a).position()[b]+"px":c):void 0})}),n.each({Height:"height",Width:"width"},function(a,b){n.each({padding:"inner"+a,content:b,"":"outer"+a},function(c,d){n.fn[d]=function(d,e){var f=arguments.length&&(c||"boolean"!=typeof d),g=c||(d===!0||e===!0?"margin":"border");return J(this,function(b,c,d){var e;return n.isWindow(b)?b.document.documentElement["client"+a]:9===b.nodeType?(e=b.documentElement,Math.max(b.body["scroll"+a],e["scroll"+a],b.body["offset"+a],e["offset"+a],e["client"+a])):void 0===d?n.css(b,c,g):n.style(b,c,d,g)},b,f?d:void 0,f,null)}})}),n.fn.size=function(){return this.length},n.fn.andSelf=n.fn.addBack,"function"==typeof define&&define.amd&&define("jquery",[],function(){return n});var Kb=a.jQuery,Lb=a.$;return n.noConflict=function(b){return a.$===n&&(a.$=Lb),b&&a.jQuery===n&&(a.jQuery=Kb),n},typeof b===U&&(a.jQuery=a.$=n),n});
diff --git a/src/Jackett/Content/libs/moment.min.js b/src/Jackett/Content/libs/moment.min.js
new file mode 100644
index 0000000000000000000000000000000000000000..8e6866af04eb12e622d2b957530e293352ea3945
--- /dev/null
+++ b/src/Jackett/Content/libs/moment.min.js
@@ -0,0 +1,7 @@
+//! moment.js
+//! version : 2.10.6
+//! authors : Tim Wood, Iskren Chernev, Moment.js contributors
+//! license : MIT
+//! momentjs.com
+!function(a,b){"object"==typeof exports&&"undefined"!=typeof module?module.exports=b():"function"==typeof define&&define.amd?define(b):a.moment=b()}(this,function(){"use strict";function a(){return Hc.apply(null,arguments)}function b(a){Hc=a}function c(a){return"[object Array]"===Object.prototype.toString.call(a)}function d(a){return a instanceof Date||"[object Date]"===Object.prototype.toString.call(a)}function e(a,b){var c,d=[];for(c=0;c<a.length;++c)d.push(b(a[c],c));return d}function f(a,b){return Object.prototype.hasOwnProperty.call(a,b)}function g(a,b){for(var c in b)f(b,c)&&(a[c]=b[c]);return f(b,"toString")&&(a.toString=b.toString),f(b,"valueOf")&&(a.valueOf=b.valueOf),a}function h(a,b,c,d){return Ca(a,b,c,d,!0).utc()}function i(){return{empty:!1,unusedTokens:[],unusedInput:[],overflow:-2,charsLeftOver:0,nullInput:!1,invalidMonth:null,invalidFormat:!1,userInvalidated:!1,iso:!1}}function j(a){return null==a._pf&&(a._pf=i()),a._pf}function k(a){if(null==a._isValid){var b=j(a);a._isValid=!(isNaN(a._d.getTime())||!(b.overflow<0)||b.empty||b.invalidMonth||b.invalidWeekday||b.nullInput||b.invalidFormat||b.userInvalidated),a._strict&&(a._isValid=a._isValid&&0===b.charsLeftOver&&0===b.unusedTokens.length&&void 0===b.bigHour)}return a._isValid}function l(a){var b=h(NaN);return null!=a?g(j(b),a):j(b).userInvalidated=!0,b}function m(a,b){var c,d,e;if("undefined"!=typeof b._isAMomentObject&&(a._isAMomentObject=b._isAMomentObject),"undefined"!=typeof b._i&&(a._i=b._i),"undefined"!=typeof b._f&&(a._f=b._f),"undefined"!=typeof b._l&&(a._l=b._l),"undefined"!=typeof b._strict&&(a._strict=b._strict),"undefined"!=typeof b._tzm&&(a._tzm=b._tzm),"undefined"!=typeof b._isUTC&&(a._isUTC=b._isUTC),"undefined"!=typeof b._offset&&(a._offset=b._offset),"undefined"!=typeof b._pf&&(a._pf=j(b)),"undefined"!=typeof b._locale&&(a._locale=b._locale),Jc.length>0)for(c in Jc)d=Jc[c],e=b[d],"undefined"!=typeof e&&(a[d]=e);return a}function n(b){m(this,b),this._d=new Date(null!=b._d?b._d.getTime():NaN),Kc===!1&&(Kc=!0,a.updateOffset(this),Kc=!1)}function o(a){return a instanceof n||null!=a&&null!=a._isAMomentObject}function p(a){return 0>a?Math.ceil(a):Math.floor(a)}function q(a){var b=+a,c=0;return 0!==b&&isFinite(b)&&(c=p(b)),c}function r(a,b,c){var d,e=Math.min(a.length,b.length),f=Math.abs(a.length-b.length),g=0;for(d=0;e>d;d++)(c&&a[d]!==b[d]||!c&&q(a[d])!==q(b[d]))&&g++;return g+f}function s(){}function t(a){return a?a.toLowerCase().replace("_","-"):a}function u(a){for(var b,c,d,e,f=0;f<a.length;){for(e=t(a[f]).split("-"),b=e.length,c=t(a[f+1]),c=c?c.split("-"):null;b>0;){if(d=v(e.slice(0,b).join("-")))return d;if(c&&c.length>=b&&r(e,c,!0)>=b-1)break;b--}f++}return null}function v(a){var b=null;if(!Lc[a]&&"undefined"!=typeof module&&module&&module.exports)try{b=Ic._abbr,require("./locale/"+a),w(b)}catch(c){}return Lc[a]}function w(a,b){var c;return a&&(c="undefined"==typeof b?y(a):x(a,b),c&&(Ic=c)),Ic._abbr}function x(a,b){return null!==b?(b.abbr=a,Lc[a]=Lc[a]||new s,Lc[a].set(b),w(a),Lc[a]):(delete Lc[a],null)}function y(a){var b;if(a&&a._locale&&a._locale._abbr&&(a=a._locale._abbr),!a)return Ic;if(!c(a)){if(b=v(a))return b;a=[a]}return u(a)}function z(a,b){var c=a.toLowerCase();Mc[c]=Mc[c+"s"]=Mc[b]=a}function A(a){return"string"==typeof a?Mc[a]||Mc[a.toLowerCase()]:void 0}function B(a){var b,c,d={};for(c in a)f(a,c)&&(b=A(c),b&&(d[b]=a[c]));return d}function C(b,c){return function(d){return null!=d?(E(this,b,d),a.updateOffset(this,c),this):D(this,b)}}function D(a,b){return a._d["get"+(a._isUTC?"UTC":"")+b]()}function E(a,b,c){return a._d["set"+(a._isUTC?"UTC":"")+b](c)}function F(a,b){var c;if("object"==typeof a)for(c in a)this.set(c,a[c]);else if(a=A(a),"function"==typeof this[a])return this[a](b);return this}function G(a,b,c){var d=""+Math.abs(a),e=b-d.length,f=a>=0;return(f?c?"+":"":"-")+Math.pow(10,Math.max(0,e)).toString().substr(1)+d}function H(a,b,c,d){var e=d;"string"==typeof d&&(e=function(){return this[d]()}),a&&(Qc[a]=e),b&&(Qc[b[0]]=function(){return G(e.apply(this,arguments),b[1],b[2])}),c&&(Qc[c]=function(){return this.localeData().ordinal(e.apply(this,arguments),a)})}function I(a){return a.match(/\[[\s\S]/)?a.replace(/^\[|\]$/g,""):a.replace(/\\/g,"")}function J(a){var b,c,d=a.match(Nc);for(b=0,c=d.length;c>b;b++)Qc[d[b]]?d[b]=Qc[d[b]]:d[b]=I(d[b]);return function(e){var f="";for(b=0;c>b;b++)f+=d[b]instanceof Function?d[b].call(e,a):d[b];return f}}function K(a,b){return a.isValid()?(b=L(b,a.localeData()),Pc[b]=Pc[b]||J(b),Pc[b](a)):a.localeData().invalidDate()}function L(a,b){function c(a){return b.longDateFormat(a)||a}var d=5;for(Oc.lastIndex=0;d>=0&&Oc.test(a);)a=a.replace(Oc,c),Oc.lastIndex=0,d-=1;return a}function M(a){return"function"==typeof a&&"[object Function]"===Object.prototype.toString.call(a)}function N(a,b,c){dd[a]=M(b)?b:function(a){return a&&c?c:b}}function O(a,b){return f(dd,a)?dd[a](b._strict,b._locale):new RegExp(P(a))}function P(a){return a.replace("\\","").replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g,function(a,b,c,d,e){return b||c||d||e}).replace(/[-\/\\^$*+?.()|[\]{}]/g,"\\$&")}function Q(a,b){var c,d=b;for("string"==typeof a&&(a=[a]),"number"==typeof b&&(d=function(a,c){c[b]=q(a)}),c=0;c<a.length;c++)ed[a[c]]=d}function R(a,b){Q(a,function(a,c,d,e){d._w=d._w||{},b(a,d._w,d,e)})}function S(a,b,c){null!=b&&f(ed,a)&&ed[a](b,c._a,c,a)}function T(a,b){return new Date(Date.UTC(a,b+1,0)).getUTCDate()}function U(a){return this._months[a.month()]}function V(a){return this._monthsShort[a.month()]}function W(a,b,c){var d,e,f;for(this._monthsParse||(this._monthsParse=[],this._longMonthsParse=[],this._shortMonthsParse=[]),d=0;12>d;d++){if(e=h([2e3,d]),c&&!this._longMonthsParse[d]&&(this._longMonthsParse[d]=new RegExp("^"+this.months(e,"").replace(".","")+"$","i"),this._shortMonthsParse[d]=new RegExp("^"+this.monthsShort(e,"").replace(".","")+"$","i")),c||this._monthsParse[d]||(f="^"+this.months(e,"")+"|^"+this.monthsShort(e,""),this._monthsParse[d]=new RegExp(f.replace(".",""),"i")),c&&"MMMM"===b&&this._longMonthsParse[d].test(a))return d;if(c&&"MMM"===b&&this._shortMonthsParse[d].test(a))return d;if(!c&&this._monthsParse[d].test(a))return d}}function X(a,b){var c;return"string"==typeof b&&(b=a.localeData().monthsParse(b),"number"!=typeof b)?a:(c=Math.min(a.date(),T(a.year(),b)),a._d["set"+(a._isUTC?"UTC":"")+"Month"](b,c),a)}function Y(b){return null!=b?(X(this,b),a.updateOffset(this,!0),this):D(this,"Month")}function Z(){return T(this.year(),this.month())}function $(a){var b,c=a._a;return c&&-2===j(a).overflow&&(b=c[gd]<0||c[gd]>11?gd:c[hd]<1||c[hd]>T(c[fd],c[gd])?hd:c[id]<0||c[id]>24||24===c[id]&&(0!==c[jd]||0!==c[kd]||0!==c[ld])?id:c[jd]<0||c[jd]>59?jd:c[kd]<0||c[kd]>59?kd:c[ld]<0||c[ld]>999?ld:-1,j(a)._overflowDayOfYear&&(fd>b||b>hd)&&(b=hd),j(a).overflow=b),a}function _(b){a.suppressDeprecationWarnings===!1&&"undefined"!=typeof console&&console.warn&&console.warn("Deprecation warning: "+b)}function aa(a,b){var c=!0;return g(function(){return c&&(_(a+"\n"+(new Error).stack),c=!1),b.apply(this,arguments)},b)}function ba(a,b){od[a]||(_(b),od[a]=!0)}function ca(a){var b,c,d=a._i,e=pd.exec(d);if(e){for(j(a).iso=!0,b=0,c=qd.length;c>b;b++)if(qd[b][1].exec(d)){a._f=qd[b][0];break}for(b=0,c=rd.length;c>b;b++)if(rd[b][1].exec(d)){a._f+=(e[6]||" ")+rd[b][0];break}d.match(ad)&&(a._f+="Z"),va(a)}else a._isValid=!1}function da(b){var c=sd.exec(b._i);return null!==c?void(b._d=new Date(+c[1])):(ca(b),void(b._isValid===!1&&(delete b._isValid,a.createFromInputFallback(b))))}function ea(a,b,c,d,e,f,g){var h=new Date(a,b,c,d,e,f,g);return 1970>a&&h.setFullYear(a),h}function fa(a){var b=new Date(Date.UTC.apply(null,arguments));return 1970>a&&b.setUTCFullYear(a),b}function ga(a){return ha(a)?366:365}function ha(a){return a%4===0&&a%100!==0||a%400===0}function ia(){return ha(this.year())}function ja(a,b,c){var d,e=c-b,f=c-a.day();return f>e&&(f-=7),e-7>f&&(f+=7),d=Da(a).add(f,"d"),{week:Math.ceil(d.dayOfYear()/7),year:d.year()}}function ka(a){return ja(a,this._week.dow,this._week.doy).week}function la(){return this._week.dow}function ma(){return this._week.doy}function na(a){var b=this.localeData().week(this);return null==a?b:this.add(7*(a-b),"d")}function oa(a){var b=ja(this,1,4).week;return null==a?b:this.add(7*(a-b),"d")}function pa(a,b,c,d,e){var f,g=6+e-d,h=fa(a,0,1+g),i=h.getUTCDay();return e>i&&(i+=7),c=null!=c?1*c:e,f=1+g+7*(b-1)-i+c,{year:f>0?a:a-1,dayOfYear:f>0?f:ga(a-1)+f}}function qa(a){var b=Math.round((this.clone().startOf("day")-this.clone().startOf("year"))/864e5)+1;return null==a?b:this.add(a-b,"d")}function ra(a,b,c){return null!=a?a:null!=b?b:c}function sa(a){var b=new Date;return a._useUTC?[b.getUTCFullYear(),b.getUTCMonth(),b.getUTCDate()]:[b.getFullYear(),b.getMonth(),b.getDate()]}function ta(a){var b,c,d,e,f=[];if(!a._d){for(d=sa(a),a._w&&null==a._a[hd]&&null==a._a[gd]&&ua(a),a._dayOfYear&&(e=ra(a._a[fd],d[fd]),a._dayOfYear>ga(e)&&(j(a)._overflowDayOfYear=!0),c=fa(e,0,a._dayOfYear),a._a[gd]=c.getUTCMonth(),a._a[hd]=c.getUTCDate()),b=0;3>b&&null==a._a[b];++b)a._a[b]=f[b]=d[b];for(;7>b;b++)a._a[b]=f[b]=null==a._a[b]?2===b?1:0:a._a[b];24===a._a[id]&&0===a._a[jd]&&0===a._a[kd]&&0===a._a[ld]&&(a._nextDay=!0,a._a[id]=0),a._d=(a._useUTC?fa:ea).apply(null,f),null!=a._tzm&&a._d.setUTCMinutes(a._d.getUTCMinutes()-a._tzm),a._nextDay&&(a._a[id]=24)}}function ua(a){var b,c,d,e,f,g,h;b=a._w,null!=b.GG||null!=b.W||null!=b.E?(f=1,g=4,c=ra(b.GG,a._a[fd],ja(Da(),1,4).year),d=ra(b.W,1),e=ra(b.E,1)):(f=a._locale._week.dow,g=a._locale._week.doy,c=ra(b.gg,a._a[fd],ja(Da(),f,g).year),d=ra(b.w,1),null!=b.d?(e=b.d,f>e&&++d):e=null!=b.e?b.e+f:f),h=pa(c,d,e,g,f),a._a[fd]=h.year,a._dayOfYear=h.dayOfYear}function va(b){if(b._f===a.ISO_8601)return void ca(b);b._a=[],j(b).empty=!0;var c,d,e,f,g,h=""+b._i,i=h.length,k=0;for(e=L(b._f,b._locale).match(Nc)||[],c=0;c<e.length;c++)f=e[c],d=(h.match(O(f,b))||[])[0],d&&(g=h.substr(0,h.indexOf(d)),g.length>0&&j(b).unusedInput.push(g),h=h.slice(h.indexOf(d)+d.length),k+=d.length),Qc[f]?(d?j(b).empty=!1:j(b).unusedTokens.push(f),S(f,d,b)):b._strict&&!d&&j(b).unusedTokens.push(f);j(b).charsLeftOver=i-k,h.length>0&&j(b).unusedInput.push(h),j(b).bigHour===!0&&b._a[id]<=12&&b._a[id]>0&&(j(b).bigHour=void 0),b._a[id]=wa(b._locale,b._a[id],b._meridiem),ta(b),$(b)}function wa(a,b,c){var d;return null==c?b:null!=a.meridiemHour?a.meridiemHour(b,c):null!=a.isPM?(d=a.isPM(c),d&&12>b&&(b+=12),d||12!==b||(b=0),b):b}function xa(a){var b,c,d,e,f;if(0===a._f.length)return j(a).invalidFormat=!0,void(a._d=new Date(NaN));for(e=0;e<a._f.length;e++)f=0,b=m({},a),null!=a._useUTC&&(b._useUTC=a._useUTC),b._f=a._f[e],va(b),k(b)&&(f+=j(b).charsLeftOver,f+=10*j(b).unusedTokens.length,j(b).score=f,(null==d||d>f)&&(d=f,c=b));g(a,c||b)}function ya(a){if(!a._d){var b=B(a._i);a._a=[b.year,b.month,b.day||b.date,b.hour,b.minute,b.second,b.millisecond],ta(a)}}function za(a){var b=new n($(Aa(a)));return b._nextDay&&(b.add(1,"d"),b._nextDay=void 0),b}function Aa(a){var b=a._i,e=a._f;return a._locale=a._locale||y(a._l),null===b||void 0===e&&""===b?l({nullInput:!0}):("string"==typeof b&&(a._i=b=a._locale.preparse(b)),o(b)?new n($(b)):(c(e)?xa(a):e?va(a):d(b)?a._d=b:Ba(a),a))}function Ba(b){var f=b._i;void 0===f?b._d=new Date:d(f)?b._d=new Date(+f):"string"==typeof f?da(b):c(f)?(b._a=e(f.slice(0),function(a){return parseInt(a,10)}),ta(b)):"object"==typeof f?ya(b):"number"==typeof f?b._d=new Date(f):a.createFromInputFallback(b)}function Ca(a,b,c,d,e){var f={};return"boolean"==typeof c&&(d=c,c=void 0),f._isAMomentObject=!0,f._useUTC=f._isUTC=e,f._l=c,f._i=a,f._f=b,f._strict=d,za(f)}function Da(a,b,c,d){return Ca(a,b,c,d,!1)}function Ea(a,b){var d,e;if(1===b.length&&c(b[0])&&(b=b[0]),!b.length)return Da();for(d=b[0],e=1;e<b.length;++e)(!b[e].isValid()||b[e][a](d))&&(d=b[e]);return d}function Fa(){var a=[].slice.call(arguments,0);return Ea("isBefore",a)}function Ga(){var a=[].slice.call(arguments,0);return Ea("isAfter",a)}function Ha(a){var b=B(a),c=b.year||0,d=b.quarter||0,e=b.month||0,f=b.week||0,g=b.day||0,h=b.hour||0,i=b.minute||0,j=b.second||0,k=b.millisecond||0;this._milliseconds=+k+1e3*j+6e4*i+36e5*h,this._days=+g+7*f,this._months=+e+3*d+12*c,this._data={},this._locale=y(),this._bubble()}function Ia(a){return a instanceof Ha}function Ja(a,b){H(a,0,0,function(){var a=this.utcOffset(),c="+";return 0>a&&(a=-a,c="-"),c+G(~~(a/60),2)+b+G(~~a%60,2)})}function Ka(a){var b=(a||"").match(ad)||[],c=b[b.length-1]||[],d=(c+"").match(xd)||["-",0,0],e=+(60*d[1])+q(d[2]);return"+"===d[0]?e:-e}function La(b,c){var e,f;return c._isUTC?(e=c.clone(),f=(o(b)||d(b)?+b:+Da(b))-+e,e._d.setTime(+e._d+f),a.updateOffset(e,!1),e):Da(b).local()}function Ma(a){return 15*-Math.round(a._d.getTimezoneOffset()/15)}function Na(b,c){var d,e=this._offset||0;return null!=b?("string"==typeof b&&(b=Ka(b)),Math.abs(b)<16&&(b=60*b),!this._isUTC&&c&&(d=Ma(this)),this._offset=b,this._isUTC=!0,null!=d&&this.add(d,"m"),e!==b&&(!c||this._changeInProgress?bb(this,Ya(b-e,"m"),1,!1):this._changeInProgress||(this._changeInProgress=!0,a.updateOffset(this,!0),this._changeInProgress=null)),this):this._isUTC?e:Ma(this)}function Oa(a,b){return null!=a?("string"!=typeof a&&(a=-a),this.utcOffset(a,b),this):-this.utcOffset()}function Pa(a){return this.utcOffset(0,a)}function Qa(a){return this._isUTC&&(this.utcOffset(0,a),this._isUTC=!1,a&&this.subtract(Ma(this),"m")),this}function Ra(){return this._tzm?this.utcOffset(this._tzm):"string"==typeof this._i&&this.utcOffset(Ka(this._i)),this}function Sa(a){return a=a?Da(a).utcOffset():0,(this.utcOffset()-a)%60===0}function Ta(){return this.utcOffset()>this.clone().month(0).utcOffset()||this.utcOffset()>this.clone().month(5).utcOffset()}function Ua(){if("undefined"!=typeof this._isDSTShifted)return this._isDSTShifted;var a={};if(m(a,this),a=Aa(a),a._a){var b=a._isUTC?h(a._a):Da(a._a);this._isDSTShifted=this.isValid()&&r(a._a,b.toArray())>0}else this._isDSTShifted=!1;return this._isDSTShifted}function Va(){return!this._isUTC}function Wa(){return this._isUTC}function Xa(){return this._isUTC&&0===this._offset}function Ya(a,b){var c,d,e,g=a,h=null;return Ia(a)?g={ms:a._milliseconds,d:a._days,M:a._months}:"number"==typeof a?(g={},b?g[b]=a:g.milliseconds=a):(h=yd.exec(a))?(c="-"===h[1]?-1:1,g={y:0,d:q(h[hd])*c,h:q(h[id])*c,m:q(h[jd])*c,s:q(h[kd])*c,ms:q(h[ld])*c}):(h=zd.exec(a))?(c="-"===h[1]?-1:1,g={y:Za(h[2],c),M:Za(h[3],c),d:Za(h[4],c),h:Za(h[5],c),m:Za(h[6],c),s:Za(h[7],c),w:Za(h[8],c)}):null==g?g={}:"object"==typeof g&&("from"in g||"to"in g)&&(e=_a(Da(g.from),Da(g.to)),g={},g.ms=e.milliseconds,g.M=e.months),d=new Ha(g),Ia(a)&&f(a,"_locale")&&(d._locale=a._locale),d}function Za(a,b){var c=a&&parseFloat(a.replace(",","."));return(isNaN(c)?0:c)*b}function $a(a,b){var c={milliseconds:0,months:0};return c.months=b.month()-a.month()+12*(b.year()-a.year()),a.clone().add(c.months,"M").isAfter(b)&&--c.months,c.milliseconds=+b-+a.clone().add(c.months,"M"),c}function _a(a,b){var c;return b=La(b,a),a.isBefore(b)?c=$a(a,b):(c=$a(b,a),c.milliseconds=-c.milliseconds,c.months=-c.months),c}function ab(a,b){return function(c,d){var e,f;return null===d||isNaN(+d)||(ba(b,"moment()."+b+"(period, number) is deprecated. Please use moment()."+b+"(number, period)."),f=c,c=d,d=f),c="string"==typeof c?+c:c,e=Ya(c,d),bb(this,e,a),this}}function bb(b,c,d,e){var f=c._milliseconds,g=c._days,h=c._months;e=null==e?!0:e,f&&b._d.setTime(+b._d+f*d),g&&E(b,"Date",D(b,"Date")+g*d),h&&X(b,D(b,"Month")+h*d),e&&a.updateOffset(b,g||h)}function cb(a,b){var c=a||Da(),d=La(c,this).startOf("day"),e=this.diff(d,"days",!0),f=-6>e?"sameElse":-1>e?"lastWeek":0>e?"lastDay":1>e?"sameDay":2>e?"nextDay":7>e?"nextWeek":"sameElse";return this.format(b&&b[f]||this.localeData().calendar(f,this,Da(c)))}function db(){return new n(this)}function eb(a,b){var c;return b=A("undefined"!=typeof b?b:"millisecond"),"millisecond"===b?(a=o(a)?a:Da(a),+this>+a):(c=o(a)?+a:+Da(a),c<+this.clone().startOf(b))}function fb(a,b){var c;return b=A("undefined"!=typeof b?b:"millisecond"),"millisecond"===b?(a=o(a)?a:Da(a),+a>+this):(c=o(a)?+a:+Da(a),+this.clone().endOf(b)<c)}function gb(a,b,c){return this.isAfter(a,c)&&this.isBefore(b,c)}function hb(a,b){var c;return b=A(b||"millisecond"),"millisecond"===b?(a=o(a)?a:Da(a),+this===+a):(c=+Da(a),+this.clone().startOf(b)<=c&&c<=+this.clone().endOf(b))}function ib(a,b,c){var d,e,f=La(a,this),g=6e4*(f.utcOffset()-this.utcOffset());return b=A(b),"year"===b||"month"===b||"quarter"===b?(e=jb(this,f),"quarter"===b?e/=3:"year"===b&&(e/=12)):(d=this-f,e="second"===b?d/1e3:"minute"===b?d/6e4:"hour"===b?d/36e5:"day"===b?(d-g)/864e5:"week"===b?(d-g)/6048e5:d),c?e:p(e)}function jb(a,b){var c,d,e=12*(b.year()-a.year())+(b.month()-a.month()),f=a.clone().add(e,"months");return 0>b-f?(c=a.clone().add(e-1,"months"),d=(b-f)/(f-c)):(c=a.clone().add(e+1,"months"),d=(b-f)/(c-f)),-(e+d)}function kb(){return this.clone().locale("en").format("ddd MMM DD YYYY HH:mm:ss [GMT]ZZ")}function lb(){var a=this.clone().utc();return 0<a.year()&&a.year()<=9999?"function"==typeof Date.prototype.toISOString?this.toDate().toISOString():K(a,"YYYY-MM-DD[T]HH:mm:ss.SSS[Z]"):K(a,"YYYYYY-MM-DD[T]HH:mm:ss.SSS[Z]")}function mb(b){var c=K(this,b||a.defaultFormat);return this.localeData().postformat(c)}function nb(a,b){return this.isValid()?Ya({to:this,from:a}).locale(this.locale()).humanize(!b):this.localeData().invalidDate()}function ob(a){return this.from(Da(),a)}function pb(a,b){return this.isValid()?Ya({from:this,to:a}).locale(this.locale()).humanize(!b):this.localeData().invalidDate()}function qb(a){return this.to(Da(),a)}function rb(a){var b;return void 0===a?this._locale._abbr:(b=y(a),null!=b&&(this._locale=b),this)}function sb(){return this._locale}function tb(a){switch(a=A(a)){case"year":this.month(0);case"quarter":case"month":this.date(1);case"week":case"isoWeek":case"day":this.hours(0);case"hour":this.minutes(0);case"minute":this.seconds(0);case"second":this.milliseconds(0)}return"week"===a&&this.weekday(0),"isoWeek"===a&&this.isoWeekday(1),"quarter"===a&&this.month(3*Math.floor(this.month()/3)),this}function ub(a){return a=A(a),void 0===a||"millisecond"===a?this:this.startOf(a).add(1,"isoWeek"===a?"week":a).subtract(1,"ms")}function vb(){return+this._d-6e4*(this._offset||0)}function wb(){return Math.floor(+this/1e3)}function xb(){return this._offset?new Date(+this):this._d}function yb(){var a=this;return[a.year(),a.month(),a.date(),a.hour(),a.minute(),a.second(),a.millisecond()]}function zb(){var a=this;return{years:a.year(),months:a.month(),date:a.date(),hours:a.hours(),minutes:a.minutes(),seconds:a.seconds(),milliseconds:a.milliseconds()}}function Ab(){return k(this)}function Bb(){return g({},j(this))}function Cb(){return j(this).overflow}function Db(a,b){H(0,[a,a.length],0,b)}function Eb(a,b,c){return ja(Da([a,11,31+b-c]),b,c).week}function Fb(a){var b=ja(this,this.localeData()._week.dow,this.localeData()._week.doy).year;return null==a?b:this.add(a-b,"y")}function Gb(a){var b=ja(this,1,4).year;return null==a?b:this.add(a-b,"y")}function Hb(){return Eb(this.year(),1,4)}function Ib(){var a=this.localeData()._week;return Eb(this.year(),a.dow,a.doy)}function Jb(a){return null==a?Math.ceil((this.month()+1)/3):this.month(3*(a-1)+this.month()%3)}function Kb(a,b){return"string"!=typeof a?a:isNaN(a)?(a=b.weekdaysParse(a),"number"==typeof a?a:null):parseInt(a,10)}function Lb(a){return this._weekdays[a.day()]}function Mb(a){return this._weekdaysShort[a.day()]}function Nb(a){return this._weekdaysMin[a.day()]}function Ob(a){var b,c,d;for(this._weekdaysParse=this._weekdaysParse||[],b=0;7>b;b++)if(this._weekdaysParse[b]||(c=Da([2e3,1]).day(b),d="^"+this.weekdays(c,"")+"|^"+this.weekdaysShort(c,"")+"|^"+this.weekdaysMin(c,""),this._weekdaysParse[b]=new RegExp(d.replace(".",""),"i")),this._weekdaysParse[b].test(a))return b}function Pb(a){var b=this._isUTC?this._d.getUTCDay():this._d.getDay();return null!=a?(a=Kb(a,this.localeData()),this.add(a-b,"d")):b}function Qb(a){var b=(this.day()+7-this.localeData()._week.dow)%7;return null==a?b:this.add(a-b,"d")}function Rb(a){return null==a?this.day()||7:this.day(this.day()%7?a:a-7)}function Sb(a,b){H(a,0,0,function(){return this.localeData().meridiem(this.hours(),this.minutes(),b)})}function Tb(a,b){return b._meridiemParse}function Ub(a){return"p"===(a+"").toLowerCase().charAt(0)}function Vb(a,b,c){return a>11?c?"pm":"PM":c?"am":"AM"}function Wb(a,b){b[ld]=q(1e3*("0."+a))}function Xb(){return this._isUTC?"UTC":""}function Yb(){return this._isUTC?"Coordinated Universal Time":""}function Zb(a){return Da(1e3*a)}function $b(){return Da.apply(null,arguments).parseZone()}function _b(a,b,c){var d=this._calendar[a];return"function"==typeof d?d.call(b,c):d}function ac(a){var b=this._longDateFormat[a],c=this._longDateFormat[a.toUpperCase()];return b||!c?b:(this._longDateFormat[a]=c.replace(/MMMM|MM|DD|dddd/g,function(a){return a.slice(1)}),this._longDateFormat[a])}function bc(){return this._invalidDate}function cc(a){return this._ordinal.replace("%d",a)}function dc(a){return a}function ec(a,b,c,d){var e=this._relativeTime[c];return"function"==typeof e?e(a,b,c,d):e.replace(/%d/i,a)}function fc(a,b){var c=this._relativeTime[a>0?"future":"past"];return"function"==typeof c?c(b):c.replace(/%s/i,b)}function gc(a){var b,c;for(c in a)b=a[c],"function"==typeof b?this[c]=b:this["_"+c]=b;this._ordinalParseLenient=new RegExp(this._ordinalParse.source+"|"+/\d{1,2}/.source)}function hc(a,b,c,d){var e=y(),f=h().set(d,b);return e[c](f,a)}function ic(a,b,c,d,e){if("number"==typeof a&&(b=a,a=void 0),a=a||"",null!=b)return hc(a,b,c,e);var f,g=[];for(f=0;d>f;f++)g[f]=hc(a,f,c,e);return g}function jc(a,b){return ic(a,b,"months",12,"month")}function kc(a,b){return ic(a,b,"monthsShort",12,"month")}function lc(a,b){return ic(a,b,"weekdays",7,"day")}function mc(a,b){return ic(a,b,"weekdaysShort",7,"day")}function nc(a,b){return ic(a,b,"weekdaysMin",7,"day")}function oc(){var a=this._data;return this._milliseconds=Wd(this._milliseconds),this._days=Wd(this._days),this._months=Wd(this._months),a.milliseconds=Wd(a.milliseconds),a.seconds=Wd(a.seconds),a.minutes=Wd(a.minutes),a.hours=Wd(a.hours),a.months=Wd(a.months),a.years=Wd(a.years),this}function pc(a,b,c,d){var e=Ya(b,c);return a._milliseconds+=d*e._milliseconds,a._days+=d*e._days,a._months+=d*e._months,a._bubble()}function qc(a,b){return pc(this,a,b,1)}function rc(a,b){return pc(this,a,b,-1)}function sc(a){return 0>a?Math.floor(a):Math.ceil(a)}function tc(){var a,b,c,d,e,f=this._milliseconds,g=this._days,h=this._months,i=this._data;return f>=0&&g>=0&&h>=0||0>=f&&0>=g&&0>=h||(f+=864e5*sc(vc(h)+g),g=0,h=0),i.milliseconds=f%1e3,a=p(f/1e3),i.seconds=a%60,b=p(a/60),i.minutes=b%60,c=p(b/60),i.hours=c%24,g+=p(c/24),e=p(uc(g)),h+=e,g-=sc(vc(e)),d=p(h/12),h%=12,i.days=g,i.months=h,i.years=d,this}function uc(a){return 4800*a/146097}function vc(a){return 146097*a/4800}function wc(a){var b,c,d=this._milliseconds;if(a=A(a),"month"===a||"year"===a)return b=this._days+d/864e5,c=this._months+uc(b),"month"===a?c:c/12;switch(b=this._days+Math.round(vc(this._months)),a){case"week":return b/7+d/6048e5;case"day":return b+d/864e5;case"hour":return 24*b+d/36e5;case"minute":return 1440*b+d/6e4;case"second":return 86400*b+d/1e3;case"millisecond":return Math.floor(864e5*b)+d;default:throw new Error("Unknown unit "+a)}}function xc(){return this._milliseconds+864e5*this._days+this._months%12*2592e6+31536e6*q(this._months/12)}function yc(a){return function(){return this.as(a)}}function zc(a){return a=A(a),this[a+"s"]()}function Ac(a){return function(){return this._data[a]}}function Bc(){return p(this.days()/7)}function Cc(a,b,c,d,e){return e.relativeTime(b||1,!!c,a,d)}function Dc(a,b,c){var d=Ya(a).abs(),e=ke(d.as("s")),f=ke(d.as("m")),g=ke(d.as("h")),h=ke(d.as("d")),i=ke(d.as("M")),j=ke(d.as("y")),k=e<le.s&&["s",e]||1===f&&["m"]||f<le.m&&["mm",f]||1===g&&["h"]||g<le.h&&["hh",g]||1===h&&["d"]||h<le.d&&["dd",h]||1===i&&["M"]||i<le.M&&["MM",i]||1===j&&["y"]||["yy",j];return k[2]=b,k[3]=+a>0,k[4]=c,Cc.apply(null,k)}function Ec(a,b){return void 0===le[a]?!1:void 0===b?le[a]:(le[a]=b,!0)}function Fc(a){var b=this.localeData(),c=Dc(this,!a,b);return a&&(c=b.pastFuture(+this,c)),b.postformat(c)}function Gc(){var a,b,c,d=me(this._milliseconds)/1e3,e=me(this._days),f=me(this._months);a=p(d/60),b=p(a/60),d%=60,a%=60,c=p(f/12),f%=12;var g=c,h=f,i=e,j=b,k=a,l=d,m=this.asSeconds();return m?(0>m?"-":"")+"P"+(g?g+"Y":"")+(h?h+"M":"")+(i?i+"D":"")+(j||k||l?"T":"")+(j?j+"H":"")+(k?k+"M":"")+(l?l+"S":""):"P0D"}var Hc,Ic,Jc=a.momentProperties=[],Kc=!1,Lc={},Mc={},Nc=/(\[[^\[]*\])|(\\)?(Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|Q|YYYYYY|YYYYY|YYYY|YY|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|mm?|ss?|S{1,9}|x|X|zz?|ZZ?|.)/g,Oc=/(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g,Pc={},Qc={},Rc=/\d/,Sc=/\d\d/,Tc=/\d{3}/,Uc=/\d{4}/,Vc=/[+-]?\d{6}/,Wc=/\d\d?/,Xc=/\d{1,3}/,Yc=/\d{1,4}/,Zc=/[+-]?\d{1,6}/,$c=/\d+/,_c=/[+-]?\d+/,ad=/Z|[+-]\d\d:?\d\d/gi,bd=/[+-]?\d+(\.\d{1,3})?/,cd=/[0-9]*['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+|[\u0600-\u06FF\/]+(\s*?[\u0600-\u06FF]+){1,2}/i,dd={},ed={},fd=0,gd=1,hd=2,id=3,jd=4,kd=5,ld=6;H("M",["MM",2],"Mo",function(){return this.month()+1}),H("MMM",0,0,function(a){return this.localeData().monthsShort(this,a)}),H("MMMM",0,0,function(a){return this.localeData().months(this,a)}),z("month","M"),N("M",Wc),N("MM",Wc,Sc),N("MMM",cd),N("MMMM",cd),Q(["M","MM"],function(a,b){b[gd]=q(a)-1}),Q(["MMM","MMMM"],function(a,b,c,d){var e=c._locale.monthsParse(a,d,c._strict);null!=e?b[gd]=e:j(c).invalidMonth=a});var md="January_February_March_April_May_June_July_August_September_October_November_December".split("_"),nd="Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),od={};a.suppressDeprecationWarnings=!1;var pd=/^\s*(?:[+-]\d{6}|\d{4})-(?:(\d\d-\d\d)|(W\d\d$)|(W\d\d-\d)|(\d\d\d))((T| )(\d\d(:\d\d(:\d\d(\.\d+)?)?)?)?([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/,qd=[["YYYYYY-MM-DD",/[+-]\d{6}-\d{2}-\d{2}/],["YYYY-MM-DD",/\d{4}-\d{2}-\d{2}/],["GGGG-[W]WW-E",/\d{4}-W\d{2}-\d/],["GGGG-[W]WW",/\d{4}-W\d{2}/],["YYYY-DDD",/\d{4}-\d{3}/]],rd=[["HH:mm:ss.SSSS",/(T| )\d\d:\d\d:\d\d\.\d+/],["HH:mm:ss",/(T| )\d\d:\d\d:\d\d/],["HH:mm",/(T| )\d\d:\d\d/],["HH",/(T| )\d\d/]],sd=/^\/?Date\((\-?\d+)/i;a.createFromInputFallback=aa("moment construction falls back to js Date. This is discouraged and will be removed in upcoming major release. Please refer to https://github.com/moment/moment/issues/1407 for more info.",function(a){a._d=new Date(a._i+(a._useUTC?" UTC":""))}),H(0,["YY",2],0,function(){return this.year()%100}),H(0,["YYYY",4],0,"year"),H(0,["YYYYY",5],0,"year"),H(0,["YYYYYY",6,!0],0,"year"),z("year","y"),N("Y",_c),N("YY",Wc,Sc),N("YYYY",Yc,Uc),N("YYYYY",Zc,Vc),N("YYYYYY",Zc,Vc),Q(["YYYYY","YYYYYY"],fd),Q("YYYY",function(b,c){c[fd]=2===b.length?a.parseTwoDigitYear(b):q(b)}),Q("YY",function(b,c){c[fd]=a.parseTwoDigitYear(b)}),a.parseTwoDigitYear=function(a){return q(a)+(q(a)>68?1900:2e3)};var td=C("FullYear",!1);H("w",["ww",2],"wo","week"),H("W",["WW",2],"Wo","isoWeek"),z("week","w"),z("isoWeek","W"),N("w",Wc),N("ww",Wc,Sc),N("W",Wc),N("WW",Wc,Sc),R(["w","ww","W","WW"],function(a,b,c,d){b[d.substr(0,1)]=q(a)});var ud={dow:0,doy:6};H("DDD",["DDDD",3],"DDDo","dayOfYear"),z("dayOfYear","DDD"),N("DDD",Xc),N("DDDD",Tc),Q(["DDD","DDDD"],function(a,b,c){c._dayOfYear=q(a)}),a.ISO_8601=function(){};var vd=aa("moment().min is deprecated, use moment.min instead. https://github.com/moment/moment/issues/1548",function(){var a=Da.apply(null,arguments);return this>a?this:a}),wd=aa("moment().max is deprecated, use moment.max instead. https://github.com/moment/moment/issues/1548",function(){var a=Da.apply(null,arguments);return a>this?this:a});Ja("Z",":"),Ja("ZZ",""),N("Z",ad),N("ZZ",ad),Q(["Z","ZZ"],function(a,b,c){c._useUTC=!0,c._tzm=Ka(a)});var xd=/([\+\-]|\d\d)/gi;a.updateOffset=function(){};var yd=/(\-)?(?:(\d*)\.)?(\d+)\:(\d+)(?:\:(\d+)\.?(\d{3})?)?/,zd=/^(-)?P(?:(?:([0-9,.]*)Y)?(?:([0-9,.]*)M)?(?:([0-9,.]*)D)?(?:T(?:([0-9,.]*)H)?(?:([0-9,.]*)M)?(?:([0-9,.]*)S)?)?|([0-9,.]*)W)$/;Ya.fn=Ha.prototype;var Ad=ab(1,"add"),Bd=ab(-1,"subtract");a.defaultFormat="YYYY-MM-DDTHH:mm:ssZ";var Cd=aa("moment().lang() is deprecated. Instead, use moment().localeData() to get the language configuration. Use moment().locale() to change languages.",function(a){return void 0===a?this.localeData():this.locale(a)});H(0,["gg",2],0,function(){return this.weekYear()%100}),H(0,["GG",2],0,function(){return this.isoWeekYear()%100}),Db("gggg","weekYear"),Db("ggggg","weekYear"),Db("GGGG","isoWeekYear"),Db("GGGGG","isoWeekYear"),z("weekYear","gg"),z("isoWeekYear","GG"),N("G",_c),N("g",_c),N("GG",Wc,Sc),N("gg",Wc,Sc),N("GGGG",Yc,Uc),N("gggg",Yc,Uc),N("GGGGG",Zc,Vc),N("ggggg",Zc,Vc),R(["gggg","ggggg","GGGG","GGGGG"],function(a,b,c,d){b[d.substr(0,2)]=q(a)}),R(["gg","GG"],function(b,c,d,e){c[e]=a.parseTwoDigitYear(b)}),H("Q",0,0,"quarter"),z("quarter","Q"),N("Q",Rc),Q("Q",function(a,b){b[gd]=3*(q(a)-1)}),H("D",["DD",2],"Do","date"),z("date","D"),N("D",Wc),N("DD",Wc,Sc),N("Do",function(a,b){return a?b._ordinalParse:b._ordinalParseLenient}),Q(["D","DD"],hd),Q("Do",function(a,b){b[hd]=q(a.match(Wc)[0],10)});var Dd=C("Date",!0);H("d",0,"do","day"),H("dd",0,0,function(a){return this.localeData().weekdaysMin(this,a)}),H("ddd",0,0,function(a){return this.localeData().weekdaysShort(this,a)}),H("dddd",0,0,function(a){return this.localeData().weekdays(this,a)}),H("e",0,0,"weekday"),H("E",0,0,"isoWeekday"),z("day","d"),z("weekday","e"),z("isoWeekday","E"),N("d",Wc),N("e",Wc),N("E",Wc),N("dd",cd),N("ddd",cd),N("dddd",cd),R(["dd","ddd","dddd"],function(a,b,c){var d=c._locale.weekdaysParse(a);null!=d?b.d=d:j(c).invalidWeekday=a}),R(["d","e","E"],function(a,b,c,d){b[d]=q(a)});var Ed="Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),Fd="Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),Gd="Su_Mo_Tu_We_Th_Fr_Sa".split("_");H("H",["HH",2],0,"hour"),H("h",["hh",2],0,function(){return this.hours()%12||12}),Sb("a",!0),Sb("A",!1),z("hour","h"),N("a",Tb),N("A",Tb),N("H",Wc),N("h",Wc),N("HH",Wc,Sc),N("hh",Wc,Sc),Q(["H","HH"],id),Q(["a","A"],function(a,b,c){c._isPm=c._locale.isPM(a),c._meridiem=a}),Q(["h","hh"],function(a,b,c){b[id]=q(a),j(c).bigHour=!0});var Hd=/[ap]\.?m?\.?/i,Id=C("Hours",!0);H("m",["mm",2],0,"minute"),z("minute","m"),N("m",Wc),N("mm",Wc,Sc),Q(["m","mm"],jd);var Jd=C("Minutes",!1);H("s",["ss",2],0,"second"),z("second","s"),N("s",Wc),N("ss",Wc,Sc),Q(["s","ss"],kd);var Kd=C("Seconds",!1);H("S",0,0,function(){return~~(this.millisecond()/100)}),H(0,["SS",2],0,function(){return~~(this.millisecond()/10)}),H(0,["SSS",3],0,"millisecond"),H(0,["SSSS",4],0,function(){return 10*this.millisecond()}),H(0,["SSSSS",5],0,function(){return 100*this.millisecond()}),H(0,["SSSSSS",6],0,function(){return 1e3*this.millisecond()}),H(0,["SSSSSSS",7],0,function(){return 1e4*this.millisecond()}),H(0,["SSSSSSSS",8],0,function(){return 1e5*this.millisecond()}),H(0,["SSSSSSSSS",9],0,function(){return 1e6*this.millisecond()}),z("millisecond","ms"),N("S",Xc,Rc),N("SS",Xc,Sc),N("SSS",Xc,Tc);var Ld;for(Ld="SSSS";Ld.length<=9;Ld+="S")N(Ld,$c);for(Ld="S";Ld.length<=9;Ld+="S")Q(Ld,Wb);var Md=C("Milliseconds",!1);H("z",0,0,"zoneAbbr"),H("zz",0,0,"zoneName");var Nd=n.prototype;Nd.add=Ad,Nd.calendar=cb,Nd.clone=db,Nd.diff=ib,Nd.endOf=ub,Nd.format=mb,Nd.from=nb,Nd.fromNow=ob,Nd.to=pb,Nd.toNow=qb,Nd.get=F,Nd.invalidAt=Cb,Nd.isAfter=eb,Nd.isBefore=fb,Nd.isBetween=gb,Nd.isSame=hb,Nd.isValid=Ab,Nd.lang=Cd,Nd.locale=rb,Nd.localeData=sb,Nd.max=wd,Nd.min=vd,Nd.parsingFlags=Bb,Nd.set=F,Nd.startOf=tb,Nd.subtract=Bd,Nd.toArray=yb,Nd.toObject=zb,Nd.toDate=xb,Nd.toISOString=lb,Nd.toJSON=lb,Nd.toString=kb,Nd.unix=wb,Nd.valueOf=vb,Nd.year=td,Nd.isLeapYear=ia,Nd.weekYear=Fb,Nd.isoWeekYear=Gb,Nd.quarter=Nd.quarters=Jb,Nd.month=Y,Nd.daysInMonth=Z,Nd.week=Nd.weeks=na,Nd.isoWeek=Nd.isoWeeks=oa,Nd.weeksInYear=Ib,Nd.isoWeeksInYear=Hb,Nd.date=Dd,Nd.day=Nd.days=Pb,Nd.weekday=Qb,Nd.isoWeekday=Rb,Nd.dayOfYear=qa,Nd.hour=Nd.hours=Id,Nd.minute=Nd.minutes=Jd,Nd.second=Nd.seconds=Kd,
+Nd.millisecond=Nd.milliseconds=Md,Nd.utcOffset=Na,Nd.utc=Pa,Nd.local=Qa,Nd.parseZone=Ra,Nd.hasAlignedHourOffset=Sa,Nd.isDST=Ta,Nd.isDSTShifted=Ua,Nd.isLocal=Va,Nd.isUtcOffset=Wa,Nd.isUtc=Xa,Nd.isUTC=Xa,Nd.zoneAbbr=Xb,Nd.zoneName=Yb,Nd.dates=aa("dates accessor is deprecated. Use date instead.",Dd),Nd.months=aa("months accessor is deprecated. Use month instead",Y),Nd.years=aa("years accessor is deprecated. Use year instead",td),Nd.zone=aa("moment().zone is deprecated, use moment().utcOffset instead. https://github.com/moment/moment/issues/1779",Oa);var Od=Nd,Pd={sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[Last] dddd [at] LT",sameElse:"L"},Qd={LTS:"h:mm:ss A",LT:"h:mm A",L:"MM/DD/YYYY",LL:"MMMM D, YYYY",LLL:"MMMM D, YYYY h:mm A",LLLL:"dddd, MMMM D, YYYY h:mm A"},Rd="Invalid date",Sd="%d",Td=/\d{1,2}/,Ud={future:"in %s",past:"%s ago",s:"a few seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",M:"a month",MM:"%d months",y:"a year",yy:"%d years"},Vd=s.prototype;Vd._calendar=Pd,Vd.calendar=_b,Vd._longDateFormat=Qd,Vd.longDateFormat=ac,Vd._invalidDate=Rd,Vd.invalidDate=bc,Vd._ordinal=Sd,Vd.ordinal=cc,Vd._ordinalParse=Td,Vd.preparse=dc,Vd.postformat=dc,Vd._relativeTime=Ud,Vd.relativeTime=ec,Vd.pastFuture=fc,Vd.set=gc,Vd.months=U,Vd._months=md,Vd.monthsShort=V,Vd._monthsShort=nd,Vd.monthsParse=W,Vd.week=ka,Vd._week=ud,Vd.firstDayOfYear=ma,Vd.firstDayOfWeek=la,Vd.weekdays=Lb,Vd._weekdays=Ed,Vd.weekdaysMin=Nb,Vd._weekdaysMin=Gd,Vd.weekdaysShort=Mb,Vd._weekdaysShort=Fd,Vd.weekdaysParse=Ob,Vd.isPM=Ub,Vd._meridiemParse=Hd,Vd.meridiem=Vb,w("en",{ordinalParse:/\d{1,2}(th|st|nd|rd)/,ordinal:function(a){var b=a%10,c=1===q(a%100/10)?"th":1===b?"st":2===b?"nd":3===b?"rd":"th";return a+c}}),a.lang=aa("moment.lang is deprecated. Use moment.locale instead.",w),a.langData=aa("moment.langData is deprecated. Use moment.localeData instead.",y);var Wd=Math.abs,Xd=yc("ms"),Yd=yc("s"),Zd=yc("m"),$d=yc("h"),_d=yc("d"),ae=yc("w"),be=yc("M"),ce=yc("y"),de=Ac("milliseconds"),ee=Ac("seconds"),fe=Ac("minutes"),ge=Ac("hours"),he=Ac("days"),ie=Ac("months"),je=Ac("years"),ke=Math.round,le={s:45,m:45,h:22,d:26,M:11},me=Math.abs,ne=Ha.prototype;ne.abs=oc,ne.add=qc,ne.subtract=rc,ne.as=wc,ne.asMilliseconds=Xd,ne.asSeconds=Yd,ne.asMinutes=Zd,ne.asHours=$d,ne.asDays=_d,ne.asWeeks=ae,ne.asMonths=be,ne.asYears=ce,ne.valueOf=xc,ne._bubble=tc,ne.get=zc,ne.milliseconds=de,ne.seconds=ee,ne.minutes=fe,ne.hours=ge,ne.days=he,ne.weeks=Bc,ne.months=ie,ne.years=je,ne.humanize=Fc,ne.toISOString=Gc,ne.toString=Gc,ne.toJSON=Gc,ne.locale=rb,ne.localeData=sb,ne.toIsoString=aa("toIsoString() is deprecated. Please use toISOString() instead (notice the capitals)",Gc),ne.lang=Cd,H("X",0,0,"unix"),H("x",0,0,"valueOf"),N("x",_c),N("X",bd),Q("X",function(a,b,c){c._d=new Date(1e3*parseFloat(a,10))}),Q("x",function(a,b,c){c._d=new Date(q(a))}),a.version="2.10.6",b(Da),a.fn=Od,a.min=Fa,a.max=Ga,a.utc=h,a.unix=Zb,a.months=jc,a.isDate=d,a.locale=w,a.invalid=l,a.duration=Ya,a.isMoment=o,a.weekdays=lc,a.parseZone=$b,a.localeData=y,a.isDuration=Ia,a.monthsShort=kc,a.weekdaysMin=nc,a.defineLocale=x,a.weekdaysShort=mc,a.normalizeUnits=A,a.relativeTimeThreshold=Ec;var oe=a;return oe});
\ No newline at end of file
diff --git a/src/Jackett/Content/login.html b/src/Jackett/Content/login.html
index 96b63710e8057b1d3dc6e0749a1b4ab0e2315db0..7d2ac00b5fd9b9d24835c441c233320dd28627d4 100644
--- a/src/Jackett/Content/login.html
+++ b/src/Jackett/Content/login.html
@@ -6,10 +6,13 @@
 
     <link rel='shortcut icon' type='image/x-icon' href='/favicon.ico' />
 
-    <script src="/jquery-2.1.3.min.js"></script>
-    <script src="/handlebars-v3.0.1.js"></script>
+    <script src="/libs/jquery.min.js"></script>
+    <script src="/libs/jquery.dataTables.min.js"></script>
+    <script src="/libs/handlebars.min.js"></script>
+    <script src="/libs/moment.min.js"></script>
+    <script src="/libs/handlebarsmoment.js"></script>
     <script src="/bootstrap/bootstrap.min.js"></script>
-    <script src="/bootstrap-notify.js"></script>
+    <script src="/libs/bootstrap-notify.js"></script>
 
     <link href="/bootstrap/bootstrap.min.css" rel="stylesheet">
     <link href="/animate.css" rel="stylesheet">
diff --git a/src/Jackett/Content/logos/demonoid.png b/src/Jackett/Content/logos/demonoid.png
new file mode 100644
index 0000000000000000000000000000000000000000..d211b9f0fb34d8bb181b3073defdc53e236009a0
Binary files /dev/null and b/src/Jackett/Content/logos/demonoid.png differ
diff --git a/src/Jackett/Content/logos/ncore.png b/src/Jackett/Content/logos/ncore.png
new file mode 100644
index 0000000000000000000000000000000000000000..052c1d667e46aaf55df83ee99d52a5645e407b71
Binary files /dev/null and b/src/Jackett/Content/logos/ncore.png differ
diff --git a/src/Jackett/Content/logos/rutor.png b/src/Jackett/Content/logos/rutor.png
new file mode 100644
index 0000000000000000000000000000000000000000..603114c3f41946e1a4b39a67cf345268f765ff12
Binary files /dev/null and b/src/Jackett/Content/logos/rutor.png differ
diff --git a/src/Jackett/Controllers/AdminController.cs b/src/Jackett/Controllers/AdminController.cs
index 651a92aacc1d49ee5ac1d64b3c469e9b02e9914f..5762c7a649377e580db8b6ceb102e8a61ca36159 100644
--- a/src/Jackett/Controllers/AdminController.cs
+++ b/src/Jackett/Controllers/AdminController.cs
@@ -1,4 +1,5 @@
 using Autofac;
+using AutoMapper;
 using Jackett.Indexers;
 using Jackett.Models;
 using Jackett.Services;
@@ -36,8 +37,9 @@ namespace Jackett.Controllers
         private IProcessService processService;
         private ICacheService cacheService;
         private Logger logger;
+        private ILogCacheService logCache;
 
-        public AdminController(IConfigurationService config, IIndexerManagerService i, IServerService ss, ISecuityService s, IProcessService p, ICacheService c, Logger l)
+        public AdminController(IConfigurationService config, IIndexerManagerService i, IServerService ss, ISecuityService s, IProcessService p, ICacheService c, Logger l, ILogCacheService lc)
         {
             this.config = config;
             indexerService = i;
@@ -46,6 +48,7 @@ namespace Jackett.Controllers
             processService = p;
             cacheService = c;
             logger = l;
+            logCache = lc;
         }
 
         private async Task<JToken> ReadPostDataJson()
@@ -150,7 +153,7 @@ namespace Jackett.Controllers
                 var postData = await ReadPostDataJson();
                 var indexer = indexerService.GetIndexer((string)postData["indexer"]);
                 var config = await indexer.GetConfigurationForSetup();
-                jsonReply["config"] = config.ToJson();
+                jsonReply["config"] = config.ToJson(null);
                 jsonReply["caps"] = indexer.TorznabCaps.CapsToJson();
                 jsonReply["name"] = indexer.DisplayName;
                 jsonReply["result"] = "success";
@@ -189,7 +192,7 @@ namespace Jackett.Controllers
                     baseIndexer.ResetBaseConfig();
                 if (ex is ExceptionWithConfigData)
                 {
-                    jsonReply["config"] = ((ExceptionWithConfigData)ex).ConfigData.ToJson();
+                    jsonReply["config"] = ((ExceptionWithConfigData)ex).ConfigData.ToJson(null);
                 } else
                 {
                     logger.Error(ex, "Exception in Configure");
@@ -283,6 +286,7 @@ namespace Jackett.Controllers
                 cfg["port"] = serverService.Config.Port;
                 cfg["external"] = serverService.Config.AllowExternal;
                 cfg["api_key"] = serverService.Config.APIKey;
+                cfg["blackholedir"] = serverService.Config.BlackholeDir;
                 cfg["password"] = string.IsNullOrEmpty(serverService.Config.AdminPassword )? string.Empty:serverService.Config.AdminPassword.Substring(0,10);
 
                 jsonReply["config"] = cfg;
@@ -297,7 +301,7 @@ namespace Jackett.Controllers
             return Json(jsonReply);
         }
 
-        [Route("set_port")]
+        [Route("set_config")]
         [HttpPost]
         public async Task<IHttpActionResult> SetConfig()
         {
@@ -309,6 +313,7 @@ namespace Jackett.Controllers
                 var postData = await ReadPostDataJson();
                 int port = (int)postData["port"];
                 bool external = (bool)postData["external"];
+                string saveDir = (string)postData["blackholedir"];
 
                 if (port != Engine.Server.Config.Port || external != Engine.Server.Config.AllowExternal)
                 {
@@ -358,6 +363,21 @@ namespace Jackett.Controllers
                     })).Start();
                 }
 
+
+                if(saveDir != Engine.Server.Config.BlackholeDir)
+                {
+                    if (!string.IsNullOrEmpty(saveDir))
+                    {
+                        if (!Directory.Exists(saveDir))
+                        {
+                            throw new Exception("Blackhole directory does not exist");
+                        }
+                    }
+
+                    Engine.Server.Config.BlackholeDir = saveDir;
+                    Engine.Server.SaveConfig();
+                }
+
                 jsonReply["result"] = "success";
                 jsonReply["port"] = port;
                 jsonReply["external"] = external;
@@ -375,7 +395,15 @@ namespace Jackett.Controllers
         [HttpGet]
         public List<TrackerCacheResult> GetCache()
         {
-            return cacheService.GetCachedResults();
+            var severUrl = string.Format("{0}://{1}:{2}/", Request.RequestUri.Scheme, Request.RequestUri.Host, Request.RequestUri.Port);
+            return cacheService.GetCachedResults(severUrl);
+        }
+
+        [Route("GetLogs")]
+        [HttpGet]
+        public List<CachedLog> GetLogs()
+        {
+            return logCache.Logs;
         }
     }
 }
diff --git a/src/Jackett/Controllers/BlackholeController.cs b/src/Jackett/Controllers/BlackholeController.cs
new file mode 100644
index 0000000000000000000000000000000000000000..88a4ecae1487b57b60e2642d33de121dc92f6997
--- /dev/null
+++ b/src/Jackett/Controllers/BlackholeController.cs
@@ -0,0 +1,71 @@
+using Jackett.Services;
+using Newtonsoft.Json.Linq;
+using NLog;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Net;
+using System.Net.Http;
+using System.Net.Http.Headers;
+using System.Text;
+using System.Threading.Tasks;
+using System.Web;
+using System.Web.Http;
+
+namespace Jackett.Controllers
+{
+    [AllowAnonymous]
+    public class BlackholeController : ApiController
+    {
+        private Logger logger;
+        private IIndexerManagerService indexerService;
+
+        public BlackholeController(IIndexerManagerService i, Logger l)
+        {
+            logger = l;
+            indexerService = i;
+        }
+
+        [HttpGet]
+        public async Task<IHttpActionResult> Blackhole(string indexerID, string path)
+        {
+
+            var jsonReply = new JObject();
+            try
+            {
+                var indexer = indexerService.GetIndexer(indexerID);
+                if (!indexer.IsConfigured)
+                {
+                    logger.Warn(string.Format("Rejected a request to {0} which is unconfigured.", indexer.DisplayName));
+                    throw new Exception("This indexer is not configured.");
+                }
+
+                var remoteFile = Encoding.UTF8.GetString(HttpServerUtility.UrlTokenDecode(path));
+                var downloadBytes = await indexer.Download(new Uri(remoteFile, UriKind.RelativeOrAbsolute));
+
+                if (string.IsNullOrWhiteSpace(Engine.Server.Config.BlackholeDir))
+                {
+                    throw new Exception("Blackhole directory not set!");
+                }
+
+                if (!Directory.Exists(Engine.Server.Config.BlackholeDir))
+                {
+                    throw new Exception("Blackhole directory does not exist: " + Engine.Server.Config.BlackholeDir);
+                }
+
+                var fileName = DateTime.Now.Ticks + ".torrent";
+                File.WriteAllBytes(Path.Combine(Engine.Server.Config.BlackholeDir, fileName), downloadBytes);
+                jsonReply["result"] = "success";
+            }
+            catch (Exception ex)
+            {
+                logger.Error(ex, "Error downloading to blackhole " + indexerID + " " + path);
+                jsonReply["result"] = "error";
+                jsonReply["error"] = ex.Message;
+            }
+
+            return Json(jsonReply);
+        }
+    }
+}
diff --git a/src/Jackett/Controllers/PotatoController.cs b/src/Jackett/Controllers/PotatoController.cs
index b3245f5349ef234f1ebfb25f4c4d700aa7bbb55a..5815baa7938393063089881687693f7cf3d1408d 100644
--- a/src/Jackett/Controllers/PotatoController.cs
+++ b/src/Jackett/Controllers/PotatoController.cs
@@ -1,4 +1,5 @@
-using Jackett.Models;
+using AutoMapper;
+using Jackett.Models;
 using Jackett.Services;
 using Jackett.Utils;
 using Jackett.Utils.Clients;
@@ -95,27 +96,18 @@ namespace Jackett.Controllers
             // Cache non query results
             if (string.IsNullOrEmpty(torznabQuery.SanitizedSearchTerm))
             {
-                cacheService.CacheRssResults(indexer.DisplayName, releases);
+                cacheService.CacheRssResults(indexer, releases);
             }
 
             releases = indexer.FilterResults(torznabQuery, releases);
-
-            var severUrl = string.Format("{0}://{1}:{2}/", Request.RequestUri.Scheme, Request.RequestUri.Host, Request.RequestUri.Port);
-            // add Jackett proxy to download links...
-            foreach (var release in releases)
-            {
-                if (release.Link == null || (release.Link.IsAbsoluteUri && release.Link.Scheme == "magnet"))
-                    continue;
-                var originalLink = release.Link;
-                var encodedLink = HttpServerUtility.UrlTokenEncode(Encoding.UTF8.GetBytes(originalLink.ToString())) + "/t.torrent";
-                var proxyLink = string.Format("{0}api/{1}/download/{2}", severUrl, indexer.ID, encodedLink);
-                release.Link = new Uri(proxyLink);
-            }
-
+            var serverUrl = string.Format("{0}://{1}:{2}/", Request.RequestUri.Scheme, Request.RequestUri.Host, Request.RequestUri.Port);
             var potatoResponse = new TorrentPotatoResponse();
 
-            foreach(var release in releases)
+            foreach(var r in releases)
             {
+                var release = Mapper.Map<ReleaseInfo>(r);
+                release.Link = release.ConvertToProxyLink(serverUrl, indexerID);
+
                 potatoResponse.results.Add(new TorrentPotatoResponseItem()
                 {
                     release_name = release.Title + "[" + indexer.DisplayName + "]", // Suffix the indexer so we can see which tracker we are using in CPS as it just says torrentpotato >.>
diff --git a/src/Jackett/Controllers/TorznabController.cs b/src/Jackett/Controllers/TorznabController.cs
index 304921ba27896ec2f01d1f55b8ff9ac800af2fec..f161dd87194e99dafc28a3e37ace78cb76f41a0f 100644
--- a/src/Jackett/Controllers/TorznabController.cs
+++ b/src/Jackett/Controllers/TorznabController.cs
@@ -1,4 +1,5 @@
-using Jackett.Models;
+using AutoMapper;
+using Jackett.Models;
 using Jackett.Services;
 using NLog;
 using System;
@@ -63,50 +64,61 @@ namespace Jackett.Controllers
 
             var releases = await indexer.PerformQuery(torznabQuery);
 
+            // Some trackers do not keep their clocks up to date and can be ~20 minutes out!
+            foreach(var release in releases)
+            {
+                if (release.PublishDate > DateTime.Now)
+                    release.PublishDate = DateTime.Now;
+            }
+
+            // Some trackers do not support multiple category filtering so filter the releases that match manually.
+            var filteredReleases = releases = indexer.FilterResults(torznabQuery, releases); 
+            int? newItemCount = null;
+
+
             // Cache non query results
             if (string.IsNullOrEmpty(torznabQuery.SanitizedSearchTerm))
             {
-                cacheService.CacheRssResults(indexer.DisplayName, releases);
+                newItemCount = cacheService.GetNewItemCount(indexer, filteredReleases);
+                cacheService.CacheRssResults(indexer, releases);
             }
 
-            releases = indexer.FilterResults(torznabQuery, releases);
-
             // Log info
-            if (string.IsNullOrWhiteSpace(torznabQuery.SanitizedSearchTerm))
-            {
-                logger.Info(string.Format("Found {0} releases from {1}", releases.Count(), indexer.DisplayName));
+            var logBuilder = new StringBuilder();
+            if (newItemCount != null)  {
+                logBuilder.AppendFormat(string.Format("Found {0} ({1} new) releases from {2}", releases.Count(), newItemCount, indexer.DisplayName));
             }
-            else
-            {
-                logger.Info(string.Format("Found {0} releases from {1} for: {2} {3}", releases.Count(), indexer.DisplayName, torznabQuery.SanitizedSearchTerm, torznabQuery.GetEpisodeSearchString()));
+            else {
+                logBuilder.AppendFormat(string.Format("Found {0} releases from {1}", releases.Count(), indexer.DisplayName));
             }
 
-            var severUrl = string.Format("{0}://{1}:{2}/", Request.RequestUri.Scheme, Request.RequestUri.Host, Request.RequestUri.Port);
+            if (!string.IsNullOrWhiteSpace(torznabQuery.SanitizedSearchTerm)) { 
+                logBuilder.AppendFormat(" for: {0} {1}", torznabQuery.SanitizedSearchTerm, torznabQuery.GetEpisodeSearchString());
+            }
 
+            logger.Info(logBuilder.ToString());
+
+            var serverUrl = string.Format("{0}://{1}:{2}/", Request.RequestUri.Scheme, Request.RequestUri.Host, Request.RequestUri.Port);
             var resultPage = new ResultPage(new ChannelInfo
             {
                 Title = indexer.DisplayName,
                 Description = indexer.DisplayDescription,
                 Link = new Uri(indexer.SiteLink),
-                ImageUrl = new Uri(severUrl + "logos/" + indexer.ID + ".png"),
+                ImageUrl = new Uri(serverUrl + "logos/" + indexer.ID + ".png"),
                 ImageTitle = indexer.DisplayName,
                 ImageLink = new Uri(indexer.SiteLink),
                 ImageDescription = indexer.DisplayName
             });
 
-            // add Jackett proxy to download links...
-            foreach (var release in releases)
+
+            foreach(var result in releases)
             {
-                if (release.Link == null || (release.Link.IsAbsoluteUri && release.Link.Scheme == "magnet"))
-                    continue;
-                var originalLink = release.Link;
-                var encodedLink = HttpServerUtility.UrlTokenEncode(Encoding.UTF8.GetBytes(originalLink.ToString())) + "/t.torrent";
-                var proxyLink = string.Format("{0}api/{1}/download/{2}", severUrl, indexer.ID, encodedLink);
-                release.Link = new Uri(proxyLink);
+                var clone = Mapper.Map<ReleaseInfo>(result);
+                clone.Link = clone.ConvertToProxyLink(serverUrl, indexerID);
+                resultPage.Releases.Add(clone);
             }
 
-            resultPage.Releases.AddRange(releases);
-            var xml = resultPage.ToXml(new Uri(severUrl));
+            var xml = resultPage.ToXml(new Uri(serverUrl));
             // Force the return as XML
             return new HttpResponseMessage()
             {
diff --git a/src/Jackett/CurlHelper.cs b/src/Jackett/CurlHelper.cs
index 99d066fa35374f033e1b6136d7a6a7dee3ea8b9d..18de4aed1526c651d7e67684850fca2727da0367 100644
--- a/src/Jackett/CurlHelper.cs
+++ b/src/Jackett/CurlHelper.cs
@@ -23,7 +23,7 @@ namespace Jackett
             public string Cookies { get; private set; }
             public string Referer { get; private set; }
             public HttpMethod Method { get; private set; }
-            public Dictionary<string, string> PostData { get; set; }
+            public IEnumerable<KeyValuePair<string, string>> PostData { get; set; }
 
             public CurlRequest(HttpMethod method, string url, string cookies = null, string referer = null)
             {
@@ -38,7 +38,7 @@ namespace Jackett
         {
             public List<string[]> HeaderList { get; private set; }
             public byte[] Content { get; private set; }
-            public HttpStatusCode Status { get; private set;}
+            public HttpStatusCode Status { get; private set; }
             public string Cookies { set; get; }
 
             public CurlResponse(List<string[]> headers, byte[] content, HttpStatusCode s, string cookies)
@@ -55,9 +55,9 @@ namespace Jackett
             var curlRequest = new CurlRequest(HttpMethod.Get, url, cookies, referer);
             var result = await PerformCurlAsync(curlRequest);
             return result;
-        }    
+        }
 
-        public static async Task<CurlResponse> PostAsync(string url, Dictionary<string, string> formData, string cookies = null, string referer = null)
+        public static async Task<CurlResponse> PostAsync(string url, IEnumerable<KeyValuePair<string, string>> formData, string cookies = null, string referer = null)
         {
             var curlRequest = new CurlRequest(HttpMethod.Post, url, cookies, referer);
             curlRequest.PostData = formData;
@@ -86,7 +86,7 @@ namespace Jackett
                     easy.BufferSize = 64 * 1024;
                     easy.UserAgent = BrowserUtil.ChromeUserAgent;
                     easy.FollowLocation = false;
-                    easy.ConnectTimeout  = 20;
+                    easy.ConnectTimeout = 20;
 
                     easy.WriteFunction = (byte[] buf, int size, int nmemb, object data) =>
                     {
@@ -109,7 +109,7 @@ namespace Jackett
                     if (curlRequest.Method == HttpMethod.Post)
                     {
                         easy.Post = true;
-                        var postString = new FormUrlEncodedContent(curlRequest.PostData).ReadAsStringAsync().Result;
+                        var postString = StringUtil.PostDataFromDict(curlRequest.PostData);
                         easy.PostFields = postString;
                         easy.PostFieldSize = Encoding.UTF8.GetByteCount(postString);
                     }
@@ -125,7 +125,7 @@ namespace Jackett
 
                     easy.Perform();
 
-                    if(easy.LastErrorCode != CurlCode.Ok)
+                    if (easy.LastErrorCode != CurlCode.Ok)
                     {
                         var message = "Error " + easy.LastErrorCode.ToString() + " " + easy.LastErrorDescription;
                         if (null != OnErrorMessage)
diff --git a/src/Jackett/CurlSharp.dll.config b/src/Jackett/CurlSharp.dll.config
new file mode 100644
index 0000000000000000000000000000000000000000..eadeb9ad70940a0323a05036e397acb7fe5dc1a9
--- /dev/null
+++ b/src/Jackett/CurlSharp.dll.config
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<configuration>
+  <dllmap dll="libcurl.dll" target="libcurl.so.4" />
+  <dllmap os="osx" dll="libcurl.dll" target="libcurl.4.dylib"/>
+  <!--<dllmap os="freebsd" dll="libcurl.dll" target="libcurl.so.4" />-->
+  <!--<dllmap os="solaris" dll="libcurl.dll" target="libcurl.so.4" />-->
+</configuration>
diff --git a/src/Jackett/Engine.cs b/src/Jackett/Engine.cs
index 19a2bc8748b1be62c4ad0fc78a0d1c41154460c6..3b07f60982eaf15b9c5763f52eca9bb1e4e7c3bb 100644
--- a/src/Jackett/Engine.cs
+++ b/src/Jackett/Engine.cs
@@ -34,6 +34,7 @@ namespace Jackett
             secondaryBuilder.RegisterInstance<IContainer>(container).SingleInstance();
             SetupLogging(secondaryBuilder);
             secondaryBuilder.Update(container);
+
         }
 
         public static IContainer GetContainer()
@@ -132,6 +133,11 @@ namespace Jackett
             var logConsoleRule = new LoggingRule("*", logLevel, logConsole);
             logConfig.LoggingRules.Add(logConsoleRule);
 
+            var logService = new LogCacheService();
+            logConfig.AddTarget("service", logService);
+            var serviceRule = new LoggingRule("*", logLevel,logService);
+            logConfig.LoggingRules.Add(serviceRule);
+
             LogManager.Configuration = logConfig;
             builder.RegisterInstance<Logger>(LogManager.GetCurrentClassLogger()).SingleInstance();
         }
diff --git a/src/Jackett/ExceptionWithConfigData.cs b/src/Jackett/ExceptionWithConfigData.cs
index 9c4c7125e6ef6ea7bcc8e88ad54529d8fbed3019..e987eb81adb2668f6aff88140f85afd1584d0b93 100644
--- a/src/Jackett/ExceptionWithConfigData.cs
+++ b/src/Jackett/ExceptionWithConfigData.cs
@@ -4,6 +4,7 @@ using System.Collections.Generic;
 using System.Linq;
 using System.Text;
 using System.Threading.Tasks;
+using Jackett.Models.IndexerConfig;
 
 namespace Jackett
 {
diff --git a/src/Jackett/Indexers/AlphaRatio.cs b/src/Jackett/Indexers/AlphaRatio.cs
index dd4e7f16a4c66604da590126d5eedd6ad48154d7..19e5f50650da7a0a360e801e689af04a009b5acd 100644
--- a/src/Jackett/Indexers/AlphaRatio.cs
+++ b/src/Jackett/Indexers/AlphaRatio.cs
@@ -14,6 +14,7 @@ using Jackett.Utils;
 using NLog;
 using Jackett.Services;
 using Jackett.Utils.Clients;
+using Jackett.Models.IndexerConfig;
 
 namespace Jackett.Indexers
 {
@@ -24,23 +25,20 @@ namespace Jackett.Indexers
         private string DownloadUrl { get { return SiteLink + "torrents.php?action=download&id="; } }
         private string GuidUrl { get { return SiteLink + "torrents.php?torrentid="; } }
 
-        public AlphaRatio(IIndexerManagerService i, IWebClient w, Logger l)
+        public AlphaRatio(IIndexerManagerService i, IWebClient w, Logger l, IProtectionService ps)
             : base(name: "AlphaRatio",
                 description: "Legendary",
                 link: "https://alpharatio.cc/",
                 caps: TorznabCapsUtil.CreateDefaultTorznabTVCaps(),
                 manager: i,
                 client: w,
-                logger: l)
+                logger: l,
+                p: ps,
+                configData: new ConfigurationDataBasicLogin())
         {
             webclient = w;
         }
 
-        public Task<ConfigurationData> GetConfigurationForSetup()
-        {
-            return Task.FromResult<ConfigurationData>(new ConfigurationDataBasicLogin());
-        }
-
         public async Task ApplyConfiguration(JToken configJson)
         {
             var incomingConfig = new ConfigurationDataBasicLogin();
@@ -54,13 +52,13 @@ namespace Jackett.Indexers
 
             // Do the login
             var response = await RequestLoginAndFollowRedirect(LoginUrl, pairs, string.Empty, true, SiteLink);
-            await ConfigureIfOK(response.Cookies, response.Content!=null && response.Content.Contains("logout.php?"), () =>
-             {
-                 CQ dom = response.Content;
-                 dom["#loginform > table"].Remove();
-                 var errorMessage = dom["#loginform"].Text().Trim().Replace("\n\t", " ");
-                 throw new ExceptionWithConfigData(errorMessage, (ConfigurationData)incomingConfig);
-             });
+            await ConfigureIfOK(response.Cookies, response.Content != null && response.Content.Contains("logout.php?"), () =>
+               {
+                   CQ dom = response.Content;
+                   dom["#loginform > table"].Remove();
+                   var errorMessage = dom["#loginform"].Text().Trim().Replace("\n\t", " ");
+                   throw new ExceptionWithConfigData(errorMessage, (ConfigurationData)incomingConfig);
+               });
         }
 
         void FillReleaseInfoFromJson(ReleaseInfo release, JObject r)
diff --git a/src/Jackett/Indexers/AnimeBytes.cs b/src/Jackett/Indexers/AnimeBytes.cs
index b8ae9758b6b58d1f85ea8a53b751c9ec089a950c..b9908c9a7df1ab40db16287cd4be4012d73629c1 100644
--- a/src/Jackett/Indexers/AnimeBytes.cs
+++ b/src/Jackett/Indexers/AnimeBytes.cs
@@ -25,28 +25,30 @@ namespace Jackett.Indexers
     {
         private string LoginUrl { get { return SiteLink + "user/login"; } }
         private string SearchUrl { get { return SiteLink + "torrents.php?filter_cat[1]=1"; } }
-        public bool AllowRaws { get; private set; }
+        public bool AllowRaws { get { return configData.IncludeRaw.Value; } }
 
-        public AnimeBytes(IIndexerManagerService i, IWebClient client, Logger l)
+        new ConfigurationDataAnimeBytes configData
+        {
+            get { return (ConfigurationDataAnimeBytes)base.configData; }
+            set { base.configData = value; }
+        }
+
+        public AnimeBytes(IIndexerManagerService i, IWebClient client, Logger l, IProtectionService ps)
             : base(name: "AnimeBytes",
                 link: "https://animebytes.tv/",
                 description: "Powered by Tentacles",
                 manager: i,
                 client: client,
                 caps: new TorznabCapabilities(TorznabCatType.Anime),
-                logger: l)
+                logger: l,
+                p: ps,
+                configData: new ConfigurationDataAnimeBytes())
         {
         }
 
-        public Task<ConfigurationData> GetConfigurationForSetup()
-        {
-            return Task.FromResult<ConfigurationData>(new ConfigurationDataBasicLoginAnimeBytes());
-        }
-
         public async Task ApplyConfiguration(JToken configJson)
         {
-            var config = new ConfigurationDataBasicLoginAnimeBytes();
-            config.LoadValuesFromJson(configJson);
+            configData.LoadValuesFromJson(configJson);
 
             lock (cache)
             {
@@ -59,18 +61,18 @@ namespace Jackett.Indexers
                 Url = LoginUrl
             });
 
-            CQ loginPageDom =loginPage.Content;
+            CQ loginPageDom = loginPage.Content;
             var csrfToken = loginPageDom["input[name=\"csrf_token\"]"].Last();
 
             // Build login form
             var pairs = new Dictionary<string, string> {
                     { "csrf_token", csrfToken.Attr("value") },
-				    { "username", config.Username.Value },
-				    { "password", config.Password.Value },
+                    { "username", configData.Username.Value },
+                    { "password", configData.Password.Value },
                     { "keeplogged_sent", "true" },
                     { "keeplogged", "on" },
                     { "login", "Log In!" }
-			};
+            };
 
             // Do the login
             var request = new Utils.Clients.WebRequest()
@@ -86,32 +88,26 @@ namespace Jackett.Indexers
             // Follow the redirect
             await FollowIfRedirect(response, request.Url, SearchUrl);
 
-            if (!(response.Content != null && response.Content.Contains("/user/logout")))
+            await ConfigureIfOK(response.Cookies, response.Content != null && response.Content.Contains("/user/logout"), () =>
             {
                 // Their login page appears to be broken and just gives a 500 error.
-                throw new ExceptionWithConfigData("Failed to login, 6 failed attempts will get you banned for 6 hours.", (ConfigurationData)config);
-            }
-            else
-            {
-                cookieHeader = response.Cookies;
-                AllowRaws = config.IncludeRaw.Value;
-                var configSaveData = new JObject();
-                configSaveData["cookies"] = cookieHeader;
-                configSaveData["raws"] = AllowRaws;
-                SaveConfig(configSaveData);
-                IsConfigured = true;
-            }
+                throw new ExceptionWithConfigData("Failed to login, 6 failed attempts will get you banned for 6 hours.", configData);
+            });
         }
 
+        // Override to load legacy config format
         public override void LoadFromSavedConfiguration(JToken jsonConfig)
         {
-            // The old config used an array - just fail to load it
-            if (!(jsonConfig["cookies"] is JArray))
+            if (jsonConfig is JObject)
             {
-                cookieHeader = (string)jsonConfig["cookies"];
-                AllowRaws = jsonConfig["raws"].Value<bool>();
+                configData.CookieHeader.Value = jsonConfig.Value<string>("cookies");
+                configData.IncludeRaw.Value = jsonConfig.Value<bool>("raws");
+                SaveConfig();
                 IsConfigured = true;
+                return;
             }
+
+            base.LoadFromSavedConfiguration(jsonConfig);
         }
 
         public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query)
@@ -257,7 +253,7 @@ namespace Jackett.Indexers
                                 release.PublishDate = release.PublishDate.AddDays(Math.Min(DateTime.Now.DayOfYear, 365) - 1);
 
                                 var infoLink = links.Get(1);
-                                release.Comments = new Uri(SiteLink  + infoLink.Attributes.GetAttribute("href"));
+                                release.Comments = new Uri(SiteLink + infoLink.Attributes.GetAttribute("href"));
                                 release.Guid = new Uri(SiteLink + infoLink.Attributes.GetAttribute("href") + "&nh=" + StringUtil.Hash(title)); // Sonarr should dedupe on this url - allow a url per name.
                                 release.Link = new Uri(downloadLink.Attributes.GetAttribute("href"), UriKind.Relative);
 
@@ -337,7 +333,7 @@ namespace Jackett.Indexers
             var response = await webclient.GetBytes(new Utils.Clients.WebRequest()
             {
                 Url = SiteLink + link.ToString(),
-                Cookies = cookieHeader
+                Cookies = CookieHeader
             });
 
             return response.Content;
diff --git a/src/Jackett/Indexers/BB.cs b/src/Jackett/Indexers/BB.cs
index 7ba01fcf2de1980c9637196e5ecd70cddc8d47ea..65edb1901cfde4a426d652a0c2b093b52106415d 100644
--- a/src/Jackett/Indexers/BB.cs
+++ b/src/Jackett/Indexers/BB.cs
@@ -13,6 +13,7 @@ using System.Net.Http;
 using System.Text;
 using System.Threading.Tasks;
 using System.Web;
+using Jackett.Models.IndexerConfig;
 
 namespace Jackett.Indexers
 {
@@ -20,34 +21,36 @@ namespace Jackett.Indexers
 
     public class BB : BaseIndexer, IIndexer
     {
-        private string BaseUrl {  get { return StringUtil.FromBase64("aHR0cHM6Ly9iYWNvbmJpdHMub3JnLw=="); } }
+        private string BaseUrl { get { return StringUtil.FromBase64("aHR0cHM6Ly9iYWNvbmJpdHMub3JnLw=="); } }
         private Uri BaseUri { get { return new Uri(BaseUrl); } }
         private string LoginUrl { get { return BaseUri + "login.php"; } }
         private string SearchUrl { get { return BaseUri + "torrents.php?searchstr={0}&searchtags=&tags_type=0&order_by=s3&order_way=desc&disablegrouping=1&filter_cat%5B10%5D=1"; } }
 
-        public BB(IIndexerManagerService i, Logger l, IWebClient w)
+        new ConfigurationDataBasicLogin configData
+        {
+            get { return (ConfigurationDataBasicLogin)base.configData; }
+            set { base.configData = value; }
+        }
+
+        public BB(IIndexerManagerService i, Logger l, IWebClient w, IProtectionService ps)
             : base(name: "bB",
                 description: "bB",
                 link: "http://www.reddit.com/r/baconbits/",
                 caps: TorznabCapsUtil.CreateDefaultTorznabTVCaps(),
                 manager: i,
                 client: w,
-                logger: l)
-        {
-        }
-
-        public Task<ConfigurationData> GetConfigurationForSetup()
+                logger: l,
+                p: ps,
+                configData: new ConfigurationDataBasicLogin())
         {
-            return Task.FromResult<ConfigurationData>(new ConfigurationDataBasicLogin());
         }
 
         public async Task ApplyConfiguration(JToken configJson)
         {
-            var incomingConfig = new ConfigurationDataBasicLogin();
-            incomingConfig.LoadValuesFromJson(configJson);
+            configData.LoadValuesFromJson(configJson);
             var pairs = new Dictionary<string, string> {
-                { "username", incomingConfig.Username.Value },
-                { "password", incomingConfig.Password.Value },
+                { "username", configData.Username.Value },
+                { "password", configData.Password.Value },
                 { "keeplogged", "1" },
                 { "login", "Log In!" }
             };
@@ -64,7 +67,7 @@ namespace Jackett.Indexers
                     messages.Add(child.Cq().Text().Trim());
                 }
                 var message = string.Join(" ", messages);
-                throw new ExceptionWithConfigData(message, (ConfigurationData)incomingConfig);
+                throw new ExceptionWithConfigData(message, configData);
 
             });
         }
diff --git a/src/Jackett/Indexers/BakaBT.cs b/src/Jackett/Indexers/BakaBT.cs
index 5680e1748c4899366aaeb40b5db1f44ceaef4e97..484650666cd11860c5a6fae0f72e54527a06258e 100644
--- a/src/Jackett/Indexers/BakaBT.cs
+++ b/src/Jackett/Indexers/BakaBT.cs
@@ -13,6 +13,7 @@ using System.Net;
 using System.Text;
 using System.Threading.Tasks;
 using System.Web;
+using Jackett.Models.IndexerConfig;
 
 namespace Jackett.Indexers
 {
@@ -21,26 +22,28 @@ namespace Jackett.Indexers
         public string SearchUrl { get { return SiteLink + "browse.php?only=0&hentai=1&incomplete=1&lossless=1&hd=1&multiaudio=1&bonus=1&c1=1&reorder=1&q="; } }
         public string LoginUrl { get { return SiteLink + "login.php"; } }
 
-        public BakaBT(IIndexerManagerService i, IWebClient wc, Logger l)
+        new ConfigurationDataBasicLogin configData
+        {
+            get { return (ConfigurationDataBasicLogin)base.configData; }
+            set { base.configData = value; }
+        }
+
+        public BakaBT(IIndexerManagerService i, IWebClient wc, Logger l, IProtectionService ps)
             : base(name: "BakaBT",
                 description: "Anime Community",
                 link: "http://bakabt.me/",
                 caps: new TorznabCapabilities(TorznabCatType.Anime),
                 manager: i,
                 client: wc,
-                logger: l)
+                logger: l,
+                p: ps,
+                configData: new ConfigurationDataBasicLogin())
         {
         }
 
-        public Task<ConfigurationData> GetConfigurationForSetup()
-        {
-            return Task.FromResult<ConfigurationData>(new ConfigurationDataBasicLogin());
-        }
-
         public async Task ApplyConfiguration(JToken configJson)
         {
-            var config = new ConfigurationDataBasicLogin();
-            config.LoadValuesFromJson(configJson);
+            configData.LoadValuesFromJson(configJson);
 
             var loginForm = await webclient.GetString(new Utils.Clients.WebRequest()
             {
@@ -49,8 +52,8 @@ namespace Jackett.Indexers
             });
 
             var pairs = new Dictionary<string, string> {
-                { "username", config.Username.Value },
-                { "password", config.Password.Value },
+                { "username", configData.Username.Value },
+                { "password", configData.Password.Value },
                 { "returnto", "/index.php" }
             };
 
@@ -61,7 +64,7 @@ namespace Jackett.Indexers
                  CQ dom = responseContent;
                  var messageEl = dom[".error"].First();
                  var errorMessage = messageEl.Text().Trim();
-                 throw new ExceptionWithConfigData(errorMessage, (ConfigurationData)config);
+                 throw new ExceptionWithConfigData(errorMessage, configData);
              });
         }
 
@@ -88,7 +91,7 @@ namespace Jackett.Indexers
 
                 foreach (var row in rows)
                 {
-                   
+
                     var qRow = row.Cq();
                     var qTitleLink = qRow.Find("a.title").First();
                     var title = qTitleLink.Text().Trim();
diff --git a/src/Jackett/Indexers/BaseIndexer.cs b/src/Jackett/Indexers/BaseIndexer.cs
index 50999b6a6d67ca96eadfbe26463f308049c31433..c2b217c65a6feb46c12af23698bee8bb4b6484ae 100644
--- a/src/Jackett/Indexers/BaseIndexer.cs
+++ b/src/Jackett/Indexers/BaseIndexer.cs
@@ -11,6 +11,7 @@ using Jackett.Utils;
 using Jackett.Utils.Clients;
 using AutoMapper;
 using System.Threading;
+using Jackett.Models.IndexerConfig;
 
 namespace Jackett.Indexers
 {
@@ -28,11 +29,19 @@ namespace Jackett.Indexers
         protected static List<CachedQueryResult> cache = new List<CachedQueryResult>();
         protected static readonly TimeSpan cacheTime = new TimeSpan(0, 9, 0);
         protected IWebClient webclient;
-        protected string cookieHeader = "";
+        protected IProtectionService protectionService;
+
+        protected string CookieHeader
+        {
+            get { return configData.CookieHeader.Value; }
+            set { configData.CookieHeader.Value = value; }
+        }
+
+        protected ConfigurationData configData;
 
         private List<CategoryMapping> categoryMapping = new List<CategoryMapping>();
 
-        public BaseIndexer(string name, string link, string description, IIndexerManagerService manager, IWebClient client, Logger logger, TorznabCapabilities caps = null)
+        public BaseIndexer(string name, string link, string description, IIndexerManagerService manager, IWebClient client, Logger logger, ConfigurationData configData, IProtectionService p, TorznabCapabilities caps = null)
         {
             if (!link.EndsWith("/"))
                 throw new Exception("Site link must end with a slash.");
@@ -43,18 +52,23 @@ namespace Jackett.Indexers
             this.logger = logger;
             indexerService = manager;
             webclient = client;
+            protectionService = p;
+
+            this.configData = configData;
 
             if (caps == null)
                 caps = TorznabCapsUtil.CreateDefaultTorznabTVCaps();
             TorznabCaps = caps;
+
         }
 
         protected int MapTrackerCatToNewznab(string input)
         {
-            if (null != input) {
+            if (null != input)
+            {
                 input = input.ToLowerInvariant();
                 var mapping = categoryMapping.Where(m => m.TrackerCategory == input).FirstOrDefault();
-                if(mapping!= null)
+                if (mapping != null)
                 {
                     return mapping.NewzNabCategory;
                 }
@@ -67,15 +81,20 @@ namespace Jackett.Indexers
             return StringUtil.StripNonAlphaNumeric(type.Name.ToLowerInvariant());
         }
 
-        public void ResetBaseConfig()
+        public virtual Task<ConfigurationData> GetConfigurationForSetup()
+        {
+            return Task.FromResult<ConfigurationData>(configData);
+        }
+
+        public virtual void ResetBaseConfig()
         {
-            cookieHeader = string.Empty;
+            CookieHeader = string.Empty;
             IsConfigured = false;
         }
 
-        protected void SaveConfig(JToken config)
+        protected virtual void SaveConfig()
         {
-            indexerService.SaveConfig(this as IIndexer, config);
+            indexerService.SaveConfig(this as IIndexer, configData.ToJson(protectionService,forDisplay: false));
         }
 
         protected void OnParseError(string results, Exception ex)
@@ -125,55 +144,57 @@ namespace Jackett.Indexers
                 {
                     Url = overrideRedirectUrl ?? incomingResponse.RedirectingTo,
                     Referer = referrer,
-                    Cookies = overrideCookies ?? cookieHeader
+                    Cookies = overrideCookies ?? CookieHeader
                 });
                 Mapper.Map(redirectedResponse, incomingResponse);
             }
         }
 
 
-        protected void LoadCookieHeaderAndConfigure(JToken jsonConfig)
+        protected void LoadLegacyCookieConfig(JToken jsonConfig)
         {
-            cookieHeader = (string)jsonConfig["cookie_header"];
-            if (!string.IsNullOrEmpty(cookieHeader))
+            string legacyCookieHeader = (string)jsonConfig["cookie_header"];
+            if (!string.IsNullOrEmpty(legacyCookieHeader))
             {
-                IsConfigured = true;
+                CookieHeader = legacyCookieHeader;
             }
             else
             {
                 // Legacy cookie key
-                var jcookes = jsonConfig["cookies"];
-                if (jcookes is JArray) {
-                    var array = (JArray)jsonConfig["cookies"];
-                    cookieHeader = string.Empty;
+                var jcookies = jsonConfig["cookies"];
+                if (jcookies is JArray)
+                {
+                    var array = (JArray)jcookies;
+                    legacyCookieHeader = string.Empty;
                     for (int i = 0; i < array.Count; i++)
                     {
                         if (i != 0)
-                            cookieHeader += "; ";
-                        cookieHeader += array[i];
+                            legacyCookieHeader += "; ";
+                        legacyCookieHeader += array[i];
                     }
+                    CookieHeader = legacyCookieHeader;
                 }
-                else
-                    cookieHeader = (string)jsonConfig["cookies"];
-               
-                if (!string.IsNullOrEmpty(cookieHeader))
+                else if (jcookies != null)
                 {
-                    IsConfigured = true;
+                    CookieHeader = (string)jcookies;
                 }
             }
         }
 
-        protected void SaveCookieHeaderAndConfigure()
-        {
-            var configSaveData = new JObject();
-            configSaveData["cookie_header"] = cookieHeader;
-            SaveConfig(configSaveData);
-            IsConfigured = !string.IsNullOrEmpty(cookieHeader);
-        }
-
         public virtual void LoadFromSavedConfiguration(JToken jsonConfig)
         {
-            LoadCookieHeaderAndConfigure(jsonConfig);
+            if (jsonConfig is JArray)
+            {
+                configData.LoadValuesFromJson(jsonConfig, protectionService);
+                IsConfigured = true;
+            }
+            // read and upgrade old settings file format
+            else if (jsonConfig is Object)
+            {
+                LoadLegacyCookieConfig(jsonConfig);
+                SaveConfig();
+                IsConfigured = true;
+            }
         }
 
         public async virtual Task<byte[]> Download(Uri link)
@@ -195,8 +216,8 @@ namespace Jackett.Indexers
                 {
                     logger.Error(string.Format("On attempt {0} downloading from {1}: {2}", (i + 1), DisplayName, e.Message));
                     lastException = e;
-                    await Task.Delay(500);
                 }
+                await Task.Delay(500);
             }
 
             throw lastException;
@@ -208,7 +229,7 @@ namespace Jackett.Indexers
             {
                 Url = url,
                 Type = RequestType.GET,
-                Cookies = cookieHeader,
+                Cookies = CookieHeader,
                 Referer = referer
             };
 
@@ -229,9 +250,9 @@ namespace Jackett.Indexers
                 catch (Exception e)
                 {
                     logger.Error(string.Format("On attempt {0} checking for results from {1}: {2}", (i + 1), DisplayName, e.Message));
-                    lastException= e;
-                    await Task.Delay(500);
+                    lastException = e;
                 }
+                await Task.Delay(500);
             }
 
             throw lastException;
@@ -243,7 +264,7 @@ namespace Jackett.Indexers
             {
                 Url = url,
                 Type = RequestType.GET,
-                Cookies = cookieOverride ?? cookieHeader
+                Cookies = cookieOverride ?? CookieHeader
             };
 
             if (cookieOverride != null)
@@ -251,39 +272,39 @@ namespace Jackett.Indexers
             return await webclient.GetBytes(request);
         }
 
-        protected async Task<WebClientStringResult> PostDataWithCookies(string url, Dictionary<string, string> data, string cookieOverride = null)
+        protected async Task<WebClientStringResult> PostDataWithCookies(string url, IEnumerable<KeyValuePair<string, string>> data, string cookieOverride = null)
         {
             var request = new Utils.Clients.WebRequest()
             {
                 Url = url,
                 Type = RequestType.POST,
-                Cookies = cookieOverride ?? cookieHeader,
+                Cookies = cookieOverride ?? CookieHeader,
                 PostData = data
             };
             return await webclient.GetString(request);
         }
 
-        protected async Task<WebClientStringResult> PostDataWithCookiesAndRetry(string url, Dictionary<string, string> data, string cookieOverride = null)
+        protected async Task<WebClientStringResult> PostDataWithCookiesAndRetry(string url, IEnumerable<KeyValuePair<string, string>> data, string cookieOverride = null)
         {
             Exception lastException = null;
             for (int i = 0; i < 3; i++)
             {
                 try
                 {
-                    return await PostDataWithCookies(url,data,cookieOverride);
+                    return await PostDataWithCookies(url, data, cookieOverride);
                 }
                 catch (Exception e)
                 {
                     logger.Error(string.Format("On attempt {0} checking for results from {1}: {2}", (i + 1), DisplayName, e.Message));
                     lastException = e;
-                    await Task.Delay(500);
                 }
+                await Task.Delay(500);
             }
 
             throw lastException;
         }
 
-        protected async Task<WebClientStringResult> RequestLoginAndFollowRedirect(string url, Dictionary<string, string> data, string cookies, bool returnCookiesFromFirstCall, string redirectUrlOverride = null, string referer =null)
+        protected async Task<WebClientStringResult> RequestLoginAndFollowRedirect(string url, IEnumerable<KeyValuePair<string, string>> data, string cookies, bool returnCookiesFromFirstCall, string redirectUrlOverride = null, string referer = null)
         {
             var request = new Utils.Clients.WebRequest()
             {
@@ -313,8 +334,9 @@ namespace Jackett.Indexers
         {
             if (isLoggedin)
             {
-                cookieHeader = cookies;
-                SaveCookieHeaderAndConfigure();
+                CookieHeader = cookies;
+                SaveConfig();
+                IsConfigured = true;
             }
             else
             {
@@ -324,9 +346,9 @@ namespace Jackett.Indexers
 
         public virtual IEnumerable<ReleaseInfo> FilterResults(TorznabQuery query, IEnumerable<ReleaseInfo> results)
         {
-            foreach(var result in results)
+            foreach (var result in results)
             {
-               if(query.Categories.Length == 0 || query.Categories.Contains(result.Category) || result.Category == 0 || TorznabCatType.QueryContainsParentCategory(query.Categories, result.Category))
+                if (query.Categories.Length == 0 || query.Categories.Contains(result.Category) || result.Category == 0 || TorznabCatType.QueryContainsParentCategory(query.Categories, result.Category))
                 {
                     yield return result;
                 }
diff --git a/src/Jackett/Indexers/BeyondHD.cs b/src/Jackett/Indexers/BeyondHD.cs
index cab8600b939d6fe9c5fe4f6710342c506fb38bcf..4e7c0830f70f4044141133fcb9b1bd5f88efc702 100644
--- a/src/Jackett/Indexers/BeyondHD.cs
+++ b/src/Jackett/Indexers/BeyondHD.cs
@@ -13,6 +13,7 @@ using System.Net.Http;
 using System.Text;
 using System.Threading.Tasks;
 using System.Web;
+using Jackett.Models.IndexerConfig;
 
 namespace Jackett.Indexers
 {
@@ -21,38 +22,39 @@ namespace Jackett.Indexers
         private string SearchUrl { get { return SiteLink + "browse.php?c40=1&c44=1&c48=1&c89=1&c46=1&c45=1&searchin=title&incldead=0&search={0}"; } }
         private string DownloadUrl { get { return SiteLink + "download.php?torrent={0}"; } }
 
-        public BeyondHD(IIndexerManagerService i, Logger l, IWebClient w)
+        new ConfigurationDataCookie configData
+        {
+            get { return (ConfigurationDataCookie)base.configData; }
+            set { base.configData = value; }
+        }
+
+        public BeyondHD(IIndexerManagerService i, Logger l, IWebClient w, IProtectionService ps)
             : base(name: "BeyondHD",
                 description: "Without BeyondHD, your HDTV is just a TV",
                 link: "https://beyondhd.me/",
                 caps: TorznabCapsUtil.CreateDefaultTorznabTVCaps(),
                 manager: i,
                 client: w,
-                logger: l)
-        {
-        }
-
-        public Task<ConfigurationData> GetConfigurationForSetup()
+                logger: l,
+                p: ps,
+                configData: new ConfigurationDataCookie())
         {
-            return Task.FromResult<ConfigurationData>(new ConfigurationDataCookie());
         }
 
         public async Task ApplyConfiguration(JToken configJson)
         {
-            var config = new ConfigurationDataCookie();
-            config.LoadValuesFromJson(configJson);
-            cookieHeader = config.CookieHeader;
+            configData.LoadValuesFromJson(configJson);
 
             var response = await webclient.GetString(new Utils.Clients.WebRequest()
             {
                 Url = SiteLink,
-                Cookies = cookieHeader
+                Cookies = configData.Cookie.Value
             });
 
-            await ConfigureIfOK(cookieHeader, response.Content.Contains("logout.php"), () =>
+            await ConfigureIfOK(CookieHeader, response.Content.Contains("logout.php"), () =>
             {
                 CQ dom = response.Content;
-                throw new ExceptionWithConfigData("Invalid cookie header", (ConfigurationData)config);
+                throw new ExceptionWithConfigData("Invalid cookie header", configData);
             });
         }
 
diff --git a/src/Jackett/Indexers/BitHdtv.cs b/src/Jackett/Indexers/BitHdtv.cs
index 1dd1e165fc0597cbe37c678011edd032e9237993..f3910a31230fc0f0ec928bf8ec72bed777f00cd2 100644
--- a/src/Jackett/Indexers/BitHdtv.cs
+++ b/src/Jackett/Indexers/BitHdtv.cs
@@ -14,6 +14,7 @@ using System.Net.Http;
 using System.Text;
 using System.Threading.Tasks;
 using System.Web;
+using Jackett.Models.IndexerConfig;
 
 namespace Jackett.Indexers
 {
@@ -23,31 +24,33 @@ namespace Jackett.Indexers
         private string SearchUrl { get { return SiteLink + "torrents.php?cat=0&search="; } }
         private string DownloadUrl { get { return SiteLink + "download.php?/{0}/dl.torrent"; } }
 
-        public BitHdtv(IIndexerManagerService i, Logger l, IWebClient w)
+        new ConfigurationDataBasicLogin configData
+        {
+            get { return (ConfigurationDataBasicLogin)base.configData; }
+            set { base.configData = value; }
+        }
+
+        public BitHdtv(IIndexerManagerService i, Logger l, IWebClient w, IProtectionService ps)
             : base(name: "BIT-HDTV",
                 description: "Home of high definition invites",
                 link: "https://www.bit-hdtv.com/",
                 caps: TorznabCapsUtil.CreateDefaultTorznabTVCaps(),
                 manager: i,
                 client: w,
-                logger: l)
-        {
-        }
-
-        public Task<ConfigurationData> GetConfigurationForSetup()
+                logger: l,
+                p: ps,
+                configData: new ConfigurationDataBasicLogin())
         {
-            return Task.FromResult<ConfigurationData>(new ConfigurationDataBasicLogin());
         }
 
         public async Task ApplyConfiguration(JToken configJson)
         {
-            var incomingConfig = new ConfigurationDataBasicLogin();
-            incomingConfig.LoadValuesFromJson(configJson);
+            configData.LoadValuesFromJson(configJson);
 
             var pairs = new Dictionary<string, string> {
-				{ "username", incomingConfig.Username.Value },
-				{ "password", incomingConfig.Password.Value }
-			};
+                { "username", configData.Username.Value },
+                { "password", configData.Password.Value }
+            };
 
             var response = await RequestLoginAndFollowRedirect(LoginUrl, pairs, null, true, null, SiteLink);
             await ConfigureIfOK(response.Cookies, response.Content != null && response.Content.Contains("logout.php"), () =>
@@ -57,7 +60,7 @@ namespace Jackett.Indexers
                 messageEl.Children("a").Remove();
                 messageEl.Children("style").Remove();
                 var errorMessage = messageEl.Text().Trim();
-                throw new ExceptionWithConfigData(errorMessage, (ConfigurationData)incomingConfig);
+                throw new ExceptionWithConfigData(errorMessage, configData);
             });
         }
 
diff --git a/src/Jackett/Indexers/BitMeTV.cs b/src/Jackett/Indexers/BitMeTV.cs
index e8b7cc123d02e3e3777089c5311c3f58ee717f63..fd555cd7273b2f9af1fb5c76142d4b07da801ab4 100644
--- a/src/Jackett/Indexers/BitMeTV.cs
+++ b/src/Jackett/Indexers/BitMeTV.cs
@@ -26,53 +26,59 @@ namespace Jackett.Indexers
         private string CaptchaUrl { get { return SiteLink + "visual.php"; } }
         private string SearchUrl { get { return SiteLink + "browse.php"; } }
 
-        public BitMeTV(IIndexerManagerService i, Logger l, IWebClient c)
+        new ConfigurationDataCaptchaLogin configData
+        {
+            get { return (ConfigurationDataCaptchaLogin)base.configData; }
+            set { base.configData = value; }
+        }
+
+        public BitMeTV(IIndexerManagerService i, Logger l, IWebClient c, IProtectionService ps)
             : base(name: "BitMeTV",
                 description: "TV Episode specialty tracker",
                 link: "http://www.bitmetv.org/",
                 caps: TorznabCapsUtil.CreateDefaultTorznabTVCaps(),
                 manager: i,
                 client: c,
-                logger: l)
+                logger: l,
+                p: ps,
+                configData: new ConfigurationDataCaptchaLogin())
         {
         }
 
-        public async Task<ConfigurationData> GetConfigurationForSetup()
+        public override async Task<ConfigurationData> GetConfigurationForSetup()
         {
             var response = await webclient.GetString(new Utils.Clients.WebRequest()
             {
                 Url = LoginUrl
             });
-            cookieHeader = response.Cookies;
+            CookieHeader = response.Cookies;
             var captchaImage = await RequestBytesWithCookies(CaptchaUrl);
-            var config = new BmtvConfig();
-            config.CaptchaImage.Value = captchaImage.Content;
-            config.CaptchaCookie.Value = captchaImage.Cookies;
-            return (ConfigurationData)config;
+            configData.CaptchaImage.Value = captchaImage.Content;
+            configData.CaptchaCookie.Value = captchaImage.Cookies;
+            return configData;
         }
 
         public async Task ApplyConfiguration(JToken configJson)
         {
-            var config = new BmtvConfig();
-            config.LoadValuesFromJson(configJson);
+            configData.LoadValuesFromJson(configJson);
 
             var pairs = new Dictionary<string, string> {
-				{ "username", config.Username.Value },
-				{ "password", config.Password.Value },
-				{ "secimage", config.CaptchaText.Value }
-			};
+                { "username", configData.Username.Value },
+                { "password", configData.Password.Value },
+                { "secimage", configData.CaptchaText.Value }
+            };
 
-            var response = await RequestLoginAndFollowRedirect(LoginPost, pairs, config.CaptchaCookie.Value, true);
+            var response = await RequestLoginAndFollowRedirect(LoginPost, pairs, configData.CaptchaCookie.Value, true);
             await ConfigureIfOK(response.Cookies, response.Content.Contains("/logout.php"), async () =>
             {
                 CQ dom = response.Content;
                 var messageEl = dom["table tr > td.embedded > h2"].Last();
                 var errorMessage = messageEl.Text();
                 var captchaImage = await RequestBytesWithCookies(CaptchaUrl);
-                config.CaptchaImage.Value = captchaImage.Content;
-                config.CaptchaText.Value = "";
-                config.CaptchaCookie.Value = captchaImage.Cookies;
-                throw new ExceptionWithConfigData(errorMessage, (ConfigurationData)config);
+                configData.CaptchaImage.Value = captchaImage.Content;
+                configData.CaptchaText.Value = "";
+                configData.CaptchaCookie.Value = captchaImage.Cookies;
+                throw new ExceptionWithConfigData(errorMessage, configData);
             });
         }
 
diff --git a/src/Jackett/Indexers/Demonoid.cs b/src/Jackett/Indexers/Demonoid.cs
new file mode 100644
index 0000000000000000000000000000000000000000..44e5d68fef9e635497a366b40eaab48bb0a24613
--- /dev/null
+++ b/src/Jackett/Indexers/Demonoid.cs
@@ -0,0 +1,134 @@
+using CsQuery;
+using Jackett.Models;
+using Jackett.Models.IndexerConfig;
+using Jackett.Services;
+using Jackett.Utils;
+using Jackett.Utils.Clients;
+using Newtonsoft.Json.Linq;
+using NLog;
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Web;
+
+namespace Jackett.Indexers
+{
+    public class Demonoid : BaseIndexer, IIndexer
+    {
+        private string LoginUrl { get { return SiteLink + "account_handler.php"; } }
+        private string SearchUrl { get { return SiteLink + "files/?category=3&subcategory=All&quality=All&seeded=0&to=1&query={0}"; } }
+
+        new ConfigurationDataBasicLogin configData
+        {
+            get { return (ConfigurationDataBasicLogin)base.configData; }
+            set { base.configData = value; }
+        }
+
+        public Demonoid(IIndexerManagerService i, Logger l, IWebClient wc, IProtectionService ps)
+            : base(name: "Demonoid",
+                description: "Demonoid",
+                link: "http://www.demonoid.pw/",
+                caps: TorznabCapsUtil.CreateDefaultTorznabTVCaps(),
+                manager: i,
+                client: wc,
+                logger: l,
+                p: ps,
+                configData: new ConfigurationDataBasicLogin())
+        {
+        }
+
+        public async Task ApplyConfiguration(JToken configJson)
+        {
+            configData.LoadValuesFromJson(configJson);
+            var pairs = new Dictionary<string, string> {
+                { "nickname", configData.Username.Value },
+                { "password", configData.Password.Value },
+                { "returnpath", "/" },
+                { "withq", "0" },
+                { "Submit", "Submit" }
+            };
+
+            var result = await RequestLoginAndFollowRedirect(LoginUrl, pairs, null, true, null, SiteLink);
+            await ConfigureIfOK(result.Cookies, result.Content != null && result.Content.Contains("user_control_panel.php"), () =>
+            {
+                CQ dom = result.Content;
+                var errorMessage = dom[".red"].ElementAt(1).Cq().Text().Trim();
+                throw new ExceptionWithConfigData(errorMessage, configData);
+            });
+        }
+
+        public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query)
+        {
+            var releases = new List<ReleaseInfo>();
+            var searchString = query.SanitizedSearchTerm + " " + query.GetEpisodeSearchString();
+            var episodeSearchUrl = string.Format(SearchUrl, HttpUtility.UrlEncode(searchString));
+            var results = await RequestStringWithCookiesAndRetry(episodeSearchUrl);
+
+            if (results.Content.Contains("No torrents found"))
+            {
+                return releases;
+            }
+
+            try
+            {
+                CQ dom = results.Content;
+                var rows = dom[".ctable_content_no_pad > table > tbody > tr"].ToArray();
+                DateTime lastDateTime = default(DateTime);
+                for (var i = 0; i < rows.Length; i++)
+                {
+                    var rowA = rows[i];
+                    var rAlign = rowA.Attributes["align"];
+                    if (rAlign == "right" || rAlign == "center")
+                        continue;
+                    if (rAlign == "left")
+                    {
+                        // ex: "Monday, Jun 01, 2015", "Monday, Aug 03, 2015"
+                        var dateStr = rowA.Cq().Text().Trim().Replace("Added on ", "");
+                        if (dateStr.ToLowerInvariant().Contains("today"))
+                            lastDateTime = DateTime.Now;
+                        else
+                            lastDateTime = DateTime.SpecifyKind(DateTime.ParseExact(dateStr, "dddd, MMM dd, yyyy", CultureInfo.InvariantCulture), DateTimeKind.Utc).ToLocalTime();
+                        continue;
+                    }
+                    if (rowA.ChildElements.Count() < 2)
+                        continue;
+
+                    var rowB = rows[++i];
+
+                    var release = new ReleaseInfo();
+                    release.MinimumRatio = 1;
+                    release.MinimumSeedTime = 172800;
+
+                    release.PublishDate = lastDateTime;
+
+                    var qLink = rowA.ChildElements.ElementAt(1).FirstElementChild.Cq();
+                    release.Title = qLink.Text().Trim();
+                    release.Description = release.Title;
+
+                    release.Comments = new Uri(SiteLink + qLink.Attr("href"));
+                    release.Guid = release.Comments;
+
+                    var qDownload = rowB.ChildElements.ElementAt(2).ChildElements.ElementAt(1).Cq();
+                    release.Link = new Uri(SiteLink + qDownload.Attr("href"));
+
+                    var sizeStr = rowB.ChildElements.ElementAt(3).Cq().Text();
+                    release.Size = ReleaseInfo.GetBytes(sizeStr);
+
+                    release.Seeders = ParseUtil.CoerceInt(rowB.ChildElements.ElementAt(6).Cq().Text());
+                    release.Peers = ParseUtil.CoerceInt(rowB.ChildElements.ElementAt(6).Cq().Text()) + release.Seeders;
+
+                    releases.Add(release);
+                }
+
+            }
+            catch (Exception ex)
+            {
+                OnParseError(results.Content, ex);
+            }
+            return releases;
+        }
+    }
+}
diff --git a/src/Jackett/Indexers/FrenchTorrentDb.cs b/src/Jackett/Indexers/FrenchTorrentDb.cs
index bfd7854d29ac31ca20de773dbf06f2ed818e8bf7..b3e3d67b8b70c6404bb6a81216af5d928c755899 100644
--- a/src/Jackett/Indexers/FrenchTorrentDb.cs
+++ b/src/Jackett/Indexers/FrenchTorrentDb.cs
@@ -8,9 +8,6 @@ using Newtonsoft.Json.Linq;
 using NLog;
 using System;
 using System.Collections.Generic;
-using System.Globalization;
-using System.Net;
-using System.Net.Http;
 using System.Threading.Tasks;
 using System.Web;
 
@@ -21,37 +18,38 @@ namespace Jackett.Indexers
         private string MainUrl { get { return SiteLink + "?section=INDEX"; } }
         private string SearchUrl { get { return SiteLink + "?section=TORRENTS&exact=1&name={0}&submit=GO"; } }
 
-        public FrenchTorrentDb(IIndexerManagerService i, Logger l, IWebClient c)
+        new ConfigurationDataCookie configData
+        {
+            get { return (ConfigurationDataCookie)base.configData; }
+            set { base.configData = value; }
+        }
+
+        public FrenchTorrentDb(IIndexerManagerService i, Logger l, IWebClient c, IProtectionService ps)
             : base(name: "FrenchTorrentDb",
                 description: "One the biggest French Torrent Tracker",
                 link: "http://www.frenchtorrentdb.com/",
                 caps: TorznabCapsUtil.CreateDefaultTorznabTVCaps(),
                 manager: i,
                 client: c,
-                logger: l)
-        {
-        }
-
-        public Task<ConfigurationData> GetConfigurationForSetup()
+                logger: l,
+                p: ps,
+                configData: new ConfigurationDataCookie())
         {
-            return Task.FromResult<ConfigurationData>(new ConfigurationDataUrl(SiteLink));
         }
 
-        public async Task ApplyConfiguration(Newtonsoft.Json.Linq.JToken configJson)
+        public async Task ApplyConfiguration(JToken configJson)
         {
-            var config = new ConfigurationDataBasicLoginFrenchTorrentDb();
-            config.LoadValuesFromJson(configJson);
-            var cookies = "WebsiteID=" + config.Cookie.Value;
+            configData.LoadValuesFromJson(configJson);
             var response = await webclient.GetString(new Utils.Clients.WebRequest()
             {
                 Url = MainUrl,
                 Type = RequestType.GET,
-                Cookies = cookies
+                Cookies = configData.Cookie.Value
             });
 
-            await ConfigureIfOK(cookies, response.Content.Contains("/?section=LOGOUT"), () =>
+            await ConfigureIfOK(configData.Cookie.Value, response.Content.Contains("/?section=LOGOUT"), () =>
             {
-                throw new ExceptionWithConfigData("Failed to login", (ConfigurationData)config);
+                throw new ExceptionWithConfigData("Failed to login", configData);
             });
         }
 
diff --git a/src/Jackett/Indexers/Freshon.cs b/src/Jackett/Indexers/Freshon.cs
index 169a7d7e3bae6f9a281443a1e701f0e76b6642c2..a6b025b44a001610198629d36c77f6e8cc82c703 100644
--- a/src/Jackett/Indexers/Freshon.cs
+++ b/src/Jackett/Indexers/Freshon.cs
@@ -17,6 +17,7 @@ using System.Text;
 using System.Threading.Tasks;
 using System.Web;
 using System.Web.UI.WebControls;
+using Jackett.Models.IndexerConfig;
 
 namespace Jackett.Indexers
 {
@@ -26,41 +27,43 @@ namespace Jackett.Indexers
         private string LoginPostUrl { get { return SiteLink + "login.php?action=makelogin"; } }
         private string SearchUrl { get { return SiteLink + "browse.php"; } }
 
-        public Freshon(IIndexerManagerService i, Logger l, IWebClient c)
+        new ConfigurationDataBasicLogin configData
+        {
+            get { return (ConfigurationDataBasicLogin)base.configData; }
+            set { base.configData = value; }
+        }
+
+        public Freshon(IIndexerManagerService i, Logger l, IWebClient c, IProtectionService ps)
             : base(name: "FreshOnTV",
                 description: "Our goal is to provide the latest stuff in the TV show domain",
                 link: "https://freshon.tv/",
                 caps: TorznabCapsUtil.CreateDefaultTorznabTVCaps(),
                 manager: i,
                 client: c,
-                logger: l)
-        {
-        }
-
-        public async Task<ConfigurationData> GetConfigurationForSetup()
+                logger: l,
+                p: ps,
+                configData: new ConfigurationDataBasicLogin())
         {
-            return await Task.FromResult< ConfigurationData>(new ConfigurationDataBasicLogin());
         }
 
         public async Task ApplyConfiguration(JToken configJson)
         {
-            var incomingConfig = new ConfigurationDataBasicLogin();
-            incomingConfig.LoadValuesFromJson(configJson);
+            configData.LoadValuesFromJson(configJson);
             var pairs = new Dictionary<string, string> {
-				{ "username", incomingConfig.Username.Value },
-				{ "password", incomingConfig.Password.Value }
-			};
+                { "username", configData.Username.Value },
+                { "password", configData.Password.Value }
+            };
 
             // Get inital cookies
-            cookieHeader = string.Empty;
-            var response = await RequestLoginAndFollowRedirect(LoginPostUrl, pairs, cookieHeader, true, null, LoginUrl);
+            CookieHeader = string.Empty;
+            var response = await RequestLoginAndFollowRedirect(LoginPostUrl, pairs, CookieHeader, true, null, LoginUrl);
 
             await ConfigureIfOK(response.Cookies, response.Content != null && response.Content.Contains("/logout.php"), () =>
             {
                 CQ dom = response.Content;
                 var messageEl = dom[".error_text"];
                 var errorMessage = messageEl.Text().Trim();
-                throw new ExceptionWithConfigData(errorMessage, (ConfigurationData)incomingConfig);
+                throw new ExceptionWithConfigData(errorMessage, configData);
             });
         }
 
diff --git a/src/Jackett/Indexers/HDSpace.cs b/src/Jackett/Indexers/HDSpace.cs
index d266a079b0c22dbfda9731067e3459aad62116a1..3cc7012dd5da78d6c5fee4fd0701a3e993bfa36a 100644
--- a/src/Jackett/Indexers/HDSpace.cs
+++ b/src/Jackett/Indexers/HDSpace.cs
@@ -13,6 +13,7 @@ using CsQuery;
 using System.Web;
 using System.Text.RegularExpressions;
 using System.Globalization;
+using Jackett.Models.IndexerConfig;
 
 namespace Jackett.Indexers
 {
@@ -21,32 +22,34 @@ namespace Jackett.Indexers
         private string LoginUrl { get { return SiteLink + "index.php?page=login"; } }
         private string SearchUrl { get { return SiteLink + "index.php?page=torrents&active=0&options=0&category=21%3B22&search={0}"; } }
 
-        public HDSpace(IIndexerManagerService i, IWebClient wc, Logger l)
+        new ConfigurationDataBasicLogin configData
+        {
+            get { return (ConfigurationDataBasicLogin)base.configData; }
+            set { base.configData = value; }
+        }
+
+        public HDSpace(IIndexerManagerService i, IWebClient wc, Logger l, IProtectionService ps)
             : base(name: "HD-Space",
                 description: "Sharing The Universe",
                 link: "https://hd-space.org/",
                 caps: TorznabCapsUtil.CreateDefaultTorznabTVCaps(),
                 manager: i,
                 client: wc,
-                logger: l)
-        {
-        }
-
-        public Task<ConfigurationData> GetConfigurationForSetup()
+                logger: l,
+                p: ps,
+                configData: new ConfigurationDataBasicLogin())
         {
-            return Task.FromResult<ConfigurationData>(new ConfigurationDataBasicLogin());
         }
 
         public async Task ApplyConfiguration(JToken configJson)
         {
-            var config = new ConfigurationDataBasicLogin();
-            config.LoadValuesFromJson(configJson);
+            configData.LoadValuesFromJson(configJson);
 
             var loginPage = await RequestStringWithCookies(LoginUrl, string.Empty);
 
             var pairs = new Dictionary<string, string> {
-                { "uid", config.Username.Value },
-                { "pwd", config.Password.Value }
+                { "uid", configData.Username.Value },
+                { "pwd", configData.Password.Value }
             };
 
             // Send Post
@@ -58,7 +61,7 @@ namespace Jackett.Indexers
                 var remainingAttemptSpan = new Regex(string.Format(errorStr, "(.*?)")).Match(loginPage.Content).Groups[1].ToString();
                 var attempts = Regex.Replace(remainingAttemptSpan, "<.*?>", String.Empty);
                 var errorMessage = string.Format(errorStr, attempts);
-                throw new ExceptionWithConfigData(errorMessage, (ConfigurationData)config);
+                throw new ExceptionWithConfigData(errorMessage, configData);
             });
         }
 
diff --git a/src/Jackett/Indexers/HDTorrents.cs b/src/Jackett/Indexers/HDTorrents.cs
index d8e3d5158ca854e7fd81e2394f68e1f99c232798..c11771d9a049d357016e23ce6eb809ccd0a8ebfe 100644
--- a/src/Jackett/Indexers/HDTorrents.cs
+++ b/src/Jackett/Indexers/HDTorrents.cs
@@ -14,6 +14,7 @@ using System.Net.Http;
 using System.Text;
 using System.Threading.Tasks;
 using System.Web;
+using Jackett.Models.IndexerConfig;
 
 namespace Jackett.Indexers
 {
@@ -23,31 +24,33 @@ namespace Jackett.Indexers
         private string LoginUrl { get { return SiteLink + "login.php"; } }
         private const int MAXPAGES = 3;
 
-        public HDTorrents(IIndexerManagerService i, Logger l, IWebClient w)
+        new ConfigurationDataBasicLogin configData
+        {
+            get { return (ConfigurationDataBasicLogin)base.configData; }
+            set { base.configData = value; }
+        }
+
+        public HDTorrents(IIndexerManagerService i, Logger l, IWebClient w, IProtectionService ps)
             : base(name: "HD-Torrents",
                 description: "HD-Torrents is a private torrent website with HD torrents and strict rules on their content.",
                 link: "http://hdts.ru/",// Of the accessible domains the .ru seems the most reliable.  https://hdts.ru | https://hd-torrents.org | https://hd-torrents.net | https://hd-torrents.me
                 caps: TorznabCapsUtil.CreateDefaultTorznabTVCaps(),
                 manager: i,
                 client: w,
-                logger: l)
-        {
-        }
-
-        public Task<ConfigurationData> GetConfigurationForSetup()
+                logger: l,
+                p: ps,
+                configData: new ConfigurationDataBasicLogin())
         {
-            return Task.FromResult<ConfigurationData>(new ConfigurationDataBasicLogin());
         }
 
         public async Task ApplyConfiguration(JToken configJson)
         {
-            var incomingConfig = new ConfigurationDataBasicLogin();
-            incomingConfig.LoadValuesFromJson(configJson);
+            configData.LoadValuesFromJson(configJson);
             var loginPage = await RequestStringWithCookies(LoginUrl, string.Empty);
 
             var pairs = new Dictionary<string, string> {
-                { "uid", incomingConfig.Username.Value },
-                { "pwd", incomingConfig.Password.Value }
+                { "uid", configData.Username.Value },
+                { "pwd", configData.Password.Value }
             };
 
             var result = await RequestLoginAndFollowRedirect(LoginUrl, pairs, loginPage.Cookies, true, null, LoginUrl);
@@ -55,7 +58,7 @@ namespace Jackett.Indexers
             await ConfigureIfOK(result.Cookies, result.Content != null && result.Content.Contains("If your browser doesn't have javascript enabled"), () =>
             {
                 var errorMessage = "Couldn't login";
-                throw new ExceptionWithConfigData(errorMessage, (ConfigurationData)incomingConfig);
+                throw new ExceptionWithConfigData(errorMessage, configData);
             });
         }
 
diff --git a/src/Jackett/Indexers/IIndexer.cs b/src/Jackett/Indexers/IIndexer.cs
index c768591eb9bfbdfddff7d1660de23d88734d55f8..662dd8ebed30d6bf5ee0b6edbc2d1d24e5019b92 100644
--- a/src/Jackett/Indexers/IIndexer.cs
+++ b/src/Jackett/Indexers/IIndexer.cs
@@ -1,4 +1,5 @@
 using Jackett.Models;
+using Jackett.Models.IndexerConfig;
 using Newtonsoft.Json.Linq;
 using System;
 using System.Collections.Generic;
diff --git a/src/Jackett/Indexers/IPTorrents.cs b/src/Jackett/Indexers/IPTorrents.cs
index 975c7a74e53d49bc1f65a06c21a4386ef979930f..ed844114f81fec4ead568afa308a3d45ba50b374 100644
--- a/src/Jackett/Indexers/IPTorrents.cs
+++ b/src/Jackett/Indexers/IPTorrents.cs
@@ -15,6 +15,7 @@ using System.Net.Http;
 using System.Text;
 using System.Threading.Tasks;
 using System.Web;
+using Jackett.Models.IndexerConfig;
 
 namespace Jackett.Indexers
 {
@@ -22,14 +23,22 @@ namespace Jackett.Indexers
     {
         private string BrowseUrl { get { return SiteLink + "t"; } }
 
-        public IPTorrents(IIndexerManagerService i, IWebClient wc, Logger l)
+        new ConfigurationDataBasicLogin configData
+        {
+            get { return (ConfigurationDataBasicLogin)base.configData; }
+            set { base.configData = value; }
+        }
+
+        public IPTorrents(IIndexerManagerService i, IWebClient wc, Logger l, IProtectionService ps)
             : base(name: "IPTorrents",
                 description: "Always a step ahead.",
                 link: "https://iptorrents.com/",
                 caps: TorznabCapsUtil.CreateDefaultTorznabTVCaps(),
                 manager: i,
                 client: wc,
-                logger: l)
+                logger: l,
+                p: ps,
+                configData: new ConfigurationDataBasicLogin())
         {
             AddCategoryMapping(72, TorznabCatType.Movies);
             AddCategoryMapping(77, TorznabCatType.MoviesSD);
@@ -74,18 +83,12 @@ namespace Jackett.Indexers
             AddCategoryMapping(94, TorznabCatType.Comic);
         }
 
-        public Task<ConfigurationData> GetConfigurationForSetup()
-        {
-            return Task.FromResult<ConfigurationData>(new ConfigurationDataBasicLogin());
-        }
-
         public async Task ApplyConfiguration(JToken configJson)
         {
-            var incomingConfig = new ConfigurationDataBasicLogin();
-            incomingConfig.LoadValuesFromJson(configJson);
+            configData.LoadValuesFromJson(configJson);
             var pairs = new Dictionary<string, string> {
-                { "username", incomingConfig.Username.Value },
-                { "password", incomingConfig.Password.Value }
+                { "username", configData.Username.Value },
+                { "password", configData.Password.Value }
             };
             var request = new Utils.Clients.WebRequest()
             {
@@ -104,7 +107,7 @@ namespace Jackett.Indexers
                 CQ dom = response.Content;
                 var messageEl = dom["body > div"].First();
                 var errorMessage = messageEl.Text().Trim();
-                throw new ExceptionWithConfigData(errorMessage, (ConfigurationData)incomingConfig);
+                throw new ExceptionWithConfigData(errorMessage, configData);
             });
         }
 
@@ -130,7 +133,7 @@ namespace Jackett.Indexers
             {
                 searchUrl += "?" + queryCollection.GetQueryString();
             }
-                       
+
             var response = await RequestStringWithCookiesAndRetry(searchUrl, null, BrowseUrl);
 
             var results = response.Content;
diff --git a/src/Jackett/Indexers/ImmortalSeed.cs b/src/Jackett/Indexers/ImmortalSeed.cs
index 7bd11569ea4df46b1b9f837b467a174146fdb5dd..f00a3849f515d72a7811d6947db8790e6699ccc8 100644
--- a/src/Jackett/Indexers/ImmortalSeed.cs
+++ b/src/Jackett/Indexers/ImmortalSeed.cs
@@ -14,6 +14,7 @@ using System.Net.Http;
 using System.Text;
 using System.Threading.Tasks;
 using System.Web;
+using Jackett.Models.IndexerConfig;
 
 namespace Jackett.Indexers
 {
@@ -23,14 +24,22 @@ namespace Jackett.Indexers
         private string LoginUrl { get { return SiteLink + "takelogin.php"; } }
         private string QueryString { get { return "?do=search&keywords={0}&search_type=t_name&category=0&include_dead_torrents=no"; } }
 
-        public ImmortalSeed(IIndexerManagerService i, IWebClient wc, Logger l)
+        new ConfigurationDataBasicLogin configData
+        {
+            get { return (ConfigurationDataBasicLogin)base.configData; }
+            set { base.configData = value; }
+        }
+
+        public ImmortalSeed(IIndexerManagerService i, IWebClient wc, Logger l, IProtectionService ps)
             : base(name: "ImmortalSeed",
                 description: "ImmortalSeed",
                 link: "http://immortalseed.me/",
                 caps: TorznabCapsUtil.CreateDefaultTorznabTVCaps(),
                 manager: i,
                 client: wc,
-                logger: l)
+                logger: l,
+                p: ps,
+                configData: new ConfigurationDataBasicLogin())
         {
             AddCategoryMapping(32, TorznabCatType.Anime);
             AddCategoryMapping(47, TorznabCatType.TVSD);
@@ -58,18 +67,12 @@ namespace Jackett.Indexers
 
         }
 
-        public Task<ConfigurationData> GetConfigurationForSetup()
-        {
-            return Task.FromResult<ConfigurationData>(new ConfigurationDataBasicLogin());
-        }
-
         public async Task ApplyConfiguration(JToken configJson)
         {
-            var incomingConfig = new ConfigurationDataBasicLogin();
-            incomingConfig.LoadValuesFromJson(configJson);
+            configData.LoadValuesFromJson(configJson);
             var pairs = new Dictionary<string, string> {
-                { "username", incomingConfig.Username.Value },
-                { "password", incomingConfig.Password.Value }
+                { "username", configData.Username.Value },
+                { "password", configData.Password.Value }
             };
             var request = new Utils.Clients.WebRequest()
             {
@@ -88,7 +91,7 @@ namespace Jackett.Indexers
             {
                 var tries = resultDom["#main tr:eq(1) td font"].First().Text();
                 var errorMessage = "Incorrect username or password! " + tries + " tries remaining.";
-                throw new ExceptionWithConfigData(errorMessage, (ConfigurationData)incomingConfig);
+                throw new ExceptionWithConfigData(errorMessage, configData);
             });
         }
 
@@ -153,6 +156,6 @@ namespace Jackett.Indexers
             return releases;
         }
 
-     
+
     }
 }
diff --git a/src/Jackett/Indexers/MoreThanTV.cs b/src/Jackett/Indexers/MoreThanTV.cs
index 8d4d74a8cbb6b009c12f92348dc54ca38b0ad881..ebfe674b5e20af98bde1d65a095e3f1245796c8b 100644
--- a/src/Jackett/Indexers/MoreThanTV.cs
+++ b/src/Jackett/Indexers/MoreThanTV.cs
@@ -14,6 +14,7 @@ using System.Net.Http;
 using System.Text;
 using System.Threading.Tasks;
 using System.Web;
+using Jackett.Models.IndexerConfig;
 
 namespace Jackett.Indexers
 {
@@ -24,32 +25,34 @@ namespace Jackett.Indexers
         private string DownloadUrl { get { return SiteLink + "torrents.php?action=download&id="; } }
         private string GuidUrl { get { return SiteLink + "torrents.php?torrentid="; } }
 
-        public MoreThanTV(IIndexerManagerService i, IWebClient c, Logger l)
+        new ConfigurationDataBasicLogin configData
+        {
+            get { return (ConfigurationDataBasicLogin)base.configData; }
+            set { base.configData = value; }
+        }
+
+        public MoreThanTV(IIndexerManagerService i, IWebClient c, Logger l, IProtectionService ps)
             : base(name: "MoreThanTV",
                 description: "ROMANIAN Private Torrent Tracker for TV / MOVIES, and the internal tracker for the release group DRACULA.",
                 link: "https://www.morethan.tv/",
                 caps: TorznabCapsUtil.CreateDefaultTorznabTVCaps(),
                 manager: i,
                 client: c,
-                logger: l)
-        {
-        }
-
-        public Task<ConfigurationData> GetConfigurationForSetup()
+                logger: l,
+                p: ps,
+                configData: new ConfigurationDataBasicLogin())
         {
-            return Task.FromResult<ConfigurationData>(new ConfigurationDataBasicLogin());
         }
 
         public async Task ApplyConfiguration(JToken configJson)
         {
-            var config = new ConfigurationDataBasicLogin();
-            config.LoadValuesFromJson(configJson);
+            configData.LoadValuesFromJson(configJson);
             var pairs = new Dictionary<string, string> {
-				{ "username", config.Username.Value },
-				{ "password", config.Password.Value },
-				{ "login", "Log in" },
-				{ "keeplogged", "1" }
-			};
+                { "username", configData.Username.Value },
+                { "password", configData.Password.Value },
+                { "login", "Log in" },
+                { "keeplogged", "1" }
+            };
 
             var result = await RequestLoginAndFollowRedirect(LoginUrl, pairs, null, true, SearchUrl, SiteLink);
             await ConfigureIfOK(result.Cookies, result.Content != null && result.Content.Contains("logout.php?"), () =>
@@ -57,7 +60,7 @@ namespace Jackett.Indexers
                 CQ dom = result.Content;
                 dom["#loginform > table"].Remove();
                 var errorMessage = dom["#loginform"].Text().Trim().Replace("\n\t", " ");
-                throw new ExceptionWithConfigData(errorMessage, (ConfigurationData)config);
+                throw new ExceptionWithConfigData(errorMessage, configData);
             });
         }
 
diff --git a/src/Jackett/Indexers/Pretome.cs b/src/Jackett/Indexers/Pretome.cs
index 2b45755612b18c0e9f9f4b3f08ce1252563dec95..6b84e3b28bf850f3c9cef4499b1187024ce458ec 100644
--- a/src/Jackett/Indexers/Pretome.cs
+++ b/src/Jackett/Indexers/Pretome.cs
@@ -21,34 +21,36 @@ namespace Jackett.Indexers
         private string LoginReferer { get { return SiteLink + "index.php?cat=1"; } }
         private string SearchUrl { get { return SiteLink + "browse.php?tags=&st=1&tf=all&cat%5B%5D=7&search={0}"; } }
 
-        public Pretome(IIndexerManagerService i, IWebClient wc, Logger l)
+        new ConfigurationDataPinNumber configData
+        {
+            get { return (ConfigurationDataPinNumber)base.configData; }
+            set { base.configData = value; }
+        }
+
+        public Pretome(IIndexerManagerService i, IWebClient wc, Logger l, IProtectionService ps)
             : base(name: "PreToMe",
                 description: "BitTorrent site for High Quality, High Definition (HD) movies and TV Shows",
                 link: "https://pretome.info/",
                 caps: TorznabCapsUtil.CreateDefaultTorznabTVCaps(),
                 client: wc,
                 manager: i,
-                logger: l)
+                logger: l,
+                p: ps,
+                configData: new ConfigurationDataPinNumber())
         {
         }
 
-        public Task<ConfigurationData> GetConfigurationForSetup()
-        {
-            return Task.FromResult<ConfigurationData>(new PretomeConfiguration());
-        }
-
         public async Task ApplyConfiguration(JToken configJson)
         {
-            var config = new PretomeConfiguration();
-            config.LoadValuesFromJson(configJson);
+            configData.LoadValuesFromJson(configJson);
 
             var loginPage = await RequestStringWithCookies(LoginUrl, string.Empty);
 
             var pairs = new Dictionary<string, string> {
                 { "returnto", "%2F" },
-                { "login_pin", config.Pin.Value },
-                { "username", config.Username.Value },
-                { "password", config.Password.Value },
+                { "login_pin", configData.Pin.Value },
+                { "username", configData.Username.Value },
+                { "password", configData.Password.Value },
                 { "login", "Login" }
             };
 
@@ -56,16 +58,16 @@ namespace Jackett.Indexers
             var result = await PostDataWithCookies(LoginUrl, pairs, loginPage.Cookies);
             if (result.RedirectingTo == null)
             {
-                throw new ExceptionWithConfigData("Login failed. Did you use the PIN number that pretome emailed you?", (ConfigurationData)config);
+                throw new ExceptionWithConfigData("Login failed. Did you use the PIN number that pretome emailed you?", configData);
             }
             var loginCookies = result.Cookies;
             // Get result from redirect
-            await FollowIfRedirect(result,LoginUrl,null, loginCookies);
+            await FollowIfRedirect(result, LoginUrl, null, loginCookies);
 
             await ConfigureIfOK(loginCookies, result.Content != null && result.Content.Contains("logout.php"), () =>
             {
-                cookieHeader = string.Empty;
-                throw new ExceptionWithConfigData("Failed", (ConfigurationData)config);
+                CookieHeader = string.Empty;
+                throw new ExceptionWithConfigData("Failed", configData);
             });
         }
 
@@ -98,7 +100,7 @@ namespace Jackett.Indexers
 
                     release.Comments = new Uri(SiteLink + qLink.Attr("href"));
                     release.Guid = release.Comments;
-                    
+
                     var qDownload = row.ChildElements.ElementAt(2).Cq().Find("a").First();
                     release.Link = new Uri(SiteLink + qDownload.Attr("href"));
 
diff --git a/src/Jackett/Indexers/PrivateHD.cs b/src/Jackett/Indexers/PrivateHD.cs
index 23a79a399fef63b45c924ea60de62be03d086c55..0b60f3333c2bd9ffd2e09375d40ab7cf72a9a83c 100644
--- a/src/Jackett/Indexers/PrivateHD.cs
+++ b/src/Jackett/Indexers/PrivateHD.cs
@@ -14,35 +14,49 @@ using System.Web;
 using Jackett.Services;
 using Jackett.Utils.Clients;
 using System.Text.RegularExpressions;
+using Jackett.Models.IndexerConfig;
 
 namespace Jackett.Indexers
 {
     public class PrivateHD : BaseIndexer, IIndexer
     {
         private string LoginUrl { get { return SiteLink + "auth/login"; } }
-        private string SearchUrl { get { return SiteLink + "torrents?in=1&type=2&search={0}"; } }
+        private string SearchUrl { get { return SiteLink + "torrents?in=1&type={0}&search={1}"; } }
 
-        public PrivateHD(IIndexerManagerService i, IWebClient wc, Logger l)
+        new ConfigurationDataBasicLogin configData
+        {
+            get { return (ConfigurationDataBasicLogin)base.configData; }
+            set { base.configData = value; }
+        }
+
+        public PrivateHD(IIndexerManagerService i, IWebClient wc, Logger l, IProtectionService ps)
             : base(name: "PrivateHD",
                 description: "BitTorrent site for High Quality, High Definition (HD) movies and TV Shows",
                 link: "https://privatehd.to/",
                 caps: TorznabCapsUtil.CreateDefaultTorznabTVCaps(),
                 manager: i,
                 client: wc,
-                logger: l)
+                logger: l,
+                p: ps,
+                configData: new ConfigurationDataBasicLogin())
         {
+            AddCategoryMapping(1, TorznabCatType.Movies);
+            AddCategoryMapping(1, TorznabCatType.MoviesForeign);
+            AddCategoryMapping(1, TorznabCatType.MoviesHD);
+            AddCategoryMapping(1, TorznabCatType.MoviesSD);
+            AddCategoryMapping(2, TorznabCatType.TV);
+            AddCategoryMapping(3, TorznabCatType.Audio);
         }
 
         public async Task ApplyConfiguration(JToken configJson)
         {
-            var incomingConfig = new ConfigurationDataBasicLogin();
-            incomingConfig.LoadValuesFromJson(configJson);
+            configData.LoadValuesFromJson(configJson);
             var loginPage = await RequestStringWithCookies(LoginUrl, string.Empty);
             var token = new Regex("Avz.CSRF_TOKEN = '(.*?)';").Match(loginPage.Content).Groups[1].ToString();
             var pairs = new Dictionary<string, string> {
                 { "_token", token },
-                { "username_email", incomingConfig.Username.Value },
-                { "password", incomingConfig.Password.Value },
+                { "username_email", configData.Username.Value },
+                { "password", configData.Password.Value },
                 { "remember", "on" }
             };
 
@@ -52,20 +66,24 @@ namespace Jackett.Indexers
                 CQ dom = result.Content;
                 var messageEl = dom[".form-error"];
                 var errorMessage = messageEl.Text().Trim();
-                throw new ExceptionWithConfigData(errorMessage, (ConfigurationData)incomingConfig);
+                throw new ExceptionWithConfigData(errorMessage, configData);
             });
         }
 
-        public Task<ConfigurationData> GetConfigurationForSetup()
-        {
-            return Task.FromResult<ConfigurationData>(new ConfigurationDataBasicLogin());
-        }
-
         public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query)
         {
             var releases = new List<ReleaseInfo>();
             var searchString = query.SanitizedSearchTerm + " " + query.GetEpisodeSearchString();
-            var episodeSearchUrl = string.Format(SearchUrl, HttpUtility.UrlEncode(searchString));
+
+            var categoryMapping = MapTorznabCapsToTrackers(query).Distinct();
+            string category = "0"; // Aka all
+            if (categoryMapping.Count() == 1)
+            {
+                category = categoryMapping.First();
+            }
+
+
+            var episodeSearchUrl = string.Format(SearchUrl, category, HttpUtility.UrlEncode(searchString));
 
             var response = await RequestStringWithCookiesAndRetry(episodeSearchUrl);
 
@@ -98,6 +116,11 @@ namespace Jackett.Indexers
                     release.Seeders = ParseUtil.CoerceInt(row.ChildElements.ElementAt(8).Cq().Text());
                     release.Peers = ParseUtil.CoerceInt(row.ChildElements.ElementAt(9).Cq().Text()) + release.Seeders;
 
+                    var cat = row.Cq().Find("td:eq(0) i").First().Attr("class")
+                                            .Replace("gi gi-film", "1")
+                                            .Replace("gi gi-tv", "2")
+                                            .Replace("gi gi-music", "3");
+                    release.Category = MapTrackerCatToNewznab(cat);
                     releases.Add(release);
                 }
             }
diff --git a/src/Jackett/Indexers/RUTor.cs b/src/Jackett/Indexers/RUTor.cs
new file mode 100644
index 0000000000000000000000000000000000000000..aaf194c731ef277252d4e90a0790d9f40de257ea
--- /dev/null
+++ b/src/Jackett/Indexers/RUTor.cs
@@ -0,0 +1,228 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Jackett.Models;
+using Newtonsoft.Json.Linq;
+using NLog;
+using Jackett.Utils;
+using System.Net;
+using System.Net.Http;
+using CsQuery;
+using System.Web;
+using Jackett.Services;
+using Jackett.Utils.Clients;
+using System.Text.RegularExpressions;
+using Jackett.Models.IndexerConfig;
+using System.Globalization;
+using Newtonsoft.Json;
+
+namespace Jackett.Indexers
+{
+    public class RuTor : BaseIndexer, IIndexer
+    {
+        private string SearchUrl { get { return SiteLink + "search/0/{0}/000/0/{1}"; } }
+        private string BrowseUrl { get { return SiteLink + "browse/0/{0}/0/0"; } }
+        readonly static string defaultSiteLink = "http://rutor.org/";
+
+        new ConfigurationDataRuTor configData
+        {
+            get { return (ConfigurationDataRuTor)base.configData; }
+            set { base.configData = value; }
+        }
+
+        public RuTor(IIndexerManagerService i, Logger l, IWebClient wc, IProtectionService ps)
+            : base(name: "RUTor",
+                description: "Свободный торрент трекер",
+                link: "http://rutor.org/",
+                caps: TorznabCapsUtil.CreateDefaultTorznabTVCaps(),
+                manager: i,
+                client: wc,
+                logger: l,
+                p: ps,
+                configData: new ConfigurationDataRuTor(defaultSiteLink))
+        {
+            TorznabCaps.Categories.Add(TorznabCatType.Anime);
+            TorznabCaps.Categories.Add(TorznabCatType.Movies);
+            TorznabCaps.Categories.Add(TorznabCatType.Audio);
+            TorznabCaps.Categories.Add(TorznabCatType.Books);
+        }
+
+        public async Task ApplyConfiguration(JToken configJson)
+        {
+            configData.LoadValuesFromJson(configJson);
+            var oldConfig = configData;
+            var releases = await PerformQuery(new TorznabQuery());
+
+            await ConfigureIfOK(string.Empty, releases.Count() > 0, () =>
+            {
+                 configData = oldConfig;
+                throw new Exception("Could not find releases from this URL");
+            });
+        }
+
+
+        protected override void SaveConfig()
+        {
+            indexerService.SaveConfig(this as IIndexer, JsonConvert.SerializeObject(configData));
+        }
+
+        // Override to load legacy config format
+        public override void LoadFromSavedConfiguration(JToken jsonConfig)
+        {
+            var json = jsonConfig.ToString();
+            configData = JsonConvert.DeserializeObject<ConfigurationDataRuTor>(json);
+            IsConfigured = true;
+        }
+
+        private readonly int CAT_ANY = 0;
+        private readonly int CAT_FOREIGN_MOVIE = 1;
+       // private readonly int CAT_OUR_MOVIES = 5;
+       // private readonly int CAT_POP_SCIFI_MOVIES = 12;
+        private readonly int CAT_TV_SERIES = 4;
+       // private readonly int CAT_TV = 6;
+       // private readonly int CAT_ANIMATION = 7;
+        private readonly int CAT_ANIME = 10;
+        private readonly int CAT_MUSIC = 2;
+       // private readonly int CAT_GAMES = 8;
+       // private readonly int CAT_SOFTWARE = 9;
+       // private readonly int CAT_SPORTS_HEALTH = 13;
+       // private readonly int CAT_HUMOR = 15;
+       // private readonly int CAT_ECONOMY_LIFE = 14;
+        private readonly int CAT_BOOKS = 11;
+       // private readonly int CAT_OTHER = 3;
+
+        public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query)
+        {
+            var releases = new List<ReleaseInfo>();
+            var searchString = query.SanitizedSearchTerm + " " + query.GetEpisodeSearchString();
+            var searchCategory = CAT_ANY;
+
+            if(query.Categories.Contains(TorznabCatType.TV.ID) ||
+                query.Categories.Contains(TorznabCatType.TVHD.ID)||
+                query.Categories.Contains(TorznabCatType.TVSD.ID)){
+                searchCategory = CAT_TV_SERIES;
+            }
+
+            if ((searchCategory == CAT_ANY) &&
+               (query.Categories.Contains(TorznabCatType.Movies.ID) ||
+               query.Categories.Contains(TorznabCatType.MoviesForeign.ID) ||
+               query.Categories.Contains(TorznabCatType.MoviesHD.ID) ||
+               query.Categories.Contains(TorznabCatType.MoviesSD.ID)))
+            {
+                searchCategory = CAT_FOREIGN_MOVIE;
+            }
+
+            if ((searchCategory == CAT_ANY) && 
+               (query.Categories.Contains(TorznabCatType.Anime.ID)))
+            {
+                searchCategory = CAT_ANIME;
+            }
+
+            if ((searchCategory == CAT_ANY) &&
+              (query.Categories.Contains(TorznabCatType.Books.ID)))
+            {
+                searchCategory = CAT_BOOKS;
+            }
+
+            if ((searchCategory == CAT_ANY) &&
+              (query.Categories.Contains(TorznabCatType.Audio.ID) ||
+              query.Categories.Contains(TorznabCatType.AudioLossless.ID) ||
+              query.Categories.Contains(TorznabCatType.AudioLossy.ID)))
+            {
+                searchCategory = CAT_MUSIC;
+            }
+
+            string queryUrl = string.Empty;
+            if (string.IsNullOrWhiteSpace(searchString))
+            {
+                queryUrl = string.Format(BrowseUrl, searchCategory);
+            } else
+            {
+                queryUrl = string.Format(SearchUrl, searchCategory, HttpUtility.UrlEncode(searchString.Trim()));
+            }
+
+            var results = await RequestStringWithCookiesAndRetry(queryUrl, string.Empty);
+            try
+            {
+                CQ dom = results.Content;
+                var rows = dom["#index table tr"];
+                foreach (var row in rows.Skip(1))
+                {
+                    var release = new ReleaseInfo();
+
+                    release.MinimumRatio = 1;
+                    release.MinimumSeedTime = 172800;
+
+                    var date = StringUtil.StripNonAlphaNumeric(row.Cq().Find("td:eq(0)").Text().Trim()
+                        .Replace("Янв", "01")
+                        .Replace("Фев", "02")
+                        .Replace("Мар", "03")
+                        .Replace("Апр", "04")
+                        .Replace("Май", "05")
+                        .Replace("Июн", "06")
+                        .Replace("Июл", "07")
+                        .Replace("Авг", "08")
+                        .Replace("Сен", "09")
+                        .Replace("Окт", "10")
+                        .Replace("Ноя", "11")
+                        .Replace("Дек", "12"));
+
+                    release.PublishDate = DateTime.ParseExact(date, "ddMMyy", CultureInfo.InvariantCulture);
+
+                    var hasTorrent = row.Cq().Find("td:eq(1) a").Length == 3;
+                    var titleIndex = 1;
+                    if (hasTorrent)
+                        titleIndex++;
+
+                    release.Title = row.Cq().Find("td:eq("+ titleIndex+")").Text().Trim();
+                    if (configData.StripRussian.Value)
+                    {
+                        var split = release.Title.IndexOf('/');
+                        if (split > -1)
+                        {
+                            release.Title = release.Title.Substring(split + 1).Trim();
+                        }
+                    }
+
+                    release.Description = release.Title;
+
+                    var hasComments = row.Cq().Find("td:eq(2) img").Length > 0;
+                    var sizeCol = 2;
+
+                    if (hasComments)
+                        sizeCol++;
+
+                    var sizeStr = StringUtil.StripRegex(row.Cq().Find("td:eq("+ sizeCol + ")").Text(), "[^a-zA-Z0-9\\. -]", " ").Trim();
+                    string[] sizeSplit = sizeStr.Split(' ');
+                    release.Size = ReleaseInfo.GetBytes(sizeSplit[1].ToLower(), ParseUtil.CoerceFloat(sizeSplit[0]));
+
+                    release.Seeders = ParseUtil.CoerceInt(row.Cq().Find(".green").Text().Trim());
+                    release.Peers = ParseUtil.CoerceInt(row.Cq().Find(".red").Text().Trim()) + release.Seeders;
+                
+                    release.Guid = new Uri(configData.Url.Value + row.Cq().Find("td:eq(1) a:eq("+ titleIndex+")").Attr("href").Substring(1));
+                    release.Comments = release.Guid;
+
+                    if (hasTorrent)
+                    {
+                        release.Link = new Uri(row.Cq().Find("td:eq(1) a:eq(0)").Attr("href"));
+                        release.MagnetUri = new Uri(row.Cq().Find("td:eq(1) a:eq(1)").Attr("href"));
+                    }
+                    else
+                    {
+                        release.MagnetUri = new Uri(row.Cq().Find("td:eq(1) a:eq(0)").Attr("href"));
+                    }
+                   
+                    releases.Add(release);
+                }
+            }
+            catch (Exception ex)
+            {
+                OnParseError(results.Content, ex);
+            }
+
+            return releases;
+        }
+    }
+}
diff --git a/src/Jackett/Indexers/SceneAccess.cs b/src/Jackett/Indexers/SceneAccess.cs
index 6add4bd218dd6bf9ea83c22b527c09ffa34d81df..624dbc10a9e85716332bc86befc4be5b07062358 100644
--- a/src/Jackett/Indexers/SceneAccess.cs
+++ b/src/Jackett/Indexers/SceneAccess.cs
@@ -12,6 +12,7 @@ using System.Net;
 using System.Net.Http;
 using System.Text;
 using System.Threading.Tasks;
+using Jackett.Models.IndexerConfig;
 
 namespace Jackett.Indexers
 {
@@ -20,30 +21,32 @@ namespace Jackett.Indexers
         private string LoginUrl { get { return SiteLink + "login"; } }
         private string SearchUrl { get { return SiteLink + "{0}?method=1&c{1}=1&search={2}"; } }
 
-        public SceneAccess(IIndexerManagerService i, IWebClient c, Logger l)
+        new ConfigurationDataBasicLogin configData
+        {
+            get { return (ConfigurationDataBasicLogin)base.configData; }
+            set { base.configData = value; }
+        }
+
+        public SceneAccess(IIndexerManagerService i, IWebClient c, Logger l, IProtectionService ps)
             : base(name: "SceneAccess",
                 description: "Your gateway to the scene",
                 link: "https://sceneaccess.eu/",
                 caps: TorznabCapsUtil.CreateDefaultTorznabTVCaps(),
                 manager: i,
                 client: c,
-                logger: l)
-        {
-        }
-
-        public Task<ConfigurationData> GetConfigurationForSetup()
+                logger: l,
+                p: ps,
+                configData: new ConfigurationDataBasicLogin())
         {
-            return Task.FromResult<ConfigurationData>(new ConfigurationDataBasicLogin());
         }
 
         public async Task ApplyConfiguration(JToken configJson)
         {
-            var config = new ConfigurationDataBasicLogin();
-            config.LoadValuesFromJson(configJson);
+            configData.LoadValuesFromJson(configJson);
 
             var pairs = new Dictionary<string, string> {
-                { "username", config.Username.Value },
-                { "password", config.Password.Value },
+                { "username", configData.Username.Value },
+                { "password", configData.Password.Value },
                 { "submit", "come on in" }
             };
 
@@ -55,7 +58,7 @@ namespace Jackett.Indexers
                 CQ dom = result.Content;
                 var messageEl = dom["#login_box_desc"];
                 var errorMessage = messageEl.Text().Trim();
-                throw new ExceptionWithConfigData(errorMessage, (ConfigurationData)config);
+                throw new ExceptionWithConfigData(errorMessage, configData);
             });
         }
 
diff --git a/src/Jackett/Indexers/SceneTime.cs b/src/Jackett/Indexers/SceneTime.cs
index 0144dfc3a960eedf10a93ec132d2de5a4fc37d1f..bb3a67115fe15b7475993c822db80794cdff6be3 100644
--- a/src/Jackett/Indexers/SceneTime.cs
+++ b/src/Jackett/Indexers/SceneTime.cs
@@ -14,6 +14,7 @@ using System.Net.Http;
 using System.Text;
 using System.Threading.Tasks;
 using System.Web;
+using Jackett.Models.IndexerConfig;
 
 namespace Jackett.Indexers
 {
@@ -23,47 +24,49 @@ namespace Jackett.Indexers
         private string SearchUrl { get { return SiteLink + "browse_API.php"; } }
         private string DownloadUrl { get { return SiteLink + "download.php/{0}/download.torrent"; } }
 
-        public SceneTime(IIndexerManagerService i, Logger l, IWebClient w)
+        new ConfigurationDataBasicLogin configData
+        {
+            get { return (ConfigurationDataBasicLogin)base.configData; }
+            set { base.configData = value; }
+        }
+
+        public SceneTime(IIndexerManagerService i, Logger l, IWebClient w, IProtectionService ps)
             : base(name: "SceneTime",
                 description: "Always on time",
                 link: "https://www.scenetime.com/",
                 caps: TorznabCapsUtil.CreateDefaultTorznabTVCaps(),
                 manager: i,
                 client: w,
-                logger: l)
-        {
-        }
-
-        public Task<ConfigurationData> GetConfigurationForSetup()
+                logger: l,
+                p: ps,
+                configData: new ConfigurationDataBasicLogin())
         {
-            return Task.FromResult<ConfigurationData>(new ConfigurationDataBasicLogin());
         }
 
         public async Task ApplyConfiguration(JToken configJson)
         {
-            var incomingConfig = new ConfigurationDataBasicLogin();
-            incomingConfig.LoadValuesFromJson(configJson);
+            configData.LoadValuesFromJson(configJson);
             var pairs = new Dictionary<string, string> {
-				{ "username", incomingConfig.Username.Value },
-				{ "password", incomingConfig.Password.Value }
-			};
+                { "username", configData.Username.Value },
+                { "password", configData.Password.Value }
+            };
 
             var result = await RequestLoginAndFollowRedirect(LoginUrl, pairs, null, true, null, LoginUrl);
             await ConfigureIfOK(result.Cookies, result.Content != null && result.Content.Contains("logout.php"), () =>
             {
                 CQ dom = result.Content;
                 var errorMessage = dom["td.text"].Text().Trim();
-                throw new ExceptionWithConfigData(errorMessage, (ConfigurationData)incomingConfig);
+                throw new ExceptionWithConfigData(errorMessage, configData);
             });
         }
 
         private Dictionary<string, string> GetSearchFormData(string searchString)
         {
             return new Dictionary<string, string> {
-				{ "c2", "1" }, { "c43", "1" }, { "c9", "1" }, { "c63", "1" }, { "c77", "1" }, { "c100", "1" }, { "c101", "1" },
+                { "c2", "1" }, { "c43", "1" }, { "c9", "1" }, { "c63", "1" }, { "c77", "1" }, { "c100", "1" }, { "c101", "1" },
                 { "cata", "yes" }, { "sec", "jax" },
                 { "search", searchString}
-			};
+            };
         }
 
         public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query)
diff --git a/src/Jackett/Indexers/ShowRSS.cs b/src/Jackett/Indexers/ShowRSS.cs
index c6fffcf7cc1ff8baec4c628820d744a386abe30c..3e87ed81cefb6d7d510df066864cf4f170e4a7f1 100644
--- a/src/Jackett/Indexers/ShowRSS.cs
+++ b/src/Jackett/Indexers/ShowRSS.cs
@@ -14,57 +14,64 @@ using System.Text;
 using System.Threading.Tasks;
 using System.Web;
 using System.Xml;
+using Jackett.Models.IndexerConfig;
 
 namespace Jackett.Indexers
 {
     public class ShowRSS : BaseIndexer, IIndexer
     {
-        private string searchAllUrl { get { return SiteLink + "feeds/all.rss"; } }
-        private string BaseUrl;
+        readonly static string defaultSiteLink = "http://showrss.info/";
 
-        public ShowRSS(IIndexerManagerService i, Logger l, IWebClient wc)
+        private Uri BaseUri
+        {
+            get { return new Uri(configData.Url.Value); }
+            set { configData.Url.Value = value.ToString(); }
+        }
+
+        private string SearchAllUrl { get { return BaseUri + "feeds/all.rss"; } }
+
+        new ConfigurationDataUrl configData
+        {
+            get { return (ConfigurationDataUrl)base.configData; }
+            set { base.configData = value; }
+        }
+
+        public ShowRSS(IIndexerManagerService i, Logger l, IWebClient wc, IProtectionService ps)
             : base(name: "ShowRSS",
                 description: "showRSS is a service that allows you to keep track of your favorite TV shows",
-                link: "http://showrss.info/",
+                link: defaultSiteLink,
                 caps: TorznabCapsUtil.CreateDefaultTorznabTVCaps(),
                 manager: i,
                 client: wc,
-                logger: l)
-        {
-        }
-
-        public Task<ConfigurationData> GetConfigurationForSetup()
+                logger: l,
+                p: ps,
+                configData: new ConfigurationDataUrl(defaultSiteLink))
         {
-            return Task.FromResult<ConfigurationData>(new ConfigurationDataUrl(SiteLink));
         }
 
-        public async Task ApplyConfiguration(Newtonsoft.Json.Linq.JToken configJson)
+        public async Task ApplyConfiguration(JToken configJson)
         {
-            var config = new ConfigurationDataUrl(SiteLink);
-            config.LoadValuesFromJson(configJson);
+            configData.LoadValuesFromJson(configJson);
+            var releases = await PerformQuery(new TorznabQuery());
 
-            var formattedUrl = config.GetFormattedHostUrl();
-            var releases = await PerformQuery(new TorznabQuery(), formattedUrl);
-            if (releases.Count() == 0)
+            await ConfigureIfOK(string.Empty, releases.Count() > 0, () =>
+            {
                 throw new Exception("Could not find releases from this URL");
-
-            BaseUrl = formattedUrl;
-
-            var configSaveData = new JObject();
-            configSaveData["base_url"] = BaseUrl;
-            SaveConfig(configSaveData);
-            IsConfigured = true;
+            });
         }
 
-        public override void LoadFromSavedConfiguration(Newtonsoft.Json.Linq.JToken jsonConfig)
+        // Override to load legacy config format
+        public override void LoadFromSavedConfiguration(JToken jsonConfig)
         {
-            BaseUrl = (string)jsonConfig["base_url"];
-            IsConfigured = true;
-        }
+            if (jsonConfig is JObject)
+            {
+                BaseUri = new Uri(jsonConfig.Value<string>("base_url"));
+                SaveConfig();
+                IsConfigured = true;
+                return;
+            }
 
-        public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query)
-        {
-            return await PerformQuery(query, BaseUrl);
+            base.LoadFromSavedConfiguration(jsonConfig);
         }
 
         public override Task<byte[]> Download(Uri link)
@@ -72,11 +79,11 @@ namespace Jackett.Indexers
             throw new NotImplementedException();
         }
 
-        async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query, string baseUrl)
+        public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query)
         {
             var releases = new List<ReleaseInfo>();
             var searchString = query.SanitizedSearchTerm + " " + query.GetEpisodeSearchString();
-            var episodeSearchUrl = string.Format(searchAllUrl);
+            var episodeSearchUrl = string.Format(SearchAllUrl);
             var result = await RequestStringWithCookiesAndRetry(episodeSearchUrl, string.Empty);
             var xmlDoc = new XmlDocument();
 
diff --git a/src/Jackett/Indexers/SpeedCD.cs b/src/Jackett/Indexers/SpeedCD.cs
index bc4009333c15ecbf489af3a53ca51f44b81c66b5..0e9ee5333b6d38e0a74b5872e9fc650a98529fbc 100644
--- a/src/Jackett/Indexers/SpeedCD.cs
+++ b/src/Jackett/Indexers/SpeedCD.cs
@@ -15,6 +15,7 @@ using System.Text;
 using System.Text.RegularExpressions;
 using System.Threading.Tasks;
 using System.Web;
+using Jackett.Models.IndexerConfig;
 
 namespace Jackett.Indexers
 {
@@ -25,38 +26,40 @@ namespace Jackett.Indexers
         private string SearchFormData { get { return "c53=1&c49=1&c2=1&c52=1&c41=1&c50=1&c30=1&jxt=4&jxw=b"; } }
         private string CommentsUrl { get { return SiteLink + "t/{0}"; } }
         private string DownloadUrl { get { return SiteLink + "download.php?torrent={0}"; } }
-       
-        public SpeedCD(IIndexerManagerService i, Logger l, IWebClient wc)
+
+        new ConfigurationDataBasicLogin configData
+        {
+            get { return (ConfigurationDataBasicLogin)base.configData; }
+            set { base.configData = value; }
+        }
+
+        public SpeedCD(IIndexerManagerService i, Logger l, IWebClient wc, IProtectionService ps)
             : base(name: "Speed.cd",
                 description: "Your home now!",
                 link: "http://speed.cd/",
                 caps: TorznabCapsUtil.CreateDefaultTorznabTVCaps(),
                 manager: i,
                 client: wc,
-                logger: l)
-        {
-        }
-
-        public Task<ConfigurationData> GetConfigurationForSetup()
+                logger: l,
+                p: ps,
+                configData: new ConfigurationDataBasicLogin())
         {
-            return Task.FromResult<ConfigurationData>(new ConfigurationDataBasicLogin());
         }
 
         public async Task ApplyConfiguration(JToken configJson)
         {
-            var incomingConfig = new ConfigurationDataBasicLogin();
-            incomingConfig.LoadValuesFromJson(configJson);
+            configData.LoadValuesFromJson(configJson);
             var pairs = new Dictionary<string, string> {
-				{ "username", incomingConfig.Username.Value },
-				{ "password", incomingConfig.Password.Value },
-			};
+                { "username", configData.Username.Value },
+                { "password", configData.Password.Value },
+            };
 
             var result = await RequestLoginAndFollowRedirect(LoginUrl, pairs, null, true, null, SiteLink);
             await ConfigureIfOK(result.Cookies, result.Content != null && result.Content.Contains("logout.php"), () =>
             {
                 CQ dom = result.Content;
                 var errorMessage = dom["h5"].First().Text().Trim();
-                throw new ExceptionWithConfigData(errorMessage, (ConfigurationData)incomingConfig);
+                throw new ExceptionWithConfigData(errorMessage, configData);
             });
         }
 
diff --git a/src/Jackett/Indexers/Strike.cs b/src/Jackett/Indexers/Strike.cs
index 997b55eacfd9cef34cecdefb88c05005638aab4a..508727aa2e43fc6a6a0028d0500976dbf0bd4d2b 100644
--- a/src/Jackett/Indexers/Strike.cs
+++ b/src/Jackett/Indexers/Strike.cs
@@ -13,48 +13,66 @@ using System.Net.Http;
 using System.Text;
 using System.Threading.Tasks;
 using System.Web;
+using Jackett.Models.IndexerConfig;
 
 namespace Jackett.Indexers
 {
     public class Strike : BaseIndexer, IIndexer
     {
-        private string DownloadUrl { get { return baseUri + "torrents/api/download/{0}.torrent"; } }
-        private string SearchUrl { get { return baseUri + "api/v2/torrents/search/?category=TV&phrase={0}"; } }
-        private string baseUrl = null;
-        private Uri baseUri { get { return new Uri(baseUrl); } }
+        readonly static string defaultSiteLink = "https://getstrike.net/";
 
-        public Strike(IIndexerManagerService i, Logger l, IWebClient wc)
+        private Uri BaseUri
+        {
+            get { return new Uri(configData.Url.Value); }
+            set { configData.Url.Value = value.ToString(); }
+        }
+
+        private string SearchUrl { get { return BaseUri + "api/v2/torrents/search/?category=TV&phrase={0}"; } }
+        private string DownloadUrl { get { return BaseUri + "torrents/api/download/{0}.torrent"; } }
+
+        new ConfigurationDataUrl configData
+        {
+            get { return (ConfigurationDataUrl)base.configData; }
+            set { base.configData = value; }
+        }
+
+
+        public Strike(IIndexerManagerService i, Logger l, IWebClient wc, IProtectionService ps)
             : base(name: "Strike",
                 description: "Torrent search engine",
-                link: "https://getstrike.net/",
+                link: defaultSiteLink,
                 caps: TorznabCapsUtil.CreateDefaultTorznabTVCaps(),
                 manager: i,
                 client: wc,
-                logger: l)
+                logger: l,
+                p: ps,
+                configData: new ConfigurationDataUrl(defaultSiteLink))
         {
         }
 
-        public Task<ConfigurationData> GetConfigurationForSetup()
+        public async Task ApplyConfiguration(JToken configJson)
         {
-            return Task.FromResult<ConfigurationData>(new ConfigurationDataUrl(SiteLink));
-        }
+            configData.LoadValuesFromJson(configJson);
+            var releases = await PerformQuery(new TorznabQuery());
 
-        public Task ApplyConfiguration(JToken configJson)
-        {
-            var config = new ConfigurationDataUrl(SiteLink);
-            config.LoadValuesFromJson(configJson);
-            baseUrl = config.GetFormattedHostUrl();
-            var configSaveData = new JObject();
-            configSaveData["base_url"] = baseUrl;
-            SaveConfig(configSaveData);
-            IsConfigured = true;
-            return Task.FromResult(0);
+            await ConfigureIfOK(string.Empty, releases.Count() > 0, () =>
+            {
+                throw new Exception("Could not find releases from this URL");
+            });
         }
 
+        // Override to load legacy config format
         public override void LoadFromSavedConfiguration(JToken jsonConfig)
         {
-            baseUrl = (string)jsonConfig["base_url"];
-            IsConfigured = !string.IsNullOrEmpty(baseUrl);
+            if (jsonConfig is JObject)
+            {
+                BaseUri = new Uri(jsonConfig.Value<string>("base_url"));
+                SaveConfig();
+                IsConfigured = true;
+                return;
+            }
+
+            base.LoadFromSavedConfiguration(jsonConfig);
         }
 
         public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query)
diff --git a/src/Jackett/Indexers/T411.cs b/src/Jackett/Indexers/T411.cs
index 17b2a6d673528f3ca0c321ab611ce3d45ee5c329..bd9caabb7df2f4e269f93528c7f0683d1532202b 100644
--- a/src/Jackett/Indexers/T411.cs
+++ b/src/Jackett/Indexers/T411.cs
@@ -14,6 +14,7 @@ using System.Net.Http.Headers;
 using System.Text;
 using System.Threading.Tasks;
 using System.Web;
+using Jackett.Models.IndexerConfig;
 
 namespace Jackett.Indexers
 {
@@ -28,19 +29,22 @@ namespace Jackett.Indexers
         HttpClientHandler handler;
         HttpClient client;
 
-        string username = string.Empty;
-        string password = string.Empty;
-        string token = string.Empty;
-        DateTime lastTokenFetch = DateTime.MinValue;
+        new ConfigurationDataLoginTokin configData
+        {
+            get { return (ConfigurationDataLoginTokin)base.configData; }
+            set { base.configData = value; }
+        }
 
-        public T411(IIndexerManagerService i, Logger l,IWebClient wc)
+        public T411(IIndexerManagerService i, Logger l, IWebClient wc, IProtectionService ps)
             : base(name: "T411",
                 description: "French Torrent Tracker",
                 link: "http://www.t411.io/",
                 caps: TorznabCapsUtil.CreateDefaultTorznabTVCaps(),
                 manager: i,
                 client: wc,
-                logger: l)
+                logger: l,
+                p: ps,
+                configData: new ConfigurationDataLoginTokin())
         {
             CommentsUrl = SiteLink + "/torrents/{0}";
             IsConfigured = false;
@@ -51,23 +55,17 @@ namespace Jackett.Indexers
             client = new HttpClient(handler);
         }
 
-        public Task<ConfigurationData> GetConfigurationForSetup()
-        {
-            var config = new ConfigurationDataBasicLogin();
-            return Task.FromResult<ConfigurationData>(config);
-        }
-
         async Task<string> GetAuthToken(bool forceFetch = false)
         {
-            if (!forceFetch && lastTokenFetch > DateTime.Now - TimeSpan.FromHours(48))
+            if (!forceFetch && configData.LastTokenFetchDateTime > DateTime.Now - TimeSpan.FromHours(48))
             {
-                return token;
+                return configData.ApiToken.Value;
             }
 
             var pairs = new Dictionary<string, string> {
-				{ "username", username },
-				{ "password", password }
-			};
+                { "username", configData.Username.Value },
+                { "password", configData.Password.Value }
+            };
 
             var content = new FormUrlEncodedContent(pairs);
 
@@ -78,44 +76,45 @@ namespace Jackett.Indexers
             {
                 throw new ApplicationException((string)jsonResponse["error"]);
             }
-            token = (string)jsonResponse["token"];
-            lastTokenFetch = DateTime.Now;
-            return token;
+            configData.ApiToken.Value = (string)jsonResponse["token"];
+            configData.LastTokenFetchDateTime = DateTime.Now;
+            return configData.ApiToken.Value;
         }
 
         public async Task ApplyConfiguration(JToken configJson)
         {
-            var config = new ConfigurationDataBasicLogin();
-            config.LoadValuesFromJson(configJson);
-
-            username = config.Username.Value;
-            password = config.Password.Value;
+            configData.LoadValuesFromJson(configJson);
 
+            Exception tokenFetchEx = null;
             try
             {
                 await GetAuthToken(true);
             }
             catch (Exception ex)
             {
-                throw new ExceptionWithConfigData(ex.Message, (ConfigurationData)config);
+                tokenFetchEx = new ExceptionWithConfigData(ex.Message, configData);
             }
 
-            var configSaveData = new JObject();
-            configSaveData["username"] = username;
-            configSaveData["password"] = password;
-            configSaveData["token"] = token;
-            configSaveData["last_token_fetch"] = lastTokenFetch;
-            SaveConfig(configSaveData);
-            IsConfigured = true;
+            await ConfigureIfOK(string.Empty, tokenFetchEx == null, () =>
+            {
+                throw tokenFetchEx;
+            });
         }
 
+        // Override to load legacy config format
         public override void LoadFromSavedConfiguration(JToken jsonConfig)
         {
-            username = (string)jsonConfig["username"];
-            password = (string)jsonConfig["password"];
-            token = (string)jsonConfig["token"];
-            lastTokenFetch = (DateTime)jsonConfig["last_token_fetch"];
-            IsConfigured = true;
+            if (jsonConfig is JObject)
+            {
+                configData.ApiToken.Value = jsonConfig.Value<string>("token"); ;
+                configData.Username.Value = jsonConfig.Value<string>("username");
+                configData.Password.Value = jsonConfig.Value<string>("password");
+                SaveConfig();
+                IsConfigured = true;
+                return;
+            }
+
+            base.LoadFromSavedConfiguration(jsonConfig);
         }
 
         public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query)
diff --git a/src/Jackett/Indexers/ThePirateBay.cs b/src/Jackett/Indexers/ThePirateBay.cs
index f37a91f10284a4b7e27aa6b508f60d66c7328b1c..86f6bc3c9389452f2e062419ee27997d8b646870 100644
--- a/src/Jackett/Indexers/ThePirateBay.cs
+++ b/src/Jackett/Indexers/ThePirateBay.cs
@@ -15,67 +15,72 @@ using System.Text;
 using System.Text.RegularExpressions;
 using System.Threading.Tasks;
 using System.Web;
+using Jackett.Models.IndexerConfig;
 
 namespace Jackett.Indexers
 {
     public class ThePirateBay : BaseIndexer, IIndexer
     {
-        private const string SearchUrl = "/search/{0}/0/99/208,205";
-        private string BaseUrl;
+        readonly static string defaultSiteLink = "https://thepiratebay.mn/";
 
-        public ThePirateBay(IIndexerManagerService i, Logger l, IWebClient wc)
+        private Uri BaseUri
+        {
+            get { return new Uri(configData.Url.Value); }
+            set { configData.Url.Value = value.ToString(); }
+        }
+
+        private string SearchUrl { get { return BaseUri + "search/{0}/0/99/208,205"; } }
+
+        new ConfigurationDataUrl configData
+        {
+            get { return (ConfigurationDataUrl)base.configData; }
+            set { base.configData = value; }
+        }
+
+        public ThePirateBay(IIndexerManagerService i, Logger l, IWebClient wc, IProtectionService ps)
             : base(name: "The Pirate Bay",
                 description: "The worlds largest bittorrent indexer",
-                link: "https://thepiratebay.mn/",
+                link: defaultSiteLink,
                 caps: TorznabCapsUtil.CreateDefaultTorznabTVCaps(),
                 manager: i,
                 client: wc,
-                logger: l)
-        {
-            BaseUrl = SiteLink.ToString();
-            IsConfigured = false;
-        }
-
-        public Task<ConfigurationData> GetConfigurationForSetup()
+                logger: l,
+                p: ps,
+                configData: new ConfigurationDataUrl(defaultSiteLink))
         {
-            return Task.FromResult<ConfigurationData>(new ConfigurationDataUrl(BaseUrl));
         }
 
         public async Task ApplyConfiguration(JToken configJson)
         {
-            var config = new ConfigurationDataUrl(SiteLink);
-            config.LoadValuesFromJson(configJson);
+            configData.LoadValuesFromJson(configJson);
+            var releases = await PerformQuery(new TorznabQuery());
 
-            var formattedUrl = config.GetFormattedHostUrl();
-            var releases = await PerformQuery(new TorznabQuery(), formattedUrl);
-            if (releases.Count() == 0)
+            await ConfigureIfOK(string.Empty, releases.Count() > 0, () =>
+            {
                 throw new Exception("Could not find releases from this URL");
-
-            BaseUrl = formattedUrl;
-
-            var configSaveData = new JObject();
-            configSaveData["base_url"] = BaseUrl;
-            SaveConfig(configSaveData);
-            IsConfigured = true;
+            });
         }
 
+        // Override to load legacy config format
         public override void LoadFromSavedConfiguration(JToken jsonConfig)
         {
-            BaseUrl = (string)jsonConfig["base_url"];
-            IsConfigured = true;
-        }
+            if (jsonConfig is JObject)
+            {
+                BaseUri = new Uri(jsonConfig.Value<string>("base_url"));
+                SaveConfig();
+                IsConfigured = true;
+                return;
+            }
 
-        public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query)
-        {
-            return await PerformQuery(query, BaseUrl);
+            base.LoadFromSavedConfiguration(jsonConfig);
         }
 
-        async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query, string baseUrl)
+        public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query)
         {
             var releases = new List<ReleaseInfo>();
             var searchString = query.SanitizedSearchTerm + " " + query.GetEpisodeSearchString();
             var queryStr = HttpUtility.UrlEncode(searchString);
-            var episodeSearchUrl = baseUrl + string.Format(SearchUrl, queryStr);
+            var episodeSearchUrl = string.Format(SearchUrl, queryStr);
             var response = await RequestStringWithCookiesAndRetry(episodeSearchUrl, string.Empty);
 
             try
@@ -94,7 +99,7 @@ namespace Jackett.Indexers
                     release.MinimumSeedTime = 172800;
                     release.Title = qLink.Text().Trim();
                     release.Description = release.Title;
-                    release.Comments = new Uri(baseUrl + "/" + qLink.Attr("href").TrimStart('/'));
+                    release.Comments = new Uri(BaseUri + qLink.Attr("href").TrimStart('/'));
                     release.Guid = release.Comments;
 
                     var downloadCol = row.ChildElements.ElementAt(1).Cq().Children("a");
diff --git a/src/Jackett/Indexers/TorrentBytes.cs b/src/Jackett/Indexers/TorrentBytes.cs
index 03304012735f297459a62439299a8dc925019058..fbaad6a8bc29b84a8377368d385fb9c290c593a8 100644
--- a/src/Jackett/Indexers/TorrentBytes.cs
+++ b/src/Jackett/Indexers/TorrentBytes.cs
@@ -15,6 +15,7 @@ using System.Net.Http;
 using System.Text;
 using System.Threading.Tasks;
 using System.Web;
+using Jackett.Models.IndexerConfig;
 
 namespace Jackett.Indexers
 {
@@ -23,16 +24,24 @@ namespace Jackett.Indexers
         private string BrowseUrl { get { return SiteLink + "browse.php"; } }
         private string LoginUrl { get { return SiteLink + "takelogin.php"; } }
 
-        public TorrentBytes(IIndexerManagerService i, IWebClient wc, Logger l)
+        new ConfigurationDataBasicLogin configData
+        {
+            get { return (ConfigurationDataBasicLogin)base.configData; }
+            set { base.configData = value; }
+        }
+
+        public TorrentBytes(IIndexerManagerService i, IWebClient wc, Logger l, IProtectionService ps)
             : base(name: "TorrentBytes",
                 description: "A decade of torrentbytes",
                 link: "https://www.torrentbytes.net/",
                 caps: TorznabCapsUtil.CreateDefaultTorznabTVCaps(),
                 manager: i,
                 client: wc,
-                logger: l)
+                logger: l,
+                p: ps,
+                configData: new ConfigurationDataBasicLogin())
         {
-           
+
             AddCategoryMapping(41, TorznabCatType.TV);
             AddCategoryMapping(33, TorznabCatType.TVSD);
             AddCategoryMapping(38, TorznabCatType.TVHD);
@@ -62,18 +71,12 @@ namespace Jackett.Indexers
             AddCategoryMapping(24, TorznabCatType.XXXImg);
         }
 
-        public Task<ConfigurationData> GetConfigurationForSetup()
-        {
-            return Task.FromResult<ConfigurationData>(new ConfigurationDataBasicLogin());
-        }
-
         public async Task ApplyConfiguration(JToken configJson)
         {
-            var incomingConfig = new ConfigurationDataBasicLogin();
-            incomingConfig.LoadValuesFromJson(configJson);
+            configData.LoadValuesFromJson(configJson);
             var pairs = new Dictionary<string, string> {
-                { "username", incomingConfig.Username.Value },
-                { "password", incomingConfig.Password.Value },
+                { "username", configData.Username.Value },
+                { "password", configData.Password.Value },
                 { "returnto", "/" },
                 { "login", "Log in!" }
             };
@@ -86,7 +89,7 @@ namespace Jackett.Indexers
                 CQ dom = result.Content;
                 var messageEl = dom["body > div"].First();
                 var errorMessage = messageEl.Text().Trim();
-                throw new ExceptionWithConfigData(errorMessage, (ConfigurationData)incomingConfig);
+                throw new ExceptionWithConfigData(errorMessage, configData);
             });
         }
 
@@ -118,7 +121,7 @@ namespace Jackett.Indexers
             searchUrl += "?" + queryCollection.GetQueryString();
 
             // 15 results per page - really don't want to call the server twice but only 15 results per page is a bit crap!
-            await ProcessPage(releases, searchUrl);  
+            await ProcessPage(releases, searchUrl);
             await ProcessPage(releases, searchUrl + "&page=1");
             return releases;
         }
diff --git a/src/Jackett/Indexers/TorrentDay.cs b/src/Jackett/Indexers/TorrentDay.cs
index cbb9daefadc23830c8b2c4618db4b4a2eb2174c5..a25dde2ece30a6aec9bd0fc953b97dd791a6768a 100644
--- a/src/Jackett/Indexers/TorrentDay.cs
+++ b/src/Jackett/Indexers/TorrentDay.cs
@@ -14,6 +14,8 @@ using System.Net.Http;
 using System.Text;
 using System.Threading.Tasks;
 using System.Web;
+using Jackett.Models.IndexerConfig;
+using System.Collections.Specialized;
 
 namespace Jackett.Indexers
 {
@@ -21,45 +23,122 @@ namespace Jackett.Indexers
     {
         private string StartPageUrl { get { return SiteLink + "login.php"; } }
         private string LoginUrl { get { return SiteLink + "tak3login.php"; } }
-        private string SearchUrl { get { return SiteLink + "browse.php?search={0}&cata=yes&c2=1&c7=1&c14=1&c24=1&c26=1&c31=1&c32=1&c33=1"; } }
+        private string SearchUrl { get { return SiteLink + "browse.php"; } }
 
-        public TorrentDay(IIndexerManagerService i, Logger l, IWebClient wc)
+        new ConfigurationDataRecaptchaLogin configData
+        {
+            get { return (ConfigurationDataRecaptchaLogin)base.configData; }
+            set { base.configData = value; }
+        }
+
+        public TorrentDay(IIndexerManagerService i, Logger l, IWebClient wc, IProtectionService ps)
             : base(name: "TorrentDay",
                 description: "TorrentDay",
                 link: "https://torrentday.eu/",
                 caps: TorznabCapsUtil.CreateDefaultTorznabTVCaps(),
                 manager: i,
                 client: wc,
-                logger: l)
+                logger: l,
+                p: ps,
+                configData: new ConfigurationDataRecaptchaLogin())
         {
+
+            AddCategoryMapping(29, TorznabCatType.Anime);
+            AddCategoryMapping(28, TorznabCatType.Apps);
+            AddCategoryMapping(28, TorznabCatType.AudioBooks);
+            AddCategoryMapping(20, TorznabCatType.Books);
+            AddCategoryMapping(30, TorznabCatType.TVDocs);
+            //Freelech
+            //Mac
+
+            AddCategoryMapping(25, TorznabCatType.MoviesSD);
+            AddCategoryMapping(11, TorznabCatType.MoviesHD);
+            AddCategoryMapping(5, TorznabCatType.MoviesHD);
+            AddCategoryMapping(3, TorznabCatType.MoviesSD);
+            AddCategoryMapping(21, TorznabCatType.MoviesSD);
+            AddCategoryMapping(22, TorznabCatType.MoviesForeign);
+            // Movie packs
+            AddCategoryMapping(44, TorznabCatType.MoviesSD);
+            AddCategoryMapping(1, TorznabCatType.MoviesSD);
+
+            // Music foreign
+            // Music packs
+            // Music videos
+
+            AddCategoryMapping(4, TorznabCatType.PCGames);
+            // ps3
+            // psp
+            // wii
+            // 360
+
+            AddCategoryMapping(24, TorznabCatType.TVSD);
+            AddCategoryMapping(32, TorznabCatType.TVHD);
+            AddCategoryMapping(31, TorznabCatType.TVSD);
+            AddCategoryMapping(33, TorznabCatType.TVSD);
+            AddCategoryMapping(14, TorznabCatType.TVHD);
+            AddCategoryMapping(26, TorznabCatType.TVSD);
+            AddCategoryMapping(7, TorznabCatType.TVHD);
+            AddCategoryMapping(2, TorznabCatType.TVSD);
+
+            AddCategoryMapping(6, TorznabCatType.XXX);
+            AddCategoryMapping(15, TorznabCatType.XXX);
         }
 
-        public Task<ConfigurationData> GetConfigurationForSetup()
+        public override async Task<ConfigurationData> GetConfigurationForSetup()
         {
-            return Task.FromResult<ConfigurationData>(new ConfigurationDataBasicLogin());
+            var loginPage = await RequestStringWithCookies(StartPageUrl, string.Empty);
+            CQ cq = loginPage.Content;
+            var result = new ConfigurationDataRecaptchaLogin();
+            result.CookieHeader.Value = loginPage.Cookies;
+            result.Captcha.SiteKey = cq.Find(".g-recaptcha").Attr("data-sitekey");
+            return result;
         }
 
         public async Task ApplyConfiguration(JToken configJson)
         {
-            var config = new ConfigurationDataBasicLogin();
-            config.LoadValuesFromJson(configJson);
-
-            var startMessage = await RequestStringWithCookies(StartPageUrl, string.Empty);
+            configData.LoadValuesFromJson(configJson);
+            var pairs = new Dictionary<string, string> {
+                { "username", configData.Username.Value },
+                { "password", configData.Password.Value },
+                { "g-recaptcha-response", configData.Captcha.Value }
+            };
 
+            if (!string.IsNullOrWhiteSpace(configData.Captcha.Cookie))
+            {
+                // Cookie was manually supplied
+                CookieHeader = configData.Captcha.Cookie;
+                try
+                {
+                    var results = await PerformQuery(new TorznabQuery());
+                    if (results.Count() == 0)
+                    {
+                        throw new Exception("Your cookie did not work");
+                    }
 
-            var pairs = new Dictionary<string, string> {
-				{ "username", config.Username.Value },
-				{ "password", config.Password.Value }
-			};
+                    SaveConfig();
+                    IsConfigured = true;
+                }
+                catch(Exception e)
+                {
+                    IsConfigured = false;
+                    throw new Exception("Your cookie did not work: " + e.Message);
+                }
+            }
 
-            var result = await RequestLoginAndFollowRedirect(LoginUrl, pairs, null, true, SiteLink, LoginUrl);
+            var result = await RequestLoginAndFollowRedirect(LoginUrl, pairs, configData.CookieHeader.Value, true, SiteLink, LoginUrl);
             await ConfigureIfOK(result.Cookies, result.Content != null && result.Content.Contains("logout.php"), () =>
             {
                 CQ dom = result.Content;
                 var messageEl = dom["#login"];
                 messageEl.Children("form").Remove();
                 var errorMessage = messageEl.Text().Trim();
-                throw new ExceptionWithConfigData(errorMessage, (ConfigurationData)config);
+
+                if (string.IsNullOrWhiteSpace(errorMessage))
+                {
+                    errorMessage = dom.Text();
+                }
+
+                throw new ExceptionWithConfigData(errorMessage, configData);
             });
         }
 
@@ -67,8 +146,23 @@ namespace Jackett.Indexers
         {
             var releases = new List<ReleaseInfo>();
             var searchString = query.SanitizedSearchTerm + " " + query.GetEpisodeSearchString();
-            var episodeSearchUrl = string.Format(SearchUrl, HttpUtility.UrlEncode(searchString));
-            var results = await RequestStringWithCookiesAndRetry(episodeSearchUrl);
+            var queryUrl = SearchUrl;
+            var queryCollection = new NameValueCollection();
+
+            if (!string.IsNullOrWhiteSpace(searchString))
+                queryCollection.Add("search", searchString);
+
+            foreach (var cat in MapTorznabCapsToTrackers(query))
+                queryCollection.Add("c"+cat,"1");
+
+            if (queryCollection.Count > 0)
+                queryUrl += "?" + queryCollection.GetQueryString();
+
+            var results = await RequestStringWithCookiesAndRetry(queryUrl);
+
+            // Check for being logged out
+            if (results.IsRedirect)
+                throw new AuthenticationException();
 
             try
             {
@@ -83,19 +177,27 @@ namespace Jackett.Indexers
                     release.MinimumSeedTime = 172800;
                     release.Title = qRow.Find(".torrentName").Text();
                     release.Description = release.Title;
-                    release.Guid = new Uri(SiteLink + "/" + qRow.Find(".torrentName").Attr("href"));
+                    release.Guid = new Uri(SiteLink  + qRow.Find(".torrentName").Attr("href"));
                     release.Comments = release.Guid;
-                    release.Link = new Uri(SiteLink + "/" + qRow.Find(".dlLinksInfo > a").Attr("href"));
+                    release.Link = new Uri(SiteLink  + qRow.Find(".dlLinksInfo > a").Attr("href"));
 
                     var sizeStr = qRow.Find(".sizeInfo").Text();
                     release.Size = ReleaseInfo.GetBytes(sizeStr);
 
                     var dateStr = qRow.Find(".ulInfo").Text().Split('|').Last().Trim();
+                    var agoIdx = dateStr.IndexOf("ago");
+                    if (agoIdx > -1)
+                    {
+                        dateStr = dateStr.Substring(0, agoIdx);
+                    }
                     release.PublishDate = DateTimeUtil.FromTimeAgo(dateStr);
 
                     release.Seeders = ParseUtil.CoerceInt(qRow.Find(".seedersInfo").Text());
                     release.Peers = ParseUtil.CoerceInt(qRow.Find(".leechersInfo").Text()) + release.Seeders;
 
+                    var cat = qRow.Find("td:eq(0) a").First().Attr("href").Substring(15);//browse.php?cat=24
+                    release.Category = MapTrackerCatToNewznab(cat);
+
                     releases.Add(release);
                 }
             }
diff --git a/src/Jackett/Indexers/TorrentLeech.cs b/src/Jackett/Indexers/TorrentLeech.cs
index 3067861008777b085ac964676970c15ef24c0ce8..6e99e639ec274c6281818bbe916762731b364cf1 100644
--- a/src/Jackett/Indexers/TorrentLeech.cs
+++ b/src/Jackett/Indexers/TorrentLeech.cs
@@ -14,6 +14,7 @@ using System.Net.Http;
 using System.Text;
 using System.Threading.Tasks;
 using System.Web;
+using Jackett.Models.IndexerConfig;
 
 namespace Jackett.Indexers
 {
@@ -22,40 +23,42 @@ namespace Jackett.Indexers
         private string LoginUrl { get { return SiteLink + "user/account/login/"; } }
         private string SearchUrl { get { return SiteLink + "torrents/browse/index/query/{0}/categories/2%2C26%2C27%2C32/orderby/added?"; } }
 
-        public TorrentLeech(IIndexerManagerService i, Logger l, IWebClient wc)
+        new ConfigurationDataBasicLogin configData
+        {
+            get { return (ConfigurationDataBasicLogin)base.configData; }
+            set { base.configData = value; }
+        }
+
+        public TorrentLeech(IIndexerManagerService i, Logger l, IWebClient wc, IProtectionService ps)
             : base(name: "TorrentLeech",
                 description: "This is what happens when you seed",
                 link: "http://www.torrentleech.org/",
                 caps: TorznabCapsUtil.CreateDefaultTorznabTVCaps(),
                 manager: i,
                 client: wc,
-                logger: l)
-        {
-        }
-
-        public Task<ConfigurationData> GetConfigurationForSetup()
+                logger: l,
+                p: ps,
+                configData: new ConfigurationDataBasicLogin())
         {
-            return Task.FromResult<ConfigurationData>(new ConfigurationDataBasicLogin());
         }
 
         public async Task ApplyConfiguration(JToken configJson)
         {
-            var config = new ConfigurationDataBasicLogin();
-            config.LoadValuesFromJson(configJson);
+            configData.LoadValuesFromJson(configJson);
             var pairs = new Dictionary<string, string> {
-				{ "username", config.Username.Value },
-				{ "password", config.Password.Value },
+                { "username", configData.Username.Value },
+                { "password", configData.Password.Value },
                 { "remember_me", "on" },
                 { "login", "submit" }
-			};
+            };
 
-            var result = await RequestLoginAndFollowRedirect(LoginUrl, pairs, null, true,null, LoginUrl);
+            var result = await RequestLoginAndFollowRedirect(LoginUrl, pairs, null, true, null, LoginUrl);
             await ConfigureIfOK(result.Cookies, result.Content != null && result.Content.Contains("/user/account/logout"), () =>
             {
                 CQ dom = result.Content;
                 var messageEl = dom[".ui-state-error"].Last();
                 var errorMessage = messageEl.Text().Trim();
-                throw new ExceptionWithConfigData(errorMessage, (ConfigurationData)config);
+                throw new ExceptionWithConfigData(errorMessage, configData);
             });
         }
 
diff --git a/src/Jackett/Indexers/TorrentShack.cs b/src/Jackett/Indexers/TorrentShack.cs
index 3823ce379022e8eae1838a25f8e21fc8e9b0f5c0..69765cf2a835e890088f8cd5f27327b7cf009287 100644
--- a/src/Jackett/Indexers/TorrentShack.cs
+++ b/src/Jackett/Indexers/TorrentShack.cs
@@ -14,6 +14,7 @@ using System.Net.Http;
 using System.Text;
 using System.Threading.Tasks;
 using System.Web;
+using Jackett.Models.IndexerConfig;
 
 namespace Jackett.Indexers
 {
@@ -22,33 +23,35 @@ namespace Jackett.Indexers
         private string LoginUrl { get { return SiteLink + "login.php"; } }
         private string SearchUrl { get { return SiteLink + "torrents.php?searchstr={0}&release_type=both&searchtags=&tags_type=0&order_by=s3&order_way=desc&torrent_preset=all&filter_cat%5B600%5D=1&filter_cat%5B620%5D=1&filter_cat%5B700%5D=1&filter_cat%5B981%5D=1&filter_cat%5B980%5D=1"; } }
 
-        public TorrentShack(IIndexerManagerService i, Logger l, IWebClient wc)
+        new ConfigurationDataBasicLogin configData
+        {
+            get { return (ConfigurationDataBasicLogin)base.configData; }
+            set { base.configData = value; }
+        }
+
+        public TorrentShack(IIndexerManagerService i, Logger l, IWebClient wc, IProtectionService ps)
             : base(name: "TorrentShack",
                 description: "TorrentShack",
                 link: "http://torrentshack.me/",
                 caps: TorznabCapsUtil.CreateDefaultTorznabTVCaps(),
                 client: wc,
                 manager: i,
-                logger: l)
-        {
-        }
-
-        public Task<ConfigurationData> GetConfigurationForSetup()
+                logger: l,
+                p: ps,
+                configData: new ConfigurationDataBasicLogin())
         {
-            return Task.FromResult<ConfigurationData>(new ConfigurationDataBasicLogin());
         }
 
         public async Task ApplyConfiguration(JToken configJson)
         {
-            var config = new ConfigurationDataBasicLogin();
-            config.LoadValuesFromJson(configJson);
+            configData.LoadValuesFromJson(configJson);
 
             var pairs = new Dictionary<string, string> {
-				{ "username", config.Username.Value },
-				{ "password", config.Password.Value },
+                { "username", configData.Username.Value },
+                { "password", configData.Password.Value },
                 { "keeplogged", "1" },
                 { "login", "Login" }
-			};
+            };
 
             var result = await RequestLoginAndFollowRedirect(LoginUrl, pairs, null, true, null, LoginUrl);
             await ConfigureIfOK(result.Cookies, result.Content != null && result.Content.Contains("logout.php"), () =>
@@ -57,7 +60,7 @@ namespace Jackett.Indexers
                 var messageEl = dom["#loginform"];
                 messageEl.Children("table").Remove();
                 var errorMessage = messageEl.Text().Trim();
-                throw new ExceptionWithConfigData(errorMessage, (ConfigurationData)config);
+                throw new ExceptionWithConfigData(errorMessage, configData);
             });
         }
 
diff --git a/src/Jackett/Indexers/Torrentz.cs b/src/Jackett/Indexers/Torrentz.cs
index c1d846da42547a7cb39176e9212388b347387c7d..ca540a2dd170511b08a2e26b37ccb87d418673a9 100644
--- a/src/Jackett/Indexers/Torrentz.cs
+++ b/src/Jackett/Indexers/Torrentz.cs
@@ -14,48 +14,68 @@ using System.Web;
 using System.Windows.Forms;
 using System.Xml;
 using System.Linq;
+using Jackett.Models.IndexerConfig;
 
 namespace Jackett.Indexers
 {
     public class Torrentz : BaseIndexer, IIndexer
     {
-        private string SearchUrl { get { return SiteLink + "feed_verifiedP?f={0}"; } }
-        private string BaseUrl;
+        readonly static string defaultSiteLink = "https://torrentz.eu/";
 
-        public Torrentz(IIndexerManagerService i, Logger l, IWebClient wc)
+        private Uri BaseUri
+        {
+            get { return new Uri(configData.Url.Value); }
+            set { configData.Url.Value = value.ToString(); }
+        }
+
+        private string SearchUrl { get { return BaseUri + "feed_verifiedP?f={0}"; } }
+
+        new ConfigurationDataUrl configData
+        {
+            get { return (ConfigurationDataUrl)base.configData; }
+            set { base.configData = value; }
+        }
+
+
+        public Torrentz(IIndexerManagerService i, Logger l, IWebClient wc, IProtectionService ps)
             : base(name: "Torrentz",
                 description: "Torrentz is a meta-search engine and a Multisearch. This means we just search other search engines.",
-                link: "https://torrentz.eu/",
+                link: defaultSiteLink,
                 caps: TorznabCapsUtil.CreateDefaultTorznabTVCaps(),
                 manager: i,
                 client: wc,
-                logger: l)
-        {
-        }
-
-        public Task<ConfigurationData> GetConfigurationForSetup()
+                logger: l,
+                p: ps,
+                configData: new ConfigurationDataUrl(defaultSiteLink))
         {
-            return Task.FromResult<ConfigurationData>(new ConfigurationDataUrl(SiteLink));
         }
 
         public async Task ApplyConfiguration(JToken configJson)
         {
-            var config = new ConfigurationDataUrl(SiteLink);
-            config.LoadValuesFromJson(configJson);
+            configData.LoadValuesFromJson(configJson);
+            var releases = await PerformQuery(new TorznabQuery());
 
-            var formattedUrl = config.GetFormattedHostUrl();
-            IEnumerable<ReleaseInfo> releases = await PerformQuery(new TorznabQuery(), formattedUrl);
-            if (releases.Count() == 0)
+            await ConfigureIfOK(string.Empty, releases.Count() > 0, () =>
+            {
                 throw new Exception("Could not find releases from this URL");
+            });
+        }
+
+        // Override to load legacy config format
+        public override void LoadFromSavedConfiguration(JToken jsonConfig)
+        {
+            if (jsonConfig is JObject)
+            {
+                BaseUri = new Uri(jsonConfig.Value<string>("base_url"));
+                SaveConfig();
+                IsConfigured = true;
+                return;
+            }
 
-            BaseUrl = formattedUrl;
-            var configSaveData = new JObject();
-            configSaveData["base_url"] = BaseUrl;
-            SaveConfig(configSaveData);
-            IsConfigured = true;
+            base.LoadFromSavedConfiguration(jsonConfig);
         }
 
-        async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query, string baseUrl)
+        public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query)
         {
             var releases = new List<ReleaseInfo>();
             var searchString = query.SanitizedSearchTerm + " " + query.GetEpisodeSearchString();
@@ -106,18 +126,6 @@ namespace Jackett.Indexers
             return releases;
         }
 
-
-        public override void LoadFromSavedConfiguration(JToken jsonConfig)
-        {
-            BaseUrl = (string)jsonConfig["base_url"];
-            IsConfigured = true;
-        }
-
-        public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query)
-        {
-            return await PerformQuery(query, BaseUrl);
-        }
-
         public override Task<byte[]> Download(Uri link)
         {
             throw new NotImplementedException();
@@ -178,7 +186,7 @@ namespace Jackett.Indexers
                 switch (counter)
                 {
                     case 0:
-                        this.Size = ReleaseInfo.GetBytes(val); 
+                        this.Size = ReleaseInfo.GetBytes(val);
                         break;
                     case 1:
                         this.Seeders = ParseUtil.CoerceInt(val.Contains(",") ? val.Remove(val.IndexOf(","), 1) : val);
diff --git a/src/Jackett/Indexers/nCore.cs b/src/Jackett/Indexers/nCore.cs
new file mode 100644
index 0000000000000000000000000000000000000000..05d6d1b341d6da3a41822c08df632f8718893ef2
--- /dev/null
+++ b/src/Jackett/Indexers/nCore.cs
@@ -0,0 +1,168 @@
+using CsQuery;
+using Jackett.Models;
+using Jackett.Services;
+using Jackett.Utils;
+using Jackett.Utils.Clients;
+using Newtonsoft.Json;
+using Newtonsoft.Json.Linq;
+using NLog;
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+using System.Net;
+using System.Net.Http;
+using System.Text;
+using System.Threading.Tasks;
+using System.Web;
+using Jackett.Models.IndexerConfig;
+
+namespace Jackett.Indexers
+{
+    public class NCore : BaseIndexer, IIndexer
+    {
+        private string LoginUrl { get { return SiteLink + "login.php"; } }
+        private string SearchUrl { get { return SiteLink + "torrents.php"; } }
+
+        new ConfigurationDataNCore configData
+        {
+            get { return (ConfigurationDataNCore)base.configData; }
+            set { base.configData = value; }
+        }
+
+        public NCore(IIndexerManagerService i, IWebClient wc, Logger l, IProtectionService ps)
+            : base(name: "nCore",
+                description: "A Hungarian private torrent site.",
+                link: "https://ncore.cc/",
+                caps: TorznabCapsUtil.CreateDefaultTorznabTVCaps(),
+                manager: i,
+                client: wc,
+                logger: l,
+                p: ps,
+                configData: new ConfigurationDataNCore())
+        {
+        }
+
+        public async Task ApplyConfiguration(JToken configJson)
+        {
+            configData.LoadValuesFromJson(configJson);
+
+            if (configData.Hungarian.Value == false && configData.English.Value == false)
+                throw new ExceptionWithConfigData("Please select atleast one language.", configData);
+
+            var loginPage = await RequestStringWithCookies(LoginUrl, string.Empty);
+            var pairs = new Dictionary<string, string> {
+                { "nev", configData.Username.Value },
+                { "pass", configData.Password.Value },
+                { "ne_leptessen_ki", "1"},
+                { "set_lang", "en" },
+                { "submitted", "1" },
+                { "submit", "Access!" }
+            };
+
+            var result = await RequestLoginAndFollowRedirect(LoginUrl, pairs, loginPage.Cookies, true, referer: SiteLink);
+            await ConfigureIfOK(result.Cookies, result.Content != null && result.Content.Contains("profile.php"), () =>
+            {
+                CQ dom = result.Content;
+                var messageEl = dom["#hibauzenet table tbody tr"];
+                var msgContainer = messageEl.Get(0).ChildElements.ElementAt(1);
+                var errorMessage = msgContainer != null ? msgContainer.InnerText : "Error while trying to login.";
+                throw new ExceptionWithConfigData(errorMessage, configData);
+            });
+        }
+
+        List<KeyValuePair<string, string>> CreateKeyValueList(params string[][] keyValues)
+        {
+            var list = new List<KeyValuePair<string, string>>();
+            foreach (var d in keyValues)
+            {
+                list.Add(new KeyValuePair<string, string>(d[0], d[1]));
+            }
+            return list;
+        }
+
+        private IEnumerable<KeyValuePair<string, string>> GetSearchFormData(string searchString)
+        {
+            const string searchTypeKey = "kivalasztott_tipus[]";
+            var baseList = CreateKeyValueList(
+                new[] { "nyit_sorozat_resz", "true" },
+                new[] { "miben", "name" },
+                new[] { "tipus", "kivalasztottak_kozott" },
+                new[] { "submit.x", "1" },
+                new[] { "submit.y", "1" },
+                new[] { "submit", "Ok" },
+                new[] { "mire", searchString }
+            );
+
+            if (configData.English.Value)
+            {
+                baseList.AddRange(CreateKeyValueList(
+                    new[] { searchTypeKey, "xvidser" },
+                    new[] { searchTypeKey, "dvdser" },
+                    new[] { searchTypeKey, "hdser" }
+                ));
+            }
+
+            if (configData.Hungarian.Value)
+            {
+                baseList.AddRange(CreateKeyValueList(
+                    new[] { searchTypeKey, "xvidser_hun" },
+                    new[] { searchTypeKey, "dvdser_hun" },
+                    new[] { searchTypeKey, "hdser_hun" }
+                ));
+            }
+            return baseList;
+        }
+
+        public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query)
+        {
+            List<ReleaseInfo> releases = new List<ReleaseInfo>();
+
+            var searchString = query.SanitizedSearchTerm + " " + query.GetEpisodeSearchString();
+            var results = await PostDataWithCookiesAndRetry(SearchUrl, GetSearchFormData(searchString));
+
+            try
+            {
+                CQ dom = results.Content;
+
+                ReleaseInfo release;
+                var rows = dom[".box_torrent_all"].Find(".box_torrent");
+
+                foreach (var row in rows)
+                {
+                    CQ qRow = row.Cq();
+
+                    release = new ReleaseInfo();
+                    var torrentTxt = qRow.Find(".torrent_txt").Find("a").Get(0);
+                    if (torrentTxt == null) continue;
+                    release.Title = torrentTxt.GetAttribute("title");
+                    release.Description = release.Title;
+                    release.MinimumRatio = 1;
+                    release.MinimumSeedTime = 172800;
+
+                    string downloadLink = SiteLink + torrentTxt.GetAttribute("href");
+                    string downloadId = downloadLink.Substring(downloadLink.IndexOf("&id=") + 4);
+
+                    release.Link = new Uri(SiteLink.ToString() + "torrents.php?action=download&id=" + downloadId);
+                    release.Comments = new Uri(SiteLink.ToString() + "torrents.php?action=details&id=" + downloadId);
+                    release.Guid = new Uri(release.Comments.ToString() + "#comments"); ;
+                    release.Seeders = ParseUtil.CoerceInt(qRow.Find(".box_s2").Find("a").First().Text());
+                    release.Peers = ParseUtil.CoerceInt(qRow.Find(".box_l2").Find("a").First().Text()) + release.Seeders;
+                    release.PublishDate = DateTime.Parse(qRow.Find(".box_feltoltve2").Get(0).InnerHTML.Replace("<br />", " "), CultureInfo.InvariantCulture);
+                    string[] sizeSplit = qRow.Find(".box_meret2").Get(0).InnerText.Split(' ');
+                    release.Size = ReleaseInfo.GetBytes(sizeSplit[1].ToLower(), ParseUtil.CoerceFloat(sizeSplit[0]));
+
+                    releases.Add(release);
+                }
+            }
+            catch (Exception ex)
+            {
+                OnParseError(results.Content, ex);
+            }
+
+
+            return releases.ToArray();
+        }
+
+    }
+}
\ No newline at end of file
diff --git a/src/Jackett/Jackett.csproj b/src/Jackett/Jackett.csproj
index 3762f618ba73ac8b40453c82d679a2bfcb9d24be..f109239cd09bc50b5b02f2eb46108ed5db277f60 100644
--- a/src/Jackett/Jackett.csproj
+++ b/src/Jackett/Jackett.csproj
@@ -148,6 +148,7 @@
       <Private>True</Private>
     </Reference>
     <Reference Include="System.Net.Http.WebRequest" />
+    <Reference Include="System.Security" />
     <Reference Include="System.ServiceProcess" />
     <Reference Include="System.Web" />
     <Reference Include="System.Web.Http, Version=5.2.3.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
@@ -170,6 +171,8 @@
     <Reference Include="System.Xml" />
   </ItemGroup>
   <ItemGroup>
+    <Compile Include="AuthenticationException.cs" />
+    <Compile Include="Controllers\BlackholeController.cs" />
     <Compile Include="Controllers\PotatoController.cs" />
     <Compile Include="Controllers\TorznabController.cs" />
     <Compile Include="Controllers\DownloadController.cs" />
@@ -181,12 +184,15 @@
     <Compile Include="Indexers\BeyondHD.cs" />
     <Compile Include="Indexers\BitHdtv.cs" />
     <Compile Include="Indexers\BitMeTV.cs" />
+    <Compile Include="Indexers\Demonoid.cs" />
     <Compile Include="Indexers\FrenchTorrentDb.cs" />
     <Compile Include="Indexers\Freshon.cs" />
     <Compile Include="Indexers\HDSpace.cs" />
     <Compile Include="Indexers\HDTorrents.cs" />
     <Compile Include="Indexers\IIndexer.cs" />
     <Compile Include="Indexers\ImmortalSeed.cs" />
+    <Compile Include="Indexers\NCore.cs" />
+    <Compile Include="Indexers\RuTor.cs" />
     <Compile Include="Indexers\TorrentBytes.cs" />
     <Compile Include="Indexers\IPTorrents.cs" />
     <Compile Include="Indexers\MoreThanTV.cs" />
@@ -203,12 +209,18 @@
     <Compile Include="Indexers\TorrentLeech.cs" />
     <Compile Include="Indexers\TorrentShack.cs" />
     <Compile Include="Indexers\Torrentz.cs" />
+    <Compile Include="JackettProtectedAttribute.cs" />
+    <Compile Include="Models\CachedLog.cs" />
     <Compile Include="Models\CachedResult.cs" />
     <Compile Include="Models\CategoryMapping.cs" />
-    <Compile Include="Models\IndexerConfig\BmtvConfig.cs" />
-    <Compile Include="Models\IndexerConfig\ConfigurationDataBasicLoginAnimeBytes.cs" />
-    <Compile Include="Models\IndexerConfig\ConfigurationDataBasicLoginFrenchTorrentDb.cs" />
-    <Compile Include="Models\IndexerConfig\PretomeConfiguration.cs" />
+    <Compile Include="Models\IndexerConfig\ConfigurationDataRecaptchaLogin.cs" />
+    <Compile Include="Models\IndexerConfig\ConfigurationDataLoginTokin.cs" />
+    <Compile Include="Models\IndexerConfig\ConfigurationDataNCore.cs" />
+    <Compile Include="Models\IndexerConfig\ConfigurationDataCaptchaLogin.cs" />
+    <Compile Include="Models\IndexerConfig\ConfigurationDataAnimeBytes.cs" />
+    <Compile Include="Models\IndexerConfig\ConfigurationDataUrl.cs" />
+    <Compile Include="Models\IndexerConfig\ISerializableConfig.cs" />
+    <Compile Include="Models\IndexerConfig\ConfigurationDataPinNumber.cs" />
     <Compile Include="Models\TorrentPotatoRequest.cs" />
     <Compile Include="Models\TorrentPotatoResponse.cs" />
     <Compile Include="Models\TorrentPotatoResponseItem.cs" />
@@ -219,6 +231,8 @@
     <Compile Include="Models\TrackerCache.cs" />
     <Compile Include="Models\TrackerCacheResult.cs" />
     <Compile Include="Services\CacheService.cs" />
+    <Compile Include="Services\LogCacheService.cs" />
+    <Compile Include="Services\ProtectionService.cs" />
     <Compile Include="Utils\Clients\BaseWebResult.cs" />
     <Compile Include="Utils\Clients\UnixLibCurlWebClient.cs" />
     <Compile Include="Utils\Clients\WebByteResult.cs" />
@@ -231,10 +245,10 @@
     <Compile Include="Utils\BrowserUtil.cs" />
     <Compile Include="Models\CachedQueryResult.cs" />
     <Compile Include="Models\ChannelInfo.cs" />
-    <Compile Include="Models\ConfigurationData.cs" />
-    <Compile Include="Models\ConfigurationDataBasicLogin.cs" />
-    <Compile Include="Models\ConfigurationDataCookie.cs" />
-    <Compile Include="Models\ConfigurationDataUrl.cs" />
+    <Compile Include="Models\IndexerConfig\ConfigurationData.cs" />
+    <Compile Include="Models\IndexerConfig\ConfigurationDataBasicLogin.cs" />
+    <Compile Include="Models\IndexerConfig\ConfigurationDataCookie.cs" />
+    <Compile Include="Models\IndexerConfig\ConfigurationDataRuTor.cs" />
     <Compile Include="Controllers\AdminController.cs" />
     <Compile Include="CookieContainerExtensions.cs" />
     <Compile Include="Utils\Clients\WebRequest.cs" />
@@ -305,6 +319,9 @@
     </None>
   </ItemGroup>
   <ItemGroup>
+    <None Include="CurlSharp.dll.config">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
     <None Include="packages.config" />
     <None Include="Resources\test.xml" />
   </ItemGroup>
@@ -339,12 +356,6 @@
     <Content Include="Content\fonts\glyphicons-halflings-regular.svg">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
-    <Content Include="Content\handlebars-intl.min.js">
-      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
-    </Content>
-    <Content Include="Content\handlebars.js">
-      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
-    </Content>
     <Content Include="Content\images\sort_asc.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
@@ -360,7 +371,19 @@
     <Content Include="Content\images\sort_desc_disabled.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
-    <Content Include="Content\jquery.dataTables.js">
+    <Content Include="Content\libs\handlebars.min.js">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="Content\libs\handlebarsmoment.js">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="Content\libs\jquery.dataTables.min.js">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="Content\libs\jquery.min.js">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="Content\libs\moment.min.js">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     <Content Include="Content\login.html">
@@ -378,6 +401,9 @@
     <Content Include="Content\logos\beyondhd.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
+    <Content Include="Content\logos\demonoid.png">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
     <Content Include="Content\logos\frenchtorrentdb.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
@@ -390,12 +416,18 @@
     <Content Include="Content\logos\immortalseed.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
+    <Content Include="Content\logos\ncore.png">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
     <Content Include="Content\logos\pretome.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     <Content Include="Content\logos\privatehd.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
+    <Content Include="Content\logos\rutor.png">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
     <Content Include="Content\logos\sceneaccess.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
@@ -426,7 +458,7 @@
     <Content Include="Content\binding_dark.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
-    <Content Include="Content\bootstrap-notify.js">
+    <Content Include="Content\libs\bootstrap-notify.js">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     <Content Include="Content\congruent_outline.png">
@@ -459,9 +491,6 @@
     <Content Include="Content\index.html">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
-    <Content Include="Content\jquery-2.1.3.min.js">
-      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
-    </Content>
     <Content Include="Content\logos\freshon.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
diff --git a/src/Jackett/JackettModule.cs b/src/Jackett/JackettModule.cs
index 74790ad76f2cc2a29499db1bdc20cbf0dd562c2f..cccbbe1927560765331955e53bbf06f15e80dc05 100644
--- a/src/Jackett/JackettModule.cs
+++ b/src/Jackett/JackettModule.cs
@@ -70,6 +70,7 @@ namespace Jackett
 
             Mapper.CreateMap<WebClientStringResult, WebClientStringResult>();
             Mapper.CreateMap<WebClientByteResult, WebClientByteResult>();
+            Mapper.CreateMap<ReleaseInfo, ReleaseInfo>();
 
             Mapper.CreateMap<ReleaseInfo, TrackerCacheResult>().AfterMap((r, t) =>
             {
diff --git a/src/Jackett/JackettProtectedAttribute.cs b/src/Jackett/JackettProtectedAttribute.cs
new file mode 100644
index 0000000000000000000000000000000000000000..a4e0d521ddc0ce005084c4eadf16fae98ba1b4e9
--- /dev/null
+++ b/src/Jackett/JackettProtectedAttribute.cs
@@ -0,0 +1,12 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Jackett
+{
+    public class JackettProtectedAttribute : Attribute
+    {
+    }
+}
diff --git a/src/Jackett/Models/CachedLog.cs b/src/Jackett/Models/CachedLog.cs
new file mode 100644
index 0000000000000000000000000000000000000000..970c16242a33f22f6a0f142847e8de5972266781
--- /dev/null
+++ b/src/Jackett/Models/CachedLog.cs
@@ -0,0 +1,16 @@
+using NLog;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Jackett.Models
+{
+    public class CachedLog
+    {
+        public string Level { set; get; }
+        public string Message { set; get; }
+        public DateTime When { set; get; }
+    }
+}
diff --git a/src/Jackett/Models/Config/ServerConfig.cs b/src/Jackett/Models/Config/ServerConfig.cs
index 36f8e1d39d2f2bc3527105c2c786aa3a1526bb53..02649ceadcf6b4bd3adc0903441e95c265e65066 100644
--- a/src/Jackett/Models/Config/ServerConfig.cs
+++ b/src/Jackett/Models/Config/ServerConfig.cs
@@ -19,6 +19,8 @@ namespace Jackett.Models.Config
         public bool AllowExternal { get; set; }
         public string APIKey { get; set; }
         public string AdminPassword { get; set; }
+        public string InstanceId { get; set; }
+        public string BlackholeDir { get; set; }
 
         public string[] GetListenAddresses(bool? external = null)
         {
@@ -38,19 +40,5 @@ namespace Jackett.Models.Config
                 };
             }
         }
-
-        public string GenerateApi()
-        {
-            var chars = "abcdefghijklmnopqrstuvwxyz0123456789";
-            var randBytes = new byte[32];
-            var rngCsp = new RNGCryptoServiceProvider();
-            rngCsp.GetBytes(randBytes);
-            var key = "";
-            foreach (var b in randBytes)
-            {
-                key += chars[b % chars.Length];
-            }
-            return key;
-        }
     }
 }
diff --git a/src/Jackett/Models/ConfigurationData.cs b/src/Jackett/Models/ConfigurationData.cs
deleted file mode 100644
index be18414467e1daea1e03638bf042610602ffa41e..0000000000000000000000000000000000000000
--- a/src/Jackett/Models/ConfigurationData.cs
+++ /dev/null
@@ -1,138 +0,0 @@
-using Jackett.Utils;
-using Newtonsoft.Json.Linq;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace Jackett.Models
-{
-    public abstract class ConfigurationData
-    {
-        public enum ItemType
-        {
-            InputString,
-            InputBool,
-            DisplayImage,
-            DisplayInfo,
-            HiddenData
-        }
-
-        public ConfigurationData()
-        {
-
-        }
-
-        public ConfigurationData(JToken json)
-        {
-            LoadValuesFromJson(json);
-        }
-
-        public void LoadValuesFromJson(JToken json)
-        {
-            // todo: match up ids with items and fill values
-            IDictionary<string, JToken> dictionary = (JObject)json;
-            foreach (var item in GetItems())
-            {
-                switch (item.ItemType)
-                {
-                    case ItemType.InputString:
-                        ((StringItem)item).Value = (string)dictionary[item.ID];
-                        break;
-                    case ItemType.InputBool:
-                        ((BoolItem)item).Value = (bool)dictionary[item.ID];
-                        break;
-                    case ItemType.HiddenData:
-                        ((HiddenItem)item).Value = (string)dictionary[item.ID];
-                        break;
-                }
-            }
-        }
-
-        public JToken ToJson()
-        {
-            var items = GetItems();
-            var jArray = new JArray();
-            foreach (var item in items)
-            {
-                var jObject = new JObject();
-                jObject["id"] = item.ID;
-                jObject["type"] = item.ItemType.ToString().ToLower();
-                jObject["name"] = item.Name;
-                switch (item.ItemType)
-                {
-                    case ItemType.InputString:
-                    case ItemType.HiddenData:
-                    case ItemType.DisplayInfo:
-                        jObject["value"] = ((StringItem)item).Value;
-                        break;
-                    case ItemType.InputBool:
-                        jObject["value"] = ((BoolItem)item).Value;
-                        break;
-                    case ItemType.DisplayImage:
-                        string dataUri = DataUrlUtils.BytesToDataUrl(((ImageItem)item).Value, "image/jpeg");
-                        jObject["value"] = dataUri;
-                        break;
-                }
-                jArray.Add(jObject);
-            }
-            return jArray;
-        }
-
-        public class Item
-        {
-            public ItemType ItemType { get; set; }
-            public string Name { get; set; }
-            public string ID { get { return Name.Replace(" ", "").ToLower(); } }
-        }
-
-        public class HiddenItem : StringItem
-        {
-            public HiddenItem(string value)
-            {
-                Value = value;
-                ItemType = ItemType.HiddenData;
-            }
-        }
-
-        public class DisplayItem : StringItem
-        {
-            public DisplayItem(string value)
-            {
-                Value = value;
-                ItemType = ItemType.DisplayInfo;
-            }
-        }
-
-        public class StringItem : Item
-        {
-            public string Value { get; set; }
-            public StringItem()
-            {
-                ItemType = ConfigurationData.ItemType.InputString;
-            }
-        }
-
-        public class BoolItem : Item
-        {
-            public bool Value { get; set; }
-            public BoolItem()
-            {
-                ItemType = ConfigurationData.ItemType.InputBool;
-            }
-        }
-
-        public class ImageItem : Item
-        {
-            public byte[] Value { get; set; }
-            public ImageItem()
-            {
-                ItemType = ConfigurationData.ItemType.DisplayImage;
-            }
-        }
-
-        public abstract Item[] GetItems();
-
-    }
-}
diff --git a/src/Jackett/Models/IndexerConfig/ConfigurationData.cs b/src/Jackett/Models/IndexerConfig/ConfigurationData.cs
new file mode 100644
index 0000000000000000000000000000000000000000..499a6879128186ab072a5e4ed79a6fc096f4773a
--- /dev/null
+++ b/src/Jackett/Models/IndexerConfig/ConfigurationData.cs
@@ -0,0 +1,206 @@
+using Jackett.Services;
+using Jackett.Utils;
+using Newtonsoft.Json.Linq;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Jackett.Models.IndexerConfig
+{
+    public abstract class ConfigurationData
+    {
+        const string PASSWORD_REPLACEMENT = "|||%%PREVJACKPASSWD%%|||";
+
+        public enum ItemType
+        {
+            InputString,
+            InputBool,
+            DisplayImage,
+            DisplayInfo,
+            HiddenData,
+            Recaptcha
+        }
+
+        public HiddenItem CookieHeader { get; private set; } = new HiddenItem { Name = "CookieHeader" };
+
+        public ConfigurationData()
+        {
+
+        }
+
+        public ConfigurationData(JToken json, IProtectionService ps)
+        {
+            LoadValuesFromJson(json, ps);
+        }
+
+        public void LoadValuesFromJson(JToken json, IProtectionService ps= null)
+        {
+            var arr = (JArray)json;
+            foreach (var item in GetItems(forDisplay: false))
+            {
+                var arrItem = arr.FirstOrDefault(f => f.Value<string>("id") == item.ID);
+                if (arrItem == null)
+                    continue;
+
+                switch (item.ItemType)
+                {
+                    case ItemType.InputString:
+                        var sItem = (StringItem)item;
+                        var newValue = arrItem.Value<string>("value");
+
+                        if (string.Equals(item.Name, "password", StringComparison.InvariantCultureIgnoreCase))
+                        {
+                            if (newValue != PASSWORD_REPLACEMENT)
+                            {
+                                sItem.Value = newValue;
+                                if (ps != null)
+                                    sItem.Value = ps.UnProtect(newValue);
+                            }
+                        } else
+                        {
+                            sItem.Value = newValue;
+                        }
+                        break;
+                    case ItemType.HiddenData:
+                        ((HiddenItem)item).Value = arrItem.Value<string>("value");
+                        break;
+                    case ItemType.InputBool:
+                        ((BoolItem)item).Value = arrItem.Value<bool>("value");
+                        break;
+                    case ItemType.Recaptcha:
+                        ((RecaptchaItem)item).Value = arrItem.Value<string>("value");
+                        ((RecaptchaItem)item).Cookie = arrItem.Value<string>("cookie");
+                        break;
+                }
+            }
+        }
+
+        public JToken ToJson(IProtectionService ps, bool forDisplay = true)
+        {
+            var items = GetItems(forDisplay);
+            var jArray = new JArray();
+            foreach (var item in items)
+            {
+                var jObject = new JObject();
+                jObject["id"] = item.ID;
+                jObject["type"] = item.ItemType.ToString().ToLower();
+                jObject["name"] = item.Name;
+                switch (item.ItemType)
+                {
+                    case ItemType.Recaptcha:
+                        jObject["sitekey"] = ((RecaptchaItem)item).SiteKey;
+                        break;
+                    case ItemType.InputString:
+                    case ItemType.HiddenData:
+                    case ItemType.DisplayInfo:
+                        var value = ((StringItem)item).Value;
+                        if (string.Equals(item.Name, "password", StringComparison.InvariantCultureIgnoreCase))
+                        {
+                            if (string.IsNullOrEmpty(value))
+                                value = string.Empty;
+                            else if (forDisplay)
+                                value = PASSWORD_REPLACEMENT;
+                            else if (ps != null)
+                                value = ps.Protect(value);
+                        }
+                        jObject["value"] = value;
+                        break;
+                    case ItemType.InputBool:
+                        jObject["value"] = ((BoolItem)item).Value;
+                        break;
+                    case ItemType.DisplayImage:
+                        string dataUri = DataUrlUtils.BytesToDataUrl(((ImageItem)item).Value, "image/jpeg");
+                        jObject["value"] = dataUri;
+                        break;
+                }
+                jArray.Add(jObject);
+            }
+            return jArray;
+        }
+
+        Item[] GetItems(bool forDisplay)
+        {
+            var properties = GetType()
+                .GetProperties()
+                .Where(p => p.CanRead)
+                .Where(p => p.PropertyType.IsSubclassOf(typeof(Item)))
+                .Select(p => (Item)p.GetValue(this));
+
+            if (!forDisplay)
+            {
+                properties = properties
+                    .Where(p => p.ItemType == ItemType.HiddenData || p.ItemType == ItemType.InputBool || p.ItemType == ItemType.InputString || p.ItemType == ItemType.Recaptcha)
+                    .ToArray();
+            }
+
+            return properties.ToArray();
+        }
+
+        public class Item
+        {
+            public ItemType ItemType { get; set; }
+            public string Name { get; set; }
+            public string ID { get { return Name.Replace(" ", "").ToLower(); } }
+        }
+
+        public class HiddenItem : StringItem
+        {
+            public HiddenItem(string value = "")
+            {
+                Value = value;
+                ItemType = ItemType.HiddenData;
+            }
+        }
+
+        public class DisplayItem : StringItem
+        {
+            public DisplayItem(string value)
+            {
+                Value = value;
+                ItemType = ItemType.DisplayInfo;
+            }
+        }
+
+        public class StringItem : Item
+        {
+            public string SiteKey { get; set; }
+            public string Value { get; set; }
+            public string Cookie { get; set; }
+            public StringItem()
+            {
+                ItemType = ConfigurationData.ItemType.InputString;
+            }
+        }
+
+        public class RecaptchaItem : StringItem
+        {
+            public RecaptchaItem()
+            {
+                ItemType = ConfigurationData.ItemType.Recaptcha;
+            }
+        }
+
+        public class BoolItem : Item
+        {
+            public bool Value { get; set; }
+            public BoolItem()
+            {
+                ItemType = ConfigurationData.ItemType.InputBool;
+            }
+        }
+
+        public class ImageItem : Item
+        {
+            public byte[] Value { get; set; }
+            public ImageItem()
+            {
+                ItemType = ConfigurationData.ItemType.DisplayImage;
+            }
+        }
+
+        //public abstract Item[] GetItems();
+    }
+}
diff --git a/src/Jackett/Models/IndexerConfig/ConfigurationDataBasicLoginAnimeBytes.cs b/src/Jackett/Models/IndexerConfig/ConfigurationDataAnimeBytes.cs
similarity index 68%
rename from src/Jackett/Models/IndexerConfig/ConfigurationDataBasicLoginAnimeBytes.cs
rename to src/Jackett/Models/IndexerConfig/ConfigurationDataAnimeBytes.cs
index 249bec8d76cdaa448dbcdec85513b610da57a405..47ddb275ea012583b24e4e492e9460f32e2669e9 100644
--- a/src/Jackett/Models/IndexerConfig/ConfigurationDataBasicLoginAnimeBytes.cs
+++ b/src/Jackett/Models/IndexerConfig/ConfigurationDataAnimeBytes.cs
@@ -7,21 +7,16 @@ using System.Threading.Tasks;
 
 namespace Jackett.Models.IndexerConfig
 {
-    class ConfigurationDataBasicLoginAnimeBytes : ConfigurationDataBasicLogin
+    class ConfigurationDataAnimeBytes : ConfigurationDataBasicLogin
     {
         public BoolItem IncludeRaw { get; private set; }
         public DisplayItem DateWarning { get; private set; }
 
-        public ConfigurationDataBasicLoginAnimeBytes()
+        public ConfigurationDataAnimeBytes()
             : base()
         {
             IncludeRaw = new BoolItem() { Name = "IncludeRaw", Value = false };
             DateWarning = new DisplayItem("This tracker does not supply upload dates so they are based off year of release.") { Name = "DateWarning" };
         }
-
-        public override Item[] GetItems()
-        {
-            return new Item[] { Username, Password, IncludeRaw, DateWarning };
-        }
     }
 }
diff --git a/src/Jackett/Models/ConfigurationDataBasicLogin.cs b/src/Jackett/Models/IndexerConfig/ConfigurationDataBasicLogin.cs
similarity index 79%
rename from src/Jackett/Models/ConfigurationDataBasicLogin.cs
rename to src/Jackett/Models/IndexerConfig/ConfigurationDataBasicLogin.cs
index fc75502847b81ae7997ee5c8bd2dc3cb88c01cee..b3023f9f07671cdaf5257bd7d343600ff62c18c4 100644
--- a/src/Jackett/Models/ConfigurationDataBasicLogin.cs
+++ b/src/Jackett/Models/IndexerConfig/ConfigurationDataBasicLogin.cs
@@ -5,7 +5,7 @@ using System.Linq;
 using System.Text;
 using System.Threading.Tasks;
 
-namespace Jackett.Models
+namespace Jackett.Models.IndexerConfig
 {
     public class ConfigurationDataBasicLogin : ConfigurationData
     {
@@ -18,9 +18,6 @@ namespace Jackett.Models
             Password = new StringItem { Name = "Password" };
         }
 
-        public override Item[] GetItems()
-        {
-            return new Item[] { Username, Password };
-        }
+
     }
 }
diff --git a/src/Jackett/Models/IndexerConfig/ConfigurationDataBasicLoginFrenchTorrentDb.cs b/src/Jackett/Models/IndexerConfig/ConfigurationDataBasicLoginFrenchTorrentDb.cs
deleted file mode 100644
index 9cfbb6d6dd9a41b907148b3daf444a0d8b020729..0000000000000000000000000000000000000000
--- a/src/Jackett/Models/IndexerConfig/ConfigurationDataBasicLoginFrenchTorrentDb.cs
+++ /dev/null
@@ -1,23 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace Jackett.Models.IndexerConfig
-{
-    class ConfigurationDataBasicLoginFrenchTorrentDb : ConfigurationData
-    {
-        public StringItem Cookie { get; private set; }
-
-        public ConfigurationDataBasicLoginFrenchTorrentDb()
-        {
-            Cookie = new StringItem { Name = "Cookie" };
-        }
-
-        public override Item[] GetItems()
-        {
-            return new Item[] { Cookie };
-        }
-    }
-}
diff --git a/src/Jackett/Models/IndexerConfig/BmtvConfig.cs b/src/Jackett/Models/IndexerConfig/ConfigurationDataCaptchaLogin.cs
similarity index 78%
rename from src/Jackett/Models/IndexerConfig/BmtvConfig.cs
rename to src/Jackett/Models/IndexerConfig/ConfigurationDataCaptchaLogin.cs
index c7f1af5587b855bd543e514d072427fcf103e52e..a3ae9b89621b2c2c2e8bd48f45db8936137bf93c 100644
--- a/src/Jackett/Models/IndexerConfig/BmtvConfig.cs
+++ b/src/Jackett/Models/IndexerConfig/ConfigurationDataCaptchaLogin.cs
@@ -6,7 +6,7 @@ using System.Threading.Tasks;
 
 namespace Jackett.Models.IndexerConfig
 {
-    class BmtvConfig : ConfigurationData
+    class ConfigurationDataCaptchaLogin : ConfigurationData
     {
         public StringItem Username { get; private set; }
 
@@ -18,7 +18,7 @@ namespace Jackett.Models.IndexerConfig
 
         public HiddenItem CaptchaCookie { get; private set; }
 
-        public BmtvConfig()
+        public ConfigurationDataCaptchaLogin()
         {
             Username = new StringItem { Name = "Username" };
             Password = new StringItem { Name = "Password" };
@@ -26,10 +26,5 @@ namespace Jackett.Models.IndexerConfig
             CaptchaText = new StringItem { Name = "Captcha Text" };
             CaptchaCookie = new HiddenItem("") { Name = "Captcha Cookie" };
         }
-
-        public override Item[] GetItems()
-        {
-            return new Item[] { Username, Password, CaptchaImage, CaptchaText, CaptchaCookie };
-        }
     }
 }
diff --git a/src/Jackett/Models/ConfigurationDataCookie.cs b/src/Jackett/Models/IndexerConfig/ConfigurationDataCookie.cs
similarity index 61%
rename from src/Jackett/Models/ConfigurationDataCookie.cs
rename to src/Jackett/Models/IndexerConfig/ConfigurationDataCookie.cs
index afa3e46e55bf7d6b7b4ca5efa1f835af09b3af82..bb1e063222d262546e4b4f3d6f5e1488826f11e1 100644
--- a/src/Jackett/Models/ConfigurationDataCookie.cs
+++ b/src/Jackett/Models/IndexerConfig/ConfigurationDataCookie.cs
@@ -4,7 +4,7 @@ using System.Linq;
 using System.Text;
 using System.Threading.Tasks;
 
-namespace Jackett.Models
+namespace Jackett.Models.IndexerConfig
 {
 
     public class ConfigurationDataCookie : ConfigurationData
@@ -17,7 +17,7 @@ namespace Jackett.Models
         {
             Cookie = new StringItem { Name = "Cookie" };
             CookieHint = new DisplayItem(
-            "<ol><li>Login to BeyondHD in your browser <li>Open the developer console, go the network tab <li>Find 'cookie' in the request headers <li>Copy & paste it to here</ol>")
+            "<ol><li>Login to this tracker in your browser <li>Open the developer console, go the network tab <li>Find 'cookie' in the request headers <li>Copy & paste it to here</ol>")
             {
                 Name = "CookieHint"
             };
@@ -27,19 +27,6 @@ namespace Jackett.Models
                 Name = "CookieExample"
             };
         }
-
-        public override Item[] GetItems()
-        {
-            return new Item[] { Cookie, CookieHint, CookieExample };
-        }
-
-        public string CookieHeader
-        {
-            get
-            {
-                return Cookie.Value.Trim().TrimStart(new char[] { '"' }).TrimEnd(new char[] { '"' });
-            }
-        }
     }
 
 }
diff --git a/src/Jackett/Models/IndexerConfig/ConfigurationDataLoginTokin.cs b/src/Jackett/Models/IndexerConfig/ConfigurationDataLoginTokin.cs
new file mode 100644
index 0000000000000000000000000000000000000000..b9e6973329bcb33bf7d79fb16204419d2a8bfae1
--- /dev/null
+++ b/src/Jackett/Models/IndexerConfig/ConfigurationDataLoginTokin.cs
@@ -0,0 +1,35 @@
+using Jackett.Utils;
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Jackett.Models.IndexerConfig
+{
+    public class ConfigurationDataLoginTokin : ConfigurationDataBasicLogin
+    {
+        public HiddenItem ApiToken { get; private set; }
+        public HiddenItem LastTokenFetchDate { get; private set; }
+
+        public DateTime LastTokenFetchDateTime
+        {
+            get
+            {
+                return DateTimeUtil.UnixTimestampToDateTime(ParseUtil.CoerceDouble(LastTokenFetchDate.Value));
+            }
+            set
+            {
+                LastTokenFetchDate.Value = DateTimeUtil.DateTimeToUnixTimestamp(value).ToString(CultureInfo.InvariantCulture);
+            }
+        }
+
+        public ConfigurationDataLoginTokin() : base()
+        {
+            ApiToken = new HiddenItem { Name = "ApiToken" };
+            LastTokenFetchDate = new HiddenItem { Name = "LastTokenFetchDate" };
+            LastTokenFetchDateTime = DateTime.MinValue;
+        }
+    }
+}
diff --git a/src/Jackett/Models/IndexerConfig/ConfigurationDataNCore.cs b/src/Jackett/Models/IndexerConfig/ConfigurationDataNCore.cs
new file mode 100644
index 0000000000000000000000000000000000000000..1dc5aaad0a621f63dfb26e6f6a3952d52ac529cc
--- /dev/null
+++ b/src/Jackett/Models/IndexerConfig/ConfigurationDataNCore.cs
@@ -0,0 +1,62 @@
+using Newtonsoft.Json;
+using Newtonsoft.Json.Linq;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Jackett.Models.IndexerConfig
+{
+    public class ConfigurationDataNCore : ConfigurationData
+    {
+        public StringItem Username { get; private set; }
+        public StringItem Password { get; private set; }
+        public BoolItem Hungarian { get; set; }
+        public BoolItem English { get; set; }
+
+        public ConfigurationDataNCore()
+        {
+            Username = new StringItem { Name = "Username", Value = "" };
+            Password = new StringItem { Name = "Password", Value = "" };
+            Hungarian = new BoolItem { Name = "Hungarian", Value = true };
+            English = new BoolItem { Name = "English", Value = true };
+        }
+
+        public ConfigurationDataNCore(JToken json)
+        {
+            ConfigurationDataNCore configData = new ConfigurationDataNCore();
+
+            dynamic configArray = JsonConvert.DeserializeObject(json.ToString());
+            foreach (var config in configArray)
+            {
+                string propertyName = UppercaseFirst((string)config.id);
+                switch (propertyName)
+                {
+                    case "Username":
+                        Username = new StringItem { Name = propertyName, Value = config.value };
+                        break;
+                    case "Password":
+                        Password = new StringItem { Name = propertyName, Value = config.value };
+                        break;
+                    case "Hungarian":
+                        Hungarian = new BoolItem { Name = propertyName, Value = config.value };
+                        break;
+                    case "English":
+                        English = new BoolItem { Name = propertyName, Value = config.value };
+                        break;
+                    default:
+                        break;
+                }
+            }
+        }
+
+        static string UppercaseFirst(string s)
+        {
+            if (string.IsNullOrEmpty(s))
+                return string.Empty;
+            return char.ToUpper(s[0]) + s.Substring(1);
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/Jackett/Models/IndexerConfig/PretomeConfiguration.cs b/src/Jackett/Models/IndexerConfig/ConfigurationDataPinNumber.cs
similarity index 57%
rename from src/Jackett/Models/IndexerConfig/PretomeConfiguration.cs
rename to src/Jackett/Models/IndexerConfig/ConfigurationDataPinNumber.cs
index 27cb36688df40f1a868e670a51ef75346a22f168..f67002a840880070da21ae84c49e978a5c49c081 100644
--- a/src/Jackett/Models/IndexerConfig/PretomeConfiguration.cs
+++ b/src/Jackett/Models/IndexerConfig/ConfigurationDataPinNumber.cs
@@ -6,18 +6,13 @@ using System.Threading.Tasks;
 
 namespace Jackett.Models.IndexerConfig
 {
-    class PretomeConfiguration : ConfigurationDataBasicLogin
+    class ConfigurationDataPinNumber : ConfigurationDataBasicLogin
     {
         public StringItem Pin { get; private set; }
 
-        public PretomeConfiguration() : base()
+        public ConfigurationDataPinNumber() : base()
         {
             Pin = new StringItem { Name = "Login Pin Number" };
         }
-
-        public override Item[] GetItems()
-        {
-            return new Item[] { Pin, Username, Password };
-        }
     }
 }
diff --git a/src/Jackett/Models/IndexerConfig/ConfigurationDataRecaptchaLogin.cs b/src/Jackett/Models/IndexerConfig/ConfigurationDataRecaptchaLogin.cs
new file mode 100644
index 0000000000000000000000000000000000000000..94991c02d57702f920cbd27888c861eea43de5a2
--- /dev/null
+++ b/src/Jackett/Models/IndexerConfig/ConfigurationDataRecaptchaLogin.cs
@@ -0,0 +1,25 @@
+using Newtonsoft.Json.Linq;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Jackett.Models.IndexerConfig
+{
+    public class ConfigurationDataRecaptchaLogin : ConfigurationData
+    {
+        public StringItem Username { get; private set; }
+        public StringItem Password { get; private set; }
+        public RecaptchaItem Captcha { get; private set; }
+
+        public ConfigurationDataRecaptchaLogin()
+        {
+            Username = new StringItem { Name = "Username" };
+            Password = new StringItem { Name = "Password" };
+            Captcha = new RecaptchaItem() { Name = "Recaptcha" };
+        }
+
+
+    }
+}
diff --git a/src/Jackett/Models/IndexerConfig/ConfigurationDataRuTor.cs b/src/Jackett/Models/IndexerConfig/ConfigurationDataRuTor.cs
new file mode 100644
index 0000000000000000000000000000000000000000..49c1024ea599215306ddd2f3225d6ce2508d08ca
--- /dev/null
+++ b/src/Jackett/Models/IndexerConfig/ConfigurationDataRuTor.cs
@@ -0,0 +1,27 @@
+using Newtonsoft.Json;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Jackett.Models.IndexerConfig
+{
+    public class ConfigurationDataRuTor : ConfigurationData
+    {
+        [JsonProperty]
+        public StringItem Url { get; private set; }
+        [JsonProperty]
+        public BoolItem StripRussian { get; private set; }
+
+        public ConfigurationDataRuTor()
+        {
+        }
+
+        public ConfigurationDataRuTor(string defaultUrl)
+        {
+            Url = new StringItem { Name = "Url", Value = defaultUrl };
+            StripRussian = new BoolItem() { Name = "StripRusNamePrefix", Value = true };
+        }
+    }
+}
diff --git a/src/Jackett/Models/ConfigurationDataUrl.cs b/src/Jackett/Models/IndexerConfig/ConfigurationDataUrl.cs
similarity index 56%
rename from src/Jackett/Models/ConfigurationDataUrl.cs
rename to src/Jackett/Models/IndexerConfig/ConfigurationDataUrl.cs
index abf834d5854ae9552e1c8c645d1bbc5a553aea06..71c23eaebc8ed1bd8928e90f4719ea8c91105759 100644
--- a/src/Jackett/Models/ConfigurationDataUrl.cs
+++ b/src/Jackett/Models/IndexerConfig/ConfigurationDataUrl.cs
@@ -4,31 +4,20 @@ using System.Linq;
 using System.Text;
 using System.Threading.Tasks;
 
-namespace Jackett.Models
+namespace Jackett.Models.IndexerConfig
 {
     public class ConfigurationDataUrl : ConfigurationData
     {
         public StringItem Url { get; private set; }
 
-        public ConfigurationDataUrl(Uri defaultUrl) 
+        public ConfigurationDataUrl(Uri defaultUrl)
         {
-            Url = new StringItem { Name = "Url", Value = defaultUrl.ToString() }; 
+            Url = new StringItem { Name = "Url", Value = defaultUrl.ToString() };
         }
 
         public ConfigurationDataUrl(string defaultUrl)
         {
             Url = new StringItem { Name = "Url", Value = defaultUrl };
         }
-
-        public override Item[] GetItems()
-        {
-            return new Item[] { Url };
-        }
-
-        public string GetFormattedHostUrl()
-        {
-            var uri = new Uri(Url.Value);
-            return string.Format("{0}://{1}", uri.Scheme, uri.Host);
-        }
     }
 }
diff --git a/src/Jackett/Models/IndexerConfig/ISerializableConfig.cs b/src/Jackett/Models/IndexerConfig/ISerializableConfig.cs
new file mode 100644
index 0000000000000000000000000000000000000000..c96756300baec9a45ee17c4bd68b1fb97fb1a8f6
--- /dev/null
+++ b/src/Jackett/Models/IndexerConfig/ISerializableConfig.cs
@@ -0,0 +1,15 @@
+using Newtonsoft.Json.Linq;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Jackett.Models.IndexerConfig
+{
+    public interface ISerializableConfig
+    {
+        JObject Serialize();
+        ISerializableConfig Deserialize(JObject jobj);
+    }
+}
diff --git a/src/Jackett/Models/ReleaseInfo.cs b/src/Jackett/Models/ReleaseInfo.cs
index 2e24293b391a6cc972bb328713b8d68409b0c982..b4dd95d1959b7b777d62140bc4e6afce33d7d779 100644
--- a/src/Jackett/Models/ReleaseInfo.cs
+++ b/src/Jackett/Models/ReleaseInfo.cs
@@ -5,6 +5,7 @@ using System.Linq;
 using System.Text;
 using System.Text.RegularExpressions;
 using System.Threading.Tasks;
+using System.Web;
 
 namespace Jackett.Models
 {
@@ -91,5 +92,14 @@ namespace Jackett.Models
             return (long)(kb * 1024f);
         }
 
+        public Uri ConvertToProxyLink(string serverUrl, string indexerId, string action = "download")
+        {
+            if (Link == null || (Link.IsAbsoluteUri && Link.Scheme == "magnet"))
+                return Link;
+            var originalLink = Link;
+            var encodedLink = HttpServerUtility.UrlTokenEncode(Encoding.UTF8.GetBytes(originalLink.ToString())) + "/t.torrent";
+            var proxyLink = string.Format("{0}api/{1}/{2}/{3}", serverUrl, indexerId, action, encodedLink);
+            return new Uri(proxyLink);
+        }
     }
 }
diff --git a/src/Jackett/Models/TorznabCatType.cs b/src/Jackett/Models/TorznabCatType.cs
index f78fb39950b6948f57a2f6c01359570629aafea0..16faba13f6610d3ea4576c5ad7ad02b84e38a222 100644
--- a/src/Jackett/Models/TorznabCatType.cs
+++ b/src/Jackett/Models/TorznabCatType.cs
@@ -16,9 +16,11 @@ namespace Jackett.Models
             cats.Add(5030, "TV/SD");
             cats.Add(5040, "TV/HD");
             cats.Add(5070, "TV/Anime");
+            cats.Add(5080, "TV/Documentary");
             cats.Add(8000, "Books");
             cats.Add(8020, "Books/Comics");
             cats.Add(4000, "PC");
+            cats.Add(4050, "PC/Games");
             cats.Add(3030, "Audio/Audiobook");
             cats.Add(2000, "Movies");
             cats.Add(2040, "Movies/HD");
@@ -82,6 +84,11 @@ namespace Jackett.Models
             get { return GetCat(5000); }
         }
 
+        public static TorznabCategory TVDocs
+        {
+            get { return GetCat(5080); }
+        }
+
         public static TorznabCategory TVSD
         {
             get { return GetCat(5030); }
@@ -107,6 +114,11 @@ namespace Jackett.Models
             get { return GetCat(4000); }
         }
 
+        public static TorznabCategory PCGames
+        {
+            get { return GetCat(4050); }
+        }
+
         public static TorznabCategory AudioBooks
         {
             get { return GetCat(3030); }
diff --git a/src/Jackett/Models/TrackerCache.cs b/src/Jackett/Models/TrackerCache.cs
index 12b2029aed4918b4b194a487cf0c29bfa67928bf..9b9dc9022b225666c596b91a6f0b9155a328eb72 100644
--- a/src/Jackett/Models/TrackerCache.cs
+++ b/src/Jackett/Models/TrackerCache.cs
@@ -9,6 +9,7 @@ namespace Jackett.Models
     class TrackerCache
     {
         public string TrackerId { set; get; }
+        public string TrackerName { set; get; }
 
         public List<CachedResult> Results = new List<CachedResult>();
     }
diff --git a/src/Jackett/Models/TrackerCacheResult.cs b/src/Jackett/Models/TrackerCacheResult.cs
index 13b1569e8fbe2297277eada265cc529de066c748..1475c4ac82db62cef488efbefe96c658eca9863d 100644
--- a/src/Jackett/Models/TrackerCacheResult.cs
+++ b/src/Jackett/Models/TrackerCacheResult.cs
@@ -11,5 +11,6 @@ namespace Jackett.Models
         public DateTime FirstSeen { get; set; }
         public string Tracker { get; set; }
         public string CategoryDesc { get; set; }
+        public Uri BlackholeLink { get; set; }
     }
 }
diff --git a/src/Jackett/Properties/AssemblyInfo.cs b/src/Jackett/Properties/AssemblyInfo.cs
index bd946bcd97976dab5723be2785996673b6033c1e..71e5f52f011db0b7bd8d3ad911cc85e765337e30 100644
--- a/src/Jackett/Properties/AssemblyInfo.cs
+++ b/src/Jackett/Properties/AssemblyInfo.cs
@@ -32,5 +32,5 @@ using System.Runtime.InteropServices;
 // You can specify all the values or you can default the Build and Revision Numbers 
 // by using the '*' as shown below:
 // [assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyVersion("0.6.0.0")]
-[assembly: AssemblyFileVersion("1.0.0.0")]
+[assembly: AssemblyVersion("0.6.1.0")]
+[assembly: AssemblyFileVersion("0.6.1.0")]
diff --git a/src/Jackett/Services/CacheService.cs b/src/Jackett/Services/CacheService.cs
index 84548bf378d0fa69045c01f5f29621c30c97c9c2..536c68620049d12b983dd3dfe532702c32cfbb48 100644
--- a/src/Jackett/Services/CacheService.cs
+++ b/src/Jackett/Services/CacheService.cs
@@ -1,4 +1,5 @@
 using AutoMapper;
+using Jackett.Indexers;
 using Jackett.Models;
 using System;
 using System.Collections.Generic;
@@ -10,25 +11,27 @@ namespace Jackett.Services
 {
     public interface ICacheService
     {
-        void CacheRssResults(string trackerId, IEnumerable<ReleaseInfo> releases);
-        List<TrackerCacheResult> GetCachedResults();
+        void CacheRssResults(IIndexer indexer, IEnumerable<ReleaseInfo> releases);
+        List<TrackerCacheResult> GetCachedResults(string serverUrl);
+        int GetNewItemCount(IIndexer indexer, IEnumerable<ReleaseInfo> releases);
     }
 
     public class CacheService : ICacheService
     {
         private readonly List<TrackerCache> cache = new List<TrackerCache>();
-        private readonly int MAX_RESULTS_PER_TRACKER = 250;
-        private readonly TimeSpan AGE_LIMIT = new TimeSpan(2, 0, 0, 0);
+        private readonly int MAX_RESULTS_PER_TRACKER = 1000;
+        private readonly TimeSpan AGE_LIMIT = new TimeSpan(7, 0, 0, 0);
 
-        public void CacheRssResults(string trackerId, IEnumerable<ReleaseInfo> releases)
+        public void CacheRssResults(IIndexer indexer, IEnumerable<ReleaseInfo> releases)
         {
             lock (cache)
             {
-                var trackerCache = cache.Where(c => c.TrackerId == trackerId).FirstOrDefault();
+                var trackerCache = cache.Where(c => c.TrackerId == indexer.ID).FirstOrDefault();
                 if (trackerCache == null)
                 {
                     trackerCache = new TrackerCache();
-                    trackerCache.TrackerId = trackerId;
+                    trackerCache.TrackerId = indexer.ID;
+                    trackerCache.TrackerName = indexer.DisplayName;
                     cache.Add(trackerCache);
                 }
 
@@ -59,7 +62,31 @@ namespace Jackett.Services
             }
         }
 
-        public List<TrackerCacheResult> GetCachedResults()
+        public int GetNewItemCount(IIndexer indexer, IEnumerable<ReleaseInfo> releases)
+        {
+            lock (cache)
+            {
+                int newItemCount = 0;
+                var trackerCache = cache.Where(c => c.TrackerId == indexer.ID).FirstOrDefault();
+                if (trackerCache != null)
+                {
+                    foreach (var release in releases)
+                    {
+                        if (trackerCache.Results.Where(i => i.Result.Guid == release.Guid).Count() == 0)
+                        {
+                            newItemCount++;
+                        }
+                    }
+                }
+                else {
+                    newItemCount++;
+                }
+
+                return newItemCount;
+            }
+        }
+
+        public List<TrackerCacheResult> GetCachedResults(string serverUrl)
         {
             lock (cache)
             {
@@ -71,13 +98,17 @@ namespace Jackett.Services
                     {
                         var item = Mapper.Map<TrackerCacheResult>(release.Result);
                         item.FirstSeen = release.Created;
-                        item.Tracker = tracker.TrackerId;
+                        item.Tracker = tracker.TrackerName;
                         item.Peers = item.Peers - item.Seeders; // Use peers as leechers
+                        item.Link = item.ConvertToProxyLink(serverUrl, tracker.TrackerId);
+                        if(item.Link!=null && item.Link.Scheme != "magnet" && !string.IsNullOrWhiteSpace(Engine.Server.Config.BlackholeDir))
+                            item.BlackholeLink = item.ConvertToProxyLink(serverUrl, tracker.TrackerId, "blackhole");
+
                         results.Add(item);
                     }
                 }
 
-                return results.OrderByDescending(i=>i.PublishDate).ToList();
+                return results.Take(3000).OrderByDescending(i=>i.PublishDate).ToList();
             }
         }
     }
diff --git a/src/Jackett/Services/IndexerManagerService.cs b/src/Jackett/Services/IndexerManagerService.cs
index f95c44a52e0592e6e7165c8947c14425940f6cf8..276c24d3cc78c1b173534159f0a74748be12df52 100644
--- a/src/Jackett/Services/IndexerManagerService.cs
+++ b/src/Jackett/Services/IndexerManagerService.cs
@@ -50,8 +50,16 @@ namespace Jackett.Services
                 var configFilePath = GetIndexerConfigFilePath(idx);
                 if (File.Exists(configFilePath))
                 {
-                    var jsonString = JObject.Parse(File.ReadAllText(configFilePath));
-                    idx.LoadFromSavedConfiguration(jsonString);
+                    var fileStr = File.ReadAllText(configFilePath);
+                    var jsonString = JToken.Parse(fileStr);
+                    try
+                    {
+                        idx.LoadFromSavedConfiguration(jsonString);
+                    }
+                    catch (Exception ex)
+                    {
+                        logger.Error(ex, "Failed loading configuration for {0}, you must reconfigure this indexer", idx.DisplayName);
+                    }
                 }
             }
         }
@@ -82,7 +90,7 @@ namespace Jackett.Services
             logger.Info(string.Format("Found {0} releases from {1}", results.Count(), indexer.DisplayName));
             if (results.Count() == 0)
                 throw new Exception("Found no results while trying to browse this tracker");
-            cacheService.CacheRssResults(indexer.DisplayName, results);
+            cacheService.CacheRssResults(indexer, results);
         }
 
         public void DeleteIndexer(string name)
diff --git a/src/Jackett/Services/LogCacheService.cs b/src/Jackett/Services/LogCacheService.cs
new file mode 100644
index 0000000000000000000000000000000000000000..4d8751a3bd3b7eeb29a8a6f990f1f580a6179672
--- /dev/null
+++ b/src/Jackett/Services/LogCacheService.cs
@@ -0,0 +1,54 @@
+using Jackett.Models;
+using NLog;
+using NLog.Targets;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Jackett.Services
+{
+    public interface ILogCacheService
+    {
+       // void AddLog(LogEventInfo l);
+        List<CachedLog> Logs { get; }
+    }
+
+    [Target("LogService")]
+    class LogCacheService: TargetWithLayout, ILogCacheService
+    {
+        private static List<CachedLog> logs = new List<CachedLog>();
+
+        public void AddLog(LogEventInfo l)
+        {
+            lock (logs)
+            {
+                logs.Insert(0, new CachedLog()
+                {
+                    Level = l.Level.Name,
+                    Message = l.Message,
+                    When = l.TimeStamp 
+                });
+                logs = logs.Take(50).ToList();
+            }
+
+        }
+
+        public List<CachedLog> Logs
+        {
+            get
+            {
+                lock (logs)
+                {
+                    return logs.ToList();
+                }
+            }
+        }
+
+        protected override void Write(LogEventInfo logEvent)
+        {
+            AddLog(logEvent);
+        }
+    }
+}
diff --git a/src/Jackett/Services/ProtectionService.cs b/src/Jackett/Services/ProtectionService.cs
new file mode 100644
index 0000000000000000000000000000000000000000..710b4f1548e6d276a4b27a5585df9e11dfc8d5fa
--- /dev/null
+++ b/src/Jackett/Services/ProtectionService.cs
@@ -0,0 +1,150 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Reflection;
+using System.Security.Cryptography;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Jackett.Services
+{
+    public interface IProtectionService
+    {
+        string Protect(string plainText);
+        string UnProtect(string plainText);
+    }
+
+    public class ProtectionService : IProtectionService
+    {
+        DataProtectionScope PROTECTION_SCOPE = DataProtectionScope.LocalMachine;
+        const string APPLICATION_KEY = "Dvz66r3n8vhTGip2/quiw5ISyM37f7L2iOdupzdKmzkvXGhAgQiWK+6F+4qpxjPVNks1qO7LdWuVqRlzgLzeW8mChC6JnBMUS1Fin4N2nS9lh4XPuCZ1che75xO92Nk2vyXUo9KSFG1hvEszAuLfG2Mcg1r0sVyVXd2gQDU/TbY=";
+
+        IServerService serverService;
+
+        public ProtectionService(IServerService s)
+        {
+            serverService = s;
+
+            if (System.Environment.OSVersion.Platform == PlatformID.Unix)
+            {
+                // We should not be running as root and will only have access to the local store.
+                PROTECTION_SCOPE = DataProtectionScope.CurrentUser;
+            }
+        }
+
+        public string Protect(string plainText)
+        {
+            if (string.IsNullOrEmpty(plainText))
+                return string.Empty;
+
+            var plainBytes = Encoding.UTF8.GetBytes(plainText);
+            var appKey = Convert.FromBase64String(APPLICATION_KEY);
+            var instanceKey = Encoding.UTF8.GetBytes(serverService.Config.InstanceId);
+            var entropy = new byte[appKey.Length + instanceKey.Length];
+            Buffer.BlockCopy(instanceKey, 0, entropy, 0, instanceKey.Length);
+            Buffer.BlockCopy(appKey, 0, entropy, instanceKey.Length, appKey.Length);
+
+            var protectedBytes = ProtectedData.Protect(plainBytes, entropy, PROTECTION_SCOPE);
+
+            using (MemoryStream ms = new MemoryStream())
+            {
+                using (RijndaelManaged AES = new RijndaelManaged())
+                {
+                    AES.KeySize = 256;
+                    AES.BlockSize = 128;
+
+                    var key = new Rfc2898DeriveBytes(instanceKey, instanceKey.Reverse().ToArray(), 64);
+                    AES.Key = key.GetBytes(AES.KeySize / 8);
+                    AES.IV = key.GetBytes(AES.BlockSize / 8);
+
+                    AES.Mode = CipherMode.CBC;
+
+                    using (var cs = new CryptoStream(ms, AES.CreateEncryptor(), CryptoStreamMode.Write))
+                    {
+                        cs.Write(protectedBytes, 0, protectedBytes.Length);
+                        cs.Close();
+                    }
+                    protectedBytes = ms.ToArray();
+                }
+            }
+
+            return Convert.ToBase64String(protectedBytes);
+        }
+
+        public string UnProtect(string plainText)
+        {
+            if (string.IsNullOrEmpty(plainText))
+                return string.Empty;
+
+            var protectedBytes = Convert.FromBase64String(plainText);
+            var instanceKey = Encoding.UTF8.GetBytes(serverService.Config.InstanceId);
+
+            using (MemoryStream ms = new MemoryStream())
+            {
+                using (RijndaelManaged AES = new RijndaelManaged())
+                {
+                    AES.KeySize = 256;
+                    AES.BlockSize = 128;
+
+                    var key = new Rfc2898DeriveBytes(instanceKey, instanceKey.Reverse().ToArray(), 64);
+                    AES.Key = key.GetBytes(AES.KeySize / 8);
+                    AES.IV = key.GetBytes(AES.BlockSize / 8);
+
+                    AES.Mode = CipherMode.CBC;
+
+                    using (var cs = new CryptoStream(ms, AES.CreateDecryptor(), CryptoStreamMode.Write))
+                    {
+                        cs.Write(protectedBytes, 0, protectedBytes.Length);
+                        cs.Close();
+                    }
+                    protectedBytes = ms.ToArray();
+                }
+            }
+
+            var appKey = Convert.FromBase64String(APPLICATION_KEY);
+            var entropy = new byte[appKey.Length + instanceKey.Length];
+            Buffer.BlockCopy(instanceKey, 0, entropy, 0, instanceKey.Length);
+            Buffer.BlockCopy(appKey, 0, entropy, instanceKey.Length, appKey.Length);
+
+            var unprotectedBytes = ProtectedData.Unprotect(protectedBytes, entropy, PROTECTION_SCOPE);
+            return Encoding.UTF8.GetString(unprotectedBytes);
+        }
+
+        public void Protect<T>(T obj)
+        {
+            var type = obj.GetType();
+
+            foreach(var property in type.GetProperties(BindingFlags.SetProperty |BindingFlags.GetProperty | BindingFlags.Public))
+            {
+                if(property.GetCustomAttributes(typeof(JackettProtectedAttribute), false).Count() > 0)
+                {
+                    var value = property.GetValue(obj);
+                    if(value is string)
+                    {
+                        var protectedString = Protect(value as string);
+                        property.SetValue(obj, protectedString);
+                    }
+                }
+            }
+        }
+
+        public void UnProtect<T>(T obj)
+        {
+            var type = obj.GetType();
+
+            foreach (var property in type.GetProperties(BindingFlags.SetProperty | BindingFlags.GetProperty | BindingFlags.Public))
+            {
+                if (property.GetCustomAttributes(typeof(JackettProtectedAttribute), false).Count() > 0)
+                {
+                    var value = property.GetValue(obj);
+                    if (value is string)
+                    {
+                        var unprotectedString = UnProtect(value as string);
+                        property.SetValue(obj, unprotectedString);
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/src/Jackett/Services/ServerService.cs b/src/Jackett/Services/ServerService.cs
index cdd82b782b1ee25365fb00ce1afb1255bd41c2db..1bf2dd6d4f220a7ae8c9e5d0821672617ba2c9b5 100644
--- a/src/Jackett/Services/ServerService.cs
+++ b/src/Jackett/Services/ServerService.cs
@@ -1,6 +1,7 @@
 using Autofac;
 using Jackett.Models.Config;
 using Jackett.Services;
+using Jackett.Utils;
 using Jackett.Utils.Clients;
 using Microsoft.Owin.Hosting;
 using Newtonsoft.Json.Linq;
@@ -16,6 +17,7 @@ using System.IO;
 using System.Linq;
 using System.Net;
 using System.Net.NetworkInformation;
+using System.Security.Cryptography;
 using System.Text;
 using System.Threading.Tasks;
 
@@ -91,10 +93,14 @@ namespace Jackett.Services
                 }
 
                 if (string.IsNullOrWhiteSpace(config.APIKey))
-                {
-                    config.APIKey = config.GenerateApi();
-                }
+                    config.APIKey = StringUtil.GenerateRandom(32);
+
+                configService.SaveConfig<ServerConfig>(config);
+            }
 
+            if (string.IsNullOrWhiteSpace(config.InstanceId))
+            {
+                config.InstanceId = StringUtil.GenerateRandom(64);
                 configService.SaveConfig<ServerConfig>(config);
             }
         }
diff --git a/src/Jackett/Startup.cs b/src/Jackett/Startup.cs
index d427afd4a2a02e46e96665bcf0fa5a58b8645f2d..5a64192238ca98a96b9b5055c3ec3ffe1417883b 100644
--- a/src/Jackett/Startup.cs
+++ b/src/Jackett/Startup.cs
@@ -115,6 +115,12 @@ namespace Jackett
                 defaults: new { controller = "Download", action = "Download" }
             );
 
+            config.Routes.MapHttpRoute(
+              name: "blackhole",
+              routeTemplate: "api/{indexerID}/blackhole/{path}/t.torrent",
+              defaults: new { controller = "Blackhole", action = "Blackhole" }
+          );
+
             appBuilder.UseFileServer(new FileServerOptions
             {
                 RequestPath = new PathString(string.Empty),
diff --git a/src/Jackett/Utils/Clients/HttpWebClient.cs b/src/Jackett/Utils/Clients/HttpWebClient.cs
index 92a88b99f481eac0d0bc5649204d7714cc7c9977..89e7eed01b741450c0cb43a841429dad531b4ba0 100644
--- a/src/Jackett/Utils/Clients/HttpWebClient.cs
+++ b/src/Jackett/Utils/Clients/HttpWebClient.cs
@@ -69,7 +69,7 @@ namespace Jackett.Utils.Clients
 
             client.DefaultRequestHeaders.Add("User-Agent", BrowserUtil.ChromeUserAgent);
             HttpResponseMessage response = null;
-           
+
             if (request.Type == RequestType.POST)
             {
                 var content = new FormUrlEncodedContent(request.PostData);
@@ -97,7 +97,7 @@ namespace Jackett.Utils.Clients
                 var cookieBuilder = new StringBuilder();
                 foreach (var c in cookieHeaders)
                 {
-                    cookieBuilder.AppendFormat("{0} ", c.Substring(0, c.IndexOf(';')+1));
+                    cookieBuilder.AppendFormat("{0} ", c.Substring(0, c.IndexOf(';') + 1));
                 }
 
                 result.Cookies = cookieBuilder.ToString().TrimEnd();
diff --git a/src/Jackett/Utils/Clients/UnixLibCurlWebClient.cs b/src/Jackett/Utils/Clients/UnixLibCurlWebClient.cs
index 58f2e024f9e0b0eafbcae896918b8c96ac0f683b..b9cd459a852f118d98a3640e78c5f4fad9f1043f 100644
--- a/src/Jackett/Utils/Clients/UnixLibCurlWebClient.cs
+++ b/src/Jackett/Utils/Clients/UnixLibCurlWebClient.cs
@@ -27,7 +27,7 @@ namespace Jackett.Utils.Clients
         {
             logger.Debug(string.Format("UnixLibCurlWebClient:GetBytes(Url:{0})", request.Url));
             var result = await Run(request);
-            logger.Debug(string.Format("UnixLibCurlWebClient:GetBytes Returning {0} => {1} bytes", result.Status, (result.Content==null?"<NULL>":result.Content.Length.ToString())));
+            logger.Debug(string.Format("UnixLibCurlWebClient:GetBytes Returning {0} => {1} bytes", result.Status, (result.Content == null ? "<NULL>" : result.Content.Length.ToString())));
             return result;
         }
 
@@ -35,20 +35,21 @@ namespace Jackett.Utils.Clients
         {
             logger.Debug(string.Format("UnixLibCurlWebClient:GetString(Url:{0})", request.Url));
             var result = await Run(request);
-            logger.Debug(string.Format("UnixLibCurlWebClient:GetString Returning {0} => {1}", result.Status, (result.Content== null?"<NULL>": Encoding.UTF8.GetString(result.Content))));
+            logger.Debug(string.Format("UnixLibCurlWebClient:GetString Returning {0} => {1}", result.Status, (result.Content == null ? "<NULL>" : Encoding.UTF8.GetString(result.Content))));
             return Mapper.Map<WebClientStringResult>(result);
         }
 
         public void Init()
         {
-            try {
+            try
+            {
                 Engine.Logger.Info("LibCurl init " + Curl.GlobalInit(CurlInitFlag.All).ToString());
                 CurlHelper.OnErrorMessage += (msg) =>
                  {
                      Engine.Logger.Error(msg);
                  };
             }
-            catch(Exception e)
+            catch (Exception e)
             {
                 Engine.Logger.Warn("Libcurl failed to initalize. Did you install it?");
                 Engine.Logger.Warn("Debian: apt-get install libcurl4-openssl-dev");
@@ -59,7 +60,7 @@ namespace Jackett.Utils.Clients
             var version = Curl.Version;
             Engine.Logger.Info("LibCurl version " + version);
 
-            if (!Startup.DoSSLFix.HasValue && version.IndexOf("NSS")>-1)
+            if (!Startup.DoSSLFix.HasValue && version.IndexOf("NSS") > -1)
             {
                 Engine.Logger.Info("NSS Detected SSL ECC workaround enabled.");
                 Startup.DoSSLFix = true;
@@ -75,9 +76,9 @@ namespace Jackett.Utils.Clients
             }
             else
             {
-                if (request.PostData != null && request.PostData.Count > 0)
+                if (request.PostData != null && request.PostData.Count() > 0)
                 {
-                    logger.Debug("UnixLibCurlWebClient: Posting " + new FormUrlEncodedContent(request.PostData).ReadAsStringAsync().Result);
+                    logger.Debug("UnixLibCurlWebClient: Posting " + StringUtil.PostDataFromDict(request.PostData));
                 }
 
                 response = await CurlHelper.PostAsync(request.Url, request.PostData, request.Cookies, request.Referer);
diff --git a/src/Jackett/Utils/Clients/UnixSafeCurlWebClient.cs b/src/Jackett/Utils/Clients/UnixSafeCurlWebClient.cs
index 7f3d8fe474639c4d2d1284b33e564c754ece0fd0..fcd4211a90fb3e2b8a50b65f24a2a41146681729 100644
--- a/src/Jackett/Utils/Clients/UnixSafeCurlWebClient.cs
+++ b/src/Jackett/Utils/Clients/UnixSafeCurlWebClient.cs
@@ -61,9 +61,9 @@ namespace Jackett.Utils.Clients
                 args.AppendFormat("--referer \"{0}\" ", request.Referer);
             }
 
-            if (request.PostData != null && request.PostData.Count > 0)
+            if (request.PostData != null && request.PostData.Count() > 0)
             {
-                var postString = new FormUrlEncodedContent(request.PostData).ReadAsStringAsync().Result;
+                var postString = StringUtil.PostDataFromDict(request.PostData);
                 args.AppendFormat("--data \"{0}\" ", postString);
             }
 
@@ -80,7 +80,7 @@ namespace Jackett.Utils.Clients
             string stdout = null;
             await Task.Run(() =>
             {
-                stdout = processService.StartProcessAndGetOutput(System.Environment.OSVersion.Platform == PlatformID.Unix?"curl":"curl.exe", args.ToString(), true);
+                stdout = processService.StartProcessAndGetOutput(System.Environment.OSVersion.Platform == PlatformID.Unix ? "curl" : "curl.exe", args.ToString(), true);
             });
 
             var outputData = File.ReadAllBytes(tempFile);
@@ -126,7 +126,7 @@ namespace Jackett.Utils.Clients
 
             result.Content = new byte[outputData.Length - (headSplit + 3)];
             var dest = 0;
-            for (int i= headSplit+4;i< outputData.Length; i++)
+            for (int i = headSplit + 4; i < outputData.Length; i++)
             {
                 result.Content[dest] = outputData[i];
                 dest++;
diff --git a/src/Jackett/Utils/Clients/WebRequest.cs b/src/Jackett/Utils/Clients/WebRequest.cs
index 78fc2f4638b816eb99b4f52d553dcdeaac8be85f..2d8862b18183b18036feb1b591f15d724ec0b04f 100644
--- a/src/Jackett/Utils/Clients/WebRequest.cs
+++ b/src/Jackett/Utils/Clients/WebRequest.cs
@@ -1,6 +1,7 @@
 using System;
 using System.Collections.Generic;
 using System.Linq;
+using System.Net.Http;
 using System.Text;
 using System.Threading.Tasks;
 
@@ -10,26 +11,27 @@ namespace Jackett.Utils.Clients
     {
         public WebRequest()
         {
-            PostData = new Dictionary<string, string>();
+            PostData = new List<KeyValuePair<string, string>>();
             Type = RequestType.GET;
         }
 
         public WebRequest(string url)
         {
-            PostData = new Dictionary<string, string>();
+            PostData = new List<KeyValuePair<string, string>>();
             Type = RequestType.GET;
             Url = url;
         }
 
         public string Url { get; set; }
-        public Dictionary<string, string> PostData { get; set; }
+        public IEnumerable<KeyValuePair<string, string>> PostData { get; set; }
         public string Cookies { get; set; }
         public string Referer { get; set; }
         public RequestType Type { get; set; }
 
+
         public override bool Equals(System.Object obj)
         {
-            if(obj is WebRequest)
+            if (obj is WebRequest)
             {
                 var other = obj as WebRequest;
                 var postDataSame = PostData == null && other.PostData == null;
@@ -37,16 +39,16 @@ namespace Jackett.Utils.Clients
                 {
                     if (!(PostData == null || other.PostData == null))
                     {
-                        var ok = PostData.Count == other.PostData.Count;
-                        foreach(var i in PostData)
+                        var ok = PostData.Count() == other.PostData.Count();
+                        foreach (var i in PostData)
                         {
-                            if (!other.PostData.ContainsKey(i.Key))
+                            if (!other.PostData.Any(item => item.Key == i.Key))
                             {
                                 ok = false;
                                 break;
                             }
 
-                            if(PostData[i.Key] != other.PostData[i.Key])
+                            if (PostData.FirstOrDefault(item => item.Key == i.Key).Value != other.PostData.FirstOrDefault(item => item.Key == i.Key).Value)
                             {
                                 ok = false;
                                 break;
@@ -66,7 +68,8 @@ namespace Jackett.Utils.Clients
                        other.Type == Type &&
                        postDataSame;
 
-            } else
+            }
+            else
             {
                 return false;
             }
diff --git a/src/Jackett/Utils/DateTimeUtil.cs b/src/Jackett/Utils/DateTimeUtil.cs
index 81b0c5c0c67f1d1200c3bc0fd3b0df49085a3993..355ae603caff12d73c256d61f0064db11794089f 100644
--- a/src/Jackett/Utils/DateTimeUtil.cs
+++ b/src/Jackett/Utils/DateTimeUtil.cs
@@ -15,6 +15,14 @@ namespace Jackett.Utils
             return new DateTime(unixStart.Ticks + unixTimeStampInTicks);
         }
 
+        public static double DateTimeToUnixTimestamp(DateTime dt)
+        {
+            var date = dt.ToUniversalTime();
+            var ticks = date.Ticks - new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc).Ticks;
+            var ts = ticks / TimeSpan.TicksPerSecond;
+            return ts;
+        }
+
         // ex: "2 hours 1 day"
         public static DateTime FromTimeAgo(string str)
         {
diff --git a/src/Jackett/Utils/ParseUtil.cs b/src/Jackett/Utils/ParseUtil.cs
index 7af7294260e0b4aec552263a00f48598b0551f88..4da72518748314898bf4ed73b62bfab0882d5b0a 100644
--- a/src/Jackett/Utils/ParseUtil.cs
+++ b/src/Jackett/Utils/ParseUtil.cs
@@ -9,6 +9,11 @@ namespace Jackett.Utils
 {
     public static class ParseUtil
     {
+        public static double CoerceDouble(string str)
+        {
+            return double.Parse(str.Trim(), NumberStyles.Any, CultureInfo.InvariantCulture);
+        }
+
         public static float CoerceFloat(string str)
         {
             return float.Parse(str.Trim(), NumberStyles.Any, CultureInfo.InvariantCulture);
@@ -25,6 +30,11 @@ namespace Jackett.Utils
         }
 
 
+        public static bool TryCoerceDouble(string str, out double result)
+        {
+            return double.TryParse(str.Trim(), NumberStyles.Any, CultureInfo.InvariantCulture, out result);
+        }
+
         public static bool TryCoerceFloat(string str, out float result)
         {
             return float.TryParse(str.Trim(), NumberStyles.Any, CultureInfo.InvariantCulture, out result);
diff --git a/src/Jackett/Utils/StringUtil.cs b/src/Jackett/Utils/StringUtil.cs
index 6fa5864e416c51400aa53eb227e2ae1fa55bb632..2e6765c3fe1f226fc7d3e2341d4c180554e44397 100644
--- a/src/Jackett/Utils/StringUtil.cs
+++ b/src/Jackett/Utils/StringUtil.cs
@@ -2,6 +2,7 @@
 using System.Collections.Generic;
 using System.Collections.Specialized;
 using System.Linq;
+using System.Net.Http;
 using System.Security.Cryptography;
 using System.Text;
 using System.Text.RegularExpressions;
@@ -12,10 +13,15 @@ namespace Jackett.Utils
 {
     public static class StringUtil
     {
-        public static string StripNonAlphaNumeric(string str)
+        public static string StripNonAlphaNumeric(string str, string replacement = "")
         {
-            Regex rgx = new Regex("[^a-zA-Z0-9 -]");
-            str = rgx.Replace(str, "");
+            return StripRegex(str, "[^a-zA-Z0-9 -]", replacement);
+        }
+
+        public static string StripRegex(string str, string regex, string replacement = "")
+        {
+            Regex rgx = new Regex(regex);
+            str = rgx.Replace(str, replacement);
             return str;
         }
 
@@ -24,6 +30,11 @@ namespace Jackett.Utils
             return Encoding.UTF8.GetString(Convert.FromBase64String(str));
         }
 
+        public static string PostDataFromDict(IEnumerable<KeyValuePair<string, string>> dict)
+        {
+            return new FormUrlEncodedContent(dict).ReadAsStringAsync().Result;
+        }
+
         public static string Hash(string input)
         {
             // Use input string to calculate MD5 hash
@@ -40,13 +51,13 @@ namespace Jackett.Utils
             return sb.ToString();
         }
 
-
         public static string GetExceptionDetails(this Exception exception)
         {
             var properties = exception.GetType()
                                     .GetProperties();
             var fields = properties
-                             .Select(property => new {
+                             .Select(property => new
+                             {
                                  Name = property.Name,
                                  Value = property.GetValue(exception, null)
                              })
@@ -62,5 +73,21 @@ namespace Jackett.Utils
         {
             return string.Join("&", collection.AllKeys.Select(a => a + "=" + HttpUtility.UrlEncode(collection[a])));
         }
+
+        public static string GenerateRandom(int length)
+        {
+            var chars = "abcdefghijklmnopqrstuvwxyz0123456789";
+            var randBytes = new byte[length];
+            using (var rngCsp = new RNGCryptoServiceProvider())
+            {
+                rngCsp.GetBytes(randBytes);
+                var key = "";
+                foreach (var b in randBytes)
+                {
+                    key += chars[b % chars.Length];
+                }
+                return key;
+            }
+        }
     }
 }