diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..691a714 --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,8 @@ + +// Sass configuration +{ + "version": "0.1.0", + "command": "node-sass", + "isShellCommand": true, + "args": ["Amen/Content/Site.scss", "Amen/Content/Site.css"] +} \ No newline at end of file diff --git a/Amen.sln b/Amen.sln new file mode 100644 index 0000000..5e8bfb7 --- /dev/null +++ b/Amen.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0.31101.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Amen", "Amen\Amen.csproj", "{599AF714-D8F5-408C-B14F-915AC646D9EA}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + Stage|Any CPU = Stage|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {599AF714-D8F5-408C-B14F-915AC646D9EA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {599AF714-D8F5-408C-B14F-915AC646D9EA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {599AF714-D8F5-408C-B14F-915AC646D9EA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {599AF714-D8F5-408C-B14F-915AC646D9EA}.Release|Any CPU.Build.0 = Release|Any CPU + {599AF714-D8F5-408C-B14F-915AC646D9EA}.Stage|Any CPU.ActiveCfg = Stage|Any CPU + {599AF714-D8F5-408C-B14F-915AC646D9EA}.Stage|Any CPU.Build.0 = Stage|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/Amen/Amen.csproj b/Amen/Amen.csproj new file mode 100644 index 0000000..9d31631 --- /dev/null +++ b/Amen/Amen.csproj @@ -0,0 +1,579 @@ + + + + + Debug + AnyCPU + + + 2.0 + {599AF714-D8F5-408C-B14F-915AC646D9EA} + {349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc} + Library + Properties + Amen + Amen + v4.8 + false + true + + + + + + + + + + + + true + full + false + bin\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\ + TRACE + prompt + 4 + + + + ..\packages\EPPlus.4.1.0\lib\net40\EPPlus.dll + + + ..\packages\Facebook.7.0.6\lib\net45\Facebook.dll + + + ..\packages\ImageResizer.4.1.9\lib\net45\ImageResizer.dll + + + ..\packages\Microsoft.Azure.KeyVault.Core.1.0.0\lib\net40\Microsoft.Azure.KeyVault.Core.dll + + + ..\packages\Microsoft.PowerPlatform.Dataverse.Client.1.0.9\lib\net48\Microsoft.Crm.Sdk.Proxy.dll + + + + False + ..\packages\Microsoft.Data.Edm.5.6.4\lib\net40\Microsoft.Data.Edm.dll + + + False + ..\packages\Microsoft.Data.OData.5.6.4\lib\net40\Microsoft.Data.OData.dll + + + False + ..\packages\Microsoft.Data.Services.Client.5.6.4\lib\net40\Microsoft.Data.Services.Client.dll + + + ..\packages\Microsoft.Extensions.Caching.Abstractions.3.1.8\lib\netstandard2.0\Microsoft.Extensions.Caching.Abstractions.dll + + + ..\packages\Microsoft.Extensions.Caching.Memory.3.1.8\lib\netstandard2.0\Microsoft.Extensions.Caching.Memory.dll + + + False + ..\packages\Microsoft.Extensions.DependencyInjection.3.1.8\lib\netstandard2.0\Microsoft.Extensions.DependencyInjection.dll + + + ..\packages\Microsoft.Extensions.DependencyInjection.Abstractions.3.1.8\lib\netstandard2.0\Microsoft.Extensions.DependencyInjection.Abstractions.dll + + + ..\packages\Microsoft.Extensions.Http.3.1.8\lib\netstandard2.0\Microsoft.Extensions.Http.dll + + + ..\packages\Microsoft.Extensions.Logging.3.1.8\lib\netstandard2.0\Microsoft.Extensions.Logging.dll + + + ..\packages\Microsoft.Extensions.Logging.Abstractions.3.1.8\lib\netstandard2.0\Microsoft.Extensions.Logging.Abstractions.dll + + + ..\packages\Microsoft.Extensions.Options.3.1.8\lib\netstandard2.0\Microsoft.Extensions.Options.dll + + + ..\packages\Microsoft.Extensions.Primitives.3.1.8\lib\netstandard2.0\Microsoft.Extensions.Primitives.dll + + + ..\packages\Microsoft.Identity.Client.4.35.1\lib\netstandard1.3\Microsoft.Identity.Client.dll + + + False + ..\packages\Microsoft.IdentityModel.Clients.ActiveDirectory.3.19.8\lib\net45\Microsoft.IdentityModel.Clients.ActiveDirectory.dll + + + ..\packages\Microsoft.IdentityModel.Clients.ActiveDirectory.3.19.8\lib\net45\Microsoft.IdentityModel.Clients.ActiveDirectory.Platform.dll + + + ..\packages\Microsoft.Owin.3.1.0-rc1\lib\net45\Microsoft.Owin.dll + + + ..\packages\Microsoft.Owin.Cors.3.1.0-rc1\lib\net45\Microsoft.Owin.Cors.dll + + + ..\packages\Microsoft.Owin.Host.SystemWeb.3.1.0-rc1\lib\net45\Microsoft.Owin.Host.SystemWeb.dll + + + ..\packages\Microsoft.Owin.Security.3.1.0-rc1\lib\net45\Microsoft.Owin.Security.dll + + + ..\packages\Microsoft.Owin.Security.Cookies.3.1.0-rc1\lib\net45\Microsoft.Owin.Security.Cookies.dll + + + ..\packages\Microsoft.Owin.Security.Facebook.3.1.0-rc1\lib\net45\Microsoft.Owin.Security.Facebook.dll + + + ..\packages\Microsoft.Owin.Security.Google.3.1.0-rc1\lib\net45\Microsoft.Owin.Security.Google.dll + + + ..\packages\Microsoft.Owin.Security.MicrosoftAccount.3.1.0-rc1\lib\net45\Microsoft.Owin.Security.MicrosoftAccount.dll + + + ..\packages\Microsoft.Owin.Security.OAuth.3.1.0-rc1\lib\net45\Microsoft.Owin.Security.OAuth.dll + + + ..\packages\Microsoft.Owin.Security.Twitter.3.1.0-rc1\lib\net45\Microsoft.Owin.Security.Twitter.dll + + + ..\packages\Microsoft.PowerPlatform.Dataverse.Client.1.0.9\lib\net48\Microsoft.PowerPlatform.Dataverse.Client.dll + + + ..\packages\Microsoft.CrmSdk.XrmTooling.CoreAssembly.9.1.1.1\lib\net462\Microsoft.Rest.ClientRuntime.dll + + + False + ..\packages\WindowsAzure.Storage.7.2.1\lib\net40\Microsoft.WindowsAzure.Storage.dll + + + ..\packages\Microsoft.PowerPlatform.Dataverse.Client.1.0.9\lib\net48\Microsoft.Xrm.Sdk.dll + + + ..\packages\Microsoft.CrmSdk.Deployment.9.0.2.25\lib\net462\Microsoft.Xrm.Sdk.Deployment.dll + + + ..\packages\Microsoft.CrmSdk.Workflow.9.0.2.42\lib\net462\Microsoft.Xrm.Sdk.Workflow.dll + + + ..\packages\Microsoft.CrmSdk.XrmTooling.CoreAssembly.9.1.1.1\lib\net462\Microsoft.Xrm.Tooling.Connector.dll + + + ..\packages\Newtonsoft.Json.13.0.1\lib\net45\Newtonsoft.Json.dll + + + ..\packages\Owin.1.0\lib\net40\Owin.dll + + + ..\packages\PagedList.1.17.0.0\lib\net40\PagedList.dll + + + ..\packages\PagedList.Mvc.4.5.0.0\lib\net40\PagedList.Mvc.dll + True + + + + ..\packages\RestSharp.105.2.2\lib\net45\RestSharp.dll + + + + + + ..\packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll + + + ..\packages\System.ComponentModel.Annotations.4.7.0\lib\net461\System.ComponentModel.Annotations.dll + + + + + + + + + + + + ..\packages\System.Memory.4.5.4\lib\net461\System.Memory.dll + + + + + ..\packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll + + + + + ..\packages\System.Runtime.CompilerServices.Unsafe.6.0.0\lib\net461\System.Runtime.CompilerServices.Unsafe.dll + + + + + + + + + + + + False + ..\packages\System.Spatial.5.6.4\lib\net40\System.Spatial.dll + + + ..\packages\System.Text.Encodings.Web.6.0.0\lib\net461\System.Text.Encodings.Web.dll + + + ..\packages\System.Text.Json.6.0.2\lib\net461\System.Text.Json.dll + + + ..\packages\System.Threading.Tasks.Extensions.4.5.4\lib\net461\System.Threading.Tasks.Extensions.dll + + + ..\packages\System.ValueTuple.4.5.0\lib\net47\System.ValueTuple.dll + + + ..\packages\Microsoft.AspNet.Cors.5.0.0\lib\net45\System.Web.Cors.dll + + + + + + + + + + + + + + + + + + + True + ..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll + + + + + + + True + ..\packages\Microsoft.AspNet.WebPages.3.2.2\lib\net45\System.Web.Helpers.dll + + + True + ..\packages\Microsoft.AspNet.Mvc.5.2.2\lib\net45\System.Web.Mvc.dll + + + ..\packages\Microsoft.AspNet.Web.Optimization.1.1.3\lib\net40\System.Web.Optimization.dll + + + True + ..\packages\Microsoft.AspNet.Razor.3.2.2\lib\net45\System.Web.Razor.dll + + + True + ..\packages\Microsoft.AspNet.WebPages.3.2.2\lib\net45\System.Web.WebPages.dll + + + True + ..\packages\Microsoft.AspNet.WebPages.3.2.2\lib\net45\System.Web.WebPages.Deployment.dll + + + True + ..\packages\Microsoft.AspNet.WebPages.3.2.2\lib\net45\System.Web.WebPages.Razor.dll + + + + + ..\packages\Twilio.4.7.2\lib\3.5\Twilio.Api.dll + + + True + ..\packages\Antlr.3.4.1.9004\lib\Antlr3.Runtime.dll + + + ..\packages\WebGrease.1.5.2\lib\WebGrease.dll + + + + + ..\packages\Microsoft.AspNet.WebApi.Client.5.2.2\lib\net45\System.Net.Http.Formatting.dll + + + ..\packages\Microsoft.AspNet.WebApi.Core.5.2.2\lib\net45\System.Web.Http.dll + + + ..\packages\Microsoft.AspNet.WebApi.WebHost.5.2.2\lib\net45\System.Web.Http.WebHost.dll + + + ..\packages\EntityFramework.6.1.1\lib\net45\EntityFramework.dll + + + ..\packages\EntityFramework.6.1.1\lib\net45\EntityFramework.SqlServer.dll + + + ..\packages\Microsoft.AspNet.Identity.Core.2.1.0\lib\net45\Microsoft.AspNet.Identity.Core.dll + + + ..\packages\Microsoft.AspNet.Identity.Owin.2.1.0\lib\net45\Microsoft.AspNet.Identity.Owin.dll + + + ..\packages\Microsoft.AspNet.Identity.EntityFramework.2.1.0\lib\net45\Microsoft.AspNet.Identity.EntityFramework.dll + + + + + + + + + + + + + + + + + + + + + + + + + + + 201701031255563_AddCreatedUTCColumns.cs + + + + 201708042356577_AddAffiliateIntructions.cs + + + + 201708050049099_AddFieldsToSupportShowingUserNameAndLocation.cs + + + + + + + + + + + + + + Global.asax + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Designer + + + Web.config + + + Web.config + Designer + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Web.config + Designer + + + + + + + + + + + + + + + + + 201701031255563_AddCreatedUTCColumns.cs + + + 201708042356577_AddAffiliateIntructions.cs + + + 201708050049099_AddFieldsToSupportShowingUserNameAndLocation.cs + + + + 10.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + bin\ + TRACE + true + pdbonly + AnyCPU + prompt + MinimumRecommendedRules.ruleset + + + + + + + + + + + + True + True + 22024 + / + http://localhost:50539/ + False + False + + + False + + + + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + \ No newline at end of file diff --git a/Amen/App_Start/BundleConfig.cs b/Amen/App_Start/BundleConfig.cs new file mode 100644 index 0000000..2e4031d --- /dev/null +++ b/Amen/App_Start/BundleConfig.cs @@ -0,0 +1,33 @@ +using System.Web; +using System.Web.Optimization; + +namespace Amen +{ + public class BundleConfig + { + // For more information on bundling, visit http://go.microsoft.com/fwlink/?LinkId=301862 + public static void RegisterBundles(BundleCollection bundles) + { + bundles.Add(new ScriptBundle("~/bundles/jquery").Include( + "~/Scripts/jquery-{version}.js")); + + bundles.Add(new ScriptBundle("~/bundles/jqueryval").Include( + "~/Scripts/jquery.validate*")); + + // Use the development version of Modernizr to develop with and learn from. Then, when you're + // ready for production, use the build tool at http://modernizr.com to pick only the tests you need. + bundles.Add(new ScriptBundle("~/bundles/modernizr").Include( + "~/Scripts/modernizr-*")); + + bundles.Add(new ScriptBundle("~/bundles/bootstrap").Include( + "~/Scripts/bootstrap.js", + "~/Scripts/bootstrap-tagsinput.min.js", + "~/Scripts/respond.js")); + + var assemblyVersion = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString(); + bundles.Add(new StyleBundle("~/Content/css").Include( + "~/Content/bootstrap.css", + "~/Content/bootstrap-tagsinput.css")); + } + } +} diff --git a/Amen/App_Start/FilterConfig.cs b/Amen/App_Start/FilterConfig.cs new file mode 100644 index 0000000..3914b80 --- /dev/null +++ b/Amen/App_Start/FilterConfig.cs @@ -0,0 +1,13 @@ +using System.Web; +using System.Web.Mvc; + +namespace Amen +{ + public class FilterConfig + { + public static void RegisterGlobalFilters(GlobalFilterCollection filters) + { + filters.Add(new HandleErrorAttribute()); + } + } +} diff --git a/Amen/App_Start/IdentityConfig.cs b/Amen/App_Start/IdentityConfig.cs new file mode 100644 index 0000000..31f73b7 --- /dev/null +++ b/Amen/App_Start/IdentityConfig.cs @@ -0,0 +1,126 @@ +using System; +using System.Collections.Generic; +using System.Data.Entity; +using System.Linq; +using System.Security.Claims; +using System.Threading.Tasks; +using System.Web; +using Microsoft.AspNet.Identity; +using Microsoft.AspNet.Identity.EntityFramework; +using Microsoft.AspNet.Identity.Owin; +using Microsoft.Owin; +using Microsoft.Owin.Security; +using Amen.Models; +using Twilio; +using System.Net; +using System.Net.Mail; +using Amen.Controllers; + +namespace Amen +{ + public class EmailService : IIdentityMessageService + { + public Task SendAsync(IdentityMessage message) + { + NotificationController.SendEmailMessage(message.Destination, message.Subject, message.Body, NotificationController.EmailSendType.Account); + + return Task.FromResult(0); + } + } + + public class SmsIdentityMessage : IdentityMessage + { + public string TwilioSID { get; set; } + public string TwilioAuthToken { get; set; } + public string TwilioPhoneNumber { get; set; } + } + + public class SmsService : IIdentityMessageService + { + public Task SendAsync(IdentityMessage message) + { + if (message is SmsIdentityMessage) + { + var smsmessage = (SmsIdentityMessage)message; + NotificationController.SendSmsMessage(smsmessage.TwilioSID, smsmessage.TwilioAuthToken, smsmessage.TwilioPhoneNumber, message.Destination, message.Body); + } + + return Task.FromResult(0); + } + } + + // Configure the application user manager used in this application. UserManager is defined in ASP.NET Identity and is used by the application. + public class ApplicationUserManager : UserManager + { + public ApplicationUserManager(IUserStore store) + : base(store) + { + } + + public static ApplicationUserManager Create(IdentityFactoryOptions options, IOwinContext context) + { + var manager = new ApplicationUserManager(new UserStore(context.Get())); + // Configure validation logic for usernames + manager.UserValidator = new UserValidator(manager) + { + AllowOnlyAlphanumericUserNames = false, + RequireUniqueEmail = true + }; + + // Configure validation logic for passwords + manager.PasswordValidator = new PasswordValidator + { + RequiredLength = 6, + RequireNonLetterOrDigit = true, + RequireDigit = true, + RequireLowercase = true, + RequireUppercase = true, + }; + + // Configure user lockout defaults + manager.UserLockoutEnabledByDefault = true; + manager.DefaultAccountLockoutTimeSpan = TimeSpan.FromMinutes(5); + manager.MaxFailedAccessAttemptsBeforeLockout = 5; + + // Register two factor authentication providers. This application uses Phone and Emails as a step of receiving a code for verifying the user + // You can write your own provider and plug it in here. + manager.RegisterTwoFactorProvider("Phone Code", new PhoneNumberTokenProvider + { + MessageFormat = "Your security code is {0}" + }); + manager.RegisterTwoFactorProvider("Email Code", new EmailTokenProvider + { + Subject = "Security Code", + BodyFormat = "Your security code is {0}" + }); + manager.EmailService = new EmailService(); + manager.SmsService = new SmsService(); + var dataProtectionProvider = options.DataProtectionProvider; + if (dataProtectionProvider != null) + { + manager.UserTokenProvider = + new DataProtectorTokenProvider(dataProtectionProvider.Create("ASP.NET Identity")); + } + return manager; + } + } + + // Configure the application sign-in manager which is used in this application. + public class ApplicationSignInManager : SignInManager + { + public ApplicationSignInManager(ApplicationUserManager userManager, IAuthenticationManager authenticationManager) + : base(userManager, authenticationManager) + { + } + + public override Task CreateUserIdentityAsync(ApplicationUser user) + { + return user.GenerateUserIdentityAsync((ApplicationUserManager)UserManager); + } + + public static ApplicationSignInManager Create(IdentityFactoryOptions options, IOwinContext context) + { + return new ApplicationSignInManager(context.GetUserManager(), context.Authentication); + } + } +} diff --git a/Amen/App_Start/RouteConfig.cs b/Amen/App_Start/RouteConfig.cs new file mode 100644 index 0000000..251be08 --- /dev/null +++ b/Amen/App_Start/RouteConfig.cs @@ -0,0 +1,85 @@ +using Amen.Controllers; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; +using System.Web.Mvc; +using System.Web.Routing; + +namespace Amen +{ + public class RouteConfig + { + public static void RegisterRoutes(RouteCollection routes) + { + routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); + + routes.MapRoute( + name: "APIRoute", + url: "API/{action}/{id}", // URL with parameters + defaults: new { controller = "API", action = "Index", id = UrlParameter.Optional, affiliatekey = ControllerHelper.DefaultAffiliateKey } + ); + + routes.MapRoute( + name: "HomeRoute", + url: "Home/{action}/{id}", // URL with parameters + defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional, affiliatekey = ControllerHelper.DefaultAffiliateKey } + ); + + routes.MapRoute( + name: "AccountRoute", + url: "Account/{action}/{id}", // URL with parameters + defaults: new { controller = "Account", action = "Index", id = UrlParameter.Optional, affiliatekey = ControllerHelper.DefaultAffiliateKey } + ); + + routes.MapRoute( + name: "ManageRoute", + url: "Manage/{action}/{id}", // URL with parameters + defaults: new { controller = "Manage", action = "Index", id = UrlParameter.Optional, affiliatekey = ControllerHelper.DefaultAffiliateKey } + ); + + routes.MapRoute( + name: "NotificationRout", + url: "Notification/{action}/{id}", // URL with parameters + defaults: new { controller = "Notification", action = "Index", id = UrlParameter.Optional, affiliatekey = ControllerHelper.DefaultAffiliateKey } + ); + + routes.MapRoute( + name: "PrayerRoute", + url: "Prayer/{action}/{id}", // URL with parameters + defaults: new { controller = "Prayer", action = "Index", id = UrlParameter.Optional, affiliatekey = ControllerHelper.DefaultAffiliateKey } + ); + + routes.MapRoute( + name: "AffiliateAdminRoute", + url: "Affiliate/{action}/{id}", // URL with parameters + defaults: new { controller = "Affiliate", action = "Index", id = UrlParameter.Optional, affiliatekey = ControllerHelper.DefaultAffiliateKey } + ); + + routes.MapRoute( + name: "AffiliateGroupAliasRoute", + url: "Group/{action}/{id}", // URL with parameters + defaults: new { controller = "Affiliate", action = "Index", id = UrlParameter.Optional, affiliatekey = ControllerHelper.DefaultAffiliateKey } + ); + + routes.MapRoute( + name: "CSSRoute", + url: "CSS/{action}/{id}", // URL with parameters + defaults: new { controller = "CSS", action = "GetTheme", id = UrlParameter.Optional, affiliatekey = ControllerHelper.DefaultAffiliateKey } + ); + + routes.MapRoute( + name: "AffiliateGroupPrayerRoute", + url: "{affiliatekey}/Group/{action}/{id}", // URL with parameters + defaults: new { controller = "Affiliate", action = "Index", id = UrlParameter.Optional, affiliatekey = ControllerHelper.DefaultAffiliateKey } + ); + + routes.MapRoute( + name: "AffiliatePrayerRoute", + url: "{affiliatekey}/{controller}/{action}/{id}", // URL with parameters + defaults: new { controller = "Prayer", action = "Index", id = UrlParameter.Optional, affiliatekey = ControllerHelper.DefaultAffiliateKey } + ); + + } + } +} diff --git a/Amen/App_Start/Startup.Auth.cs b/Amen/App_Start/Startup.Auth.cs new file mode 100644 index 0000000..f5a51b8 --- /dev/null +++ b/Amen/App_Start/Startup.Auth.cs @@ -0,0 +1,93 @@ +using System; +using Microsoft.AspNet.Identity; +using Microsoft.AspNet.Identity.Owin; +using Microsoft.Owin; +using Microsoft.Owin.Security.Cookies; +using Microsoft.Owin.Security.Google; +using Owin; +using Amen.Models; +using Microsoft.Owin.Security.Facebook; +using System.Threading.Tasks; +using System.Configuration; +using System.Security.Claims; + +namespace Amen +{ + public partial class Startup + { + // For more information on configuring authentication, please visit http://go.microsoft.com/fwlink/?LinkId=301864 + public void ConfigureAuth(IAppBuilder app) + { + // Configure the db context, user manager and signin manager to use a single instance per request + app.CreatePerOwinContext(ApplicationDbContext.Create); + app.CreatePerOwinContext(ApplicationUserManager.Create); + app.CreatePerOwinContext(ApplicationSignInManager.Create); + + // Enable the application to use a cookie to store information for the signed in user + // and to use a cookie to temporarily store information about a user logging in with a third party login provider + // Configure the sign in cookie + app.UseCookieAuthentication(new CookieAuthenticationOptions + { + AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie, + LoginPath = new PathString("/Account/Login"), + Provider = new CookieAuthenticationProvider + { + // Enables the application to validate the security stamp when the user logs in. + // This is a security feature which is used when you change a password or add an external login to your account. + OnValidateIdentity = SecurityStampValidator.OnValidateIdentity( + validateInterval: TimeSpan.FromMinutes(30), + regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager)) + } + }); + app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie); + + // Enables the application to temporarily store user information when they are verifying the second factor in the two-factor authentication process. + app.UseTwoFactorSignInCookie(DefaultAuthenticationTypes.TwoFactorCookie, TimeSpan.FromMinutes(5)); + + // Enables the application to remember the second login verification factor such as phone or email. + // Once you check this option, your second step of verification during the login process will be remembered on the device where you logged in from. + // This is similar to the RememberMe option when you log in. + app.UseTwoFactorRememberBrowserCookie(DefaultAuthenticationTypes.TwoFactorRememberBrowserCookie); + + // Uncomment the following lines to enable logging in with third party login providers + //app.UseMicrosoftAccountAuthentication( + // clientId: "", + // clientSecret: ""); + + //app.UseTwitterAuthentication( + // consumerKey: "", + // consumerSecret: ""); + + + //dev app id + //app.UseFacebookAuthentication( + // appId: "632247943624667", + // appSecret: "6e7ea1d9453593071b1bc350cda718b7"); + + app.UseFacebookAuthentication(new FacebookAuthenticationOptions + { + //AppId = "1837084549899587", + //AppSecret = "53452d285d8cf760f8fe8da491ddfb20", + + AppId = ConfigurationManager.AppSettings["FacebookAppId"], + AppSecret = ConfigurationManager.AppSettings["FacebookAppSecret"], + Scope = { "email" }, + Provider = new FacebookAuthenticationProvider + { + OnAuthenticated = context => + { + context.Identity.AddClaim(new System.Security.Claims.Claim("FacebookAccessToken", context.AccessToken)); + return Task.FromResult(true); + } + }, + //BackchannelHttpHandler = new FacebookBackChannelHandler() + }); + + //app.UseGoogleAuthentication(new GoogleOAuth2AuthenticationOptions() + //{ + // ClientId = "", + // ClientSecret = "" + //}); + } + } +} \ No newline at end of file diff --git a/Amen/App_Start/WebApiConfig.cs b/Amen/App_Start/WebApiConfig.cs new file mode 100644 index 0000000..0877222 --- /dev/null +++ b/Amen/App_Start/WebApiConfig.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web.Http; + +namespace Amen +{ + public static class WebApiConfig + { + public static void Register(HttpConfiguration config) + { + // Web API configuration and services + + // Web API routes + config.MapHttpAttributeRoutes(); + + config.Routes.MapHttpRoute( + name: "DefaultApi", + routeTemplate: "api/{controller}/{id}", + defaults: new { id = RouteParameter.Optional } + ); + } + } +} diff --git a/Amen/Content/Images/Blank.png b/Amen/Content/Images/Blank.png new file mode 100644 index 0000000..1e3ee07 Binary files /dev/null and b/Amen/Content/Images/Blank.png differ diff --git a/Amen/Content/Images/ajax-loader-2.gif b/Amen/Content/Images/ajax-loader-2.gif new file mode 100644 index 0000000..0ca7ada Binary files /dev/null and b/Amen/Content/Images/ajax-loader-2.gif differ diff --git a/Amen/Content/Images/ajax-loader.gif b/Amen/Content/Images/ajax-loader.gif new file mode 100644 index 0000000..d0bce15 Binary files /dev/null and b/Amen/Content/Images/ajax-loader.gif differ diff --git a/Amen/Content/Images/amen-logo-flyin.gif b/Amen/Content/Images/amen-logo-flyin.gif new file mode 100644 index 0000000..9438ebb Binary files /dev/null and b/Amen/Content/Images/amen-logo-flyin.gif differ diff --git a/Amen/Content/Images/amenico100.png b/Amen/Content/Images/amenico100.png new file mode 100644 index 0000000..a41e465 Binary files /dev/null and b/Amen/Content/Images/amenico100.png differ diff --git a/Amen/Content/Images/fb-share-logo-small.png b/Amen/Content/Images/fb-share-logo-small.png new file mode 100644 index 0000000..b10e39c Binary files /dev/null and b/Amen/Content/Images/fb-share-logo-small.png differ diff --git a/Amen/Content/Images/fb-share-logo.png b/Amen/Content/Images/fb-share-logo.png new file mode 100644 index 0000000..75f9323 Binary files /dev/null and b/Amen/Content/Images/fb-share-logo.png differ diff --git a/Amen/Content/Images/poweredbyamenprayer.png b/Amen/Content/Images/poweredbyamenprayer.png new file mode 100644 index 0000000..bdf173c Binary files /dev/null and b/Amen/Content/Images/poweredbyamenprayer.png differ diff --git a/Amen/Content/PagedList.css b/Amen/Content/PagedList.css new file mode 100644 index 0000000..d9b9f5d --- /dev/null +++ b/Amen/Content/PagedList.css @@ -0,0 +1,166 @@ +.pagination { + display: inline-block; + padding-left: 0; + margin: 20px 0; + border-radius: 4px; +} + +.pagination > li { + display: inline; +} + +.pagination > li > a, +.pagination > li > span { + position: relative; + float: left; + padding: 6px 12px; + margin-left: -1px; + line-height: 1.428571429; + text-decoration: none; + background-color: #ffffff; + border: 1px solid #dddddd; +} + +.pagination > li:first-child > a, +.pagination > li:first-child > span { + margin-left: 0; + border-bottom-left-radius: 4px; + border-top-left-radius: 4px; +} + +.pagination > li:last-child > a, +.pagination > li:last-child > span { + border-top-right-radius: 4px; + border-bottom-right-radius: 4px; +} + +.pagination > li > a:hover, +.pagination > li > span:hover, +.pagination > li > a:focus, +.pagination > li > span:focus { + background-color: #eeeeee; +} + +.pagination > .active > a, +.pagination > .active > span, +.pagination > .active > a:hover, +.pagination > .active > span:hover, +.pagination > .active > a:focus, +.pagination > .active > span:focus { + z-index: 2; + color: #ffffff; + cursor: default; + background-color: #428bca; + border-color: #428bca; +} + +.pagination > .disabled > span, +.pagination > .disabled > a, +.pagination > .disabled > a:hover, +.pagination > .disabled > a:focus { + color: #999999; + cursor: not-allowed; + background-color: #ffffff; + border-color: #dddddd; +} + +.pagination-lg > li > a, +.pagination-lg > li > span { + padding: 10px 16px; + font-size: 18px; +} + +.pagination-lg > li:first-child > a, +.pagination-lg > li:first-child > span { + border-bottom-left-radius: 6px; + border-top-left-radius: 6px; +} + +.pagination-lg > li:last-child > a, +.pagination-lg > li:last-child > span { + border-top-right-radius: 6px; + border-bottom-right-radius: 6px; +} + +.pagination-sm > li > a, +.pagination-sm > li > span { + padding: 5px 10px; + font-size: 12px; +} + +.pagination-sm > li:first-child > a, +.pagination-sm > li:first-child > span { + border-bottom-left-radius: 3px; + border-top-left-radius: 3px; +} + +.pagination-sm > li:last-child > a, +.pagination-sm > li:last-child > span { + border-top-right-radius: 3px; + border-bottom-right-radius: 3px; +} + +.pager { + padding-left: 0; + margin: 20px 0; + text-align: center; + list-style: none; +} + +.pager:before, +.pager:after { + display: table; + content: " "; +} + +.pager:after { + clear: both; +} + +.pager:before, +.pager:after { + display: table; + content: " "; +} + +.pager:after { + clear: both; +} + +.pager li { + display: inline; +} + +.pager li > a, +.pager li > span { + display: inline-block; + padding: 5px 14px; + background-color: #ffffff; + border: 1px solid #dddddd; + border-radius: 15px; +} + +.pager li > a:hover, +.pager li > a:focus { + text-decoration: none; + background-color: #eeeeee; +} + +.pager .next > a, +.pager .next > span { + float: right; +} + +.pager .previous > a, +.pager .previous > span { + float: left; +} + +.pager .disabled > a, +.pager .disabled > a:hover, +.pager .disabled > a:focus, +.pager .disabled > span { + color: #999999; + cursor: not-allowed; + background-color: #ffffff; +} \ No newline at end of file diff --git a/Amen/Content/Site.css b/Amen/Content/Site.css new file mode 100644 index 0000000..5adc532 --- /dev/null +++ b/Amen/Content/Site.css @@ -0,0 +1,581 @@ +/* +$SiteLightColor: #FDEFEF; +$SiteMediumColor: rgba(172, 25, 25, 0.5); +$SiteDarkColor: #741111; +$SiteForeground: #ffffff; +$SiteForegroundHover: #F9D4D4; +$SiteBorder: #F7CACA; +$SiteButtonHilight: #F9D9D9; + +*/ +body { + padding-top: 0px; + padding-bottom: 20px; + font-family: "Source Sans Pro", sans-serif; + font-size: 15px; } + +.container { + padding-right: 0px; + padding-left: 0px; + margin-right: auto; + margin-left: auto; } + +h2 { + color: #1a346b; + font-weight: 200; } + +a { + color: #1a346b; + text-decoration: none; } + +/* Set padding to keep content from hitting the edges */ +.body-content { + padding-left: 15px; + padding-right: 15px; } + +.btn.btn-default.prayer-item-edit-submit { + background: #dcecf7; + padding-left: 40px; + padding-right: 40px; + margin-top: 20px; + float: left; } + +.btn.btn-default.prayer-item-edit-cancel { + padding-left: 40px; + padding-right: 40px; + margin-top: 20px; + float: left; } + +/* Override the default bootstrap behavior where horizontal description lists + will truncate terms that are too long to fit in the left column +*/ +.dl-horizontal dt { + white-space: normal; } + +/* Set width on the form input elements since they're 100% wide by default */ +html, body { + height: 100%; } + +#wrap { + min-height: 100%; + padding-left: 15px; + padding-right: 15px; } + +#main { + overflow: auto; + padding-bottom: 40px; + /* this needs to be bigger than footer height*/ + max-width: 940px; + padding-top: 91px; } + +.prayer-item-popup-container { + max-width: 940px; + margin-left: auto; + margin-right: auto; } + +@media (min-width: 1095px) { + #main { + padding-top: 0px; } } + +.prayer-instructions { + margin-bottom: 20px; + margin-top: 0px; + padding: 10px; } + +.prayer-item-edit-instructions { + margin-bottom: 10px; + margin-top: 20px; + padding: 10px; } + +.footer { + position: relative; + margin-top: -40px; + /* negative value of footer height */ + height: 40px; + clear: both; + padding-top: 30px; + text-align: center; } + +.enable-animation { + -webkit-transition: .3s ease-in-out; + -moz-transition: .3s ease-in-out; + -o-transition: .3s ease-in-out; + -ms-transition: .3s ease-in-out; + transition: .3s ease-in-out; } + +.transparent { + opacity: 0; + pointer-events: none; } + +.page-top { + position: fixed; + bottom: 20px; + right: 15px; + width: 100px; + height: 40px; + line-height: 40px; + text-align: center; + background-color: rgba(91, 131, 165, 0.7); + color: #fff !important; + text-decoration: none !important; + opacity: 0.0; + z-index: 1000; + pointer-events: none; } + +.full-page-shim { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color: rgba(0, 0, 0, 0.5); + z-index: 1000; } + +.page-top.page-top-visible { + opacity: 1.0; + pointer-events: all; } + +.page-top.page-top-faded { + opacity: 0.5; } + +.page-top.page-top-faded:hover { + opacity: 1.0; } + +.prayer-item { + position: relative; + width: 100%; + min-height: 80px; + border: 1px solid #d8e2e9; + padding: 15px; + padding-top: 8px; + margin-bottom: 20px; + margin-top: 10px; + box-shadow: 0px 4px 4px #F3F6F9; + background: white; } + +.prayer-item-prayed div { + display: inline-block; + margin: 0; } + +.prayer-item-sort { + display: inline-block; + margin-top: 10px; + float: right; } + + +.prayer-item-name-location{ + padding-right: 5px; + display: inline-block; + color: #1a346b; } + +@media (max-width: 480px) { + +.prayer-item-name-location{ + display: block; } + + .prayer-item-sort { + display: none; } } + +.prayer-item-sort .selected { + text-decoration: none !important; + color: #1a346b; + font-weight: bold; } + +.prayer-item-new-actions { + display: inline-block; + float: left; + margin-bottom: 5px; } + +.prayer-item-new-add { + background: #d8e2e9; } + +.prayer-item-actions { + display: inline; +} + +.prayer-item-content { + margin-bottom: 20px; + margin-top: 5px; } + +.prayer-item-summary { + font-size: 18px; + margin-top: 10px; + font-weight: bold; + color: #1a346b; } + +.prayer-item-submitted { + display: inline-block; + color: rgba(91, 131, 165, 0.7); } + +.prayer-item-prayed { + float: left; + margin-right: 2px; } + +.prayer-item-prayed .btn.btn-default { + padding-left: 35px; + padding-right: 35px; } + +.prayer-item-prayed .btn { + padding-left: 15px; + padding-right: 15px; } + +.prayer-item-prayed-count { + font-weight: bold; + font-size: 16px; + margin-right: 1px; } + +.prayer-item-flag, .prayer-item-edit, .prayer-item-sendnote { + position: absolute; + top: 70px; + left: 0px; + width: 100%; + height: 100%; + padding: 20px; + background-color: #fff; + z-index: 1001; } + +.prayer-item-edit input[type=text], +.prayer-item-edit textarea, +.prayer-item-flag input[type=text], +.prayer-item-flag textarea, +.prayer-item-sendnote input[type=text], +.prayer-item-sendnote textarea, +.prayer-item-edit select { + width: 100%; + min-width: 100%; + margin-bottom: 20px; } + +.prayer-item-edit-cancel, +.prayer-item-edit-submit, +.prayer-item-flag-cancel, +.prayer-item-flag-submit, +.prayer-item-sendnote-cancel, +.prayer-item-sendnote-submit { + float: right; + margin-left: 5px; } + +.prayer-item-edit .checkbox { + font-size: 13px; } + +.prayer-item-prayer-stats { + color: rgba(91, 131, 165, 0.7); + float: right; + margin: 10px; + top: 0px; + right: 10px; + position: absolute; } + + .prayer-item-logo{ + position: absolute; + bottom: 15px; + right: 10px; + } + +.navbar-inverse { + background-color: #ffffff; + border-color: #d8e2e9; + font-family: 'Open Sans', sans-serif; } + +.navbar-inverse .navbar-toggle .icon-bar { + background-color: #1a346b; } + +.navbar-inverse .navbar-brand { + color: #1a346b; + font-size: 22px; + margin-right: 30px; + padding-left: 25px; + padding-right: 25px; } + +.navbar-inverse .navbar-toggle { + border-color: #d8e2e9; } + +.navbar-toggle { + position: relative; + float: right; + padding: 9px 10px; + margin-top: 18px; + margin-bottom: 8px; + background-color: transparent; + border: 1px solid transparent; + border-radius: 0px; + margin-right: 30px; } + +.navbar { + max-width: 940px; + margin-right: auto !important; + margin-left: auto !important; + width: 100%; } + +.navbar-inverse .navbar-collapse, .navbar-inverse .navbar-form { + border-color: rgba(91, 131, 165, 0.7); } + +.navbar-inverse .navbar-toggle:hover, .navbar-inverse .navbar-toggle:focus { + background-color: #F3F6F9; } + +.navbar-inverse .navbar-brand:hover, .navbar-inverse .navbar-brand:focus { + color: #1a346b; + background-color: #d8e2e9; } + +.navbar-inverse .navbar-nav > li > a { + font-size: 18px; + color: #1a346b; } + +.navbar-nav > li > a { + padding-top: 10px; + padding-bottom: 10px; + margin-bottom: 10px; + margin-top: 15px; + margin-right: 10px; } + +@media (min-width: 768px) { + .navbar-nav > li > a.selected, + .navbar-nav > li > a:active { + border-bottom: 2px solid #1a346b; + margin-right: 10px; } + .navbar-nav { + margin-left: 40px; } + .navbar-inverse .navbar-nav > li > a:hover, .navbar-inverse .navbar-nav > li > a:focus { + color: #1a346b; + background-color: #F3F6F9; + border-bottom: 2px solid rgba(91, 131, 165, 0.7); } } + +.navbar-inverse .navbar-nav > li > a:hover, .navbar-inverse .navbar-nav > li > a:focus { + color: #1a346b; + background-color: #F3F6F9; } + +.container > .navbar-header, .container > .navbar-collapse { + margin-left: 0px; } + +.affiliate-logo-link { + float: right; } + +.affiliate-logo { + height: 50px; + margin: 10px; } + +.btn { + display: inline-block; + margin-bottom: 0; + text-align: center; + white-space: nowrap; + vertical-align: middle; + cursor: pointer; + border-radius: 0px; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + -o-user-select: none; + user-select: none; + font-family: "Source Sans Pro", sans-serif; + border: none; + color: #1a346b; + text-align: center; + text-decoration: none; + display: inline-block; + font-size: 15px; + border: 1px solid #d8e2e9; + background: #F3F6F9; } + +.btn:hover { + border: 1px solid rgba(91, 131, 165, 0.7); + background: white; } + +.fa { + color: #1a346b; } + +.lefticon { + margin-right: 10px; } + +.actions-collapse { + top: 0px; + left: 0px; + width: 100%; + z-index: 1000; + margin-bottom: 35px; + clear: both; } + +.actions-expaned-btn { + margin-bottom: 0; + text-align: center; + white-space: nowrap; + vertical-align: middle; + cursor: pointer; + border-radius: 0px; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + -o-user-select: none; + user-select: none; + font-family: "Source Sans Pro", sans-serif; + border: none; + color: #1a346b; + text-align: left; + text-decoration: none; + display: block; + font-size: 15px; + border: 1px solid #d8e2e9; + background: #F3F6F9; + padding-left: 20px; + padding-top: 10px; + padding-bottom: 10px; } + +.actions-toggle-btn { + background: transparent; + border: 1px solid transparent; } + +.back-nav-link { + font-size: 16px; } + +.backnav { + margin-right: 6px; } + +.prayer-item-submitted.detail { + margin-top: 20px; } + +.form-horizontal .form-group, .row { + margin-left: 0 !important; + margin-right: 0 !important; } + +.form-control { + border-radius: 4px; } + +label { + display: inline-block; + margin-bottom: 5px; + font-weight: bold; + color: #1a346b; } + +.copyright { + color: rgba(91, 131, 165, 0.7); } + +@media (min-width: 768px) { + .container { + max-width: none; } } + +@media (min-width: 992px) { + .container { + max-width: none; } } + +.affiliate-select { + list-style-type: none; + margin: 0px; + padding: 0px; } + +.affiliate-select li { + margin: 5px; } + +.affiliate-select li a { + width: 100%; + clear: both; + float: left; + border: 1px solid #d8e2e9; } + +.affiliate-select li a:hover { + background: #F3F6F9; + border: 1px solid #1a346b; + text-decoration: none; } + +.select-header { + color: #1a346b; } + +.moretoggle::after { + content: "more"; + margin-left: 6px; + margin-right: 6px; + font-family: "Source Sans Pro", sans-serif; } + +.lesstoggle::after { + content: "less"; + margin-left: 6px; + margin-right: 6px; + font-family: "Source Sans Pro", sans-serif; } + +.moretoggle::before { + content: "\f107"; + margin-left: 6px; + display: inline-block; + font: normal normal normal 14px/1 FontAwesome; + font-size: inherit; + text-rendering: auto; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; } + +.lesstoggle::before { + content: "\f106"; + margin-left: 6px; + display: inline-block; + font: normal normal normal 14px/1 FontAwesome; + font-size: inherit; + text-rendering: auto; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; } + +@media all and (orientation: landscape) { + .navbar-fixed-top, .navbar-fixed-bottom { + position: relative; } + #main { + padding-top: 0px; } } + +.full-page-shim { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color: white; + z-index: 1000; } + +.radio label, .checkbox label { + display: inline; + margin-bottom: 5px; + font-weight: normal; + cursor: pointer; } + +.fixedContainer { + position: fixed; } + +.relativeContainer { + position: relative; } + +.dl-horizontal dt, .dl-horizontal dd { + text-align: left; + margin-bottom: 20px; + border-top: 1px solid rgba(91, 131, 165, 0.3); + padding: 10px; } + +.dl-horizontal dd { + background: #F3F6F9; + box-shadow: inset 0px 0px 5px rgba(91, 131, 165, 0.3); + color: rgba(91, 131, 165, 0.7); } + +@media (min-width: 768px) { + .form-horizontal .control-label { + text-align: left; } } + +.form-control { + border-radius: 0px; + margin-top: 10px; } + +.form-group { + margin-bottom: 25px; + border-top: 1px solid #e4e4e4; } + +.text-right { + text-align: right; + margin-bottom: 20px; + margin-top: 15px; } + +.in-iframe #main { + padding-top: 0px; } + +.in-iframe .navbar { + display: none; } + +.poweredbycontainer { + width: 100%; + text-align: center; } + +.poweredby { + margin-top: 40px; + margin-right: auto; + margin-left: auto; } diff --git a/Amen/Content/Site.scss b/Amen/Content/Site.scss new file mode 100644 index 0000000..42335fd --- /dev/null +++ b/Amen/Content/Site.scss @@ -0,0 +1,724 @@ +$LargeScreenSiteWidth: 940px; +$SiteFontFamily: 'Source Sans Pro', sans-serif; + + +$SiteLightColor: #F3F6F9; +$SiteMediumShadowColor: rgba(91, 131, 165, 0.3); +$SiteMediumColor: rgba(91, 131, 165, 0.7); +$SiteDarkColor: #1a346b; +$SiteForeground: #ffffff; +$SiteForegroundHover: #DCEDF1; +$SiteBorder: #d8e2e9; +$SiteButtonHilight: #dcecf7; + +/* +$SiteLightColor: #FDEFEF; +$SiteMediumColor: rgba(172, 25, 25, 0.5); +$SiteDarkColor: #741111; +$SiteForeground: #ffffff; +$SiteForegroundHover: #F9D4D4; +$SiteBorder: #F7CACA; +$SiteButtonHilight: #F9D9D9; + +*/ + + +body { + padding-top: 0px; + padding-bottom: 20px; + font-family: $SiteFontFamily; + font-size:15px; +} +.container { + padding-right: 0px; + padding-left: 0px; + margin-right: auto; + margin-left: auto; + +} + +h2 { + color: $SiteDarkColor; + font-weight: 200; +} + +a { + color: $SiteDarkColor; + text-decoration: none; +} + + +/* Set padding to keep content from hitting the edges */ +.body-content { + padding-left: 15px; + padding-right: 15px; +} + +.btn.btn-default.prayer-item-edit-submit +{ + background: $SiteButtonHilight; + padding-left:40px; + padding-right:40px; + margin-top:20px; + float:left; +} +.btn.btn-default.prayer-item-edit-cancel +{ + padding-left:40px; + padding-right:40px; + margin-top:20px; + float:left; +} + +/* Override the default bootstrap behavior where horizontal description lists + will truncate terms that are too long to fit in the left column +*/ +.dl-horizontal dt { + white-space: normal; +} + +/* Set width on the form input elements since they're 100% wide by default */ +input, +select, +textarea { + +} + +html, body { + height: 100%; +} + +#wrap { + min-height: 100%; + padding-left: 15px; + padding-right: 15px; + +} + +#main { + overflow: auto; + padding-bottom: 40px; /* this needs to be bigger than footer height*/ + max-width: $LargeScreenSiteWidth; + padding-top: 91px; +} +.prayer-item-popup-container { + max-width: $LargeScreenSiteWidth; + margin-left:auto; + margin-right:auto; +} + +@media (min-width: 1095px){ +#main { + padding-top: 0px; +} + +} + +.prayer-instructions { + margin-bottom: 20px; + margin-top: 0px; + padding: 10px; + +} + +.prayer-item-edit-instructions { + margin-bottom: 10px; + margin-top: 20px; + padding: 10px; + +} + +.footer { + position: relative; + margin-top: -40px; /* negative value of footer height */ + height: 40px; + clear: both; + padding-top: 30px; + text-align: center; +} + +.enable-animation { + -webkit-transition: .3s ease-in-out; + -moz-transition: .3s ease-in-out; + -o-transition: .3s ease-in-out; + -ms-transition: .3s ease-in-out; + transition: .3s ease-in-out; +} + +.transparent{ + opacity: 0; + pointer-events: none; +} + +.page-top { + position: fixed; + bottom: 20px; + right: 15px; + width: 100px; + height: 40px; + line-height: 40px; + text-align: center; + background-color: $SiteMediumColor; + color: #fff !important; + text-decoration: none !important; + opacity: 0.0; + z-index: 1000; + pointer-events: none; +} +.full-page-shim{ + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color: rgba(0,0,0,0.5); + z-index: 1000; +} + + .page-top.page-top-visible { + opacity: 1.0; + pointer-events: all; + } + + .page-top.page-top-faded { + opacity: 0.5; + } + + .page-top.page-top-faded:hover { + opacity: 1.0; + } + +.prayer-item { + position: relative; + width: 100%; + min-height: 80px; + border: 1px solid $SiteBorder; + padding: 15px; + padding-top:8px; + margin-bottom: 20px; + margin-top: 10px; + box-shadow: 0px 4px 4px $SiteLightColor; + background: white; +} + +.prayer-item-prayed div { + display: inline-block; + margin: 0; +} + +.prayer-item-sort{ + display: inline-block; + margin-top: 10px; + float:right; +} + +.prayer-item-name-location{ + padding-right: 5px; + display: inline-block; + color: $SiteDarkColor; +} + +@media (max-width: 480px) { + .prayer-item-name-location{ + display: block; + } + + .prayer-item-sort { + display: none; + } +} + +.prayer-item-sort .selected { + text-decoration: none !important; + color: $SiteDarkColor; + font-weight: bold; +} + +.prayer-item-new-actions{ + display: inline-block; + float: left; + margin-bottom: 5px; +} + +.prayer-item-new-add{ + background: $SiteBorder; +} + +.prayer-item-actions { + display:inline; +} + +.prayer-item-content { + margin-bottom:20px; + margin-top:5px; +} + +.prayer-item-summary { + font-size: 18px; + margin-top:10px; + font-weight: bold; + color: $SiteDarkColor; +} + +.prayer-item-submitted { + + display: inline-block; + color: $SiteMediumColor; + +} + +.prayer-item-prayed { + float:left; + margin-right:2px; +} + +.prayer-item-prayed .btn.btn-default { + padding-left:35px; + padding-right:35px; +} +.prayer-item-prayed .btn{ + padding-left:15px; + padding-right:15px; +} +.prayer-item-prayed-count{ +font-weight: bold; +font-size: 16px; + margin-right: 1px; + +} + + +.prayer-item-flag, .prayer-item-edit, .prayer-item-sendnote { + position: absolute; + top: 70px; + left: 0px; + width: 100%; + height: 100%; + padding: 20px; + background-color: #fff; + z-index: 1001; +} + + .prayer-item-edit input[type=text], + .prayer-item-edit textarea, + .prayer-item-flag input[type=text], + .prayer-item-flag textarea, + .prayer-item-sendnote input[type=text], + .prayer-item-sendnote textarea, + .prayer-item-edit select + { + width: 100%; + min-width: 100%; + margin-bottom: 20px; + } + + .prayer-item-edit-cancel, + .prayer-item-edit-submit, + + .prayer-item-flag-cancel, + .prayer-item-flag-submit, + + .prayer-item-sendnote-cancel, + .prayer-item-sendnote-submit{ + float: right; + margin-left: 5px; + } + + + .prayer-item-edit .checkbox{ + font-size: 13px; + } + + .prayer-item-prayer-stats{ + color:$SiteMediumColor; + float: right; + margin: 10px; + top: 0px; + right: 10px; + position: absolute; +} + + .prayer-item-logo{ + position: absolute; + bottom: 15px; + right: 10px; + } + + .navbar-inverse { + background-color: $SiteForeground; + border-color: $SiteBorder; + font-family: 'Open Sans', sans-serif; +} + +.navbar-inverse .navbar-toggle .icon-bar { + background-color: $SiteDarkColor; +} + +.navbar-inverse .navbar-brand { + color:$SiteDarkColor; + font-size:22px; + margin-right:30px; + padding-left:25px; + padding-right: 25px; +} + +.navbar-inverse .navbar-toggle { + border-color: $SiteBorder; +} + +.navbar-toggle { + position: relative; + float: right; + padding: 9px 10px; + margin-top: 18px; + margin-bottom: 8px; + background-color: transparent; + border: 1px solid transparent; + border-radius: 0px; + margin-right:30px; +} + +.navbar { + max-width: $LargeScreenSiteWidth; + margin-right: auto !important; + margin-left: auto !important; + width: 100%; + +} + +.navbar-inverse .navbar-collapse, .navbar-inverse .navbar-form { + border-color: $SiteMediumColor; +} + + +.navbar-inverse .navbar-toggle:hover, .navbar-inverse .navbar-toggle:focus { + background-color: $SiteLightColor; +} + +.navbar-inverse .navbar-brand:hover, .navbar-inverse .navbar-brand:focus { + color:$SiteDarkColor; + background-color: $SiteBorder; +} + +.navbar-inverse .navbar-nav > li > a { + font-size:18px; + color:$SiteDarkColor; +} + +.navbar-nav > li > a { + padding-top: 10px; + padding-bottom: 10px; + margin-bottom:10px; + margin-top:15px; + margin-right: 10px; + +} +@media (min-width: 768px){ +.navbar-nav > li > a.selected, +.navbar-nav > li > a:active { + border-bottom: 2px solid $SiteDarkColor; + margin-right: 10px; +} + +.navbar-nav { + margin-left:40px; +} + + +.navbar-inverse .navbar-nav > li > a:hover, .navbar-inverse .navbar-nav > li > a:focus { + color:$SiteDarkColor; + background-color: $SiteLightColor; + border-bottom: 2px solid $SiteMediumColor; +} +} +.navbar-inverse .navbar-nav > li > a:hover, .navbar-inverse .navbar-nav > li > a:focus { + color:$SiteDarkColor; + background-color: $SiteLightColor; +} + +.container > .navbar-header, .container > .navbar-collapse { + margin-left: 0px; +} + + +.affiliate-logo-link{ + float:right; +} + +.affiliate-logo{ + height:50px; + margin:10px; +} + +.btn { + display: inline-block; + margin-bottom: 0; + text-align: center; + white-space: nowrap; + vertical-align: middle; + cursor: pointer; + border-radius: 0px; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + -o-user-select: none; + user-select: none; + font-family: $SiteFontFamily; + border: none; + color: $SiteDarkColor; + text-align: center; + text-decoration: none; + display: inline-block; + font-size: 15px; + border: 1px solid $SiteBorder; + background: $SiteLightColor; +} +.btn:hover { + border:1px solid $SiteMediumColor; + background: white; +} + +.fa { + color: $SiteDarkColor; +} + +.lefticon { + margin-right: 10px; +} + +.actions-collapse +{ + top: 0px; + left:0px; + width: 100%; + z-index: 1000; + margin-bottom: 35px; + clear:both; +} + +.actions-expaned-btn +{ + margin-bottom: 0; + text-align: center; + white-space: nowrap; + vertical-align: middle; + cursor: pointer; + border-radius: 0px; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + -o-user-select: none; + user-select: none; + font-family: $SiteFontFamily; + border: none; + color: $SiteDarkColor; + text-align: left; + text-decoration: none; + display: block; + font-size: 15px; + border: 1px solid $SiteBorder; + background: $SiteLightColor; + padding-left: 20px; + padding-top:10px; + padding-bottom:10px; +} +.actions-toggle-btn { + background: transparent; + border: 1px solid transparent; +} + +.back-nav-link +{ +font-size:16px; +} +.backnav +{ + margin-right:6px; +} + +.prayer-item-submitted.detail +{ + margin-top:20px; +} + +.form-horizontal .form-group, .row{ + margin-left: 0 !important; + margin-right: 0 !important; +} + +.form-control { + border-radius: 4px; +} + +label { + display: inline-block; + margin-bottom: 5px; + font-weight: bold; + color: $SiteDarkColor; +} + +.copyright +{ + color:$SiteMediumColor; +} + + +@media (min-width: 768px){ +.container { + max-width: none; +} +} + +@media (min-width: 992px){ +.container { + max-width: none; +} + +} + .affiliate-select{ + list-style-type: none; + margin:0px; + padding:0px; + } + .affiliate-select li{ + margin: 5px; + } + .affiliate-select li a{ + width: 100%; + clear:both; + float:left; + border: 1px solid $SiteBorder; + } + .affiliate-select li a:hover{ + background: $SiteLightColor; + border: 1px solid $SiteDarkColor; + text-decoration: none; + + } + .select-header{ + color: $SiteDarkColor; + } + +.moretoggle::after { + content: "more"; + margin-left:6px; + margin-right:6px; + font-family: $SiteFontFamily; +} +.lesstoggle::after { + content: "less"; + margin-left:6px; + margin-right:6px; + font-family: $SiteFontFamily; +} + +.moretoggle::before { + content: "\f107"; + margin-left:6px; + display: inline-block; + font: normal normal normal 14px/1 FontAwesome; + font-size: inherit; + text-rendering: auto; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} +.lesstoggle::before { + content: "\f106"; + margin-left:6px; + display: inline-block; + font: normal normal normal 14px/1 FontAwesome; + font-size: inherit; + text-rendering: auto; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + + +@media all and (orientation:landscape) { +.navbar-fixed-top, .navbar-fixed-bottom { + position: relative; +} +#main { + padding-top: 0px; +} +} + +.full-page-shim { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color:white; + z-index: 1000; +} + +.radio label, .checkbox label { + display: inline; + margin-bottom: 5px; + font-weight: normal; + cursor: pointer; +} +.fixedContainer{ + position:fixed; +} +.relativeContainer{ + position: relative; +} +.dl-horizontal dt, .dl-horizontal dd, { +text-align: left; +margin-bottom: 20px; +border-top: 1px solid $SiteMediumShadowColor; +padding:10px; + + +} +.dl-horizontal dd { +background: $SiteLightColor; +box-shadow: inset 0px 0px 5px $SiteMediumShadowColor; +color: $SiteMediumColor; +} + +@media (min-width: 768px){ +.form-horizontal .control-label { + text-align: left; +} +} + + + +.form-control { + border-radius: 0px; + margin-top:10px; +} +.form-group { + margin-bottom: 25px; +border-top: 1px solid #e4e4e4; + + +} +.text-right { + text-align: right; + margin-bottom: 20px; + margin-top: 15px; +} + +.in-iframe #main { + padding-top:0px; +} + +.in-iframe .navbar { + display:none; +} + +.poweredbycontainer +{ + width:100%; + text-align: center; +} +.poweredby +{ + margin-top: 40px; + margin-right: auto; + margin-left:auto; +} \ No newline at end of file diff --git a/Amen/Content/SiteCustom.css b/Amen/Content/SiteCustom.css new file mode 100644 index 0000000..a28d75a --- /dev/null +++ b/Amen/Content/SiteCustom.css @@ -0,0 +1,187 @@ + + + +/* background behind prayers */ +body +{ + background: rgba(255, 0, 0, 0.05); +} + + /* all hyperlinks */ +a +{ + color: red; +} + + /* all hyperlinks hover state */ +a:hover +{ + color: red; +} + +/* box arond each prayer item */ +.prayer-item +{ + border: 1px solid rgba(255, 0, 0, 0.2); + box-shadow: 0px 4px 4px rgba(255, 0, 0, 0.05); + background: white; +} + +/* title of each prayer */ +.prayer-title { + color: red; + } + + /* title of each prayer */ +.prayer-title:hover { + color: red; + } + + /* date of each prayer */ + .prayer-item-submitted +{ + color:red; +} + + /* number of prayers of each prayer */ +.prayer-item-prayer-stats +{ + color:red; +} + + /* action buttons on each prayer*/ +.btn +{ + color: red; + border: 1px solid rgba(255, 0, 0, 0.3); + background: rgba(255, 0, 0, 0.1); +} + + /* action buttons hover state on each prayer*/ +.btn:hover +{ + color: red; + border: 1px solid rgba(255, 0, 0, 0.7); + background: white; +} + + /* icons */ +.fa +{ + color:red; +} + +/* ************* */ +/* site elements */ +/* ************* */ + +/* message at the top of the prayers list */ +.prayer-instructions { + margin-bottom: 20px; + margin-top: 0px; + padding: 10px; + box-shadow: 0px 4px 4px rgba(255, 0, 0, 0.05); + background-color: rgba(177, 183, 249, 0.12); + border: solid 1px #6666cc; +} + + +/* message above button on submit a prayer page*/ +.prayer-item-edit-instructions { + margin-bottom: 10px; + margin-top: 20px; + padding: 10px; + box-shadow: 0px 4px 4px rgba(255, 0, 0, 0.05); + background-color: rgba(177, 183, 249, 0.12); + border: solid 1px #6666cc; +} + +/* sort UI at top of prayers selected state */ +.prayer-item-sort .selected +{ + color: red; +} + +/* draws the bottom border on the navbar in full width */ +.navbar +{ + border-bottom: 1px solid red; +} + +/* nav bar menu item */ +.navbar-inverse .navbar-nav > li > a { + color: red; +} + +/* nav bar menu item hover state */ +.navbar-inverse .navbar-nav > li > a:hover { + background: rgba(255, 0, 0, 0.1); + color: red; +} + +/* button at bottom that navigates back to top*/ +.page-top +{ + background: rgba(255, 0, 0, 0.7); +} + +/* copyright at bottom of page */ +.copyright +{ + color:red; +} + +/* collapsed navbar border color */ +.navbar-inverse .navbar-collapse, .navbar-inverse .navbar-form { + border-color: red; +} + +/* toggle button at top of page */ +.navbar-toggle.collapsed +{ + color: red; + border: 1px solid rgba(255, 0, 0, 0.3); + background: rgba(255, 0, 0, 0.1); +} + +.navbar-toggle.collapsed:hover +{ + color: red; + border: 1px solid rgba(255, 0, 0, 0.3); + background: rgba(255, 0, 0, 0.1); +} + +.navbar-toggle +{ + color: red; + border: 1px solid rgba(255, 0, 0, 0.3); + background: rgba(255, 0, 0, 0.1); +} + +.navbar-inverse .navbar-toggle:hover, .navbar-inverse .navbar-toggle:focus +{ + background-color: rgba(255, 0, 0, 0.1); + border: 1px solid rgba(255, 0, 0, 0.7); +} + +.navbar-inverse .navbar-toggle .icon-bar +{ + background-color: red; +} + +.navbar-nav > li > a.selected, .navbar-nav > li > a:active +{ + border-bottom: 2px solid red; +} + +.navbar-nav > li > a.selected, .navbar-nav > li > a:hover +{ + border-bottom: 2px solid red; +} + +.navbar-inverse .navbar-nav > li > a:hover, .navbar-inverse .navbar-nav > li > a:focus +{ + border-bottom: 2px solid red; +} + + diff --git a/Amen/Content/bootstrap-tagsinput-typeahead.css b/Amen/Content/bootstrap-tagsinput-typeahead.css new file mode 100644 index 0000000..537cf9c --- /dev/null +++ b/Amen/Content/bootstrap-tagsinput-typeahead.css @@ -0,0 +1,54 @@ +/* + * bootstrap-tagsinput v0.8.0 + * + */ + +.twitter-typeahead .tt-query, +.twitter-typeahead .tt-hint { + margin-bottom: 0; +} + +.twitter-typeahead .tt-hint +{ + display: none; +} + +.tt-menu { + position: absolute; + top: 100%; + left: 0; + z-index: 1000; + display: none; + float: left; + min-width: 160px; + padding: 5px 0; + margin: 2px 0 0; + list-style: none; + font-size: 14px; + background-color: #ffffff; + border: 1px solid #cccccc; + border: 1px solid rgba(0, 0, 0, 0.15); + border-radius: 4px; + -webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175); + box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175); + background-clip: padding-box; + cursor: pointer; +} + +.tt-suggestion { + display: block; + padding: 3px 20px; + clear: both; + font-weight: normal; + line-height: 1.428571429; + color: #333333; + white-space: nowrap; +} + +.tt-suggestion:hover, +.tt-suggestion:focus { + color: #ffffff; + text-decoration: none; + outline: 0; + background-color: #428bca; +} diff --git a/Amen/Content/bootstrap-tagsinput.css b/Amen/Content/bootstrap-tagsinput.css new file mode 100644 index 0000000..7fced30 --- /dev/null +++ b/Amen/Content/bootstrap-tagsinput.css @@ -0,0 +1,60 @@ +/* + * bootstrap-tagsinput v0.8.0 + * + */ + +.bootstrap-tagsinput { + background-color: #fff; + border: 1px solid #ccc; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + display: inline-block; + padding: 4px 6px; + color: #555; + vertical-align: middle; + border-radius: 4px; + max-width: 100%; + line-height: 22px; + cursor: text; +} +.bootstrap-tagsinput input { + border: none; + box-shadow: none; + outline: none; + background-color: transparent; + padding: 0 6px; + margin: 0; + width: auto; + max-width: inherit; +} +.bootstrap-tagsinput.form-control input::-moz-placeholder { + color: #777; + opacity: 1; +} +.bootstrap-tagsinput.form-control input:-ms-input-placeholder { + color: #777; +} +.bootstrap-tagsinput.form-control input::-webkit-input-placeholder { + color: #777; +} +.bootstrap-tagsinput input:focus { + border: none; + box-shadow: none; +} +.bootstrap-tagsinput .tag { + margin-right: 2px; + color: white; +} +.bootstrap-tagsinput .tag [data-role="remove"] { + margin-left: 8px; + cursor: pointer; +} +.bootstrap-tagsinput .tag [data-role="remove"]:after { + content: "x"; + padding: 0px 2px; +} +.bootstrap-tagsinput .tag [data-role="remove"]:hover { + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); +} +.bootstrap-tagsinput .tag [data-role="remove"]:hover:active { + box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); +} diff --git a/Amen/Content/bootstrap-tagsinput.less b/Amen/Content/bootstrap-tagsinput.less new file mode 100644 index 0000000..face63f --- /dev/null +++ b/Amen/Content/bootstrap-tagsinput.less @@ -0,0 +1,50 @@ +.bootstrap-tagsinput { + background-color: #fff; + border: 1px solid #ccc; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + display: inline-block; + padding: 4px 6px; + margin-bottom: 10px; + color: #555; + vertical-align: middle; + border-radius: 4px; + max-width: 100%; + line-height: 22px; + cursor: text; + + input { + border: none; + box-shadow: none; + outline: none; + background-color: transparent; + padding: 0; + margin: 0; + width: auto !important; + max-width: inherit; + + &:focus { + border: none; + box-shadow: none; + } + } + + .tag { + margin-right: 2px; + color: white; + + [data-role="remove"] { + margin-left:8px; + cursor:pointer; + &:after{ + content: "x"; + padding:0px 2px; + } + &:hover { + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + &:active { + box-shadow: inset 0 3px 5px rgba(0,0,0,0.125); + } + } + } + } +} diff --git a/Amen/Content/bootstrap.css b/Amen/Content/bootstrap.css new file mode 100644 index 0000000..6d6e682 --- /dev/null +++ b/Amen/Content/bootstrap.css @@ -0,0 +1,6816 @@ +/* NUGET: BEGIN LICENSE TEXT + * + * Microsoft grants you the right to use these script files for the sole + * purpose of either: (i) interacting through your browser with the Microsoft + * website or online service, subject to the applicable licensing or use + * terms; or (ii) using the files as included with a Microsoft product subject + * to that product's license terms. Microsoft reserves all other rights to the + * files not expressly granted by Microsoft, whether by implication, estoppel + * or otherwise. The notices and licenses below are for informational purposes only. + * + * NUGET: END LICENSE TEXT */ +/*! + * Bootstrap v3.0.0 + * + * Copyright 2013 Twitter, Inc + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Designed and built with all the love in the world by @mdo and @fat. + */ + +/*! normalize.css v2.1.0 | MIT License | git.io/normalize */ + +article, +aside, +details, +figcaption, +figure, +footer, +header, +hgroup, +main, +nav, +section, +summary { + display: block; +} + +audio, +canvas, +video { + display: inline-block; +} + +audio:not([controls]) { + display: none; + height: 0; +} + +[hidden] { + display: none; +} + +html { + font-family: sans-serif; + -webkit-text-size-adjust: 100%; + -ms-text-size-adjust: 100%; +} + +body { + margin: 0; +} + +a:focus { + outline: thin dotted; +} + +a:active, +a:hover { + outline: 0; +} + +h1 { + margin: 0.67em 0; + font-size: 2em; +} + +abbr[title] { + border-bottom: 1px dotted; +} + +b, +strong { + font-weight: bold; +} + +dfn { + font-style: italic; +} + +hr { + height: 0; + -moz-box-sizing: content-box; + box-sizing: content-box; +} + +mark { + color: #000; + background: #ff0; +} + +code, +kbd, +pre, +samp { + font-family: monospace, serif; + font-size: 1em; +} + +pre { + white-space: pre-wrap; +} + +q { + quotes: "\201C" "\201D" "\2018" "\2019"; +} + +small { + font-size: 80%; +} + +sub, +sup { + position: relative; + font-size: 75%; + line-height: 0; + vertical-align: baseline; +} + +sup { + top: -0.5em; +} + +sub { + bottom: -0.25em; +} + +img { + border: 0; +} + +svg:not(:root) { + overflow: hidden; +} + +figure { + margin: 0; +} + +fieldset { + padding: 0.35em 0.625em 0.75em; + margin: 0 2px; + border: 1px solid #c0c0c0; +} + +legend { + padding: 0; + border: 0; +} + +button, +input, +select, +textarea { + margin: 0; + font-family: inherit; + font-size: 100%; +} + +button, +input { + line-height: normal; +} + +button, +select { + text-transform: none; +} + +button, +html input[type="button"], +input[type="reset"], +input[type="submit"] { + cursor: pointer; + -webkit-appearance: button; +} + +button[disabled], +html input[disabled] { + cursor: default; +} + +input[type="checkbox"], +input[type="radio"] { + padding: 0; + box-sizing: border-box; +} + +input[type="search"] { + -webkit-box-sizing: content-box; + -moz-box-sizing: content-box; + box-sizing: content-box; + -webkit-appearance: textfield; +} + +input[type="search"]::-webkit-search-cancel-button, +input[type="search"]::-webkit-search-decoration { + -webkit-appearance: none; +} + +button::-moz-focus-inner, +input::-moz-focus-inner { + padding: 0; + border: 0; +} + +textarea { + overflow: auto; + vertical-align: top; +} + +table { + border-collapse: collapse; + border-spacing: 0; +} + +@media print { + * { + color: #000 !important; + text-shadow: none !important; + background: transparent !important; + box-shadow: none !important; + } + a, + a:visited { + text-decoration: underline; + } + a[href]:after { + content: " (" attr(href) ")"; + } + abbr[title]:after { + content: " (" attr(title) ")"; + } + .ir a:after, + a[href^="javascript:"]:after, + a[href^="#"]:after { + content: ""; + } + pre, + blockquote { + border: 1px solid #999; + page-break-inside: avoid; + } + thead { + display: table-header-group; + } + tr, + img { + page-break-inside: avoid; + } + img { + max-width: 100% !important; + } + @page { + margin: 2cm .5cm; + } + p, + h2, + h3 { + orphans: 3; + widows: 3; + } + h2, + h3 { + page-break-after: avoid; + } + .navbar { + display: none; + } + .table td, + .table th { + background-color: #fff !important; + } + .btn > .caret, + .dropup > .btn > .caret { + border-top-color: #000 !important; + } + .label { + border: 1px solid #000; + } + .table { + border-collapse: collapse !important; + } + .table-bordered th, + .table-bordered td { + border: 1px solid #ddd !important; + } +} + +*, +*:before, +*:after { + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} + +html { + font-size: 62.5%; + -webkit-tap-highlight-color: rgba(0, 0, 0, 0); +} + +body { + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 14px; + line-height: 1.428571429; + color: #333333; + background-color: #ffffff; +} + +input, +button, +select, +textarea { + font-family: inherit; + font-size: inherit; + line-height: inherit; +} + +button, +input, +select[multiple], +textarea { + background-image: none; +} + +a { + color: #428bca; + text-decoration: none; +} + +a:hover, +a:focus { + color: #2a6496; + text-decoration: underline; +} + +a:focus { + outline: thin dotted #333; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} + +img { + vertical-align: middle; +} + +.img-responsive { + display: block; + height: auto; + max-width: 100%; +} + +.img-rounded { + border-radius: 6px; +} + +.img-thumbnail { + display: inline-block; + height: auto; + max-width: 100%; + padding: 4px; + line-height: 1.428571429; + background-color: #ffffff; + border: 1px solid #dddddd; + border-radius: 4px; + -webkit-transition: all 0.2s ease-in-out; + transition: all 0.2s ease-in-out; +} + +.img-circle { + border-radius: 50%; +} + +hr { + margin-top: 20px; + margin-bottom: 20px; + border: 0; + border-top: 1px solid #eeeeee; +} + +.sr-only { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0 0 0 0); + border: 0; +} + +p { + margin: 0 0 10px; +} + +.lead { + margin-bottom: 20px; + font-size: 16.099999999999998px; + font-weight: 200; + line-height: 1.4; +} + +@media (min-width: 768px) { + .lead { + font-size: 21px; + } +} + +small { + font-size: 85%; +} + +cite { + font-style: normal; +} + +.text-muted { + color: #999999; +} + +.text-primary { + color: #428bca; +} + +.text-warning { + color: #c09853; +} + +.text-danger { + color: #b94a48; +} + +.text-success { + color: #468847; +} + +.text-info { + color: #3a87ad; +} + +.text-left { + text-align: left; +} + +.text-right { + text-align: right; +} + +.text-center { + text-align: center; +} + +h1, +h2, +h3, +h4, +h5, +h6, +.h1, +.h2, +.h3, +.h4, +.h5, +.h6 { + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-weight: 500; + line-height: 1.1; +} + +h1 small, +h2 small, +h3 small, +h4 small, +h5 small, +h6 small, +.h1 small, +.h2 small, +.h3 small, +.h4 small, +.h5 small, +.h6 small { + font-weight: normal; + line-height: 1; + color: #999999; +} + +h1, +h2, +h3 { + margin-top: 20px; + margin-bottom: 10px; +} + +h4, +h5, +h6 { + margin-top: 10px; + margin-bottom: 10px; +} + +h1, +.h1 { + font-size: 36px; +} + +h2, +.h2 { + font-size: 30px; +} + +h3, +.h3 { + font-size: 24px; +} + +h4, +.h4 { + font-size: 18px; +} + +h5, +.h5 { + font-size: 14px; +} + +h6, +.h6 { + font-size: 12px; +} + +h1 small, +.h1 small { + font-size: 24px; +} + +h2 small, +.h2 small { + font-size: 18px; +} + +h3 small, +.h3 small, +h4 small, +.h4 small { + font-size: 14px; +} + +.page-header { + padding-bottom: 9px; + margin: 40px 0 20px; + border-bottom: 1px solid #eeeeee; +} + +ul, +ol { + margin-top: 0; + margin-bottom: 10px; +} + +ul ul, +ol ul, +ul ol, +ol ol { + margin-bottom: 0; +} + +.list-unstyled { + padding-left: 0; + list-style: none; +} + +.list-inline { + padding-left: 0; + list-style: none; +} + +.list-inline > li { + display: inline-block; + padding-right: 5px; + padding-left: 5px; +} + +dl { + margin-bottom: 20px; +} + +dt, +dd { + line-height: 1.428571429; +} + +dt { + font-weight: bold; +} + +dd { + margin-left: 0; +} + +@media (min-width: 768px) { + .dl-horizontal dt { + float: left; + width: 160px; + overflow: hidden; + clear: left; + text-align: right; + text-overflow: ellipsis; + white-space: nowrap; + } + .dl-horizontal dd { + margin-left: 180px; + } + .dl-horizontal dd:before, + .dl-horizontal dd:after { + display: table; + content: " "; + } + .dl-horizontal dd:after { + clear: both; + } + .dl-horizontal dd:before, + .dl-horizontal dd:after { + display: table; + content: " "; + } + .dl-horizontal dd:after { + clear: both; + } +} + +abbr[title], +abbr[data-original-title] { + cursor: help; + border-bottom: 1px dotted #999999; +} + +abbr.initialism { + font-size: 90%; + text-transform: uppercase; +} + +blockquote { + padding: 10px 20px; + margin: 0 0 20px; + border-left: 5px solid #eeeeee; +} + +blockquote p { + font-size: 17.5px; + font-weight: 300; + line-height: 1.25; +} + +blockquote p:last-child { + margin-bottom: 0; +} + +blockquote small { + display: block; + line-height: 1.428571429; + color: #999999; +} + +blockquote small:before { + content: '\2014 \00A0'; +} + +blockquote.pull-right { + padding-right: 15px; + padding-left: 0; + border-right: 5px solid #eeeeee; + border-left: 0; +} + +blockquote.pull-right p, +blockquote.pull-right small { + text-align: right; +} + +blockquote.pull-right small:before { + content: ''; +} + +blockquote.pull-right small:after { + content: '\00A0 \2014'; +} + +q:before, +q:after, +blockquote:before, +blockquote:after { + content: ""; +} + +address { + display: block; + margin-bottom: 20px; + font-style: normal; + line-height: 1.428571429; +} + +code, +pre { + font-family: Monaco, Menlo, Consolas, "Courier New", monospace; +} + +code { + padding: 2px 4px; + font-size: 90%; + color: #c7254e; + white-space: nowrap; + background-color: #f9f2f4; + border-radius: 4px; +} + +pre { + display: block; + padding: 9.5px; + margin: 0 0 10px; + font-size: 13px; + line-height: 1.428571429; + color: #333333; + word-break: break-all; + word-wrap: break-word; + background-color: #f5f5f5; + border: 1px solid #cccccc; + border-radius: 4px; +} + +pre.prettyprint { + margin-bottom: 20px; +} + +pre code { + padding: 0; + font-size: inherit; + color: inherit; + white-space: pre-wrap; + background-color: transparent; + border: 0; +} + +.pre-scrollable { + max-height: 340px; + overflow-y: scroll; +} + +.container { + padding-right: 15px; + padding-left: 15px; + margin-right: auto; + margin-left: auto; +} + +.container:before, +.container:after { + display: table; + content: " "; +} + +.container:after { + clear: both; +} + +.container:before, +.container:after { + display: table; + content: " "; +} + +.container:after { + clear: both; +} + +.row { + margin-right: -15px; + margin-left: -15px; +} + +.row:before, +.row:after { + display: table; + content: " "; +} + +.row:after { + clear: both; +} + +.row:before, +.row:after { + display: table; + content: " "; +} + +.row:after { + clear: both; +} + +.col-xs-1, +.col-xs-2, +.col-xs-3, +.col-xs-4, +.col-xs-5, +.col-xs-6, +.col-xs-7, +.col-xs-8, +.col-xs-9, +.col-xs-10, +.col-xs-11, +.col-xs-12, +.col-sm-1, +.col-sm-2, +.col-sm-3, +.col-sm-4, +.col-sm-5, +.col-sm-6, +.col-sm-7, +.col-sm-8, +.col-sm-9, +.col-sm-10, +.col-sm-11, +.col-sm-12, +.col-md-1, +.col-md-2, +.col-md-3, +.col-md-4, +.col-md-5, +.col-md-6, +.col-md-7, +.col-md-8, +.col-md-9, +.col-md-10, +.col-md-11, +.col-md-12, +.col-lg-1, +.col-lg-2, +.col-lg-3, +.col-lg-4, +.col-lg-5, +.col-lg-6, +.col-lg-7, +.col-lg-8, +.col-lg-9, +.col-lg-10, +.col-lg-11, +.col-lg-12 { + position: relative; + min-height: 1px; + padding-right: 15px; + padding-left: 15px; +} + +.col-xs-1, +.col-xs-2, +.col-xs-3, +.col-xs-4, +.col-xs-5, +.col-xs-6, +.col-xs-7, +.col-xs-8, +.col-xs-9, +.col-xs-10, +.col-xs-11 { + float: left; +} + +.col-xs-1 { + width: 8.333333333333332%; +} + +.col-xs-2 { + width: 16.666666666666664%; +} + +.col-xs-3 { + width: 25%; +} + +.col-xs-4 { + width: 33.33333333333333%; +} + +.col-xs-5 { + width: 41.66666666666667%; +} + +.col-xs-6 { + width: 50%; +} + +.col-xs-7 { + width: 58.333333333333336%; +} + +.col-xs-8 { + width: 66.66666666666666%; +} + +.col-xs-9 { + width: 75%; +} + +.col-xs-10 { + width: 83.33333333333334%; +} + +.col-xs-11 { + width: 91.66666666666666%; +} + +.col-xs-12 { + width: 100%; +} + +@media (min-width: 768px) { + .container { + max-width: 750px; + } + .col-sm-1, + .col-sm-2, + .col-sm-3, + .col-sm-4, + .col-sm-5, + .col-sm-6, + .col-sm-7, + .col-sm-8, + .col-sm-9, + .col-sm-10, + .col-sm-11 { + float: left; + } + .col-sm-1 { + width: 8.333333333333332%; + } + .col-sm-2 { + width: 16.666666666666664%; + } + .col-sm-3 { + width: 25%; + } + .col-sm-4 { + width: 33.33333333333333%; + } + .col-sm-5 { + width: 41.66666666666667%; + } + .col-sm-6 { + width: 50%; + } + .col-sm-7 { + width: 58.333333333333336%; + } + .col-sm-8 { + width: 66.66666666666666%; + } + .col-sm-9 { + width: 75%; + } + .col-sm-10 { + width: 83.33333333333334%; + } + .col-sm-11 { + width: 91.66666666666666%; + } + .col-sm-12 { + width: 100%; + } + .col-sm-push-1 { + left: 8.333333333333332%; + } + .col-sm-push-2 { + left: 16.666666666666664%; + } + .col-sm-push-3 { + left: 25%; + } + .col-sm-push-4 { + left: 33.33333333333333%; + } + .col-sm-push-5 { + left: 41.66666666666667%; + } + .col-sm-push-6 { + left: 50%; + } + .col-sm-push-7 { + left: 58.333333333333336%; + } + .col-sm-push-8 { + left: 66.66666666666666%; + } + .col-sm-push-9 { + left: 75%; + } + .col-sm-push-10 { + left: 83.33333333333334%; + } + .col-sm-push-11 { + left: 91.66666666666666%; + } + .col-sm-pull-1 { + right: 8.333333333333332%; + } + .col-sm-pull-2 { + right: 16.666666666666664%; + } + .col-sm-pull-3 { + right: 25%; + } + .col-sm-pull-4 { + right: 33.33333333333333%; + } + .col-sm-pull-5 { + right: 41.66666666666667%; + } + .col-sm-pull-6 { + right: 50%; + } + .col-sm-pull-7 { + right: 58.333333333333336%; + } + .col-sm-pull-8 { + right: 66.66666666666666%; + } + .col-sm-pull-9 { + right: 75%; + } + .col-sm-pull-10 { + right: 83.33333333333334%; + } + .col-sm-pull-11 { + right: 91.66666666666666%; + } + .col-sm-offset-1 { + margin-left: 8.333333333333332%; + } + .col-sm-offset-2 { + margin-left: 16.666666666666664%; + } + .col-sm-offset-3 { + margin-left: 25%; + } + .col-sm-offset-4 { + margin-left: 33.33333333333333%; + } + .col-sm-offset-5 { + margin-left: 41.66666666666667%; + } + .col-sm-offset-6 { + margin-left: 50%; + } + .col-sm-offset-7 { + margin-left: 58.333333333333336%; + } + .col-sm-offset-8 { + margin-left: 66.66666666666666%; + } + .col-sm-offset-9 { + margin-left: 75%; + } + .col-sm-offset-10 { + margin-left: 83.33333333333334%; + } + .col-sm-offset-11 { + margin-left: 91.66666666666666%; + } +} + +@media (min-width: 992px) { + .container { + max-width: 970px; + } + .col-md-1, + .col-md-2, + .col-md-3, + .col-md-4, + .col-md-5, + .col-md-6, + .col-md-7, + .col-md-8, + .col-md-9, + .col-md-10, + .col-md-11 { + float: left; + } + .col-md-1 { + width: 8.333333333333332%; + } + .col-md-2 { + width: 16.666666666666664%; + } + .col-md-3 { + width: 25%; + } + .col-md-4 { + width: 33.33333333333333%; + } + .col-md-5 { + width: 41.66666666666667%; + } + .col-md-6 { + width: 50%; + } + .col-md-7 { + width: 58.333333333333336%; + } + .col-md-8 { + width: 66.66666666666666%; + } + .col-md-9 { + width: 75%; + } + .col-md-10 { + width: 83.33333333333334%; + } + .col-md-11 { + width: 91.66666666666666%; + } + .col-md-12 { + width: 100%; + } + .col-md-push-0 { + left: auto; + } + .col-md-push-1 { + left: 8.333333333333332%; + } + .col-md-push-2 { + left: 16.666666666666664%; + } + .col-md-push-3 { + left: 25%; + } + .col-md-push-4 { + left: 33.33333333333333%; + } + .col-md-push-5 { + left: 41.66666666666667%; + } + .col-md-push-6 { + left: 50%; + } + .col-md-push-7 { + left: 58.333333333333336%; + } + .col-md-push-8 { + left: 66.66666666666666%; + } + .col-md-push-9 { + left: 75%; + } + .col-md-push-10 { + left: 83.33333333333334%; + } + .col-md-push-11 { + left: 91.66666666666666%; + } + .col-md-pull-0 { + right: auto; + } + .col-md-pull-1 { + right: 8.333333333333332%; + } + .col-md-pull-2 { + right: 16.666666666666664%; + } + .col-md-pull-3 { + right: 25%; + } + .col-md-pull-4 { + right: 33.33333333333333%; + } + .col-md-pull-5 { + right: 41.66666666666667%; + } + .col-md-pull-6 { + right: 50%; + } + .col-md-pull-7 { + right: 58.333333333333336%; + } + .col-md-pull-8 { + right: 66.66666666666666%; + } + .col-md-pull-9 { + right: 75%; + } + .col-md-pull-10 { + right: 83.33333333333334%; + } + .col-md-pull-11 { + right: 91.66666666666666%; + } + .col-md-offset-0 { + margin-left: 0; + } + .col-md-offset-1 { + margin-left: 8.333333333333332%; + } + .col-md-offset-2 { + margin-left: 16.666666666666664%; + } + .col-md-offset-3 { + margin-left: 25%; + } + .col-md-offset-4 { + margin-left: 33.33333333333333%; + } + .col-md-offset-5 { + margin-left: 41.66666666666667%; + } + .col-md-offset-6 { + margin-left: 50%; + } + .col-md-offset-7 { + margin-left: 58.333333333333336%; + } + .col-md-offset-8 { + margin-left: 66.66666666666666%; + } + .col-md-offset-9 { + margin-left: 75%; + } + .col-md-offset-10 { + margin-left: 83.33333333333334%; + } + .col-md-offset-11 { + margin-left: 91.66666666666666%; + } +} + +@media (min-width: 1200px) { + .container { + max-width: 1170px; + } + .col-lg-1, + .col-lg-2, + .col-lg-3, + .col-lg-4, + .col-lg-5, + .col-lg-6, + .col-lg-7, + .col-lg-8, + .col-lg-9, + .col-lg-10, + .col-lg-11 { + float: left; + } + .col-lg-1 { + width: 8.333333333333332%; + } + .col-lg-2 { + width: 16.666666666666664%; + } + .col-lg-3 { + width: 25%; + } + .col-lg-4 { + width: 33.33333333333333%; + } + .col-lg-5 { + width: 41.66666666666667%; + } + .col-lg-6 { + width: 50%; + } + .col-lg-7 { + width: 58.333333333333336%; + } + .col-lg-8 { + width: 66.66666666666666%; + } + .col-lg-9 { + width: 75%; + } + .col-lg-10 { + width: 83.33333333333334%; + } + .col-lg-11 { + width: 91.66666666666666%; + } + .col-lg-12 { + width: 100%; + } + .col-lg-push-0 { + left: auto; + } + .col-lg-push-1 { + left: 8.333333333333332%; + } + .col-lg-push-2 { + left: 16.666666666666664%; + } + .col-lg-push-3 { + left: 25%; + } + .col-lg-push-4 { + left: 33.33333333333333%; + } + .col-lg-push-5 { + left: 41.66666666666667%; + } + .col-lg-push-6 { + left: 50%; + } + .col-lg-push-7 { + left: 58.333333333333336%; + } + .col-lg-push-8 { + left: 66.66666666666666%; + } + .col-lg-push-9 { + left: 75%; + } + .col-lg-push-10 { + left: 83.33333333333334%; + } + .col-lg-push-11 { + left: 91.66666666666666%; + } + .col-lg-pull-0 { + right: auto; + } + .col-lg-pull-1 { + right: 8.333333333333332%; + } + .col-lg-pull-2 { + right: 16.666666666666664%; + } + .col-lg-pull-3 { + right: 25%; + } + .col-lg-pull-4 { + right: 33.33333333333333%; + } + .col-lg-pull-5 { + right: 41.66666666666667%; + } + .col-lg-pull-6 { + right: 50%; + } + .col-lg-pull-7 { + right: 58.333333333333336%; + } + .col-lg-pull-8 { + right: 66.66666666666666%; + } + .col-lg-pull-9 { + right: 75%; + } + .col-lg-pull-10 { + right: 83.33333333333334%; + } + .col-lg-pull-11 { + right: 91.66666666666666%; + } + .col-lg-offset-0 { + margin-left: 0; + } + .col-lg-offset-1 { + margin-left: 8.333333333333332%; + } + .col-lg-offset-2 { + margin-left: 16.666666666666664%; + } + .col-lg-offset-3 { + margin-left: 25%; + } + .col-lg-offset-4 { + margin-left: 33.33333333333333%; + } + .col-lg-offset-5 { + margin-left: 41.66666666666667%; + } + .col-lg-offset-6 { + margin-left: 50%; + } + .col-lg-offset-7 { + margin-left: 58.333333333333336%; + } + .col-lg-offset-8 { + margin-left: 66.66666666666666%; + } + .col-lg-offset-9 { + margin-left: 75%; + } + .col-lg-offset-10 { + margin-left: 83.33333333333334%; + } + .col-lg-offset-11 { + margin-left: 91.66666666666666%; + } +} + +table { + max-width: 100%; + background-color: transparent; +} + +th { + text-align: left; +} + +.table { + width: 100%; + margin-bottom: 20px; +} + +.table thead > tr > th, +.table tbody > tr > th, +.table tfoot > tr > th, +.table thead > tr > td, +.table tbody > tr > td, +.table tfoot > tr > td { + padding: 8px; + line-height: 1.428571429; + vertical-align: top; + border-top: 1px solid #dddddd; +} + +.table thead > tr > th { + vertical-align: bottom; + border-bottom: 2px solid #dddddd; +} + +.table caption + thead tr:first-child th, +.table colgroup + thead tr:first-child th, +.table thead:first-child tr:first-child th, +.table caption + thead tr:first-child td, +.table colgroup + thead tr:first-child td, +.table thead:first-child tr:first-child td { + border-top: 0; +} + +.table tbody + tbody { + border-top: 2px solid #dddddd; +} + +.table .table { + background-color: #ffffff; +} + +.table-condensed thead > tr > th, +.table-condensed tbody > tr > th, +.table-condensed tfoot > tr > th, +.table-condensed thead > tr > td, +.table-condensed tbody > tr > td, +.table-condensed tfoot > tr > td { + padding: 5px; +} + +.table-bordered { + border: 1px solid #dddddd; +} + +.table-bordered > thead > tr > th, +.table-bordered > tbody > tr > th, +.table-bordered > tfoot > tr > th, +.table-bordered > thead > tr > td, +.table-bordered > tbody > tr > td, +.table-bordered > tfoot > tr > td { + border: 1px solid #dddddd; +} + +.table-bordered > thead > tr > th, +.table-bordered > thead > tr > td { + border-bottom-width: 2px; +} + +.table-striped > tbody > tr:nth-child(odd) > td, +.table-striped > tbody > tr:nth-child(odd) > th { + background-color: #f9f9f9; +} + +.table-hover > tbody > tr:hover > td, +.table-hover > tbody > tr:hover > th { + background-color: #f5f5f5; +} + +table col[class*="col-"] { + display: table-column; + float: none; +} + +table td[class*="col-"], +table th[class*="col-"] { + display: table-cell; + float: none; +} + +.table > thead > tr > td.active, +.table > tbody > tr > td.active, +.table > tfoot > tr > td.active, +.table > thead > tr > th.active, +.table > tbody > tr > th.active, +.table > tfoot > tr > th.active, +.table > thead > tr.active > td, +.table > tbody > tr.active > td, +.table > tfoot > tr.active > td, +.table > thead > tr.active > th, +.table > tbody > tr.active > th, +.table > tfoot > tr.active > th { + background-color: #f5f5f5; +} + +.table > thead > tr > td.success, +.table > tbody > tr > td.success, +.table > tfoot > tr > td.success, +.table > thead > tr > th.success, +.table > tbody > tr > th.success, +.table > tfoot > tr > th.success, +.table > thead > tr.success > td, +.table > tbody > tr.success > td, +.table > tfoot > tr.success > td, +.table > thead > tr.success > th, +.table > tbody > tr.success > th, +.table > tfoot > tr.success > th { + background-color: #dff0d8; + border-color: #d6e9c6; +} + +.table-hover > tbody > tr > td.success:hover, +.table-hover > tbody > tr > th.success:hover, +.table-hover > tbody > tr.success:hover > td { + background-color: #d0e9c6; + border-color: #c9e2b3; +} + +.table > thead > tr > td.danger, +.table > tbody > tr > td.danger, +.table > tfoot > tr > td.danger, +.table > thead > tr > th.danger, +.table > tbody > tr > th.danger, +.table > tfoot > tr > th.danger, +.table > thead > tr.danger > td, +.table > tbody > tr.danger > td, +.table > tfoot > tr.danger > td, +.table > thead > tr.danger > th, +.table > tbody > tr.danger > th, +.table > tfoot > tr.danger > th { + background-color: #f2dede; + border-color: #eed3d7; +} + +.table-hover > tbody > tr > td.danger:hover, +.table-hover > tbody > tr > th.danger:hover, +.table-hover > tbody > tr.danger:hover > td { + background-color: #ebcccc; + border-color: #e6c1c7; +} + +.table > thead > tr > td.warning, +.table > tbody > tr > td.warning, +.table > tfoot > tr > td.warning, +.table > thead > tr > th.warning, +.table > tbody > tr > th.warning, +.table > tfoot > tr > th.warning, +.table > thead > tr.warning > td, +.table > tbody > tr.warning > td, +.table > tfoot > tr.warning > td, +.table > thead > tr.warning > th, +.table > tbody > tr.warning > th, +.table > tfoot > tr.warning > th { + background-color: #fcf8e3; + border-color: #fbeed5; +} + +.table-hover > tbody > tr > td.warning:hover, +.table-hover > tbody > tr > th.warning:hover, +.table-hover > tbody > tr.warning:hover > td { + background-color: #faf2cc; + border-color: #f8e5be; +} + +@media (max-width: 768px) { + .table-responsive { + width: 100%; + margin-bottom: 15px; + overflow-x: scroll; + overflow-y: hidden; + border: 1px solid #dddddd; + } + .table-responsive > .table { + margin-bottom: 0; + background-color: #fff; + } + .table-responsive > .table > thead > tr > th, + .table-responsive > .table > tbody > tr > th, + .table-responsive > .table > tfoot > tr > th, + .table-responsive > .table > thead > tr > td, + .table-responsive > .table > tbody > tr > td, + .table-responsive > .table > tfoot > tr > td { + white-space: nowrap; + } + .table-responsive > .table-bordered { + border: 0; + } + .table-responsive > .table-bordered > thead > tr > th:first-child, + .table-responsive > .table-bordered > tbody > tr > th:first-child, + .table-responsive > .table-bordered > tfoot > tr > th:first-child, + .table-responsive > .table-bordered > thead > tr > td:first-child, + .table-responsive > .table-bordered > tbody > tr > td:first-child, + .table-responsive > .table-bordered > tfoot > tr > td:first-child { + border-left: 0; + } + .table-responsive > .table-bordered > thead > tr > th:last-child, + .table-responsive > .table-bordered > tbody > tr > th:last-child, + .table-responsive > .table-bordered > tfoot > tr > th:last-child, + .table-responsive > .table-bordered > thead > tr > td:last-child, + .table-responsive > .table-bordered > tbody > tr > td:last-child, + .table-responsive > .table-bordered > tfoot > tr > td:last-child { + border-right: 0; + } + .table-responsive > .table-bordered > thead > tr:last-child > th, + .table-responsive > .table-bordered > tbody > tr:last-child > th, + .table-responsive > .table-bordered > tfoot > tr:last-child > th, + .table-responsive > .table-bordered > thead > tr:last-child > td, + .table-responsive > .table-bordered > tbody > tr:last-child > td, + .table-responsive > .table-bordered > tfoot > tr:last-child > td { + border-bottom: 0; + } +} + +fieldset { + padding: 0; + margin: 0; + border: 0; +} + +legend { + display: block; + width: 100%; + padding: 0; + margin-bottom: 20px; + font-size: 21px; + line-height: inherit; + color: #333333; + border: 0; + border-bottom: 1px solid #e5e5e5; +} + +label { + display: inline-block; + margin-bottom: 5px; + font-weight: bold; +} + +input[type="search"] { + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} + +input[type="radio"], +input[type="checkbox"] { + margin: 4px 0 0; + margin-top: 1px \9; + /* IE8-9 */ + + line-height: normal; +} + +input[type="file"] { + display: block; +} + +select[multiple], +select[size] { + height: auto; +} + +select optgroup { + font-family: inherit; + font-size: inherit; + font-style: inherit; +} + +input[type="file"]:focus, +input[type="radio"]:focus, +input[type="checkbox"]:focus { + outline: thin dotted #333; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} + +input[type="number"]::-webkit-outer-spin-button, +input[type="number"]::-webkit-inner-spin-button { + height: auto; +} + +.form-control:-moz-placeholder { + color: #999999; +} + +.form-control::-moz-placeholder { + color: #999999; +} + +.form-control:-ms-input-placeholder { + color: #999999; +} + +.form-control::-webkit-input-placeholder { + color: #999999; +} + +.form-control { + display: block; + width: 100%; + height: 34px; + padding: 6px 12px; + font-size: 14px; + line-height: 1.428571429; + color: #555555; + vertical-align: middle; + background-color: #ffffff; + border: 1px solid #cccccc; + border-radius: 4px; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -webkit-transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s; + transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s; +} + +.form-control:focus { + border-color: #66afe9; + outline: 0; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(102, 175, 233, 0.6); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(102, 175, 233, 0.6); +} + +.form-control[disabled], +.form-control[readonly], +fieldset[disabled] .form-control { + cursor: not-allowed; + background-color: #eeeeee; +} + +textarea.form-control { + height: auto; +} + +.form-group { + margin-bottom: 15px; +} + +.radio, +.checkbox { + display: block; + min-height: 20px; + padding-left: 20px; + margin-top: 10px; + margin-bottom: 10px; + vertical-align: middle; +} + +.radio label, +.checkbox label { + display: inline; + margin-bottom: 0; + font-weight: normal; + cursor: pointer; +} + +.radio input[type="radio"], +.radio-inline input[type="radio"], +.checkbox input[type="checkbox"], +.checkbox-inline input[type="checkbox"] { + float: left; + margin-left: -20px; +} + +.radio + .radio, +.checkbox + .checkbox { + margin-top: -5px; +} + +.radio-inline, +.checkbox-inline { + display: inline-block; + padding-left: 20px; + margin-bottom: 0; + font-weight: normal; + vertical-align: middle; + cursor: pointer; +} + +.radio-inline + .radio-inline, +.checkbox-inline + .checkbox-inline { + margin-top: 0; + margin-left: 10px; +} + +input[type="radio"][disabled], +input[type="checkbox"][disabled], +.radio[disabled], +.radio-inline[disabled], +.checkbox[disabled], +.checkbox-inline[disabled], +fieldset[disabled] input[type="radio"], +fieldset[disabled] input[type="checkbox"], +fieldset[disabled] .radio, +fieldset[disabled] .radio-inline, +fieldset[disabled] .checkbox, +fieldset[disabled] .checkbox-inline { + cursor: not-allowed; +} + +.input-sm { + height: 30px; + padding: 5px 10px; + font-size: 12px; + line-height: 1.5; + border-radius: 3px; +} + +select.input-sm { + height: 30px; + line-height: 30px; +} + +textarea.input-sm { + height: auto; +} + +.input-lg { + height: 45px; + padding: 10px 16px; + font-size: 18px; + line-height: 1.33; + border-radius: 6px; +} + +select.input-lg { + height: 45px; + line-height: 45px; +} + +textarea.input-lg { + height: auto; +} + +.has-warning .help-block, +.has-warning .control-label { + color: #c09853; +} + +.has-warning .form-control { + border-color: #c09853; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); +} + +.has-warning .form-control:focus { + border-color: #a47e3c; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #dbc59e; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #dbc59e; +} + +.has-warning .input-group-addon { + color: #c09853; + background-color: #fcf8e3; + border-color: #c09853; +} + +.has-error .help-block, +.has-error .control-label { + color: #b94a48; +} + +.has-error .form-control { + border-color: #b94a48; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); +} + +.has-error .form-control:focus { + border-color: #953b39; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #d59392; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #d59392; +} + +.has-error .input-group-addon { + color: #b94a48; + background-color: #f2dede; + border-color: #b94a48; +} + +.has-success .help-block, +.has-success .control-label { + color: #468847; +} + +.has-success .form-control { + border-color: #468847; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); +} + +.has-success .form-control:focus { + border-color: #356635; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7aba7b; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7aba7b; +} + +.has-success .input-group-addon { + color: #468847; + background-color: #dff0d8; + border-color: #468847; +} + +.form-control-static { + padding-top: 7px; + margin-bottom: 0; +} + +.help-block { + display: block; + margin-top: 5px; + margin-bottom: 10px; + color: #737373; +} + +@media (min-width: 768px) { + .form-inline .form-group { + display: inline-block; + margin-bottom: 0; + vertical-align: middle; + } + .form-inline .form-control { + display: inline-block; + } + .form-inline .radio, + .form-inline .checkbox { + display: inline-block; + padding-left: 0; + margin-top: 0; + margin-bottom: 0; + } + .form-inline .radio input[type="radio"], + .form-inline .checkbox input[type="checkbox"] { + float: none; + margin-left: 0; + } +} + +.form-horizontal .control-label, +.form-horizontal .radio, +.form-horizontal .checkbox, +.form-horizontal .radio-inline, +.form-horizontal .checkbox-inline { + padding-top: 7px; + margin-top: 0; + margin-bottom: 0; +} + +.form-horizontal .form-group { + margin-right: -15px; + margin-left: -15px; +} + +.form-horizontal .form-group:before, +.form-horizontal .form-group:after { + display: table; + content: " "; +} + +.form-horizontal .form-group:after { + clear: both; +} + +.form-horizontal .form-group:before, +.form-horizontal .form-group:after { + display: table; + content: " "; +} + +.form-horizontal .form-group:after { + clear: both; +} + +@media (min-width: 768px) { + .form-horizontal .control-label { + text-align: right; + } +} + +.btn { + display: inline-block; + padding: 6px 12px; + margin-bottom: 0; + font-size: 14px; + font-weight: normal; + line-height: 1.428571429; + text-align: center; + white-space: nowrap; + vertical-align: middle; + cursor: pointer; + border: 1px solid transparent; + border-radius: 4px; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + -o-user-select: none; + user-select: none; +} + +.btn:focus { + outline: thin dotted #333; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} + +.btn:hover, +.btn:focus { + color: #333333; + text-decoration: none; +} + +.btn:active, +.btn.active { + background-image: none; + outline: 0; + -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); +} + +.btn.disabled, +.btn[disabled], +fieldset[disabled] .btn { + pointer-events: none; + cursor: not-allowed; + opacity: 0.65; + filter: alpha(opacity=65); + -webkit-box-shadow: none; + box-shadow: none; +} + +.btn-default { + color: #333333; + background-color: #ffffff; + border-color: #cccccc; +} + +.btn-default:hover, +.btn-default:focus, +.btn-default:active, +.btn-default.active, +.open .dropdown-toggle.btn-default { + color: #333333; + background-color: #ebebeb; + border-color: #adadad; +} + +.btn-default:active, +.btn-default.active, +.open .dropdown-toggle.btn-default { + background-image: none; +} + +.btn-default.disabled, +.btn-default[disabled], +fieldset[disabled] .btn-default, +.btn-default.disabled:hover, +.btn-default[disabled]:hover, +fieldset[disabled] .btn-default:hover, +.btn-default.disabled:focus, +.btn-default[disabled]:focus, +fieldset[disabled] .btn-default:focus, +.btn-default.disabled:active, +.btn-default[disabled]:active, +fieldset[disabled] .btn-default:active, +.btn-default.disabled.active, +.btn-default[disabled].active, +fieldset[disabled] .btn-default.active { + background-color: #ffffff; + border-color: #cccccc; +} + +.btn-primary { + color: #ffffff; + background-color: #428bca; + border-color: #357ebd; +} + +.btn-primary:hover, +.btn-primary:focus, +.btn-primary:active, +.btn-primary.active, +.open .dropdown-toggle.btn-primary { + color: #ffffff; + background-color: #3276b1; + border-color: #285e8e; +} + +.btn-primary:active, +.btn-primary.active, +.open .dropdown-toggle.btn-primary { + background-image: none; +} + +.btn-primary.disabled, +.btn-primary[disabled], +fieldset[disabled] .btn-primary, +.btn-primary.disabled:hover, +.btn-primary[disabled]:hover, +fieldset[disabled] .btn-primary:hover, +.btn-primary.disabled:focus, +.btn-primary[disabled]:focus, +fieldset[disabled] .btn-primary:focus, +.btn-primary.disabled:active, +.btn-primary[disabled]:active, +fieldset[disabled] .btn-primary:active, +.btn-primary.disabled.active, +.btn-primary[disabled].active, +fieldset[disabled] .btn-primary.active { + background-color: #428bca; + border-color: #357ebd; +} + +.btn-warning { + color: #ffffff; + background-color: #f0ad4e; + border-color: #eea236; +} + +.btn-warning:hover, +.btn-warning:focus, +.btn-warning:active, +.btn-warning.active, +.open .dropdown-toggle.btn-warning { + color: #ffffff; + background-color: #ed9c28; + border-color: #d58512; +} + +.btn-warning:active, +.btn-warning.active, +.open .dropdown-toggle.btn-warning { + background-image: none; +} + +.btn-warning.disabled, +.btn-warning[disabled], +fieldset[disabled] .btn-warning, +.btn-warning.disabled:hover, +.btn-warning[disabled]:hover, +fieldset[disabled] .btn-warning:hover, +.btn-warning.disabled:focus, +.btn-warning[disabled]:focus, +fieldset[disabled] .btn-warning:focus, +.btn-warning.disabled:active, +.btn-warning[disabled]:active, +fieldset[disabled] .btn-warning:active, +.btn-warning.disabled.active, +.btn-warning[disabled].active, +fieldset[disabled] .btn-warning.active { + background-color: #f0ad4e; + border-color: #eea236; +} + +.btn-danger { + color: #ffffff; + background-color: #d9534f; + border-color: #d43f3a; +} + +.btn-danger:hover, +.btn-danger:focus, +.btn-danger:active, +.btn-danger.active, +.open .dropdown-toggle.btn-danger { + color: #ffffff; + background-color: #d2322d; + border-color: #ac2925; +} + +.btn-danger:active, +.btn-danger.active, +.open .dropdown-toggle.btn-danger { + background-image: none; +} + +.btn-danger.disabled, +.btn-danger[disabled], +fieldset[disabled] .btn-danger, +.btn-danger.disabled:hover, +.btn-danger[disabled]:hover, +fieldset[disabled] .btn-danger:hover, +.btn-danger.disabled:focus, +.btn-danger[disabled]:focus, +fieldset[disabled] .btn-danger:focus, +.btn-danger.disabled:active, +.btn-danger[disabled]:active, +fieldset[disabled] .btn-danger:active, +.btn-danger.disabled.active, +.btn-danger[disabled].active, +fieldset[disabled] .btn-danger.active { + background-color: #d9534f; + border-color: #d43f3a; +} + +.btn-success { + color: #ffffff; + background-color: #5cb85c; + border-color: #4cae4c; +} + +.btn-success:hover, +.btn-success:focus, +.btn-success:active, +.btn-success.active, +.open .dropdown-toggle.btn-success { + color: #ffffff; + background-color: #47a447; + border-color: #398439; +} + +.btn-success:active, +.btn-success.active, +.open .dropdown-toggle.btn-success { + background-image: none; +} + +.btn-success.disabled, +.btn-success[disabled], +fieldset[disabled] .btn-success, +.btn-success.disabled:hover, +.btn-success[disabled]:hover, +fieldset[disabled] .btn-success:hover, +.btn-success.disabled:focus, +.btn-success[disabled]:focus, +fieldset[disabled] .btn-success:focus, +.btn-success.disabled:active, +.btn-success[disabled]:active, +fieldset[disabled] .btn-success:active, +.btn-success.disabled.active, +.btn-success[disabled].active, +fieldset[disabled] .btn-success.active { + background-color: #5cb85c; + border-color: #4cae4c; +} + +.btn-info { + color: #ffffff; + background-color: #5bc0de; + border-color: #46b8da; +} + +.btn-info:hover, +.btn-info:focus, +.btn-info:active, +.btn-info.active, +.open .dropdown-toggle.btn-info { + color: #ffffff; + background-color: #39b3d7; + border-color: #269abc; +} + +.btn-info:active, +.btn-info.active, +.open .dropdown-toggle.btn-info { + background-image: none; +} + +.btn-info.disabled, +.btn-info[disabled], +fieldset[disabled] .btn-info, +.btn-info.disabled:hover, +.btn-info[disabled]:hover, +fieldset[disabled] .btn-info:hover, +.btn-info.disabled:focus, +.btn-info[disabled]:focus, +fieldset[disabled] .btn-info:focus, +.btn-info.disabled:active, +.btn-info[disabled]:active, +fieldset[disabled] .btn-info:active, +.btn-info.disabled.active, +.btn-info[disabled].active, +fieldset[disabled] .btn-info.active { + background-color: #5bc0de; + border-color: #46b8da; +} + +.btn-link { + font-weight: normal; + color: #428bca; + cursor: pointer; + border-radius: 0; +} + +.btn-link, +.btn-link:active, +.btn-link[disabled], +fieldset[disabled] .btn-link { + background-color: transparent; + -webkit-box-shadow: none; + box-shadow: none; +} + +.btn-link, +.btn-link:hover, +.btn-link:focus, +.btn-link:active { + border-color: transparent; +} + +.btn-link:hover, +.btn-link:focus { + color: #2a6496; + text-decoration: underline; + background-color: transparent; +} + +.btn-link[disabled]:hover, +fieldset[disabled] .btn-link:hover, +.btn-link[disabled]:focus, +fieldset[disabled] .btn-link:focus { + color: #999999; + text-decoration: none; +} + +.btn-lg { + padding: 10px 16px; + font-size: 18px; + line-height: 1.33; + border-radius: 6px; +} + +.btn-sm, +.btn-xs { + padding: 5px 10px; + font-size: 12px; + line-height: 1.5; + border-radius: 3px; +} + +.btn-xs { + padding: 1px 5px; +} + +.btn-block { + display: block; + width: 100%; + padding-right: 0; + padding-left: 0; +} + +.btn-block + .btn-block { + margin-top: 5px; +} + +input[type="submit"].btn-block, +input[type="reset"].btn-block, +input[type="button"].btn-block { + width: 100%; +} + +.fade { + opacity: 0; + -webkit-transition: opacity 0.15s linear; + transition: opacity 0.15s linear; +} + +.fade.in { + opacity: 1; +} + +.collapse { + display: none; +} + +.collapse.in { + display: block; +} + +.collapsing { + position: relative; + height: 0; + overflow: hidden; + -webkit-transition: height 0.35s ease; + transition: height 0.35s ease; +} + +@font-face { + font-family: 'Glyphicons Halflings'; + src: url('../fonts/glyphicons-halflings-regular.eot'); + src: url('../fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'), url('../fonts/glyphicons-halflings-regular.woff') format('woff'), url('../fonts/glyphicons-halflings-regular.ttf') format('truetype'), url('../fonts/glyphicons-halflings-regular.svg#glyphicons-halflingsregular') format('svg'); +} + +.glyphicon { + position: relative; + top: 1px; + display: inline-block; + font-family: 'Glyphicons Halflings'; + -webkit-font-smoothing: antialiased; + font-style: normal; + font-weight: normal; + line-height: 1; +} + +.glyphicon-asterisk:before { + content: "\2a"; +} + +.glyphicon-plus:before { + content: "\2b"; +} + +.glyphicon-euro:before { + content: "\20ac"; +} + +.glyphicon-minus:before { + content: "\2212"; +} + +.glyphicon-cloud:before { + content: "\2601"; +} + +.glyphicon-envelope:before { + content: "\2709"; +} + +.glyphicon-pencil:before { + content: "\270f"; +} + +.glyphicon-glass:before { + content: "\e001"; +} + +.glyphicon-music:before { + content: "\e002"; +} + +.glyphicon-search:before { + content: "\e003"; +} + +.glyphicon-heart:before { + content: "\e005"; +} + +.glyphicon-star:before { + content: "\e006"; +} + +.glyphicon-star-empty:before { + content: "\e007"; +} + +.glyphicon-user:before { + content: "\e008"; +} + +.glyphicon-film:before { + content: "\e009"; +} + +.glyphicon-th-large:before { + content: "\e010"; +} + +.glyphicon-th:before { + content: "\e011"; +} + +.glyphicon-th-list:before { + content: "\e012"; +} + +.glyphicon-ok:before { + content: "\e013"; +} + +.glyphicon-remove:before { + content: "\e014"; +} + +.glyphicon-zoom-in:before { + content: "\e015"; +} + +.glyphicon-zoom-out:before { + content: "\e016"; +} + +.glyphicon-off:before { + content: "\e017"; +} + +.glyphicon-signal:before { + content: "\e018"; +} + +.glyphicon-cog:before { + content: "\e019"; +} + +.glyphicon-trash:before { + content: "\e020"; +} + +.glyphicon-home:before { + content: "\e021"; +} + +.glyphicon-file:before { + content: "\e022"; +} + +.glyphicon-time:before { + content: "\e023"; +} + +.glyphicon-road:before { + content: "\e024"; +} + +.glyphicon-download-alt:before { + content: "\e025"; +} + +.glyphicon-download:before { + content: "\e026"; +} + +.glyphicon-upload:before { + content: "\e027"; +} + +.glyphicon-inbox:before { + content: "\e028"; +} + +.glyphicon-play-circle:before { + content: "\e029"; +} + +.glyphicon-repeat:before { + content: "\e030"; +} + +.glyphicon-refresh:before { + content: "\e031"; +} + +.glyphicon-list-alt:before { + content: "\e032"; +} + +.glyphicon-flag:before { + content: "\e034"; +} + +.glyphicon-headphones:before { + content: "\e035"; +} + +.glyphicon-volume-off:before { + content: "\e036"; +} + +.glyphicon-volume-down:before { + content: "\e037"; +} + +.glyphicon-volume-up:before { + content: "\e038"; +} + +.glyphicon-qrcode:before { + content: "\e039"; +} + +.glyphicon-barcode:before { + content: "\e040"; +} + +.glyphicon-tag:before { + content: "\e041"; +} + +.glyphicon-tags:before { + content: "\e042"; +} + +.glyphicon-book:before { + content: "\e043"; +} + +.glyphicon-print:before { + content: "\e045"; +} + +.glyphicon-font:before { + content: "\e047"; +} + +.glyphicon-bold:before { + content: "\e048"; +} + +.glyphicon-italic:before { + content: "\e049"; +} + +.glyphicon-text-height:before { + content: "\e050"; +} + +.glyphicon-text-width:before { + content: "\e051"; +} + +.glyphicon-align-left:before { + content: "\e052"; +} + +.glyphicon-align-center:before { + content: "\e053"; +} + +.glyphicon-align-right:before { + content: "\e054"; +} + +.glyphicon-align-justify:before { + content: "\e055"; +} + +.glyphicon-list:before { + content: "\e056"; +} + +.glyphicon-indent-left:before { + content: "\e057"; +} + +.glyphicon-indent-right:before { + content: "\e058"; +} + +.glyphicon-facetime-video:before { + content: "\e059"; +} + +.glyphicon-picture:before { + content: "\e060"; +} + +.glyphicon-map-marker:before { + content: "\e062"; +} + +.glyphicon-adjust:before { + content: "\e063"; +} + +.glyphicon-tint:before { + content: "\e064"; +} + +.glyphicon-edit:before { + content: "\e065"; +} + +.glyphicon-share:before { + content: "\e066"; +} + +.glyphicon-check:before { + content: "\e067"; +} + +.glyphicon-move:before { + content: "\e068"; +} + +.glyphicon-step-backward:before { + content: "\e069"; +} + +.glyphicon-fast-backward:before { + content: "\e070"; +} + +.glyphicon-backward:before { + content: "\e071"; +} + +.glyphicon-play:before { + content: "\e072"; +} + +.glyphicon-pause:before { + content: "\e073"; +} + +.glyphicon-stop:before { + content: "\e074"; +} + +.glyphicon-forward:before { + content: "\e075"; +} + +.glyphicon-fast-forward:before { + content: "\e076"; +} + +.glyphicon-step-forward:before { + content: "\e077"; +} + +.glyphicon-eject:before { + content: "\e078"; +} + +.glyphicon-chevron-left:before { + content: "\e079"; +} + +.glyphicon-chevron-right:before { + content: "\e080"; +} + +.glyphicon-plus-sign:before { + content: "\e081"; +} + +.glyphicon-minus-sign:before { + content: "\e082"; +} + +.glyphicon-remove-sign:before { + content: "\e083"; +} + +.glyphicon-ok-sign:before { + content: "\e084"; +} + +.glyphicon-question-sign:before { + content: "\e085"; +} + +.glyphicon-info-sign:before { + content: "\e086"; +} + +.glyphicon-screenshot:before { + content: "\e087"; +} + +.glyphicon-remove-circle:before { + content: "\e088"; +} + +.glyphicon-ok-circle:before { + content: "\e089"; +} + +.glyphicon-ban-circle:before { + content: "\e090"; +} + +.glyphicon-arrow-left:before { + content: "\e091"; +} + +.glyphicon-arrow-right:before { + content: "\e092"; +} + +.glyphicon-arrow-up:before { + content: "\e093"; +} + +.glyphicon-arrow-down:before { + content: "\e094"; +} + +.glyphicon-share-alt:before { + content: "\e095"; +} + +.glyphicon-resize-full:before { + content: "\e096"; +} + +.glyphicon-resize-small:before { + content: "\e097"; +} + +.glyphicon-exclamation-sign:before { + content: "\e101"; +} + +.glyphicon-gift:before { + content: "\e102"; +} + +.glyphicon-leaf:before { + content: "\e103"; +} + +.glyphicon-eye-open:before { + content: "\e105"; +} + +.glyphicon-eye-close:before { + content: "\e106"; +} + +.glyphicon-warning-sign:before { + content: "\e107"; +} + +.glyphicon-plane:before { + content: "\e108"; +} + +.glyphicon-random:before { + content: "\e110"; +} + +.glyphicon-comment:before { + content: "\e111"; +} + +.glyphicon-magnet:before { + content: "\e112"; +} + +.glyphicon-chevron-up:before { + content: "\e113"; +} + +.glyphicon-chevron-down:before { + content: "\e114"; +} + +.glyphicon-retweet:before { + content: "\e115"; +} + +.glyphicon-shopping-cart:before { + content: "\e116"; +} + +.glyphicon-folder-close:before { + content: "\e117"; +} + +.glyphicon-folder-open:before { + content: "\e118"; +} + +.glyphicon-resize-vertical:before { + content: "\e119"; +} + +.glyphicon-resize-horizontal:before { + content: "\e120"; +} + +.glyphicon-hdd:before { + content: "\e121"; +} + +.glyphicon-bullhorn:before { + content: "\e122"; +} + +.glyphicon-certificate:before { + content: "\e124"; +} + +.glyphicon-thumbs-up:before { + content: "\e125"; +} + +.glyphicon-thumbs-down:before { + content: "\e126"; +} + +.glyphicon-hand-right:before { + content: "\e127"; +} + +.glyphicon-hand-left:before { + content: "\e128"; +} + +.glyphicon-hand-up:before { + content: "\e129"; +} + +.glyphicon-hand-down:before { + content: "\e130"; +} + +.glyphicon-circle-arrow-right:before { + content: "\e131"; +} + +.glyphicon-circle-arrow-left:before { + content: "\e132"; +} + +.glyphicon-circle-arrow-up:before { + content: "\e133"; +} + +.glyphicon-circle-arrow-down:before { + content: "\e134"; +} + +.glyphicon-globe:before { + content: "\e135"; +} + +.glyphicon-tasks:before { + content: "\e137"; +} + +.glyphicon-filter:before { + content: "\e138"; +} + +.glyphicon-fullscreen:before { + content: "\e140"; +} + +.glyphicon-dashboard:before { + content: "\e141"; +} + +.glyphicon-heart-empty:before { + content: "\e143"; +} + +.glyphicon-link:before { + content: "\e144"; +} + +.glyphicon-phone:before { + content: "\e145"; +} + +.glyphicon-usd:before { + content: "\e148"; +} + +.glyphicon-gbp:before { + content: "\e149"; +} + +.glyphicon-sort:before { + content: "\e150"; +} + +.glyphicon-sort-by-alphabet:before { + content: "\e151"; +} + +.glyphicon-sort-by-alphabet-alt:before { + content: "\e152"; +} + +.glyphicon-sort-by-order:before { + content: "\e153"; +} + +.glyphicon-sort-by-order-alt:before { + content: "\e154"; +} + +.glyphicon-sort-by-attributes:before { + content: "\e155"; +} + +.glyphicon-sort-by-attributes-alt:before { + content: "\e156"; +} + +.glyphicon-unchecked:before { + content: "\e157"; +} + +.glyphicon-expand:before { + content: "\e158"; +} + +.glyphicon-collapse-down:before { + content: "\e159"; +} + +.glyphicon-collapse-up:before { + content: "\e160"; +} + +.glyphicon-log-in:before { + content: "\e161"; +} + +.glyphicon-flash:before { + content: "\e162"; +} + +.glyphicon-log-out:before { + content: "\e163"; +} + +.glyphicon-new-window:before { + content: "\e164"; +} + +.glyphicon-record:before { + content: "\e165"; +} + +.glyphicon-save:before { + content: "\e166"; +} + +.glyphicon-open:before { + content: "\e167"; +} + +.glyphicon-saved:before { + content: "\e168"; +} + +.glyphicon-import:before { + content: "\e169"; +} + +.glyphicon-export:before { + content: "\e170"; +} + +.glyphicon-send:before { + content: "\e171"; +} + +.glyphicon-floppy-disk:before { + content: "\e172"; +} + +.glyphicon-floppy-saved:before { + content: "\e173"; +} + +.glyphicon-floppy-remove:before { + content: "\e174"; +} + +.glyphicon-floppy-save:before { + content: "\e175"; +} + +.glyphicon-floppy-open:before { + content: "\e176"; +} + +.glyphicon-credit-card:before { + content: "\e177"; +} + +.glyphicon-transfer:before { + content: "\e178"; +} + +.glyphicon-cutlery:before { + content: "\e179"; +} + +.glyphicon-header:before { + content: "\e180"; +} + +.glyphicon-compressed:before { + content: "\e181"; +} + +.glyphicon-earphone:before { + content: "\e182"; +} + +.glyphicon-phone-alt:before { + content: "\e183"; +} + +.glyphicon-tower:before { + content: "\e184"; +} + +.glyphicon-stats:before { + content: "\e185"; +} + +.glyphicon-sd-video:before { + content: "\e186"; +} + +.glyphicon-hd-video:before { + content: "\e187"; +} + +.glyphicon-subtitles:before { + content: "\e188"; +} + +.glyphicon-sound-stereo:before { + content: "\e189"; +} + +.glyphicon-sound-dolby:before { + content: "\e190"; +} + +.glyphicon-sound-5-1:before { + content: "\e191"; +} + +.glyphicon-sound-6-1:before { + content: "\e192"; +} + +.glyphicon-sound-7-1:before { + content: "\e193"; +} + +.glyphicon-copyright-mark:before { + content: "\e194"; +} + +.glyphicon-registration-mark:before { + content: "\e195"; +} + +.glyphicon-cloud-download:before { + content: "\e197"; +} + +.glyphicon-cloud-upload:before { + content: "\e198"; +} + +.glyphicon-tree-conifer:before { + content: "\e199"; +} + +.glyphicon-tree-deciduous:before { + content: "\e200"; +} + +.glyphicon-briefcase:before { + content: "\1f4bc"; +} + +.glyphicon-calendar:before { + content: "\1f4c5"; +} + +.glyphicon-pushpin:before { + content: "\1f4cc"; +} + +.glyphicon-paperclip:before { + content: "\1f4ce"; +} + +.glyphicon-camera:before { + content: "\1f4f7"; +} + +.glyphicon-lock:before { + content: "\1f512"; +} + +.glyphicon-bell:before { + content: "\1f514"; +} + +.glyphicon-bookmark:before { + content: "\1f516"; +} + +.glyphicon-fire:before { + content: "\1f525"; +} + +.glyphicon-wrench:before { + content: "\1f527"; +} + +.caret { + display: inline-block; + width: 0; + height: 0; + margin-left: 2px; + vertical-align: middle; + border-top: 4px solid #000000; + border-right: 4px solid transparent; + border-bottom: 0 dotted; + border-left: 4px solid transparent; + content: ""; +} + +.dropdown { + position: relative; +} + +.dropdown-toggle:focus { + outline: 0; +} + +.dropdown-menu { + position: absolute; + top: 100%; + left: 0; + z-index: 1000; + display: none; + float: left; + min-width: 160px; + padding: 5px 0; + margin: 2px 0 0; + font-size: 14px; + list-style: none; + background-color: #ffffff; + border: 1px solid #cccccc; + border: 1px solid rgba(0, 0, 0, 0.15); + border-radius: 4px; + -webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175); + box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175); + background-clip: padding-box; +} + +.dropdown-menu.pull-right { + right: 0; + left: auto; +} + +.dropdown-menu .divider { + height: 1px; + margin: 9px 0; + overflow: hidden; + background-color: #e5e5e5; +} + +.dropdown-menu > li > a { + display: block; + padding: 3px 20px; + clear: both; + font-weight: normal; + line-height: 1.428571429; + color: #333333; + white-space: nowrap; +} + +.dropdown-menu > li > a:hover, +.dropdown-menu > li > a:focus { + color: #ffffff; + text-decoration: none; + background-color: #428bca; +} + +.dropdown-menu > .active > a, +.dropdown-menu > .active > a:hover, +.dropdown-menu > .active > a:focus { + color: #ffffff; + text-decoration: none; + background-color: #428bca; + outline: 0; +} + +.dropdown-menu > .disabled > a, +.dropdown-menu > .disabled > a:hover, +.dropdown-menu > .disabled > a:focus { + color: #999999; +} + +.dropdown-menu > .disabled > a:hover, +.dropdown-menu > .disabled > a:focus { + text-decoration: none; + cursor: not-allowed; + background-color: transparent; + background-image: none; + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); +} + +.open > .dropdown-menu { + display: block; +} + +.open > a { + outline: 0; +} + +.dropdown-header { + display: block; + padding: 3px 20px; + font-size: 12px; + line-height: 1.428571429; + color: #999999; +} + +.dropdown-backdrop { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 990; +} + +.pull-right > .dropdown-menu { + right: 0; + left: auto; +} + +.dropup .caret, +.navbar-fixed-bottom .dropdown .caret { + border-top: 0 dotted; + border-bottom: 4px solid #000000; + content: ""; +} + +.dropup .dropdown-menu, +.navbar-fixed-bottom .dropdown .dropdown-menu { + top: auto; + bottom: 100%; + margin-bottom: 1px; +} + +@media (min-width: 768px) { + .navbar-right .dropdown-menu { + right: 0; + left: auto; + } +} + +.btn-default .caret { + border-top-color: #333333; +} + +.btn-primary .caret, +.btn-success .caret, +.btn-warning .caret, +.btn-danger .caret, +.btn-info .caret { + border-top-color: #fff; +} + +.dropup .btn-default .caret { + border-bottom-color: #333333; +} + +.dropup .btn-primary .caret, +.dropup .btn-success .caret, +.dropup .btn-warning .caret, +.dropup .btn-danger .caret, +.dropup .btn-info .caret { + border-bottom-color: #fff; +} + +.btn-group, +.btn-group-vertical { + position: relative; + display: inline-block; + vertical-align: middle; +} + +.btn-group > .btn, +.btn-group-vertical > .btn { + position: relative; + float: left; +} + +.btn-group > .btn:hover, +.btn-group-vertical > .btn:hover, +.btn-group > .btn:focus, +.btn-group-vertical > .btn:focus, +.btn-group > .btn:active, +.btn-group-vertical > .btn:active, +.btn-group > .btn.active, +.btn-group-vertical > .btn.active { + z-index: 2; +} + +.btn-group > .btn:focus, +.btn-group-vertical > .btn:focus { + outline: none; +} + +.btn-group .btn + .btn, +.btn-group .btn + .btn-group, +.btn-group .btn-group + .btn, +.btn-group .btn-group + .btn-group { + margin-left: -1px; +} + +.btn-toolbar:before, +.btn-toolbar:after { + display: table; + content: " "; +} + +.btn-toolbar:after { + clear: both; +} + +.btn-toolbar:before, +.btn-toolbar:after { + display: table; + content: " "; +} + +.btn-toolbar:after { + clear: both; +} + +.btn-toolbar .btn-group { + float: left; +} + +.btn-toolbar > .btn + .btn, +.btn-toolbar > .btn-group + .btn, +.btn-toolbar > .btn + .btn-group, +.btn-toolbar > .btn-group + .btn-group { + margin-left: 5px; +} + +.btn-group > .btn:not(:first-child):not(:last-child):not(.dropdown-toggle) { + border-radius: 0; +} + +.btn-group > .btn:first-child { + margin-left: 0; +} + +.btn-group > .btn:first-child:not(:last-child):not(.dropdown-toggle) { + border-top-right-radius: 0; + border-bottom-right-radius: 0; +} + +.btn-group > .btn:last-child:not(:first-child), +.btn-group > .dropdown-toggle:not(:first-child) { + border-bottom-left-radius: 0; + border-top-left-radius: 0; +} + +.btn-group > .btn-group { + float: left; +} + +.btn-group > .btn-group:not(:first-child):not(:last-child) > .btn { + border-radius: 0; +} + +.btn-group > .btn-group:first-child > .btn:last-child, +.btn-group > .btn-group:first-child > .dropdown-toggle { + border-top-right-radius: 0; + border-bottom-right-radius: 0; +} + +.btn-group > .btn-group:last-child > .btn:first-child { + border-bottom-left-radius: 0; + border-top-left-radius: 0; +} + +.btn-group .dropdown-toggle:active, +.btn-group.open .dropdown-toggle { + outline: 0; +} + +.btn-group-xs > .btn { + padding: 5px 10px; + padding: 1px 5px; + font-size: 12px; + line-height: 1.5; + border-radius: 3px; +} + +.btn-group-sm > .btn { + padding: 5px 10px; + font-size: 12px; + line-height: 1.5; + border-radius: 3px; +} + +.btn-group-lg > .btn { + padding: 10px 16px; + font-size: 18px; + line-height: 1.33; + border-radius: 6px; +} + +.btn-group > .btn + .dropdown-toggle { + padding-right: 8px; + padding-left: 8px; +} + +.btn-group > .btn-lg + .dropdown-toggle { + padding-right: 12px; + padding-left: 12px; +} + +.btn-group.open .dropdown-toggle { + -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); +} + +.btn .caret { + margin-left: 0; +} + +.btn-lg .caret { + border-width: 5px 5px 0; + border-bottom-width: 0; +} + +.dropup .btn-lg .caret { + border-width: 0 5px 5px; +} + +.btn-group-vertical > .btn, +.btn-group-vertical > .btn-group { + display: block; + float: none; + width: 100%; + max-width: 100%; +} + +.btn-group-vertical > .btn-group:before, +.btn-group-vertical > .btn-group:after { + display: table; + content: " "; +} + +.btn-group-vertical > .btn-group:after { + clear: both; +} + +.btn-group-vertical > .btn-group:before, +.btn-group-vertical > .btn-group:after { + display: table; + content: " "; +} + +.btn-group-vertical > .btn-group:after { + clear: both; +} + +.btn-group-vertical > .btn-group > .btn { + float: none; +} + +.btn-group-vertical > .btn + .btn, +.btn-group-vertical > .btn + .btn-group, +.btn-group-vertical > .btn-group + .btn, +.btn-group-vertical > .btn-group + .btn-group { + margin-top: -1px; + margin-left: 0; +} + +.btn-group-vertical > .btn:not(:first-child):not(:last-child) { + border-radius: 0; +} + +.btn-group-vertical > .btn:first-child:not(:last-child) { + border-top-right-radius: 4px; + border-bottom-right-radius: 0; + border-bottom-left-radius: 0; +} + +.btn-group-vertical > .btn:last-child:not(:first-child) { + border-top-right-radius: 0; + border-bottom-left-radius: 4px; + border-top-left-radius: 0; +} + +.btn-group-vertical > .btn-group:not(:first-child):not(:last-child) > .btn { + border-radius: 0; +} + +.btn-group-vertical > .btn-group:first-child > .btn:last-child, +.btn-group-vertical > .btn-group:first-child > .dropdown-toggle { + border-bottom-right-radius: 0; + border-bottom-left-radius: 0; +} + +.btn-group-vertical > .btn-group:last-child > .btn:first-child { + border-top-right-radius: 0; + border-top-left-radius: 0; +} + +.btn-group-justified { + display: table; + width: 100%; + border-collapse: separate; + table-layout: fixed; +} + +.btn-group-justified .btn { + display: table-cell; + float: none; + width: 1%; +} + +[data-toggle="buttons"] > .btn > input[type="radio"], +[data-toggle="buttons"] > .btn > input[type="checkbox"] { + display: none; +} + +.input-group { + position: relative; + display: table; + border-collapse: separate; +} + +.input-group.col { + float: none; + padding-right: 0; + padding-left: 0; +} + +.input-group .form-control { + width: 100%; + margin-bottom: 0; +} + +.input-group-lg > .form-control, +.input-group-lg > .input-group-addon, +.input-group-lg > .input-group-btn > .btn { + height: 45px; + padding: 10px 16px; + font-size: 18px; + line-height: 1.33; + border-radius: 6px; +} + +select.input-group-lg > .form-control, +select.input-group-lg > .input-group-addon, +select.input-group-lg > .input-group-btn > .btn { + height: 45px; + line-height: 45px; +} + +textarea.input-group-lg > .form-control, +textarea.input-group-lg > .input-group-addon, +textarea.input-group-lg > .input-group-btn > .btn { + height: auto; +} + +.input-group-sm > .form-control, +.input-group-sm > .input-group-addon, +.input-group-sm > .input-group-btn > .btn { + height: 30px; + padding: 5px 10px; + font-size: 12px; + line-height: 1.5; + border-radius: 3px; +} + +select.input-group-sm > .form-control, +select.input-group-sm > .input-group-addon, +select.input-group-sm > .input-group-btn > .btn { + height: 30px; + line-height: 30px; +} + +textarea.input-group-sm > .form-control, +textarea.input-group-sm > .input-group-addon, +textarea.input-group-sm > .input-group-btn > .btn { + height: auto; +} + +.input-group-addon, +.input-group-btn, +.input-group .form-control { + display: table-cell; +} + +.input-group-addon:not(:first-child):not(:last-child), +.input-group-btn:not(:first-child):not(:last-child), +.input-group .form-control:not(:first-child):not(:last-child) { + border-radius: 0; +} + +.input-group-addon, +.input-group-btn { + width: 1%; + white-space: nowrap; + vertical-align: middle; +} + +.input-group-addon { + padding: 6px 12px; + font-size: 14px; + font-weight: normal; + line-height: 1; + text-align: center; + background-color: #eeeeee; + border: 1px solid #cccccc; + border-radius: 4px; +} + +.input-group-addon.input-sm { + padding: 5px 10px; + font-size: 12px; + border-radius: 3px; +} + +.input-group-addon.input-lg { + padding: 10px 16px; + font-size: 18px; + border-radius: 6px; +} + +.input-group-addon input[type="radio"], +.input-group-addon input[type="checkbox"] { + margin-top: 0; +} + +.input-group .form-control:first-child, +.input-group-addon:first-child, +.input-group-btn:first-child > .btn, +.input-group-btn:first-child > .dropdown-toggle, +.input-group-btn:last-child > .btn:not(:last-child):not(.dropdown-toggle) { + border-top-right-radius: 0; + border-bottom-right-radius: 0; +} + +.input-group-addon:first-child { + border-right: 0; +} + +.input-group .form-control:last-child, +.input-group-addon:last-child, +.input-group-btn:last-child > .btn, +.input-group-btn:last-child > .dropdown-toggle, +.input-group-btn:first-child > .btn:not(:first-child) { + border-bottom-left-radius: 0; + border-top-left-radius: 0; +} + +.input-group-addon:last-child { + border-left: 0; +} + +.input-group-btn { + position: relative; + white-space: nowrap; +} + +.input-group-btn > .btn { + position: relative; +} + +.input-group-btn > .btn + .btn { + margin-left: -4px; +} + +.input-group-btn > .btn:hover, +.input-group-btn > .btn:active { + z-index: 2; +} + +.nav { + padding-left: 0; + margin-bottom: 0; + list-style: none; +} + +.nav:before, +.nav:after { + display: table; + content: " "; +} + +.nav:after { + clear: both; +} + +.nav:before, +.nav:after { + display: table; + content: " "; +} + +.nav:after { + clear: both; +} + +.nav > li { + position: relative; + display: block; +} + +.nav > li > a { + position: relative; + display: block; + padding: 10px 15px; +} + +.nav > li > a:hover, +.nav > li > a:focus { + text-decoration: none; + background-color: #eeeeee; +} + +.nav > li.disabled > a { + color: #999999; +} + +.nav > li.disabled > a:hover, +.nav > li.disabled > a:focus { + color: #999999; + text-decoration: none; + cursor: not-allowed; + background-color: transparent; +} + +.nav .open > a, +.nav .open > a:hover, +.nav .open > a:focus { + background-color: #eeeeee; + border-color: #428bca; +} + +.nav .nav-divider { + height: 1px; + margin: 9px 0; + overflow: hidden; + background-color: #e5e5e5; +} + +.nav > li > a > img { + max-width: none; +} + +.nav-tabs { + border-bottom: 1px solid #dddddd; +} + +.nav-tabs > li { + float: left; + margin-bottom: -1px; +} + +.nav-tabs > li > a { + margin-right: 2px; + line-height: 1.428571429; + border: 1px solid transparent; + border-radius: 4px 4px 0 0; +} + +.nav-tabs > li > a:hover { + border-color: #eeeeee #eeeeee #dddddd; +} + +.nav-tabs > li.active > a, +.nav-tabs > li.active > a:hover, +.nav-tabs > li.active > a:focus { + color: #555555; + cursor: default; + background-color: #ffffff; + border: 1px solid #dddddd; + border-bottom-color: transparent; +} + +.nav-tabs.nav-justified { + width: 100%; + border-bottom: 0; +} + +.nav-tabs.nav-justified > li { + float: none; +} + +.nav-tabs.nav-justified > li > a { + text-align: center; +} + +@media (min-width: 768px) { + .nav-tabs.nav-justified > li { + display: table-cell; + width: 1%; + } +} + +.nav-tabs.nav-justified > li > a { + margin-right: 0; + border-bottom: 1px solid #dddddd; +} + +.nav-tabs.nav-justified > .active > a { + border-bottom-color: #ffffff; +} + +.nav-pills > li { + float: left; +} + +.nav-pills > li > a { + border-radius: 5px; +} + +.nav-pills > li + li { + margin-left: 2px; +} + +.nav-pills > li.active > a, +.nav-pills > li.active > a:hover, +.nav-pills > li.active > a:focus { + color: #ffffff; + background-color: #428bca; +} + +.nav-stacked > li { + float: none; +} + +.nav-stacked > li + li { + margin-top: 2px; + margin-left: 0; +} + +.nav-justified { + width: 100%; +} + +.nav-justified > li { + float: none; +} + +.nav-justified > li > a { + text-align: center; +} + +@media (min-width: 768px) { + .nav-justified > li { + display: table-cell; + width: 1%; + } +} + +.nav-tabs-justified { + border-bottom: 0; +} + +.nav-tabs-justified > li > a { + margin-right: 0; + border-bottom: 1px solid #dddddd; +} + +.nav-tabs-justified > .active > a { + border-bottom-color: #ffffff; +} + +.tabbable:before, +.tabbable:after { + display: table; + content: " "; +} + +.tabbable:after { + clear: both; +} + +.tabbable:before, +.tabbable:after { + display: table; + content: " "; +} + +.tabbable:after { + clear: both; +} + +.tab-content > .tab-pane, +.pill-content > .pill-pane { + display: none; +} + +.tab-content > .active, +.pill-content > .active { + display: block; +} + +.nav .caret { + border-top-color: #428bca; + border-bottom-color: #428bca; +} + +.nav a:hover .caret { + border-top-color: #2a6496; + border-bottom-color: #2a6496; +} + +.nav-tabs .dropdown-menu { + margin-top: -1px; + border-top-right-radius: 0; + border-top-left-radius: 0; +} + +.navbar { + position: relative; + z-index: 1000; + min-height: 50px; + margin-bottom: 20px; + border: 1px solid transparent; +} + +.navbar:before, +.navbar:after { + display: table; + content: " "; +} + +.navbar:after { + clear: both; +} + +.navbar:before, +.navbar:after { + display: table; + content: " "; +} + +.navbar:after { + clear: both; +} + +@media (min-width: 768px) { + .navbar { + border-radius: 4px; + } +} + +.navbar-header:before, +.navbar-header:after { + display: table; + content: " "; +} + +.navbar-header:after { + clear: both; +} + +.navbar-header:before, +.navbar-header:after { + display: table; + content: " "; +} + +.navbar-header:after { + clear: both; +} + +@media (min-width: 768px) { + .navbar-header { + float: left; + } +} + +.navbar-collapse { + max-height: 340px; + padding-right: 15px; + padding-left: 15px; + overflow-x: visible; + border-top: 1px solid transparent; + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1); + -webkit-overflow-scrolling: touch; +} + +.navbar-collapse:before, +.navbar-collapse:after { + display: table; + content: " "; +} + +.navbar-collapse:after { + clear: both; +} + +.navbar-collapse:before, +.navbar-collapse:after { + display: table; + content: " "; +} + +.navbar-collapse:after { + clear: both; +} + +.navbar-collapse.in { + overflow-y: auto; +} + +@media (min-width: 768px) { + .navbar-collapse { + width: auto; + border-top: 0; + box-shadow: none; + } + .navbar-collapse.collapse { + display: block !important; + height: auto !important; + padding-bottom: 0; + overflow: visible !important; + } + .navbar-collapse.in { + overflow-y: visible; + } + .navbar-collapse .navbar-nav.navbar-left:first-child { + margin-left: -15px; + } + .navbar-collapse .navbar-nav.navbar-right:last-child { + margin-right: -15px; + } + .navbar-collapse .navbar-text:last-child { + margin-right: 0; + } +} + +.container > .navbar-header, +.container > .navbar-collapse { + margin-right: -15px; + margin-left: -15px; +} + +@media (min-width: 768px) { + .container > .navbar-header, + .container > .navbar-collapse { + margin-right: 0; + margin-left: 0; + } +} + +.navbar-static-top { + border-width: 0 0 1px; +} + +@media (min-width: 768px) { + .navbar-static-top { + border-radius: 0; + } +} + +.navbar-fixed-top, +.navbar-fixed-bottom { + position: fixed; + right: 0; + left: 0; + border-width: 0 0 1px; +} + +@media (min-width: 768px) { + .navbar-fixed-top, + .navbar-fixed-bottom { + border-radius: 0; + } +} + +.navbar-fixed-top { + top: 0; + z-index: 1030; +} + +.navbar-fixed-bottom { + bottom: 0; + margin-bottom: 0; +} + +.navbar-brand { + float: left; + padding: 15px 15px; + font-size: 18px; + line-height: 20px; +} + +.navbar-brand:hover, +.navbar-brand:focus { + text-decoration: none; +} + +@media (min-width: 768px) { + .navbar > .container .navbar-brand { + margin-left: -15px; + } +} + +.navbar-toggle { + position: relative; + float: right; + padding: 9px 10px; + margin-top: 8px; + margin-right: 15px; + margin-bottom: 8px; + background-color: transparent; + border: 1px solid transparent; + border-radius: 4px; +} + +.navbar-toggle .icon-bar { + display: block; + width: 22px; + height: 2px; + border-radius: 1px; +} + +.navbar-toggle .icon-bar + .icon-bar { + margin-top: 4px; +} + +@media (min-width: 768px) { + .navbar-toggle { + display: none; + } +} + +.navbar-nav { + margin: 7.5px -15px; +} + +.navbar-nav > li > a { + padding-top: 10px; + padding-bottom: 10px; + line-height: 20px; +} + +@media (max-width: 767px) { + .navbar-nav .open .dropdown-menu { + position: static; + float: none; + width: auto; + margin-top: 0; + background-color: transparent; + border: 0; + box-shadow: none; + } + .navbar-nav .open .dropdown-menu > li > a, + .navbar-nav .open .dropdown-menu .dropdown-header { + padding: 5px 15px 5px 25px; + } + .navbar-nav .open .dropdown-menu > li > a { + line-height: 20px; + } + .navbar-nav .open .dropdown-menu > li > a:hover, + .navbar-nav .open .dropdown-menu > li > a:focus { + background-image: none; + } +} + +@media (min-width: 768px) { + .navbar-nav { + float: left; + margin: 0; + } + .navbar-nav > li { + float: left; + } + .navbar-nav > li > a { + padding-top: 15px; + padding-bottom: 15px; + } +} + +@media (min-width: 768px) { + .navbar-left { + float: left !important; + } + .navbar-right { + float: right !important; + } +} + +.navbar-form { + padding: 10px 15px; + margin-top: 8px; + margin-right: -15px; + margin-bottom: 8px; + margin-left: -15px; + border-top: 1px solid transparent; + border-bottom: 1px solid transparent; + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); +} + +@media (min-width: 768px) { + .navbar-form .form-group { + display: inline-block; + margin-bottom: 0; + vertical-align: middle; + } + .navbar-form .form-control { + display: inline-block; + } + .navbar-form .radio, + .navbar-form .checkbox { + display: inline-block; + padding-left: 0; + margin-top: 0; + margin-bottom: 0; + } + .navbar-form .radio input[type="radio"], + .navbar-form .checkbox input[type="checkbox"] { + float: none; + margin-left: 0; + } +} + +@media (max-width: 767px) { + .navbar-form .form-group { + margin-bottom: 5px; + } +} + +@media (min-width: 768px) { + .navbar-form { + width: auto; + padding-top: 0; + padding-bottom: 0; + margin-right: 0; + margin-left: 0; + border: 0; + -webkit-box-shadow: none; + box-shadow: none; + } +} + +.navbar-nav > li > .dropdown-menu { + margin-top: 0; + border-top-right-radius: 0; + border-top-left-radius: 0; +} + +.navbar-fixed-bottom .navbar-nav > li > .dropdown-menu { + border-bottom-right-radius: 0; + border-bottom-left-radius: 0; +} + +.navbar-nav.pull-right > li > .dropdown-menu, +.navbar-nav > li > .dropdown-menu.pull-right { + right: 0; + left: auto; +} + +.navbar-btn { + margin-top: 8px; + margin-bottom: 8px; +} + +.navbar-text { + float: left; + margin-top: 15px; + margin-bottom: 15px; +} + +@media (min-width: 768px) { + .navbar-text { + margin-right: 15px; + margin-left: 15px; + } +} + +.navbar-default { + background-color: #f8f8f8; + border-color: #e7e7e7; +} + +.navbar-default .navbar-brand { + color: #777777; +} + +.navbar-default .navbar-brand:hover, +.navbar-default .navbar-brand:focus { + color: #5e5e5e; + background-color: transparent; +} + +.navbar-default .navbar-text { + color: #777777; +} + +.navbar-default .navbar-nav > li > a { + color: #777777; +} + +.navbar-default .navbar-nav > li > a:hover, +.navbar-default .navbar-nav > li > a:focus { + color: #333333; + background-color: transparent; +} + +.navbar-default .navbar-nav > .active > a, +.navbar-default .navbar-nav > .active > a:hover, +.navbar-default .navbar-nav > .active > a:focus { + color: #555555; + background-color: #e7e7e7; +} + +.navbar-default .navbar-nav > .disabled > a, +.navbar-default .navbar-nav > .disabled > a:hover, +.navbar-default .navbar-nav > .disabled > a:focus { + color: #cccccc; + background-color: transparent; +} + +.navbar-default .navbar-toggle { + border-color: #dddddd; +} + +.navbar-default .navbar-toggle:hover, +.navbar-default .navbar-toggle:focus { + background-color: #dddddd; +} + +.navbar-default .navbar-toggle .icon-bar { + background-color: #cccccc; +} + +.navbar-default .navbar-collapse, +.navbar-default .navbar-form { + border-color: #e6e6e6; +} + +.navbar-default .navbar-nav > .dropdown > a:hover .caret, +.navbar-default .navbar-nav > .dropdown > a:focus .caret { + border-top-color: #333333; + border-bottom-color: #333333; +} + +.navbar-default .navbar-nav > .open > a, +.navbar-default .navbar-nav > .open > a:hover, +.navbar-default .navbar-nav > .open > a:focus { + color: #555555; + background-color: #e7e7e7; +} + +.navbar-default .navbar-nav > .open > a .caret, +.navbar-default .navbar-nav > .open > a:hover .caret, +.navbar-default .navbar-nav > .open > a:focus .caret { + border-top-color: #555555; + border-bottom-color: #555555; +} + +.navbar-default .navbar-nav > .dropdown > a .caret { + border-top-color: #777777; + border-bottom-color: #777777; +} + +@media (max-width: 767px) { + .navbar-default .navbar-nav .open .dropdown-menu > li > a { + color: #777777; + } + .navbar-default .navbar-nav .open .dropdown-menu > li > a:hover, + .navbar-default .navbar-nav .open .dropdown-menu > li > a:focus { + color: #333333; + background-color: transparent; + } + .navbar-default .navbar-nav .open .dropdown-menu > .active > a, + .navbar-default .navbar-nav .open .dropdown-menu > .active > a:hover, + .navbar-default .navbar-nav .open .dropdown-menu > .active > a:focus { + color: #555555; + background-color: #e7e7e7; + } + .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a, + .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:hover, + .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:focus { + color: #cccccc; + background-color: transparent; + } +} + +.navbar-default .navbar-link { + color: #777777; +} + +.navbar-default .navbar-link:hover { + color: #333333; +} + +.navbar-inverse { + background-color: #222222; + border-color: #080808; +} + +.navbar-inverse .navbar-brand { + color: #999999; +} + +.navbar-inverse .navbar-brand:hover, +.navbar-inverse .navbar-brand:focus { + color: #ffffff; + background-color: transparent; +} + +.navbar-inverse .navbar-text { + color: #999999; +} + +.navbar-inverse .navbar-nav > li > a { + color: #999999; +} + +.navbar-inverse .navbar-nav > li > a:hover, +.navbar-inverse .navbar-nav > li > a:focus { + color: #ffffff; + background-color: transparent; +} + +.navbar-inverse .navbar-nav > .active > a, +.navbar-inverse .navbar-nav > .active > a:hover, +.navbar-inverse .navbar-nav > .active > a:focus { + color: #ffffff; + background-color: #080808; +} + +.navbar-inverse .navbar-nav > .disabled > a, +.navbar-inverse .navbar-nav > .disabled > a:hover, +.navbar-inverse .navbar-nav > .disabled > a:focus { + color: #444444; + background-color: transparent; +} + +.navbar-inverse .navbar-toggle { + border-color: #333333; +} + +.navbar-inverse .navbar-toggle:hover, +.navbar-inverse .navbar-toggle:focus { + background-color: #333333; +} + +.navbar-inverse .navbar-toggle .icon-bar { + background-color: #ffffff; +} + +.navbar-inverse .navbar-collapse, +.navbar-inverse .navbar-form { + border-color: #101010; +} + +.navbar-inverse .navbar-nav > .open > a, +.navbar-inverse .navbar-nav > .open > a:hover, +.navbar-inverse .navbar-nav > .open > a:focus { + color: #ffffff; + background-color: #080808; +} + +.navbar-inverse .navbar-nav > .dropdown > a:hover .caret { + border-top-color: #ffffff; + border-bottom-color: #ffffff; +} + +.navbar-inverse .navbar-nav > .dropdown > a .caret { + border-top-color: #999999; + border-bottom-color: #999999; +} + +.navbar-inverse .navbar-nav > .open > a .caret, +.navbar-inverse .navbar-nav > .open > a:hover .caret, +.navbar-inverse .navbar-nav > .open > a:focus .caret { + border-top-color: #ffffff; + border-bottom-color: #ffffff; +} + +@media (max-width: 767px) { + .navbar-inverse .navbar-nav .open .dropdown-menu > .dropdown-header { + border-color: #080808; + } + .navbar-inverse .navbar-nav .open .dropdown-menu > li > a { + color: #999999; + } + .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:hover, + .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:focus { + color: #ffffff; + background-color: transparent; + } + .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a, + .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:hover, + .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:focus { + color: #ffffff; + background-color: #080808; + } + .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a, + .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:hover, + .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:focus { + color: #444444; + background-color: transparent; + } +} + +.navbar-inverse .navbar-link { + color: #999999; +} + +.navbar-inverse .navbar-link:hover { + color: #ffffff; +} + +.breadcrumb { + padding: 8px 15px; + margin-bottom: 20px; + list-style: none; + background-color: #f5f5f5; + border-radius: 4px; +} + +.breadcrumb > li { + display: inline-block; +} + +.breadcrumb > li + li:before { + padding: 0 5px; + color: #cccccc; + content: "/\00a0"; +} + +.breadcrumb > .active { + color: #999999; +} + +.pagination { + display: inline-block; + padding-left: 0; + margin: 20px 0; + border-radius: 4px; +} + +.pagination > li { + display: inline; +} + +.pagination > li > a, +.pagination > li > span { + position: relative; + float: left; + padding: 6px 12px; + margin-left: -1px; + line-height: 1.428571429; + text-decoration: none; + background-color: #ffffff; + border: 1px solid #dddddd; +} + +.pagination > li:first-child > a, +.pagination > li:first-child > span { + margin-left: 0; + border-bottom-left-radius: 4px; + border-top-left-radius: 4px; +} + +.pagination > li:last-child > a, +.pagination > li:last-child > span { + border-top-right-radius: 4px; + border-bottom-right-radius: 4px; +} + +.pagination > li > a:hover, +.pagination > li > span:hover, +.pagination > li > a:focus, +.pagination > li > span:focus { + background-color: #eeeeee; +} + +.pagination > .active > a, +.pagination > .active > span, +.pagination > .active > a:hover, +.pagination > .active > span:hover, +.pagination > .active > a:focus, +.pagination > .active > span:focus { + z-index: 2; + color: #ffffff; + cursor: default; + background-color: #428bca; + border-color: #428bca; +} + +.pagination > .disabled > span, +.pagination > .disabled > a, +.pagination > .disabled > a:hover, +.pagination > .disabled > a:focus { + color: #999999; + cursor: not-allowed; + background-color: #ffffff; + border-color: #dddddd; +} + +.pagination-lg > li > a, +.pagination-lg > li > span { + padding: 10px 16px; + font-size: 18px; +} + +.pagination-lg > li:first-child > a, +.pagination-lg > li:first-child > span { + border-bottom-left-radius: 6px; + border-top-left-radius: 6px; +} + +.pagination-lg > li:last-child > a, +.pagination-lg > li:last-child > span { + border-top-right-radius: 6px; + border-bottom-right-radius: 6px; +} + +.pagination-sm > li > a, +.pagination-sm > li > span { + padding: 5px 10px; + font-size: 12px; +} + +.pagination-sm > li:first-child > a, +.pagination-sm > li:first-child > span { + border-bottom-left-radius: 3px; + border-top-left-radius: 3px; +} + +.pagination-sm > li:last-child > a, +.pagination-sm > li:last-child > span { + border-top-right-radius: 3px; + border-bottom-right-radius: 3px; +} + +.pager { + padding-left: 0; + margin: 20px 0; + text-align: center; + list-style: none; +} + +.pager:before, +.pager:after { + display: table; + content: " "; +} + +.pager:after { + clear: both; +} + +.pager:before, +.pager:after { + display: table; + content: " "; +} + +.pager:after { + clear: both; +} + +.pager li { + display: inline; +} + +.pager li > a, +.pager li > span { + display: inline-block; + padding: 5px 14px; + background-color: #ffffff; + border: 1px solid #dddddd; + border-radius: 15px; +} + +.pager li > a:hover, +.pager li > a:focus { + text-decoration: none; + background-color: #eeeeee; +} + +.pager .next > a, +.pager .next > span { + float: right; +} + +.pager .previous > a, +.pager .previous > span { + float: left; +} + +.pager .disabled > a, +.pager .disabled > a:hover, +.pager .disabled > a:focus, +.pager .disabled > span { + color: #999999; + cursor: not-allowed; + background-color: #ffffff; +} + +.label { + display: inline; + padding: .2em .6em .3em; + font-size: 75%; + font-weight: bold; + line-height: 1; + color: #ffffff; + text-align: center; + white-space: nowrap; + vertical-align: baseline; + border-radius: .25em; +} + +.label[href]:hover, +.label[href]:focus { + color: #ffffff; + text-decoration: none; + cursor: pointer; +} + +.label:empty { + display: none; +} + +.label-default { + background-color: #999999; +} + +.label-default[href]:hover, +.label-default[href]:focus { + background-color: #808080; +} + +.label-primary { + background-color: #428bca; +} + +.label-primary[href]:hover, +.label-primary[href]:focus { + background-color: #3071a9; +} + +.label-success { + background-color: #5cb85c; +} + +.label-success[href]:hover, +.label-success[href]:focus { + background-color: #449d44; +} + +.label-info { + background-color: #5bc0de; +} + +.label-info[href]:hover, +.label-info[href]:focus { + background-color: #31b0d5; +} + +.label-warning { + background-color: #f0ad4e; +} + +.label-warning[href]:hover, +.label-warning[href]:focus { + background-color: #ec971f; +} + +.label-danger { + background-color: #d9534f; +} + +.label-danger[href]:hover, +.label-danger[href]:focus { + background-color: #c9302c; +} + +.badge { + display: inline-block; + min-width: 10px; + padding: 3px 7px; + font-size: 12px; + font-weight: bold; + line-height: 1; + color: #ffffff; + text-align: center; + white-space: nowrap; + vertical-align: baseline; + background-color: #999999; + border-radius: 10px; +} + +.badge:empty { + display: none; +} + +a.badge:hover, +a.badge:focus { + color: #ffffff; + text-decoration: none; + cursor: pointer; +} + +.btn .badge { + position: relative; + top: -1px; +} + +a.list-group-item.active > .badge, +.nav-pills > .active > a > .badge { + color: #428bca; + background-color: #ffffff; +} + +.nav-pills > li > a > .badge { + margin-left: 3px; +} + +.jumbotron { + padding: 30px; + margin-bottom: 30px; + font-size: 21px; + font-weight: 200; + line-height: 2.1428571435; + color: inherit; + background-color: #eeeeee; +} + +.jumbotron h1 { + line-height: 1; + color: inherit; +} + +.jumbotron p { + line-height: 1.4; +} + +.container .jumbotron { + border-radius: 6px; +} + +@media screen and (min-width: 768px) { + .jumbotron { + padding-top: 48px; + padding-bottom: 48px; + } + .container .jumbotron { + padding-right: 60px; + padding-left: 60px; + } + .jumbotron h1 { + font-size: 63px; + } +} + +.thumbnail { + display: inline-block; + display: block; + height: auto; + max-width: 100%; + padding: 4px; + line-height: 1.428571429; + background-color: #ffffff; + border: 1px solid #dddddd; + border-radius: 4px; + -webkit-transition: all 0.2s ease-in-out; + transition: all 0.2s ease-in-out; +} + +.thumbnail > img { + display: block; + height: auto; + max-width: 100%; +} + +a.thumbnail:hover, +a.thumbnail:focus { + border-color: #428bca; +} + +.thumbnail > img { + margin-right: auto; + margin-left: auto; +} + +.thumbnail .caption { + padding: 9px; + color: #333333; +} + +.alert { + padding: 15px; + margin-bottom: 20px; + border: 1px solid transparent; + border-radius: 4px; +} + +.alert h4 { + margin-top: 0; + color: inherit; +} + +.alert .alert-link { + font-weight: bold; +} + +.alert > p, +.alert > ul { + margin-bottom: 0; +} + +.alert > p + p { + margin-top: 5px; +} + +.alert-dismissable { + padding-right: 35px; +} + +.alert-dismissable .close { + position: relative; + top: -2px; + right: -21px; + color: inherit; +} + +.alert-success { + color: #468847; + background-color: #dff0d8; + border-color: #d6e9c6; +} + +.alert-success hr { + border-top-color: #c9e2b3; +} + +.alert-success .alert-link { + color: #356635; +} + +.alert-info { + color: #3a87ad; + background-color: #d9edf7; + border-color: #bce8f1; +} + +.alert-info hr { + border-top-color: #a6e1ec; +} + +.alert-info .alert-link { + color: #2d6987; +} + +.alert-warning { + color: #c09853; + background-color: #fcf8e3; + border-color: #fbeed5; +} + +.alert-warning hr { + border-top-color: #f8e5be; +} + +.alert-warning .alert-link { + color: #a47e3c; +} + +.alert-danger { + color: #b94a48; + background-color: #f2dede; + border-color: #eed3d7; +} + +.alert-danger hr { + border-top-color: #e6c1c7; +} + +.alert-danger .alert-link { + color: #953b39; +} + +@-webkit-keyframes progress-bar-stripes { + from { + background-position: 40px 0; + } + to { + background-position: 0 0; + } +} + +@-moz-keyframes progress-bar-stripes { + from { + background-position: 40px 0; + } + to { + background-position: 0 0; + } +} + +@-o-keyframes progress-bar-stripes { + from { + background-position: 0 0; + } + to { + background-position: 40px 0; + } +} + +@keyframes progress-bar-stripes { + from { + background-position: 40px 0; + } + to { + background-position: 0 0; + } +} + +.progress { + height: 20px; + margin-bottom: 20px; + overflow: hidden; + background-color: #f5f5f5; + border-radius: 4px; + -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); +} + +.progress-bar { + float: left; + width: 0; + height: 100%; + font-size: 12px; + color: #ffffff; + text-align: center; + background-color: #428bca; + -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + -webkit-transition: width 0.6s ease; + transition: width 0.6s ease; +} + +.progress-striped .progress-bar { + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-size: 40px 40px; +} + +.progress.active .progress-bar { + -webkit-animation: progress-bar-stripes 2s linear infinite; + -moz-animation: progress-bar-stripes 2s linear infinite; + -ms-animation: progress-bar-stripes 2s linear infinite; + -o-animation: progress-bar-stripes 2s linear infinite; + animation: progress-bar-stripes 2s linear infinite; +} + +.progress-bar-success { + background-color: #5cb85c; +} + +.progress-striped .progress-bar-success { + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} + +.progress-bar-info { + background-color: #5bc0de; +} + +.progress-striped .progress-bar-info { + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} + +.progress-bar-warning { + background-color: #f0ad4e; +} + +.progress-striped .progress-bar-warning { + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} + +.progress-bar-danger { + background-color: #d9534f; +} + +.progress-striped .progress-bar-danger { + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} + +.media, +.media-body { + overflow: hidden; + zoom: 1; +} + +.media, +.media .media { + margin-top: 15px; +} + +.media:first-child { + margin-top: 0; +} + +.media-object { + display: block; +} + +.media-heading { + margin: 0 0 5px; +} + +.media > .pull-left { + margin-right: 10px; +} + +.media > .pull-right { + margin-left: 10px; +} + +.media-list { + padding-left: 0; + list-style: none; +} + +.list-group { + padding-left: 0; + margin-bottom: 20px; +} + +.list-group-item { + position: relative; + display: block; + padding: 10px 15px; + margin-bottom: -1px; + background-color: #ffffff; + border: 1px solid #dddddd; +} + +.list-group-item:first-child { + border-top-right-radius: 4px; + border-top-left-radius: 4px; +} + +.list-group-item:last-child { + margin-bottom: 0; + border-bottom-right-radius: 4px; + border-bottom-left-radius: 4px; +} + +.list-group-item > .badge { + float: right; +} + +.list-group-item > .badge + .badge { + margin-right: 5px; +} + +a.list-group-item { + color: #555555; +} + +a.list-group-item .list-group-item-heading { + color: #333333; +} + +a.list-group-item:hover, +a.list-group-item:focus { + text-decoration: none; + background-color: #f5f5f5; +} + +.list-group-item.active, +.list-group-item.active:hover, +.list-group-item.active:focus { + z-index: 2; + color: #ffffff; + background-color: #428bca; + border-color: #428bca; +} + +.list-group-item.active .list-group-item-heading, +.list-group-item.active:hover .list-group-item-heading, +.list-group-item.active:focus .list-group-item-heading { + color: inherit; +} + +.list-group-item.active .list-group-item-text, +.list-group-item.active:hover .list-group-item-text, +.list-group-item.active:focus .list-group-item-text { + color: #e1edf7; +} + +.list-group-item-heading { + margin-top: 0; + margin-bottom: 5px; +} + +.list-group-item-text { + margin-bottom: 0; + line-height: 1.3; +} + +.panel { + margin-bottom: 20px; + background-color: #ffffff; + border: 1px solid transparent; + border-radius: 4px; + -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05); + box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05); +} + +.panel-body { + padding: 15px; +} + +.panel-body:before, +.panel-body:after { + display: table; + content: " "; +} + +.panel-body:after { + clear: both; +} + +.panel-body:before, +.panel-body:after { + display: table; + content: " "; +} + +.panel-body:after { + clear: both; +} + +.panel > .list-group { + margin-bottom: 0; +} + +.panel > .list-group .list-group-item { + border-width: 1px 0; +} + +.panel > .list-group .list-group-item:first-child { + border-top-right-radius: 0; + border-top-left-radius: 0; +} + +.panel > .list-group .list-group-item:last-child { + border-bottom: 0; +} + +.panel-heading + .list-group .list-group-item:first-child { + border-top-width: 0; +} + +.panel > .table { + margin-bottom: 0; +} + +.panel > .panel-body + .table { + border-top: 1px solid #dddddd; +} + +.panel-heading { + padding: 10px 15px; + border-bottom: 1px solid transparent; + border-top-right-radius: 3px; + border-top-left-radius: 3px; +} + +.panel-title { + margin-top: 0; + margin-bottom: 0; + font-size: 16px; +} + +.panel-title > a { + color: inherit; +} + +.panel-footer { + padding: 10px 15px; + background-color: #f5f5f5; + border-top: 1px solid #dddddd; + border-bottom-right-radius: 3px; + border-bottom-left-radius: 3px; +} + +.panel-group .panel { + margin-bottom: 0; + overflow: hidden; + border-radius: 4px; +} + +.panel-group .panel + .panel { + margin-top: 5px; +} + +.panel-group .panel-heading { + border-bottom: 0; +} + +.panel-group .panel-heading + .panel-collapse .panel-body { + border-top: 1px solid #dddddd; +} + +.panel-group .panel-footer { + border-top: 0; +} + +.panel-group .panel-footer + .panel-collapse .panel-body { + border-bottom: 1px solid #dddddd; +} + +.panel-default { + border-color: #dddddd; +} + +.panel-default > .panel-heading { + color: #333333; + background-color: #f5f5f5; + border-color: #dddddd; +} + +.panel-default > .panel-heading + .panel-collapse .panel-body { + border-top-color: #dddddd; +} + +.panel-default > .panel-footer + .panel-collapse .panel-body { + border-bottom-color: #dddddd; +} + +.panel-primary { + border-color: #428bca; +} + +.panel-primary > .panel-heading { + color: #ffffff; + background-color: #428bca; + border-color: #428bca; +} + +.panel-primary > .panel-heading + .panel-collapse .panel-body { + border-top-color: #428bca; +} + +.panel-primary > .panel-footer + .panel-collapse .panel-body { + border-bottom-color: #428bca; +} + +.panel-success { + border-color: #d6e9c6; +} + +.panel-success > .panel-heading { + color: #468847; + background-color: #dff0d8; + border-color: #d6e9c6; +} + +.panel-success > .panel-heading + .panel-collapse .panel-body { + border-top-color: #d6e9c6; +} + +.panel-success > .panel-footer + .panel-collapse .panel-body { + border-bottom-color: #d6e9c6; +} + +.panel-warning { + border-color: #fbeed5; +} + +.panel-warning > .panel-heading { + color: #c09853; + background-color: #fcf8e3; + border-color: #fbeed5; +} + +.panel-warning > .panel-heading + .panel-collapse .panel-body { + border-top-color: #fbeed5; +} + +.panel-warning > .panel-footer + .panel-collapse .panel-body { + border-bottom-color: #fbeed5; +} + +.panel-danger { + border-color: #eed3d7; +} + +.panel-danger > .panel-heading { + color: #b94a48; + background-color: #f2dede; + border-color: #eed3d7; +} + +.panel-danger > .panel-heading + .panel-collapse .panel-body { + border-top-color: #eed3d7; +} + +.panel-danger > .panel-footer + .panel-collapse .panel-body { + border-bottom-color: #eed3d7; +} + +.panel-info { + border-color: #bce8f1; +} + +.panel-info > .panel-heading { + color: #3a87ad; + background-color: #d9edf7; + border-color: #bce8f1; +} + +.panel-info > .panel-heading + .panel-collapse .panel-body { + border-top-color: #bce8f1; +} + +.panel-info > .panel-footer + .panel-collapse .panel-body { + border-bottom-color: #bce8f1; +} + +.well { + min-height: 20px; + padding: 19px; + margin-bottom: 20px; + background-color: #f5f5f5; + border: 1px solid #e3e3e3; + border-radius: 4px; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); +} + +.well blockquote { + border-color: #ddd; + border-color: rgba(0, 0, 0, 0.15); +} + +.well-lg { + padding: 24px; + border-radius: 6px; +} + +.well-sm { + padding: 9px; + border-radius: 3px; +} + +.close { + float: right; + font-size: 21px; + font-weight: bold; + line-height: 1; + color: #000000; + text-shadow: 0 1px 0 #ffffff; + opacity: 0.2; + filter: alpha(opacity=20); +} + +.close:hover, +.close:focus { + color: #000000; + text-decoration: none; + cursor: pointer; + opacity: 0.5; + filter: alpha(opacity=50); +} + +button.close { + padding: 0; + cursor: pointer; + background: transparent; + border: 0; + -webkit-appearance: none; +} + +.modal-open { + overflow: hidden; +} + +body.modal-open, +.modal-open .navbar-fixed-top, +.modal-open .navbar-fixed-bottom { + margin-right: 15px; +} + +.modal { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 1040; + display: none; + overflow: auto; + overflow-y: scroll; +} + +.modal.fade .modal-dialog { + -webkit-transform: translate(0, -25%); + -ms-transform: translate(0, -25%); + transform: translate(0, -25%); + -webkit-transition: -webkit-transform 0.3s ease-out; + -moz-transition: -moz-transform 0.3s ease-out; + -o-transition: -o-transform 0.3s ease-out; + transition: transform 0.3s ease-out; +} + +.modal.in .modal-dialog { + -webkit-transform: translate(0, 0); + -ms-transform: translate(0, 0); + transform: translate(0, 0); +} + +.modal-dialog { + z-index: 1050; + width: auto; + padding: 10px; + margin-right: auto; + margin-left: auto; +} + +.modal-content { + position: relative; + background-color: #ffffff; + border: 1px solid #999999; + border: 1px solid rgba(0, 0, 0, 0.2); + border-radius: 6px; + outline: none; + -webkit-box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5); + box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5); + background-clip: padding-box; +} + +.modal-backdrop { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 1030; + background-color: #000000; +} + +.modal-backdrop.fade { + opacity: 0; + filter: alpha(opacity=0); +} + +.modal-backdrop.in { + opacity: 0.5; + filter: alpha(opacity=50); +} + +.modal-header { + min-height: 16.428571429px; + padding: 15px; + border-bottom: 1px solid #e5e5e5; +} + +.modal-header .close { + margin-top: -2px; +} + +.modal-title { + margin: 0; + line-height: 1.428571429; +} + +.modal-body { + position: relative; + padding: 20px; +} + +.modal-footer { + padding: 19px 20px 20px; + margin-top: 15px; + text-align: right; + border-top: 1px solid #e5e5e5; +} + +.modal-footer:before, +.modal-footer:after { + display: table; + content: " "; +} + +.modal-footer:after { + clear: both; +} + +.modal-footer:before, +.modal-footer:after { + display: table; + content: " "; +} + +.modal-footer:after { + clear: both; +} + +.modal-footer .btn + .btn { + margin-bottom: 0; + margin-left: 5px; +} + +.modal-footer .btn-group .btn + .btn { + margin-left: -1px; +} + +.modal-footer .btn-block + .btn-block { + margin-left: 0; +} + +@media screen and (min-width: 768px) { + .modal-dialog { + right: auto; + left: 50%; + width: 600px; + padding-top: 30px; + padding-bottom: 30px; + } + .modal-content { + -webkit-box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5); + box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5); + } +} + +.tooltip { + position: absolute; + z-index: 1030; + display: block; + font-size: 12px; + line-height: 1.4; + opacity: 0; + filter: alpha(opacity=0); + visibility: visible; +} + +.tooltip.in { + opacity: 0.9; + filter: alpha(opacity=90); +} + +.tooltip.top { + padding: 5px 0; + margin-top: -3px; +} + +.tooltip.right { + padding: 0 5px; + margin-left: 3px; +} + +.tooltip.bottom { + padding: 5px 0; + margin-top: 3px; +} + +.tooltip.left { + padding: 0 5px; + margin-left: -3px; +} + +.tooltip-inner { + max-width: 200px; + padding: 3px 8px; + color: #ffffff; + text-align: center; + text-decoration: none; + background-color: #000000; + border-radius: 4px; +} + +.tooltip-arrow { + position: absolute; + width: 0; + height: 0; + border-color: transparent; + border-style: solid; +} + +.tooltip.top .tooltip-arrow { + bottom: 0; + left: 50%; + margin-left: -5px; + border-top-color: #000000; + border-width: 5px 5px 0; +} + +.tooltip.top-left .tooltip-arrow { + bottom: 0; + left: 5px; + border-top-color: #000000; + border-width: 5px 5px 0; +} + +.tooltip.top-right .tooltip-arrow { + right: 5px; + bottom: 0; + border-top-color: #000000; + border-width: 5px 5px 0; +} + +.tooltip.right .tooltip-arrow { + top: 50%; + left: 0; + margin-top: -5px; + border-right-color: #000000; + border-width: 5px 5px 5px 0; +} + +.tooltip.left .tooltip-arrow { + top: 50%; + right: 0; + margin-top: -5px; + border-left-color: #000000; + border-width: 5px 0 5px 5px; +} + +.tooltip.bottom .tooltip-arrow { + top: 0; + left: 50%; + margin-left: -5px; + border-bottom-color: #000000; + border-width: 0 5px 5px; +} + +.tooltip.bottom-left .tooltip-arrow { + top: 0; + left: 5px; + border-bottom-color: #000000; + border-width: 0 5px 5px; +} + +.tooltip.bottom-right .tooltip-arrow { + top: 0; + right: 5px; + border-bottom-color: #000000; + border-width: 0 5px 5px; +} + +.popover { + position: absolute; + top: 0; + left: 0; + z-index: 1010; + display: none; + max-width: 276px; + padding: 1px; + text-align: left; + white-space: normal; + background-color: #ffffff; + border: 1px solid #cccccc; + border: 1px solid rgba(0, 0, 0, 0.2); + border-radius: 6px; + -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + background-clip: padding-box; +} + +.popover.top { + margin-top: -10px; +} + +.popover.right { + margin-left: 10px; +} + +.popover.bottom { + margin-top: 10px; +} + +.popover.left { + margin-left: -10px; +} + +.popover-title { + padding: 8px 14px; + margin: 0; + font-size: 14px; + font-weight: normal; + line-height: 18px; + background-color: #f7f7f7; + border-bottom: 1px solid #ebebeb; + border-radius: 5px 5px 0 0; +} + +.popover-content { + padding: 9px 14px; +} + +.popover .arrow, +.popover .arrow:after { + position: absolute; + display: block; + width: 0; + height: 0; + border-color: transparent; + border-style: solid; +} + +.popover .arrow { + border-width: 11px; +} + +.popover .arrow:after { + border-width: 10px; + content: ""; +} + +.popover.top .arrow { + bottom: -11px; + left: 50%; + margin-left: -11px; + border-top-color: #999999; + border-top-color: rgba(0, 0, 0, 0.25); + border-bottom-width: 0; +} + +.popover.top .arrow:after { + bottom: 1px; + margin-left: -10px; + border-top-color: #ffffff; + border-bottom-width: 0; + content: " "; +} + +.popover.right .arrow { + top: 50%; + left: -11px; + margin-top: -11px; + border-right-color: #999999; + border-right-color: rgba(0, 0, 0, 0.25); + border-left-width: 0; +} + +.popover.right .arrow:after { + bottom: -10px; + left: 1px; + border-right-color: #ffffff; + border-left-width: 0; + content: " "; +} + +.popover.bottom .arrow { + top: -11px; + left: 50%; + margin-left: -11px; + border-bottom-color: #999999; + border-bottom-color: rgba(0, 0, 0, 0.25); + border-top-width: 0; +} + +.popover.bottom .arrow:after { + top: 1px; + margin-left: -10px; + border-bottom-color: #ffffff; + border-top-width: 0; + content: " "; +} + +.popover.left .arrow { + top: 50%; + right: -11px; + margin-top: -11px; + border-left-color: #999999; + border-left-color: rgba(0, 0, 0, 0.25); + border-right-width: 0; +} + +.popover.left .arrow:after { + right: 1px; + bottom: -10px; + border-left-color: #ffffff; + border-right-width: 0; + content: " "; +} + +.carousel { + position: relative; +} + +.carousel-inner { + position: relative; + width: 100%; + overflow: hidden; +} + +.carousel-inner > .item { + position: relative; + display: none; + -webkit-transition: 0.6s ease-in-out left; + transition: 0.6s ease-in-out left; +} + +.carousel-inner > .item > img, +.carousel-inner > .item > a > img { + display: block; + height: auto; + max-width: 100%; + line-height: 1; +} + +.carousel-inner > .active, +.carousel-inner > .next, +.carousel-inner > .prev { + display: block; +} + +.carousel-inner > .active { + left: 0; +} + +.carousel-inner > .next, +.carousel-inner > .prev { + position: absolute; + top: 0; + width: 100%; +} + +.carousel-inner > .next { + left: 100%; +} + +.carousel-inner > .prev { + left: -100%; +} + +.carousel-inner > .next.left, +.carousel-inner > .prev.right { + left: 0; +} + +.carousel-inner > .active.left { + left: -100%; +} + +.carousel-inner > .active.right { + left: 100%; +} + +.carousel-control { + position: absolute; + top: 0; + bottom: 0; + left: 0; + width: 15%; + font-size: 20px; + color: #ffffff; + text-align: center; + text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6); + opacity: 0.5; + filter: alpha(opacity=50); +} + +.carousel-control.left { + background-image: -webkit-gradient(linear, 0 top, 100% top, from(rgba(0, 0, 0, 0.5)), to(rgba(0, 0, 0, 0.0001))); + background-image: -webkit-linear-gradient(left, color-stop(rgba(0, 0, 0, 0.5) 0), color-stop(rgba(0, 0, 0, 0.0001) 100%)); + background-image: -moz-linear-gradient(left, rgba(0, 0, 0, 0.5) 0, rgba(0, 0, 0, 0.0001) 100%); + background-image: linear-gradient(to right, rgba(0, 0, 0, 0.5) 0, rgba(0, 0, 0, 0.0001) 100%); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1); +} + +.carousel-control.right { + right: 0; + left: auto; + background-image: -webkit-gradient(linear, 0 top, 100% top, from(rgba(0, 0, 0, 0.0001)), to(rgba(0, 0, 0, 0.5))); + background-image: -webkit-linear-gradient(left, color-stop(rgba(0, 0, 0, 0.0001) 0), color-stop(rgba(0, 0, 0, 0.5) 100%)); + background-image: -moz-linear-gradient(left, rgba(0, 0, 0, 0.0001) 0, rgba(0, 0, 0, 0.5) 100%); + background-image: linear-gradient(to right, rgba(0, 0, 0, 0.0001) 0, rgba(0, 0, 0, 0.5) 100%); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1); +} + +.carousel-control:hover, +.carousel-control:focus { + color: #ffffff; + text-decoration: none; + opacity: 0.9; + filter: alpha(opacity=90); +} + +.carousel-control .icon-prev, +.carousel-control .icon-next, +.carousel-control .glyphicon-chevron-left, +.carousel-control .glyphicon-chevron-right { + position: absolute; + top: 50%; + left: 50%; + z-index: 5; + display: inline-block; +} + +.carousel-control .icon-prev, +.carousel-control .icon-next { + width: 20px; + height: 20px; + margin-top: -10px; + margin-left: -10px; + font-family: serif; +} + +.carousel-control .icon-prev:before { + content: '\2039'; +} + +.carousel-control .icon-next:before { + content: '\203a'; +} + +.carousel-indicators { + position: absolute; + bottom: 10px; + left: 50%; + z-index: 15; + width: 60%; + padding-left: 0; + margin-left: -30%; + text-align: center; + list-style: none; +} + +.carousel-indicators li { + display: inline-block; + width: 10px; + height: 10px; + margin: 1px; + text-indent: -999px; + cursor: pointer; + border: 1px solid #ffffff; + border-radius: 10px; +} + +.carousel-indicators .active { + width: 12px; + height: 12px; + margin: 0; + background-color: #ffffff; +} + +.carousel-caption { + position: absolute; + right: 15%; + bottom: 20px; + left: 15%; + z-index: 10; + padding-top: 20px; + padding-bottom: 20px; + color: #ffffff; + text-align: center; + text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6); +} + +.carousel-caption .btn { + text-shadow: none; +} + +@media screen and (min-width: 768px) { + .carousel-control .icon-prev, + .carousel-control .icon-next { + width: 30px; + height: 30px; + margin-top: -15px; + margin-left: -15px; + font-size: 30px; + } + .carousel-caption { + right: 20%; + left: 20%; + padding-bottom: 30px; + } + .carousel-indicators { + bottom: 20px; + } +} + +.clearfix:before, +.clearfix:after { + display: table; + content: " "; +} + +.clearfix:after { + clear: both; +} + +.pull-right { + float: right !important; +} + +.pull-left { + float: left !important; +} + +.hide { + display: none !important; +} + +.show { + display: block !important; +} + +.invisible { + visibility: hidden; +} + +.text-hide { + font: 0/0 a; + color: transparent; + text-shadow: none; + background-color: transparent; + border: 0; +} + +.affix { + position: fixed; +} + +@-ms-viewport { + width: device-width; +} + +@media screen and (max-width: 400px) { + @-ms-viewport { + width: 320px; + } +} + +.hidden { + display: none !important; + visibility: hidden !important; +} + +.visible-xs { + display: none !important; +} + +tr.visible-xs { + display: none !important; +} + +th.visible-xs, +td.visible-xs { + display: none !important; +} + +@media (max-width: 767px) { + .visible-xs { + display: block !important; + } + tr.visible-xs { + display: table-row !important; + } + th.visible-xs, + td.visible-xs { + display: table-cell !important; + } +} + +@media (min-width: 768px) and (max-width: 991px) { + .visible-xs.visible-sm { + display: block !important; + } + tr.visible-xs.visible-sm { + display: table-row !important; + } + th.visible-xs.visible-sm, + td.visible-xs.visible-sm { + display: table-cell !important; + } +} + +@media (min-width: 992px) and (max-width: 1199px) { + .visible-xs.visible-md { + display: block !important; + } + tr.visible-xs.visible-md { + display: table-row !important; + } + th.visible-xs.visible-md, + td.visible-xs.visible-md { + display: table-cell !important; + } +} + +@media (min-width: 1200px) { + .visible-xs.visible-lg { + display: block !important; + } + tr.visible-xs.visible-lg { + display: table-row !important; + } + th.visible-xs.visible-lg, + td.visible-xs.visible-lg { + display: table-cell !important; + } +} + +.visible-sm { + display: none !important; +} + +tr.visible-sm { + display: none !important; +} + +th.visible-sm, +td.visible-sm { + display: none !important; +} + +@media (max-width: 767px) { + .visible-sm.visible-xs { + display: block !important; + } + tr.visible-sm.visible-xs { + display: table-row !important; + } + th.visible-sm.visible-xs, + td.visible-sm.visible-xs { + display: table-cell !important; + } +} + +@media (min-width: 768px) and (max-width: 991px) { + .visible-sm { + display: block !important; + } + tr.visible-sm { + display: table-row !important; + } + th.visible-sm, + td.visible-sm { + display: table-cell !important; + } +} + +@media (min-width: 992px) and (max-width: 1199px) { + .visible-sm.visible-md { + display: block !important; + } + tr.visible-sm.visible-md { + display: table-row !important; + } + th.visible-sm.visible-md, + td.visible-sm.visible-md { + display: table-cell !important; + } +} + +@media (min-width: 1200px) { + .visible-sm.visible-lg { + display: block !important; + } + tr.visible-sm.visible-lg { + display: table-row !important; + } + th.visible-sm.visible-lg, + td.visible-sm.visible-lg { + display: table-cell !important; + } +} + +.visible-md { + display: none !important; +} + +tr.visible-md { + display: none !important; +} + +th.visible-md, +td.visible-md { + display: none !important; +} + +@media (max-width: 767px) { + .visible-md.visible-xs { + display: block !important; + } + tr.visible-md.visible-xs { + display: table-row !important; + } + th.visible-md.visible-xs, + td.visible-md.visible-xs { + display: table-cell !important; + } +} + +@media (min-width: 768px) and (max-width: 991px) { + .visible-md.visible-sm { + display: block !important; + } + tr.visible-md.visible-sm { + display: table-row !important; + } + th.visible-md.visible-sm, + td.visible-md.visible-sm { + display: table-cell !important; + } +} + +@media (min-width: 992px) and (max-width: 1199px) { + .visible-md { + display: block !important; + } + tr.visible-md { + display: table-row !important; + } + th.visible-md, + td.visible-md { + display: table-cell !important; + } +} + +@media (min-width: 1200px) { + .visible-md.visible-lg { + display: block !important; + } + tr.visible-md.visible-lg { + display: table-row !important; + } + th.visible-md.visible-lg, + td.visible-md.visible-lg { + display: table-cell !important; + } +} + +.visible-lg { + display: none !important; +} + +tr.visible-lg { + display: none !important; +} + +th.visible-lg, +td.visible-lg { + display: none !important; +} + +@media (max-width: 767px) { + .visible-lg.visible-xs { + display: block !important; + } + tr.visible-lg.visible-xs { + display: table-row !important; + } + th.visible-lg.visible-xs, + td.visible-lg.visible-xs { + display: table-cell !important; + } +} + +@media (min-width: 768px) and (max-width: 991px) { + .visible-lg.visible-sm { + display: block !important; + } + tr.visible-lg.visible-sm { + display: table-row !important; + } + th.visible-lg.visible-sm, + td.visible-lg.visible-sm { + display: table-cell !important; + } +} + +@media (min-width: 992px) and (max-width: 1199px) { + .visible-lg.visible-md { + display: block !important; + } + tr.visible-lg.visible-md { + display: table-row !important; + } + th.visible-lg.visible-md, + td.visible-lg.visible-md { + display: table-cell !important; + } +} + +@media (min-width: 1200px) { + .visible-lg { + display: block !important; + } + tr.visible-lg { + display: table-row !important; + } + th.visible-lg, + td.visible-lg { + display: table-cell !important; + } +} + +.hidden-xs { + display: block !important; +} + +tr.hidden-xs { + display: table-row !important; +} + +th.hidden-xs, +td.hidden-xs { + display: table-cell !important; +} + +@media (max-width: 767px) { + .hidden-xs { + display: none !important; + } + tr.hidden-xs { + display: none !important; + } + th.hidden-xs, + td.hidden-xs { + display: none !important; + } +} + +@media (min-width: 768px) and (max-width: 991px) { + .hidden-xs.hidden-sm { + display: none !important; + } + tr.hidden-xs.hidden-sm { + display: none !important; + } + th.hidden-xs.hidden-sm, + td.hidden-xs.hidden-sm { + display: none !important; + } +} + +@media (min-width: 992px) and (max-width: 1199px) { + .hidden-xs.hidden-md { + display: none !important; + } + tr.hidden-xs.hidden-md { + display: none !important; + } + th.hidden-xs.hidden-md, + td.hidden-xs.hidden-md { + display: none !important; + } +} + +@media (min-width: 1200px) { + .hidden-xs.hidden-lg { + display: none !important; + } + tr.hidden-xs.hidden-lg { + display: none !important; + } + th.hidden-xs.hidden-lg, + td.hidden-xs.hidden-lg { + display: none !important; + } +} + +.hidden-sm { + display: block !important; +} + +tr.hidden-sm { + display: table-row !important; +} + +th.hidden-sm, +td.hidden-sm { + display: table-cell !important; +} + +@media (max-width: 767px) { + .hidden-sm.hidden-xs { + display: none !important; + } + tr.hidden-sm.hidden-xs { + display: none !important; + } + th.hidden-sm.hidden-xs, + td.hidden-sm.hidden-xs { + display: none !important; + } +} + +@media (min-width: 768px) and (max-width: 991px) { + .hidden-sm { + display: none !important; + } + tr.hidden-sm { + display: none !important; + } + th.hidden-sm, + td.hidden-sm { + display: none !important; + } +} + +@media (min-width: 992px) and (max-width: 1199px) { + .hidden-sm.hidden-md { + display: none !important; + } + tr.hidden-sm.hidden-md { + display: none !important; + } + th.hidden-sm.hidden-md, + td.hidden-sm.hidden-md { + display: none !important; + } +} + +@media (min-width: 1200px) { + .hidden-sm.hidden-lg { + display: none !important; + } + tr.hidden-sm.hidden-lg { + display: none !important; + } + th.hidden-sm.hidden-lg, + td.hidden-sm.hidden-lg { + display: none !important; + } +} + +.hidden-md { + display: block !important; +} + +tr.hidden-md { + display: table-row !important; +} + +th.hidden-md, +td.hidden-md { + display: table-cell !important; +} + +@media (max-width: 767px) { + .hidden-md.hidden-xs { + display: none !important; + } + tr.hidden-md.hidden-xs { + display: none !important; + } + th.hidden-md.hidden-xs, + td.hidden-md.hidden-xs { + display: none !important; + } +} + +@media (min-width: 768px) and (max-width: 991px) { + .hidden-md.hidden-sm { + display: none !important; + } + tr.hidden-md.hidden-sm { + display: none !important; + } + th.hidden-md.hidden-sm, + td.hidden-md.hidden-sm { + display: none !important; + } +} + +@media (min-width: 992px) and (max-width: 1199px) { + .hidden-md { + display: none !important; + } + tr.hidden-md { + display: none !important; + } + th.hidden-md, + td.hidden-md { + display: none !important; + } +} + +@media (min-width: 1200px) { + .hidden-md.hidden-lg { + display: none !important; + } + tr.hidden-md.hidden-lg { + display: none !important; + } + th.hidden-md.hidden-lg, + td.hidden-md.hidden-lg { + display: none !important; + } +} + +.hidden-lg { + display: block !important; +} + +tr.hidden-lg { + display: table-row !important; +} + +th.hidden-lg, +td.hidden-lg { + display: table-cell !important; +} + +@media (max-width: 767px) { + .hidden-lg.hidden-xs { + display: none !important; + } + tr.hidden-lg.hidden-xs { + display: none !important; + } + th.hidden-lg.hidden-xs, + td.hidden-lg.hidden-xs { + display: none !important; + } +} + +@media (min-width: 768px) and (max-width: 991px) { + .hidden-lg.hidden-sm { + display: none !important; + } + tr.hidden-lg.hidden-sm { + display: none !important; + } + th.hidden-lg.hidden-sm, + td.hidden-lg.hidden-sm { + display: none !important; + } +} + +@media (min-width: 992px) and (max-width: 1199px) { + .hidden-lg.hidden-md { + display: none !important; + } + tr.hidden-lg.hidden-md { + display: none !important; + } + th.hidden-lg.hidden-md, + td.hidden-lg.hidden-md { + display: none !important; + } +} + +@media (min-width: 1200px) { + .hidden-lg { + display: none !important; + } + tr.hidden-lg { + display: none !important; + } + th.hidden-lg, + td.hidden-lg { + display: none !important; + } +} + +.visible-print { + display: none !important; +} + +tr.visible-print { + display: none !important; +} + +th.visible-print, +td.visible-print { + display: none !important; +} + +@media print { + .visible-print { + display: block !important; + } + tr.visible-print { + display: table-row !important; + } + th.visible-print, + td.visible-print { + display: table-cell !important; + } + .hidden-print { + display: none !important; + } + tr.hidden-print { + display: none !important; + } + th.hidden-print, + td.hidden-print { + display: none !important; + } +} \ No newline at end of file diff --git a/Amen/Content/bootstrap.min.css b/Amen/Content/bootstrap.min.css new file mode 100644 index 0000000..df89a50 --- /dev/null +++ b/Amen/Content/bootstrap.min.css @@ -0,0 +1,20 @@ +/* NUGET: BEGIN LICENSE TEXT + * + * Microsoft grants you the right to use these script files for the sole + * purpose of either: (i) interacting through your browser with the Microsoft + * website or online service, subject to the applicable licensing or use + * terms; or (ii) using the files as included with a Microsoft product subject + * to that product's license terms. Microsoft reserves all other rights to the + * files not expressly granted by Microsoft, whether by implication, estoppel + * or otherwise. The notices and licenses below are for informational purposes only. + * + * NUGET: END LICENSE TEXT */ +/*! + * Bootstrap v3.0.0 + * + * Copyright 2013 Twitter, Inc + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Designed and built with all the love in the world by @mdo and @fat. + *//*! normalize.css v2.1.0 | MIT License | git.io/normalize */article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block}audio,canvas,video{display:inline-block}audio:not([controls]){display:none;height:0}[hidden]{display:none}html{font-family:sans-serif;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}a:focus{outline:thin dotted}a:active,a:hover{outline:0}h1{margin:.67em 0;font-size:2em}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:bold}dfn{font-style:italic}hr{height:0;-moz-box-sizing:content-box;box-sizing:content-box}mark{color:#000;background:#ff0}code,kbd,pre,samp{font-family:monospace,serif;font-size:1em}pre{white-space:pre-wrap}q{quotes:"\201C" "\201D" "\2018" "\2019"}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:0}fieldset{padding:.35em .625em .75em;margin:0 2px;border:1px solid #c0c0c0}legend{padding:0;border:0}button,input,select,textarea{margin:0;font-family:inherit;font-size:100%}button,input{line-height:normal}button,select{text-transform:none}button,html input[type="button"],input[type="reset"],input[type="submit"]{cursor:pointer;-webkit-appearance:button}button[disabled],html input[disabled]{cursor:default}input[type="checkbox"],input[type="radio"]{padding:0;box-sizing:border-box}input[type="search"]{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-appearance:textfield}input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration{-webkit-appearance:none}button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0}textarea{overflow:auto;vertical-align:top}table{border-collapse:collapse;border-spacing:0}@media print{*{color:#000!important;text-shadow:none!important;background:transparent!important;box-shadow:none!important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100%!important}@page{margin:2cm .5cm}p,h2,h3{orphans:3;widows:3}h2,h3{page-break-after:avoid}.navbar{display:none}.table td,.table th{background-color:#fff!important}.btn>.caret,.dropup>.btn>.caret{border-top-color:#000!important}.label{border:1px solid #000}.table{border-collapse:collapse!important}.table-bordered th,.table-bordered td{border:1px solid #ddd!important}}*,*:before,*:after{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:62.5%;-webkit-tap-highlight-color:rgba(0,0,0,0)}body{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:1.428571429;color:#333;background-color:#fff}input,button,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit}button,input,select[multiple],textarea{background-image:none}a{color:#428bca;text-decoration:none}a:hover,a:focus{color:#2a6496;text-decoration:underline}a:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}img{vertical-align:middle}.img-responsive{display:block;height:auto;max-width:100%}.img-rounded{border-radius:6px}.img-thumbnail{display:inline-block;height:auto;max-width:100%;padding:4px;line-height:1.428571429;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.img-circle{border-radius:50%}hr{margin-top:20px;margin-bottom:20px;border:0;border-top:1px solid #eee}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0 0 0 0);border:0}p{margin:0 0 10px}.lead{margin-bottom:20px;font-size:16.099999999999998px;font-weight:200;line-height:1.4}@media(min-width:768px){.lead{font-size:21px}}small{font-size:85%}cite{font-style:normal}.text-muted{color:#999}.text-primary{color:#428bca}.text-warning{color:#c09853}.text-danger{color:#b94a48}.text-success{color:#468847}.text-info{color:#3a87ad}.text-left{text-align:left}.text-right{text-align:right}.text-center{text-align:center}h1,h2,h3,h4,h5,h6,.h1,.h2,.h3,.h4,.h5,.h6{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-weight:500;line-height:1.1}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small,.h1 small,.h2 small,.h3 small,.h4 small,.h5 small,.h6 small{font-weight:normal;line-height:1;color:#999}h1,h2,h3{margin-top:20px;margin-bottom:10px}h4,h5,h6{margin-top:10px;margin-bottom:10px}h1,.h1{font-size:36px}h2,.h2{font-size:30px}h3,.h3{font-size:24px}h4,.h4{font-size:18px}h5,.h5{font-size:14px}h6,.h6{font-size:12px}h1 small,.h1 small{font-size:24px}h2 small,.h2 small{font-size:18px}h3 small,.h3 small,h4 small,.h4 small{font-size:14px}.page-header{padding-bottom:9px;margin:40px 0 20px;border-bottom:1px solid #eee}ul,ol{margin-top:0;margin-bottom:10px}ul ul,ol ul,ul ol,ol ol{margin-bottom:0}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;list-style:none}.list-inline>li{display:inline-block;padding-right:5px;padding-left:5px}dl{margin-bottom:20px}dt,dd{line-height:1.428571429}dt{font-weight:bold}dd{margin-left:0}@media(min-width:768px){.dl-horizontal dt{float:left;width:160px;overflow:hidden;clear:left;text-align:right;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:180px}.dl-horizontal dd:before,.dl-horizontal dd:after{display:table;content:" "}.dl-horizontal dd:after{clear:both}.dl-horizontal dd:before,.dl-horizontal dd:after{display:table;content:" "}.dl-horizontal dd:after{clear:both}}abbr[title],abbr[data-original-title]{cursor:help;border-bottom:1px dotted #999}abbr.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:10px 20px;margin:0 0 20px;border-left:5px solid #eee}blockquote p{font-size:17.5px;font-weight:300;line-height:1.25}blockquote p:last-child{margin-bottom:0}blockquote small{display:block;line-height:1.428571429;color:#999}blockquote small:before{content:'\2014 \00A0'}blockquote.pull-right{padding-right:15px;padding-left:0;border-right:5px solid #eee;border-left:0}blockquote.pull-right p,blockquote.pull-right small{text-align:right}blockquote.pull-right small:before{content:''}blockquote.pull-right small:after{content:'\00A0 \2014'}q:before,q:after,blockquote:before,blockquote:after{content:""}address{display:block;margin-bottom:20px;font-style:normal;line-height:1.428571429}code,pre{font-family:Monaco,Menlo,Consolas,"Courier New",monospace}code{padding:2px 4px;font-size:90%;color:#c7254e;white-space:nowrap;background-color:#f9f2f4;border-radius:4px}pre{display:block;padding:9.5px;margin:0 0 10px;font-size:13px;line-height:1.428571429;color:#333;word-break:break-all;word-wrap:break-word;background-color:#f5f5f5;border:1px solid #ccc;border-radius:4px}pre.prettyprint{margin-bottom:20px}pre code{padding:0;font-size:inherit;color:inherit;white-space:pre-wrap;background-color:transparent;border:0}.pre-scrollable{max-height:340px;overflow-y:scroll}.container{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}.container:before,.container:after{display:table;content:" "}.container:after{clear:both}.container:before,.container:after{display:table;content:" "}.container:after{clear:both}.row{margin-right:-15px;margin-left:-15px}.row:before,.row:after{display:table;content:" "}.row:after{clear:both}.row:before,.row:after{display:table;content:" "}.row:after{clear:both}.col-xs-1,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9,.col-xs-10,.col-xs-11,.col-xs-12,.col-sm-1,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-sm-10,.col-sm-11,.col-sm-12,.col-md-1,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-md-10,.col-md-11,.col-md-12,.col-lg-1,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-lg-10,.col-lg-11,.col-lg-12{position:relative;min-height:1px;padding-right:15px;padding-left:15px}.col-xs-1,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9,.col-xs-10,.col-xs-11{float:left}.col-xs-1{width:8.333333333333332%}.col-xs-2{width:16.666666666666664%}.col-xs-3{width:25%}.col-xs-4{width:33.33333333333333%}.col-xs-5{width:41.66666666666667%}.col-xs-6{width:50%}.col-xs-7{width:58.333333333333336%}.col-xs-8{width:66.66666666666666%}.col-xs-9{width:75%}.col-xs-10{width:83.33333333333334%}.col-xs-11{width:91.66666666666666%}.col-xs-12{width:100%}@media(min-width:768px){.container{max-width:750px}.col-sm-1,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-sm-10,.col-sm-11{float:left}.col-sm-1{width:8.333333333333332%}.col-sm-2{width:16.666666666666664%}.col-sm-3{width:25%}.col-sm-4{width:33.33333333333333%}.col-sm-5{width:41.66666666666667%}.col-sm-6{width:50%}.col-sm-7{width:58.333333333333336%}.col-sm-8{width:66.66666666666666%}.col-sm-9{width:75%}.col-sm-10{width:83.33333333333334%}.col-sm-11{width:91.66666666666666%}.col-sm-12{width:100%}.col-sm-push-1{left:8.333333333333332%}.col-sm-push-2{left:16.666666666666664%}.col-sm-push-3{left:25%}.col-sm-push-4{left:33.33333333333333%}.col-sm-push-5{left:41.66666666666667%}.col-sm-push-6{left:50%}.col-sm-push-7{left:58.333333333333336%}.col-sm-push-8{left:66.66666666666666%}.col-sm-push-9{left:75%}.col-sm-push-10{left:83.33333333333334%}.col-sm-push-11{left:91.66666666666666%}.col-sm-pull-1{right:8.333333333333332%}.col-sm-pull-2{right:16.666666666666664%}.col-sm-pull-3{right:25%}.col-sm-pull-4{right:33.33333333333333%}.col-sm-pull-5{right:41.66666666666667%}.col-sm-pull-6{right:50%}.col-sm-pull-7{right:58.333333333333336%}.col-sm-pull-8{right:66.66666666666666%}.col-sm-pull-9{right:75%}.col-sm-pull-10{right:83.33333333333334%}.col-sm-pull-11{right:91.66666666666666%}.col-sm-offset-1{margin-left:8.333333333333332%}.col-sm-offset-2{margin-left:16.666666666666664%}.col-sm-offset-3{margin-left:25%}.col-sm-offset-4{margin-left:33.33333333333333%}.col-sm-offset-5{margin-left:41.66666666666667%}.col-sm-offset-6{margin-left:50%}.col-sm-offset-7{margin-left:58.333333333333336%}.col-sm-offset-8{margin-left:66.66666666666666%}.col-sm-offset-9{margin-left:75%}.col-sm-offset-10{margin-left:83.33333333333334%}.col-sm-offset-11{margin-left:91.66666666666666%}}@media(min-width:992px){.container{max-width:970px}.col-md-1,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-md-10,.col-md-11{float:left}.col-md-1{width:8.333333333333332%}.col-md-2{width:16.666666666666664%}.col-md-3{width:25%}.col-md-4{width:33.33333333333333%}.col-md-5{width:41.66666666666667%}.col-md-6{width:50%}.col-md-7{width:58.333333333333336%}.col-md-8{width:66.66666666666666%}.col-md-9{width:75%}.col-md-10{width:83.33333333333334%}.col-md-11{width:91.66666666666666%}.col-md-12{width:100%}.col-md-push-0{left:auto}.col-md-push-1{left:8.333333333333332%}.col-md-push-2{left:16.666666666666664%}.col-md-push-3{left:25%}.col-md-push-4{left:33.33333333333333%}.col-md-push-5{left:41.66666666666667%}.col-md-push-6{left:50%}.col-md-push-7{left:58.333333333333336%}.col-md-push-8{left:66.66666666666666%}.col-md-push-9{left:75%}.col-md-push-10{left:83.33333333333334%}.col-md-push-11{left:91.66666666666666%}.col-md-pull-0{right:auto}.col-md-pull-1{right:8.333333333333332%}.col-md-pull-2{right:16.666666666666664%}.col-md-pull-3{right:25%}.col-md-pull-4{right:33.33333333333333%}.col-md-pull-5{right:41.66666666666667%}.col-md-pull-6{right:50%}.col-md-pull-7{right:58.333333333333336%}.col-md-pull-8{right:66.66666666666666%}.col-md-pull-9{right:75%}.col-md-pull-10{right:83.33333333333334%}.col-md-pull-11{right:91.66666666666666%}.col-md-offset-0{margin-left:0}.col-md-offset-1{margin-left:8.333333333333332%}.col-md-offset-2{margin-left:16.666666666666664%}.col-md-offset-3{margin-left:25%}.col-md-offset-4{margin-left:33.33333333333333%}.col-md-offset-5{margin-left:41.66666666666667%}.col-md-offset-6{margin-left:50%}.col-md-offset-7{margin-left:58.333333333333336%}.col-md-offset-8{margin-left:66.66666666666666%}.col-md-offset-9{margin-left:75%}.col-md-offset-10{margin-left:83.33333333333334%}.col-md-offset-11{margin-left:91.66666666666666%}}@media(min-width:1200px){.container{max-width:1170px}.col-lg-1,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-lg-10,.col-lg-11{float:left}.col-lg-1{width:8.333333333333332%}.col-lg-2{width:16.666666666666664%}.col-lg-3{width:25%}.col-lg-4{width:33.33333333333333%}.col-lg-5{width:41.66666666666667%}.col-lg-6{width:50%}.col-lg-7{width:58.333333333333336%}.col-lg-8{width:66.66666666666666%}.col-lg-9{width:75%}.col-lg-10{width:83.33333333333334%}.col-lg-11{width:91.66666666666666%}.col-lg-12{width:100%}.col-lg-push-0{left:auto}.col-lg-push-1{left:8.333333333333332%}.col-lg-push-2{left:16.666666666666664%}.col-lg-push-3{left:25%}.col-lg-push-4{left:33.33333333333333%}.col-lg-push-5{left:41.66666666666667%}.col-lg-push-6{left:50%}.col-lg-push-7{left:58.333333333333336%}.col-lg-push-8{left:66.66666666666666%}.col-lg-push-9{left:75%}.col-lg-push-10{left:83.33333333333334%}.col-lg-push-11{left:91.66666666666666%}.col-lg-pull-0{right:auto}.col-lg-pull-1{right:8.333333333333332%}.col-lg-pull-2{right:16.666666666666664%}.col-lg-pull-3{right:25%}.col-lg-pull-4{right:33.33333333333333%}.col-lg-pull-5{right:41.66666666666667%}.col-lg-pull-6{right:50%}.col-lg-pull-7{right:58.333333333333336%}.col-lg-pull-8{right:66.66666666666666%}.col-lg-pull-9{right:75%}.col-lg-pull-10{right:83.33333333333334%}.col-lg-pull-11{right:91.66666666666666%}.col-lg-offset-0{margin-left:0}.col-lg-offset-1{margin-left:8.333333333333332%}.col-lg-offset-2{margin-left:16.666666666666664%}.col-lg-offset-3{margin-left:25%}.col-lg-offset-4{margin-left:33.33333333333333%}.col-lg-offset-5{margin-left:41.66666666666667%}.col-lg-offset-6{margin-left:50%}.col-lg-offset-7{margin-left:58.333333333333336%}.col-lg-offset-8{margin-left:66.66666666666666%}.col-lg-offset-9{margin-left:75%}.col-lg-offset-10{margin-left:83.33333333333334%}.col-lg-offset-11{margin-left:91.66666666666666%}}table{max-width:100%;background-color:transparent}th{text-align:left}.table{width:100%;margin-bottom:20px}.table thead>tr>th,.table tbody>tr>th,.table tfoot>tr>th,.table thead>tr>td,.table tbody>tr>td,.table tfoot>tr>td{padding:8px;line-height:1.428571429;vertical-align:top;border-top:1px solid #ddd}.table thead>tr>th{vertical-align:bottom;border-bottom:2px solid #ddd}.table caption+thead tr:first-child th,.table colgroup+thead tr:first-child th,.table thead:first-child tr:first-child th,.table caption+thead tr:first-child td,.table colgroup+thead tr:first-child td,.table thead:first-child tr:first-child td{border-top:0}.table tbody+tbody{border-top:2px solid #ddd}.table .table{background-color:#fff}.table-condensed thead>tr>th,.table-condensed tbody>tr>th,.table-condensed tfoot>tr>th,.table-condensed thead>tr>td,.table-condensed tbody>tr>td,.table-condensed tfoot>tr>td{padding:5px}.table-bordered{border:1px solid #ddd}.table-bordered>thead>tr>th,.table-bordered>tbody>tr>th,.table-bordered>tfoot>tr>th,.table-bordered>thead>tr>td,.table-bordered>tbody>tr>td,.table-bordered>tfoot>tr>td{border:1px solid #ddd}.table-bordered>thead>tr>th,.table-bordered>thead>tr>td{border-bottom-width:2px}.table-striped>tbody>tr:nth-child(odd)>td,.table-striped>tbody>tr:nth-child(odd)>th{background-color:#f9f9f9}.table-hover>tbody>tr:hover>td,.table-hover>tbody>tr:hover>th{background-color:#f5f5f5}table col[class*="col-"]{display:table-column;float:none}table td[class*="col-"],table th[class*="col-"]{display:table-cell;float:none}.table>thead>tr>td.active,.table>tbody>tr>td.active,.table>tfoot>tr>td.active,.table>thead>tr>th.active,.table>tbody>tr>th.active,.table>tfoot>tr>th.active,.table>thead>tr.active>td,.table>tbody>tr.active>td,.table>tfoot>tr.active>td,.table>thead>tr.active>th,.table>tbody>tr.active>th,.table>tfoot>tr.active>th{background-color:#f5f5f5}.table>thead>tr>td.success,.table>tbody>tr>td.success,.table>tfoot>tr>td.success,.table>thead>tr>th.success,.table>tbody>tr>th.success,.table>tfoot>tr>th.success,.table>thead>tr.success>td,.table>tbody>tr.success>td,.table>tfoot>tr.success>td,.table>thead>tr.success>th,.table>tbody>tr.success>th,.table>tfoot>tr.success>th{background-color:#dff0d8;border-color:#d6e9c6}.table-hover>tbody>tr>td.success:hover,.table-hover>tbody>tr>th.success:hover,.table-hover>tbody>tr.success:hover>td{background-color:#d0e9c6;border-color:#c9e2b3}.table>thead>tr>td.danger,.table>tbody>tr>td.danger,.table>tfoot>tr>td.danger,.table>thead>tr>th.danger,.table>tbody>tr>th.danger,.table>tfoot>tr>th.danger,.table>thead>tr.danger>td,.table>tbody>tr.danger>td,.table>tfoot>tr.danger>td,.table>thead>tr.danger>th,.table>tbody>tr.danger>th,.table>tfoot>tr.danger>th{background-color:#f2dede;border-color:#eed3d7}.table-hover>tbody>tr>td.danger:hover,.table-hover>tbody>tr>th.danger:hover,.table-hover>tbody>tr.danger:hover>td{background-color:#ebcccc;border-color:#e6c1c7}.table>thead>tr>td.warning,.table>tbody>tr>td.warning,.table>tfoot>tr>td.warning,.table>thead>tr>th.warning,.table>tbody>tr>th.warning,.table>tfoot>tr>th.warning,.table>thead>tr.warning>td,.table>tbody>tr.warning>td,.table>tfoot>tr.warning>td,.table>thead>tr.warning>th,.table>tbody>tr.warning>th,.table>tfoot>tr.warning>th{background-color:#fcf8e3;border-color:#fbeed5}.table-hover>tbody>tr>td.warning:hover,.table-hover>tbody>tr>th.warning:hover,.table-hover>tbody>tr.warning:hover>td{background-color:#faf2cc;border-color:#f8e5be}@media(max-width:768px){.table-responsive{width:100%;margin-bottom:15px;overflow-x:scroll;overflow-y:hidden;border:1px solid #ddd}.table-responsive>.table{margin-bottom:0;background-color:#fff}.table-responsive>.table>thead>tr>th,.table-responsive>.table>tbody>tr>th,.table-responsive>.table>tfoot>tr>th,.table-responsive>.table>thead>tr>td,.table-responsive>.table>tbody>tr>td,.table-responsive>.table>tfoot>tr>td{white-space:nowrap}.table-responsive>.table-bordered{border:0}.table-responsive>.table-bordered>thead>tr>th:first-child,.table-responsive>.table-bordered>tbody>tr>th:first-child,.table-responsive>.table-bordered>tfoot>tr>th:first-child,.table-responsive>.table-bordered>thead>tr>td:first-child,.table-responsive>.table-bordered>tbody>tr>td:first-child,.table-responsive>.table-bordered>tfoot>tr>td:first-child{border-left:0}.table-responsive>.table-bordered>thead>tr>th:last-child,.table-responsive>.table-bordered>tbody>tr>th:last-child,.table-responsive>.table-bordered>tfoot>tr>th:last-child,.table-responsive>.table-bordered>thead>tr>td:last-child,.table-responsive>.table-bordered>tbody>tr>td:last-child,.table-responsive>.table-bordered>tfoot>tr>td:last-child{border-right:0}.table-responsive>.table-bordered>thead>tr:last-child>th,.table-responsive>.table-bordered>tbody>tr:last-child>th,.table-responsive>.table-bordered>tfoot>tr:last-child>th,.table-responsive>.table-bordered>thead>tr:last-child>td,.table-responsive>.table-bordered>tbody>tr:last-child>td,.table-responsive>.table-bordered>tfoot>tr:last-child>td{border-bottom:0}}fieldset{padding:0;margin:0;border:0}legend{display:block;width:100%;padding:0;margin-bottom:20px;font-size:21px;line-height:inherit;color:#333;border:0;border-bottom:1px solid #e5e5e5}label{display:inline-block;margin-bottom:5px;font-weight:bold}input[type="search"]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type="radio"],input[type="checkbox"]{margin:4px 0 0;margin-top:1px \9;line-height:normal}input[type="file"]{display:block}select[multiple],select[size]{height:auto}select optgroup{font-family:inherit;font-size:inherit;font-style:inherit}input[type="file"]:focus,input[type="radio"]:focus,input[type="checkbox"]:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}input[type="number"]::-webkit-outer-spin-button,input[type="number"]::-webkit-inner-spin-button{height:auto}.form-control:-moz-placeholder{color:#999}.form-control::-moz-placeholder{color:#999}.form-control:-ms-input-placeholder{color:#999}.form-control::-webkit-input-placeholder{color:#999}.form-control{display:block;width:100%;height:34px;padding:6px 12px;font-size:14px;line-height:1.428571429;color:#555;vertical-align:middle;background-color:#fff;border:1px solid #ccc;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-webkit-transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s}.form-control:focus{border-color:#66afe9;outline:0;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(102,175,233,0.6);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(102,175,233,0.6)}.form-control[disabled],.form-control[readonly],fieldset[disabled] .form-control{cursor:not-allowed;background-color:#eee}textarea.form-control{height:auto}.form-group{margin-bottom:15px}.radio,.checkbox{display:block;min-height:20px;padding-left:20px;margin-top:10px;margin-bottom:10px;vertical-align:middle}.radio label,.checkbox label{display:inline;margin-bottom:0;font-weight:normal;cursor:pointer}.radio input[type="radio"],.radio-inline input[type="radio"],.checkbox input[type="checkbox"],.checkbox-inline input[type="checkbox"]{float:left;margin-left:-20px}.radio+.radio,.checkbox+.checkbox{margin-top:-5px}.radio-inline,.checkbox-inline{display:inline-block;padding-left:20px;margin-bottom:0;font-weight:normal;vertical-align:middle;cursor:pointer}.radio-inline+.radio-inline,.checkbox-inline+.checkbox-inline{margin-top:0;margin-left:10px}input[type="radio"][disabled],input[type="checkbox"][disabled],.radio[disabled],.radio-inline[disabled],.checkbox[disabled],.checkbox-inline[disabled],fieldset[disabled] input[type="radio"],fieldset[disabled] input[type="checkbox"],fieldset[disabled] .radio,fieldset[disabled] .radio-inline,fieldset[disabled] .checkbox,fieldset[disabled] .checkbox-inline{cursor:not-allowed}.input-sm{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-sm{height:30px;line-height:30px}textarea.input-sm{height:auto}.input-lg{height:45px;padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}select.input-lg{height:45px;line-height:45px}textarea.input-lg{height:auto}.has-warning .help-block,.has-warning .control-label{color:#c09853}.has-warning .form-control{border-color:#c09853;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.has-warning .form-control:focus{border-color:#a47e3c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #dbc59e;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #dbc59e}.has-warning .input-group-addon{color:#c09853;background-color:#fcf8e3;border-color:#c09853}.has-error .help-block,.has-error .control-label{color:#b94a48}.has-error .form-control{border-color:#b94a48;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.has-error .form-control:focus{border-color:#953b39;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #d59392;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #d59392}.has-error .input-group-addon{color:#b94a48;background-color:#f2dede;border-color:#b94a48}.has-success .help-block,.has-success .control-label{color:#468847}.has-success .form-control{border-color:#468847;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.has-success .form-control:focus{border-color:#356635;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7aba7b;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7aba7b}.has-success .input-group-addon{color:#468847;background-color:#dff0d8;border-color:#468847}.form-control-static{padding-top:7px;margin-bottom:0}.help-block{display:block;margin-top:5px;margin-bottom:10px;color:#737373}@media(min-width:768px){.form-inline .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.form-inline .form-control{display:inline-block}.form-inline .radio,.form-inline .checkbox{display:inline-block;padding-left:0;margin-top:0;margin-bottom:0}.form-inline .radio input[type="radio"],.form-inline .checkbox input[type="checkbox"]{float:none;margin-left:0}}.form-horizontal .control-label,.form-horizontal .radio,.form-horizontal .checkbox,.form-horizontal .radio-inline,.form-horizontal .checkbox-inline{padding-top:7px;margin-top:0;margin-bottom:0}.form-horizontal .form-group{margin-right:-15px;margin-left:-15px}.form-horizontal .form-group:before,.form-horizontal .form-group:after{display:table;content:" "}.form-horizontal .form-group:after{clear:both}.form-horizontal .form-group:before,.form-horizontal .form-group:after{display:table;content:" "}.form-horizontal .form-group:after{clear:both}@media(min-width:768px){.form-horizontal .control-label{text-align:right}}.btn{display:inline-block;padding:6px 12px;margin-bottom:0;font-size:14px;font-weight:normal;line-height:1.428571429;text-align:center;white-space:nowrap;vertical-align:middle;cursor:pointer;border:1px solid transparent;border-radius:4px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;user-select:none}.btn:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.btn:hover,.btn:focus{color:#333;text-decoration:none}.btn:active,.btn.active{background-image:none;outline:0;-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,0.125);box-shadow:inset 0 3px 5px rgba(0,0,0,0.125)}.btn.disabled,.btn[disabled],fieldset[disabled] .btn{pointer-events:none;cursor:not-allowed;opacity:.65;filter:alpha(opacity=65);-webkit-box-shadow:none;box-shadow:none}.btn-default{color:#333;background-color:#fff;border-color:#ccc}.btn-default:hover,.btn-default:focus,.btn-default:active,.btn-default.active,.open .dropdown-toggle.btn-default{color:#333;background-color:#ebebeb;border-color:#adadad}.btn-default:active,.btn-default.active,.open .dropdown-toggle.btn-default{background-image:none}.btn-default.disabled,.btn-default[disabled],fieldset[disabled] .btn-default,.btn-default.disabled:hover,.btn-default[disabled]:hover,fieldset[disabled] .btn-default:hover,.btn-default.disabled:focus,.btn-default[disabled]:focus,fieldset[disabled] .btn-default:focus,.btn-default.disabled:active,.btn-default[disabled]:active,fieldset[disabled] .btn-default:active,.btn-default.disabled.active,.btn-default[disabled].active,fieldset[disabled] .btn-default.active{background-color:#fff;border-color:#ccc}.btn-primary{color:#fff;background-color:#428bca;border-color:#357ebd}.btn-primary:hover,.btn-primary:focus,.btn-primary:active,.btn-primary.active,.open .dropdown-toggle.btn-primary{color:#fff;background-color:#3276b1;border-color:#285e8e}.btn-primary:active,.btn-primary.active,.open .dropdown-toggle.btn-primary{background-image:none}.btn-primary.disabled,.btn-primary[disabled],fieldset[disabled] .btn-primary,.btn-primary.disabled:hover,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary:hover,.btn-primary.disabled:focus,.btn-primary[disabled]:focus,fieldset[disabled] .btn-primary:focus,.btn-primary.disabled:active,.btn-primary[disabled]:active,fieldset[disabled] .btn-primary:active,.btn-primary.disabled.active,.btn-primary[disabled].active,fieldset[disabled] .btn-primary.active{background-color:#428bca;border-color:#357ebd}.btn-warning{color:#fff;background-color:#f0ad4e;border-color:#eea236}.btn-warning:hover,.btn-warning:focus,.btn-warning:active,.btn-warning.active,.open .dropdown-toggle.btn-warning{color:#fff;background-color:#ed9c28;border-color:#d58512}.btn-warning:active,.btn-warning.active,.open .dropdown-toggle.btn-warning{background-image:none}.btn-warning.disabled,.btn-warning[disabled],fieldset[disabled] .btn-warning,.btn-warning.disabled:hover,.btn-warning[disabled]:hover,fieldset[disabled] .btn-warning:hover,.btn-warning.disabled:focus,.btn-warning[disabled]:focus,fieldset[disabled] .btn-warning:focus,.btn-warning.disabled:active,.btn-warning[disabled]:active,fieldset[disabled] .btn-warning:active,.btn-warning.disabled.active,.btn-warning[disabled].active,fieldset[disabled] .btn-warning.active{background-color:#f0ad4e;border-color:#eea236}.btn-danger{color:#fff;background-color:#d9534f;border-color:#d43f3a}.btn-danger:hover,.btn-danger:focus,.btn-danger:active,.btn-danger.active,.open .dropdown-toggle.btn-danger{color:#fff;background-color:#d2322d;border-color:#ac2925}.btn-danger:active,.btn-danger.active,.open .dropdown-toggle.btn-danger{background-image:none}.btn-danger.disabled,.btn-danger[disabled],fieldset[disabled] .btn-danger,.btn-danger.disabled:hover,.btn-danger[disabled]:hover,fieldset[disabled] .btn-danger:hover,.btn-danger.disabled:focus,.btn-danger[disabled]:focus,fieldset[disabled] .btn-danger:focus,.btn-danger.disabled:active,.btn-danger[disabled]:active,fieldset[disabled] .btn-danger:active,.btn-danger.disabled.active,.btn-danger[disabled].active,fieldset[disabled] .btn-danger.active{background-color:#d9534f;border-color:#d43f3a}.btn-success{color:#fff;background-color:#5cb85c;border-color:#4cae4c}.btn-success:hover,.btn-success:focus,.btn-success:active,.btn-success.active,.open .dropdown-toggle.btn-success{color:#fff;background-color:#47a447;border-color:#398439}.btn-success:active,.btn-success.active,.open .dropdown-toggle.btn-success{background-image:none}.btn-success.disabled,.btn-success[disabled],fieldset[disabled] .btn-success,.btn-success.disabled:hover,.btn-success[disabled]:hover,fieldset[disabled] .btn-success:hover,.btn-success.disabled:focus,.btn-success[disabled]:focus,fieldset[disabled] .btn-success:focus,.btn-success.disabled:active,.btn-success[disabled]:active,fieldset[disabled] .btn-success:active,.btn-success.disabled.active,.btn-success[disabled].active,fieldset[disabled] .btn-success.active{background-color:#5cb85c;border-color:#4cae4c}.btn-info{color:#fff;background-color:#5bc0de;border-color:#46b8da}.btn-info:hover,.btn-info:focus,.btn-info:active,.btn-info.active,.open .dropdown-toggle.btn-info{color:#fff;background-color:#39b3d7;border-color:#269abc}.btn-info:active,.btn-info.active,.open .dropdown-toggle.btn-info{background-image:none}.btn-info.disabled,.btn-info[disabled],fieldset[disabled] .btn-info,.btn-info.disabled:hover,.btn-info[disabled]:hover,fieldset[disabled] .btn-info:hover,.btn-info.disabled:focus,.btn-info[disabled]:focus,fieldset[disabled] .btn-info:focus,.btn-info.disabled:active,.btn-info[disabled]:active,fieldset[disabled] .btn-info:active,.btn-info.disabled.active,.btn-info[disabled].active,fieldset[disabled] .btn-info.active{background-color:#5bc0de;border-color:#46b8da}.btn-link{font-weight:normal;color:#428bca;cursor:pointer;border-radius:0}.btn-link,.btn-link:active,.btn-link[disabled],fieldset[disabled] .btn-link{background-color:transparent;-webkit-box-shadow:none;box-shadow:none}.btn-link,.btn-link:hover,.btn-link:focus,.btn-link:active{border-color:transparent}.btn-link:hover,.btn-link:focus{color:#2a6496;text-decoration:underline;background-color:transparent}.btn-link[disabled]:hover,fieldset[disabled] .btn-link:hover,.btn-link[disabled]:focus,fieldset[disabled] .btn-link:focus{color:#999;text-decoration:none}.btn-lg{padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}.btn-sm,.btn-xs{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.btn-xs{padding:1px 5px}.btn-block{display:block;width:100%;padding-right:0;padding-left:0}.btn-block+.btn-block{margin-top:5px}input[type="submit"].btn-block,input[type="reset"].btn-block,input[type="button"].btn-block{width:100%}.fade{opacity:0;-webkit-transition:opacity .15s linear;transition:opacity .15s linear}.fade.in{opacity:1}.collapse{display:none}.collapse.in{display:block}.collapsing{position:relative;height:0;overflow:hidden;-webkit-transition:height .35s ease;transition:height .35s ease}@font-face{font-family:'Glyphicons Halflings';src:url('../fonts/glyphicons-halflings-regular.eot');src:url('../fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'),url('../fonts/glyphicons-halflings-regular.woff') format('woff'),url('../fonts/glyphicons-halflings-regular.ttf') format('truetype'),url('../fonts/glyphicons-halflings-regular.svg#glyphicons-halflingsregular') format('svg')}.glyphicon{position:relative;top:1px;display:inline-block;font-family:'Glyphicons Halflings';-webkit-font-smoothing:antialiased;font-style:normal;font-weight:normal;line-height:1}.glyphicon-asterisk:before{content:"\2a"}.glyphicon-plus:before{content:"\2b"}.glyphicon-euro:before{content:"\20ac"}.glyphicon-minus:before{content:"\2212"}.glyphicon-cloud:before{content:"\2601"}.glyphicon-envelope:before{content:"\2709"}.glyphicon-pencil:before{content:"\270f"}.glyphicon-glass:before{content:"\e001"}.glyphicon-music:before{content:"\e002"}.glyphicon-search:before{content:"\e003"}.glyphicon-heart:before{content:"\e005"}.glyphicon-star:before{content:"\e006"}.glyphicon-star-empty:before{content:"\e007"}.glyphicon-user:before{content:"\e008"}.glyphicon-film:before{content:"\e009"}.glyphicon-th-large:before{content:"\e010"}.glyphicon-th:before{content:"\e011"}.glyphicon-th-list:before{content:"\e012"}.glyphicon-ok:before{content:"\e013"}.glyphicon-remove:before{content:"\e014"}.glyphicon-zoom-in:before{content:"\e015"}.glyphicon-zoom-out:before{content:"\e016"}.glyphicon-off:before{content:"\e017"}.glyphicon-signal:before{content:"\e018"}.glyphicon-cog:before{content:"\e019"}.glyphicon-trash:before{content:"\e020"}.glyphicon-home:before{content:"\e021"}.glyphicon-file:before{content:"\e022"}.glyphicon-time:before{content:"\e023"}.glyphicon-road:before{content:"\e024"}.glyphicon-download-alt:before{content:"\e025"}.glyphicon-download:before{content:"\e026"}.glyphicon-upload:before{content:"\e027"}.glyphicon-inbox:before{content:"\e028"}.glyphicon-play-circle:before{content:"\e029"}.glyphicon-repeat:before{content:"\e030"}.glyphicon-refresh:before{content:"\e031"}.glyphicon-list-alt:before{content:"\e032"}.glyphicon-flag:before{content:"\e034"}.glyphicon-headphones:before{content:"\e035"}.glyphicon-volume-off:before{content:"\e036"}.glyphicon-volume-down:before{content:"\e037"}.glyphicon-volume-up:before{content:"\e038"}.glyphicon-qrcode:before{content:"\e039"}.glyphicon-barcode:before{content:"\e040"}.glyphicon-tag:before{content:"\e041"}.glyphicon-tags:before{content:"\e042"}.glyphicon-book:before{content:"\e043"}.glyphicon-print:before{content:"\e045"}.glyphicon-font:before{content:"\e047"}.glyphicon-bold:before{content:"\e048"}.glyphicon-italic:before{content:"\e049"}.glyphicon-text-height:before{content:"\e050"}.glyphicon-text-width:before{content:"\e051"}.glyphicon-align-left:before{content:"\e052"}.glyphicon-align-center:before{content:"\e053"}.glyphicon-align-right:before{content:"\e054"}.glyphicon-align-justify:before{content:"\e055"}.glyphicon-list:before{content:"\e056"}.glyphicon-indent-left:before{content:"\e057"}.glyphicon-indent-right:before{content:"\e058"}.glyphicon-facetime-video:before{content:"\e059"}.glyphicon-picture:before{content:"\e060"}.glyphicon-map-marker:before{content:"\e062"}.glyphicon-adjust:before{content:"\e063"}.glyphicon-tint:before{content:"\e064"}.glyphicon-edit:before{content:"\e065"}.glyphicon-share:before{content:"\e066"}.glyphicon-check:before{content:"\e067"}.glyphicon-move:before{content:"\e068"}.glyphicon-step-backward:before{content:"\e069"}.glyphicon-fast-backward:before{content:"\e070"}.glyphicon-backward:before{content:"\e071"}.glyphicon-play:before{content:"\e072"}.glyphicon-pause:before{content:"\e073"}.glyphicon-stop:before{content:"\e074"}.glyphicon-forward:before{content:"\e075"}.glyphicon-fast-forward:before{content:"\e076"}.glyphicon-step-forward:before{content:"\e077"}.glyphicon-eject:before{content:"\e078"}.glyphicon-chevron-left:before{content:"\e079"}.glyphicon-chevron-right:before{content:"\e080"}.glyphicon-plus-sign:before{content:"\e081"}.glyphicon-minus-sign:before{content:"\e082"}.glyphicon-remove-sign:before{content:"\e083"}.glyphicon-ok-sign:before{content:"\e084"}.glyphicon-question-sign:before{content:"\e085"}.glyphicon-info-sign:before{content:"\e086"}.glyphicon-screenshot:before{content:"\e087"}.glyphicon-remove-circle:before{content:"\e088"}.glyphicon-ok-circle:before{content:"\e089"}.glyphicon-ban-circle:before{content:"\e090"}.glyphicon-arrow-left:before{content:"\e091"}.glyphicon-arrow-right:before{content:"\e092"}.glyphicon-arrow-up:before{content:"\e093"}.glyphicon-arrow-down:before{content:"\e094"}.glyphicon-share-alt:before{content:"\e095"}.glyphicon-resize-full:before{content:"\e096"}.glyphicon-resize-small:before{content:"\e097"}.glyphicon-exclamation-sign:before{content:"\e101"}.glyphicon-gift:before{content:"\e102"}.glyphicon-leaf:before{content:"\e103"}.glyphicon-eye-open:before{content:"\e105"}.glyphicon-eye-close:before{content:"\e106"}.glyphicon-warning-sign:before{content:"\e107"}.glyphicon-plane:before{content:"\e108"}.glyphicon-random:before{content:"\e110"}.glyphicon-comment:before{content:"\e111"}.glyphicon-magnet:before{content:"\e112"}.glyphicon-chevron-up:before{content:"\e113"}.glyphicon-chevron-down:before{content:"\e114"}.glyphicon-retweet:before{content:"\e115"}.glyphicon-shopping-cart:before{content:"\e116"}.glyphicon-folder-close:before{content:"\e117"}.glyphicon-folder-open:before{content:"\e118"}.glyphicon-resize-vertical:before{content:"\e119"}.glyphicon-resize-horizontal:before{content:"\e120"}.glyphicon-hdd:before{content:"\e121"}.glyphicon-bullhorn:before{content:"\e122"}.glyphicon-certificate:before{content:"\e124"}.glyphicon-thumbs-up:before{content:"\e125"}.glyphicon-thumbs-down:before{content:"\e126"}.glyphicon-hand-right:before{content:"\e127"}.glyphicon-hand-left:before{content:"\e128"}.glyphicon-hand-up:before{content:"\e129"}.glyphicon-hand-down:before{content:"\e130"}.glyphicon-circle-arrow-right:before{content:"\e131"}.glyphicon-circle-arrow-left:before{content:"\e132"}.glyphicon-circle-arrow-up:before{content:"\e133"}.glyphicon-circle-arrow-down:before{content:"\e134"}.glyphicon-globe:before{content:"\e135"}.glyphicon-tasks:before{content:"\e137"}.glyphicon-filter:before{content:"\e138"}.glyphicon-fullscreen:before{content:"\e140"}.glyphicon-dashboard:before{content:"\e141"}.glyphicon-heart-empty:before{content:"\e143"}.glyphicon-link:before{content:"\e144"}.glyphicon-phone:before{content:"\e145"}.glyphicon-usd:before{content:"\e148"}.glyphicon-gbp:before{content:"\e149"}.glyphicon-sort:before{content:"\e150"}.glyphicon-sort-by-alphabet:before{content:"\e151"}.glyphicon-sort-by-alphabet-alt:before{content:"\e152"}.glyphicon-sort-by-order:before{content:"\e153"}.glyphicon-sort-by-order-alt:before{content:"\e154"}.glyphicon-sort-by-attributes:before{content:"\e155"}.glyphicon-sort-by-attributes-alt:before{content:"\e156"}.glyphicon-unchecked:before{content:"\e157"}.glyphicon-expand:before{content:"\e158"}.glyphicon-collapse-down:before{content:"\e159"}.glyphicon-collapse-up:before{content:"\e160"}.glyphicon-log-in:before{content:"\e161"}.glyphicon-flash:before{content:"\e162"}.glyphicon-log-out:before{content:"\e163"}.glyphicon-new-window:before{content:"\e164"}.glyphicon-record:before{content:"\e165"}.glyphicon-save:before{content:"\e166"}.glyphicon-open:before{content:"\e167"}.glyphicon-saved:before{content:"\e168"}.glyphicon-import:before{content:"\e169"}.glyphicon-export:before{content:"\e170"}.glyphicon-send:before{content:"\e171"}.glyphicon-floppy-disk:before{content:"\e172"}.glyphicon-floppy-saved:before{content:"\e173"}.glyphicon-floppy-remove:before{content:"\e174"}.glyphicon-floppy-save:before{content:"\e175"}.glyphicon-floppy-open:before{content:"\e176"}.glyphicon-credit-card:before{content:"\e177"}.glyphicon-transfer:before{content:"\e178"}.glyphicon-cutlery:before{content:"\e179"}.glyphicon-header:before{content:"\e180"}.glyphicon-compressed:before{content:"\e181"}.glyphicon-earphone:before{content:"\e182"}.glyphicon-phone-alt:before{content:"\e183"}.glyphicon-tower:before{content:"\e184"}.glyphicon-stats:before{content:"\e185"}.glyphicon-sd-video:before{content:"\e186"}.glyphicon-hd-video:before{content:"\e187"}.glyphicon-subtitles:before{content:"\e188"}.glyphicon-sound-stereo:before{content:"\e189"}.glyphicon-sound-dolby:before{content:"\e190"}.glyphicon-sound-5-1:before{content:"\e191"}.glyphicon-sound-6-1:before{content:"\e192"}.glyphicon-sound-7-1:before{content:"\e193"}.glyphicon-copyright-mark:before{content:"\e194"}.glyphicon-registration-mark:before{content:"\e195"}.glyphicon-cloud-download:before{content:"\e197"}.glyphicon-cloud-upload:before{content:"\e198"}.glyphicon-tree-conifer:before{content:"\e199"}.glyphicon-tree-deciduous:before{content:"\e200"}.glyphicon-briefcase:before{content:"\1f4bc"}.glyphicon-calendar:before{content:"\1f4c5"}.glyphicon-pushpin:before{content:"\1f4cc"}.glyphicon-paperclip:before{content:"\1f4ce"}.glyphicon-camera:before{content:"\1f4f7"}.glyphicon-lock:before{content:"\1f512"}.glyphicon-bell:before{content:"\1f514"}.glyphicon-bookmark:before{content:"\1f516"}.glyphicon-fire:before{content:"\1f525"}.glyphicon-wrench:before{content:"\1f527"}.caret{display:inline-block;width:0;height:0;margin-left:2px;vertical-align:middle;border-top:4px solid #000;border-right:4px solid transparent;border-bottom:0 dotted;border-left:4px solid transparent;content:""}.dropdown{position:relative}.dropdown-toggle:focus{outline:0}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;font-size:14px;list-style:none;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.15);border-radius:4px;-webkit-box-shadow:0 6px 12px rgba(0,0,0,0.175);box-shadow:0 6px 12px rgba(0,0,0,0.175);background-clip:padding-box}.dropdown-menu.pull-right{right:0;left:auto}.dropdown-menu .divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.dropdown-menu>li>a{display:block;padding:3px 20px;clear:both;font-weight:normal;line-height:1.428571429;color:#333;white-space:nowrap}.dropdown-menu>li>a:hover,.dropdown-menu>li>a:focus{color:#fff;text-decoration:none;background-color:#428bca}.dropdown-menu>.active>a,.dropdown-menu>.active>a:hover,.dropdown-menu>.active>a:focus{color:#fff;text-decoration:none;background-color:#428bca;outline:0}.dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{color:#999}.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{text-decoration:none;cursor:not-allowed;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.open>.dropdown-menu{display:block}.open>a{outline:0}.dropdown-header{display:block;padding:3px 20px;font-size:12px;line-height:1.428571429;color:#999}.dropdown-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:990}.pull-right>.dropdown-menu{right:0;left:auto}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{border-top:0 dotted;border-bottom:4px solid #000;content:""}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:1px}@media(min-width:768px){.navbar-right .dropdown-menu{right:0;left:auto}}.btn-default .caret{border-top-color:#333}.btn-primary .caret,.btn-success .caret,.btn-warning .caret,.btn-danger .caret,.btn-info .caret{border-top-color:#fff}.dropup .btn-default .caret{border-bottom-color:#333}.dropup .btn-primary .caret,.dropup .btn-success .caret,.dropup .btn-warning .caret,.dropup .btn-danger .caret,.dropup .btn-info .caret{border-bottom-color:#fff}.btn-group,.btn-group-vertical{position:relative;display:inline-block;vertical-align:middle}.btn-group>.btn,.btn-group-vertical>.btn{position:relative;float:left}.btn-group>.btn:hover,.btn-group-vertical>.btn:hover,.btn-group>.btn:focus,.btn-group-vertical>.btn:focus,.btn-group>.btn:active,.btn-group-vertical>.btn:active,.btn-group>.btn.active,.btn-group-vertical>.btn.active{z-index:2}.btn-group>.btn:focus,.btn-group-vertical>.btn:focus{outline:0}.btn-group .btn+.btn,.btn-group .btn+.btn-group,.btn-group .btn-group+.btn,.btn-group .btn-group+.btn-group{margin-left:-1px}.btn-toolbar:before,.btn-toolbar:after{display:table;content:" "}.btn-toolbar:after{clear:both}.btn-toolbar:before,.btn-toolbar:after{display:table;content:" "}.btn-toolbar:after{clear:both}.btn-toolbar .btn-group{float:left}.btn-toolbar>.btn+.btn,.btn-toolbar>.btn-group+.btn,.btn-toolbar>.btn+.btn-group,.btn-toolbar>.btn-group+.btn-group{margin-left:5px}.btn-group>.btn:not(:first-child):not(:last-child):not(.dropdown-toggle){border-radius:0}.btn-group>.btn:first-child{margin-left:0}.btn-group>.btn:first-child:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn:last-child:not(:first-child),.btn-group>.dropdown-toggle:not(:first-child){border-bottom-left-radius:0;border-top-left-radius:0}.btn-group>.btn-group{float:left}.btn-group>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group>.btn-group:first-child>.btn:last-child,.btn-group>.btn-group:first-child>.dropdown-toggle{border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn-group:last-child>.btn:first-child{border-bottom-left-radius:0;border-top-left-radius:0}.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}.btn-group-xs>.btn{padding:5px 10px;padding:1px 5px;font-size:12px;line-height:1.5;border-radius:3px}.btn-group-sm>.btn{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.btn-group-lg>.btn{padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}.btn-group>.btn+.dropdown-toggle{padding-right:8px;padding-left:8px}.btn-group>.btn-lg+.dropdown-toggle{padding-right:12px;padding-left:12px}.btn-group.open .dropdown-toggle{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,0.125);box-shadow:inset 0 3px 5px rgba(0,0,0,0.125)}.btn .caret{margin-left:0}.btn-lg .caret{border-width:5px 5px 0;border-bottom-width:0}.dropup .btn-lg .caret{border-width:0 5px 5px}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group{display:block;float:none;width:100%;max-width:100%}.btn-group-vertical>.btn-group:before,.btn-group-vertical>.btn-group:after{display:table;content:" "}.btn-group-vertical>.btn-group:after{clear:both}.btn-group-vertical>.btn-group:before,.btn-group-vertical>.btn-group:after{display:table;content:" "}.btn-group-vertical>.btn-group:after{clear:both}.btn-group-vertical>.btn-group>.btn{float:none}.btn-group-vertical>.btn+.btn,.btn-group-vertical>.btn+.btn-group,.btn-group-vertical>.btn-group+.btn,.btn-group-vertical>.btn-group+.btn-group{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn:not(:first-child):not(:last-child){border-radius:0}.btn-group-vertical>.btn:first-child:not(:last-child){border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn:last-child:not(:first-child){border-top-right-radius:0;border-bottom-left-radius:4px;border-top-left-radius:0}.btn-group-vertical>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group-vertical>.btn-group:first-child>.btn:last-child,.btn-group-vertical>.btn-group:first-child>.dropdown-toggle{border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:last-child>.btn:first-child{border-top-right-radius:0;border-top-left-radius:0}.btn-group-justified{display:table;width:100%;border-collapse:separate;table-layout:fixed}.btn-group-justified .btn{display:table-cell;float:none;width:1%}[data-toggle="buttons"]>.btn>input[type="radio"],[data-toggle="buttons"]>.btn>input[type="checkbox"]{display:none}.input-group{position:relative;display:table;border-collapse:separate}.input-group.col{float:none;padding-right:0;padding-left:0}.input-group .form-control{width:100%;margin-bottom:0}.input-group-lg>.form-control,.input-group-lg>.input-group-addon,.input-group-lg>.input-group-btn>.btn{height:45px;padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}select.input-group-lg>.form-control,select.input-group-lg>.input-group-addon,select.input-group-lg>.input-group-btn>.btn{height:45px;line-height:45px}textarea.input-group-lg>.form-control,textarea.input-group-lg>.input-group-addon,textarea.input-group-lg>.input-group-btn>.btn{height:auto}.input-group-sm>.form-control,.input-group-sm>.input-group-addon,.input-group-sm>.input-group-btn>.btn{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-group-sm>.form-control,select.input-group-sm>.input-group-addon,select.input-group-sm>.input-group-btn>.btn{height:30px;line-height:30px}textarea.input-group-sm>.form-control,textarea.input-group-sm>.input-group-addon,textarea.input-group-sm>.input-group-btn>.btn{height:auto}.input-group-addon,.input-group-btn,.input-group .form-control{display:table-cell}.input-group-addon:not(:first-child):not(:last-child),.input-group-btn:not(:first-child):not(:last-child),.input-group .form-control:not(:first-child):not(:last-child){border-radius:0}.input-group-addon,.input-group-btn{width:1%;white-space:nowrap;vertical-align:middle}.input-group-addon{padding:6px 12px;font-size:14px;font-weight:normal;line-height:1;text-align:center;background-color:#eee;border:1px solid #ccc;border-radius:4px}.input-group-addon.input-sm{padding:5px 10px;font-size:12px;border-radius:3px}.input-group-addon.input-lg{padding:10px 16px;font-size:18px;border-radius:6px}.input-group-addon input[type="radio"],.input-group-addon input[type="checkbox"]{margin-top:0}.input-group .form-control:first-child,.input-group-addon:first-child,.input-group-btn:first-child>.btn,.input-group-btn:first-child>.dropdown-toggle,.input-group-btn:last-child>.btn:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.input-group-addon:first-child{border-right:0}.input-group .form-control:last-child,.input-group-addon:last-child,.input-group-btn:last-child>.btn,.input-group-btn:last-child>.dropdown-toggle,.input-group-btn:first-child>.btn:not(:first-child){border-bottom-left-radius:0;border-top-left-radius:0}.input-group-addon:last-child{border-left:0}.input-group-btn{position:relative;white-space:nowrap}.input-group-btn>.btn{position:relative}.input-group-btn>.btn+.btn{margin-left:-4px}.input-group-btn>.btn:hover,.input-group-btn>.btn:active{z-index:2}.nav{padding-left:0;margin-bottom:0;list-style:none}.nav:before,.nav:after{display:table;content:" "}.nav:after{clear:both}.nav:before,.nav:after{display:table;content:" "}.nav:after{clear:both}.nav>li{position:relative;display:block}.nav>li>a{position:relative;display:block;padding:10px 15px}.nav>li>a:hover,.nav>li>a:focus{text-decoration:none;background-color:#eee}.nav>li.disabled>a{color:#999}.nav>li.disabled>a:hover,.nav>li.disabled>a:focus{color:#999;text-decoration:none;cursor:not-allowed;background-color:transparent}.nav .open>a,.nav .open>a:hover,.nav .open>a:focus{background-color:#eee;border-color:#428bca}.nav .nav-divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.nav>li>a>img{max-width:none}.nav-tabs{border-bottom:1px solid #ddd}.nav-tabs>li{float:left;margin-bottom:-1px}.nav-tabs>li>a{margin-right:2px;line-height:1.428571429;border:1px solid transparent;border-radius:4px 4px 0 0}.nav-tabs>li>a:hover{border-color:#eee #eee #ddd}.nav-tabs>li.active>a,.nav-tabs>li.active>a:hover,.nav-tabs>li.active>a:focus{color:#555;cursor:default;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent}.nav-tabs.nav-justified{width:100%;border-bottom:0}.nav-tabs.nav-justified>li{float:none}.nav-tabs.nav-justified>li>a{text-align:center}@media(min-width:768px){.nav-tabs.nav-justified>li{display:table-cell;width:1%}}.nav-tabs.nav-justified>li>a{margin-right:0;border-bottom:1px solid #ddd}.nav-tabs.nav-justified>.active>a{border-bottom-color:#fff}.nav-pills>li{float:left}.nav-pills>li>a{border-radius:5px}.nav-pills>li+li{margin-left:2px}.nav-pills>li.active>a,.nav-pills>li.active>a:hover,.nav-pills>li.active>a:focus{color:#fff;background-color:#428bca}.nav-stacked>li{float:none}.nav-stacked>li+li{margin-top:2px;margin-left:0}.nav-justified{width:100%}.nav-justified>li{float:none}.nav-justified>li>a{text-align:center}@media(min-width:768px){.nav-justified>li{display:table-cell;width:1%}}.nav-tabs-justified{border-bottom:0}.nav-tabs-justified>li>a{margin-right:0;border-bottom:1px solid #ddd}.nav-tabs-justified>.active>a{border-bottom-color:#fff}.tabbable:before,.tabbable:after{display:table;content:" "}.tabbable:after{clear:both}.tabbable:before,.tabbable:after{display:table;content:" "}.tabbable:after{clear:both}.tab-content>.tab-pane,.pill-content>.pill-pane{display:none}.tab-content>.active,.pill-content>.active{display:block}.nav .caret{border-top-color:#428bca;border-bottom-color:#428bca}.nav a:hover .caret{border-top-color:#2a6496;border-bottom-color:#2a6496}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-right-radius:0;border-top-left-radius:0}.navbar{position:relative;z-index:1000;min-height:50px;margin-bottom:20px;border:1px solid transparent}.navbar:before,.navbar:after{display:table;content:" "}.navbar:after{clear:both}.navbar:before,.navbar:after{display:table;content:" "}.navbar:after{clear:both}@media(min-width:768px){.navbar{border-radius:4px}}.navbar-header:before,.navbar-header:after{display:table;content:" "}.navbar-header:after{clear:both}.navbar-header:before,.navbar-header:after{display:table;content:" "}.navbar-header:after{clear:both}@media(min-width:768px){.navbar-header{float:left}}.navbar-collapse{max-height:340px;padding-right:15px;padding-left:15px;overflow-x:visible;border-top:1px solid transparent;box-shadow:inset 0 1px 0 rgba(255,255,255,0.1);-webkit-overflow-scrolling:touch}.navbar-collapse:before,.navbar-collapse:after{display:table;content:" "}.navbar-collapse:after{clear:both}.navbar-collapse:before,.navbar-collapse:after{display:table;content:" "}.navbar-collapse:after{clear:both}.navbar-collapse.in{overflow-y:auto}@media(min-width:768px){.navbar-collapse{width:auto;border-top:0;box-shadow:none}.navbar-collapse.collapse{display:block!important;height:auto!important;padding-bottom:0;overflow:visible!important}.navbar-collapse.in{overflow-y:visible}.navbar-collapse .navbar-nav.navbar-left:first-child{margin-left:-15px}.navbar-collapse .navbar-nav.navbar-right:last-child{margin-right:-15px}.navbar-collapse .navbar-text:last-child{margin-right:0}}.container>.navbar-header,.container>.navbar-collapse{margin-right:-15px;margin-left:-15px}@media(min-width:768px){.container>.navbar-header,.container>.navbar-collapse{margin-right:0;margin-left:0}}.navbar-static-top{border-width:0 0 1px}@media(min-width:768px){.navbar-static-top{border-radius:0}}.navbar-fixed-top,.navbar-fixed-bottom{position:fixed;right:0;left:0;border-width:0 0 1px}@media(min-width:768px){.navbar-fixed-top,.navbar-fixed-bottom{border-radius:0}}.navbar-fixed-top{top:0;z-index:1030}.navbar-fixed-bottom{bottom:0;margin-bottom:0}.navbar-brand{float:left;padding:15px 15px;font-size:18px;line-height:20px}.navbar-brand:hover,.navbar-brand:focus{text-decoration:none}@media(min-width:768px){.navbar>.container .navbar-brand{margin-left:-15px}}.navbar-toggle{position:relative;float:right;padding:9px 10px;margin-top:8px;margin-right:15px;margin-bottom:8px;background-color:transparent;border:1px solid transparent;border-radius:4px}.navbar-toggle .icon-bar{display:block;width:22px;height:2px;border-radius:1px}.navbar-toggle .icon-bar+.icon-bar{margin-top:4px}@media(min-width:768px){.navbar-toggle{display:none}}.navbar-nav{margin:7.5px -15px}.navbar-nav>li>a{padding-top:10px;padding-bottom:10px;line-height:20px}@media(max-width:767px){.navbar-nav .open .dropdown-menu{position:static;float:none;width:auto;margin-top:0;background-color:transparent;border:0;box-shadow:none}.navbar-nav .open .dropdown-menu>li>a,.navbar-nav .open .dropdown-menu .dropdown-header{padding:5px 15px 5px 25px}.navbar-nav .open .dropdown-menu>li>a{line-height:20px}.navbar-nav .open .dropdown-menu>li>a:hover,.navbar-nav .open .dropdown-menu>li>a:focus{background-image:none}}@media(min-width:768px){.navbar-nav{float:left;margin:0}.navbar-nav>li{float:left}.navbar-nav>li>a{padding-top:15px;padding-bottom:15px}}@media(min-width:768px){.navbar-left{float:left!important}.navbar-right{float:right!important}}.navbar-form{padding:10px 15px;margin-top:8px;margin-right:-15px;margin-bottom:8px;margin-left:-15px;border-top:1px solid transparent;border-bottom:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1);box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1)}@media(min-width:768px){.navbar-form .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.navbar-form .form-control{display:inline-block}.navbar-form .radio,.navbar-form .checkbox{display:inline-block;padding-left:0;margin-top:0;margin-bottom:0}.navbar-form .radio input[type="radio"],.navbar-form .checkbox input[type="checkbox"]{float:none;margin-left:0}}@media(max-width:767px){.navbar-form .form-group{margin-bottom:5px}}@media(min-width:768px){.navbar-form{width:auto;padding-top:0;padding-bottom:0;margin-right:0;margin-left:0;border:0;-webkit-box-shadow:none;box-shadow:none}}.navbar-nav>li>.dropdown-menu{margin-top:0;border-top-right-radius:0;border-top-left-radius:0}.navbar-fixed-bottom .navbar-nav>li>.dropdown-menu{border-bottom-right-radius:0;border-bottom-left-radius:0}.navbar-nav.pull-right>li>.dropdown-menu,.navbar-nav>li>.dropdown-menu.pull-right{right:0;left:auto}.navbar-btn{margin-top:8px;margin-bottom:8px}.navbar-text{float:left;margin-top:15px;margin-bottom:15px}@media(min-width:768px){.navbar-text{margin-right:15px;margin-left:15px}}.navbar-default{background-color:#f8f8f8;border-color:#e7e7e7}.navbar-default .navbar-brand{color:#777}.navbar-default .navbar-brand:hover,.navbar-default .navbar-brand:focus{color:#5e5e5e;background-color:transparent}.navbar-default .navbar-text{color:#777}.navbar-default .navbar-nav>li>a{color:#777}.navbar-default .navbar-nav>li>a:hover,.navbar-default .navbar-nav>li>a:focus{color:#333;background-color:transparent}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.active>a:hover,.navbar-default .navbar-nav>.active>a:focus{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav>.disabled>a,.navbar-default .navbar-nav>.disabled>a:hover,.navbar-default .navbar-nav>.disabled>a:focus{color:#ccc;background-color:transparent}.navbar-default .navbar-toggle{border-color:#ddd}.navbar-default .navbar-toggle:hover,.navbar-default .navbar-toggle:focus{background-color:#ddd}.navbar-default .navbar-toggle .icon-bar{background-color:#ccc}.navbar-default .navbar-collapse,.navbar-default .navbar-form{border-color:#e6e6e6}.navbar-default .navbar-nav>.dropdown>a:hover .caret,.navbar-default .navbar-nav>.dropdown>a:focus .caret{border-top-color:#333;border-bottom-color:#333}.navbar-default .navbar-nav>.open>a,.navbar-default .navbar-nav>.open>a:hover,.navbar-default .navbar-nav>.open>a:focus{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav>.open>a .caret,.navbar-default .navbar-nav>.open>a:hover .caret,.navbar-default .navbar-nav>.open>a:focus .caret{border-top-color:#555;border-bottom-color:#555}.navbar-default .navbar-nav>.dropdown>a .caret{border-top-color:#777;border-bottom-color:#777}@media(max-width:767px){.navbar-default .navbar-nav .open .dropdown-menu>li>a{color:#777}.navbar-default .navbar-nav .open .dropdown-menu>li>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>li>a:focus{color:#333;background-color:transparent}.navbar-default .navbar-nav .open .dropdown-menu>.active>a,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:focus{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:focus{color:#ccc;background-color:transparent}}.navbar-default .navbar-link{color:#777}.navbar-default .navbar-link:hover{color:#333}.navbar-inverse{background-color:#222;border-color:#080808}.navbar-inverse .navbar-brand{color:#999}.navbar-inverse .navbar-brand:hover,.navbar-inverse .navbar-brand:focus{color:#fff;background-color:transparent}.navbar-inverse .navbar-text{color:#999}.navbar-inverse .navbar-nav>li>a{color:#999}.navbar-inverse .navbar-nav>li>a:hover,.navbar-inverse .navbar-nav>li>a:focus{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav>.active>a,.navbar-inverse .navbar-nav>.active>a:hover,.navbar-inverse .navbar-nav>.active>a:focus{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav>.disabled>a,.navbar-inverse .navbar-nav>.disabled>a:hover,.navbar-inverse .navbar-nav>.disabled>a:focus{color:#444;background-color:transparent}.navbar-inverse .navbar-toggle{border-color:#333}.navbar-inverse .navbar-toggle:hover,.navbar-inverse .navbar-toggle:focus{background-color:#333}.navbar-inverse .navbar-toggle .icon-bar{background-color:#fff}.navbar-inverse .navbar-collapse,.navbar-inverse .navbar-form{border-color:#101010}.navbar-inverse .navbar-nav>.open>a,.navbar-inverse .navbar-nav>.open>a:hover,.navbar-inverse .navbar-nav>.open>a:focus{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav>.dropdown>a:hover .caret{border-top-color:#fff;border-bottom-color:#fff}.navbar-inverse .navbar-nav>.dropdown>a .caret{border-top-color:#999;border-bottom-color:#999}.navbar-inverse .navbar-nav>.open>a .caret,.navbar-inverse .navbar-nav>.open>a:hover .caret,.navbar-inverse .navbar-nav>.open>a:focus .caret{border-top-color:#fff;border-bottom-color:#fff}@media(max-width:767px){.navbar-inverse .navbar-nav .open .dropdown-menu>.dropdown-header{border-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a{color:#999}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:focus{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:focus{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:focus{color:#444;background-color:transparent}}.navbar-inverse .navbar-link{color:#999}.navbar-inverse .navbar-link:hover{color:#fff}.breadcrumb{padding:8px 15px;margin-bottom:20px;list-style:none;background-color:#f5f5f5;border-radius:4px}.breadcrumb>li{display:inline-block}.breadcrumb>li+li:before{padding:0 5px;color:#ccc;content:"/\00a0"}.breadcrumb>.active{color:#999}.pagination{display:inline-block;padding-left:0;margin:20px 0;border-radius:4px}.pagination>li{display:inline}.pagination>li>a,.pagination>li>span{position:relative;float:left;padding:6px 12px;margin-left:-1px;line-height:1.428571429;text-decoration:none;background-color:#fff;border:1px solid #ddd}.pagination>li:first-child>a,.pagination>li:first-child>span{margin-left:0;border-bottom-left-radius:4px;border-top-left-radius:4px}.pagination>li:last-child>a,.pagination>li:last-child>span{border-top-right-radius:4px;border-bottom-right-radius:4px}.pagination>li>a:hover,.pagination>li>span:hover,.pagination>li>a:focus,.pagination>li>span:focus{background-color:#eee}.pagination>.active>a,.pagination>.active>span,.pagination>.active>a:hover,.pagination>.active>span:hover,.pagination>.active>a:focus,.pagination>.active>span:focus{z-index:2;color:#fff;cursor:default;background-color:#428bca;border-color:#428bca}.pagination>.disabled>span,.pagination>.disabled>a,.pagination>.disabled>a:hover,.pagination>.disabled>a:focus{color:#999;cursor:not-allowed;background-color:#fff;border-color:#ddd}.pagination-lg>li>a,.pagination-lg>li>span{padding:10px 16px;font-size:18px}.pagination-lg>li:first-child>a,.pagination-lg>li:first-child>span{border-bottom-left-radius:6px;border-top-left-radius:6px}.pagination-lg>li:last-child>a,.pagination-lg>li:last-child>span{border-top-right-radius:6px;border-bottom-right-radius:6px}.pagination-sm>li>a,.pagination-sm>li>span{padding:5px 10px;font-size:12px}.pagination-sm>li:first-child>a,.pagination-sm>li:first-child>span{border-bottom-left-radius:3px;border-top-left-radius:3px}.pagination-sm>li:last-child>a,.pagination-sm>li:last-child>span{border-top-right-radius:3px;border-bottom-right-radius:3px}.pager{padding-left:0;margin:20px 0;text-align:center;list-style:none}.pager:before,.pager:after{display:table;content:" "}.pager:after{clear:both}.pager:before,.pager:after{display:table;content:" "}.pager:after{clear:both}.pager li{display:inline}.pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;border-radius:15px}.pager li>a:hover,.pager li>a:focus{text-decoration:none;background-color:#eee}.pager .next>a,.pager .next>span{float:right}.pager .previous>a,.pager .previous>span{float:left}.pager .disabled>a,.pager .disabled>a:hover,.pager .disabled>a:focus,.pager .disabled>span{color:#999;cursor:not-allowed;background-color:#fff}.label{display:inline;padding:.2em .6em .3em;font-size:75%;font-weight:bold;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25em}.label[href]:hover,.label[href]:focus{color:#fff;text-decoration:none;cursor:pointer}.label:empty{display:none}.label-default{background-color:#999}.label-default[href]:hover,.label-default[href]:focus{background-color:#808080}.label-primary{background-color:#428bca}.label-primary[href]:hover,.label-primary[href]:focus{background-color:#3071a9}.label-success{background-color:#5cb85c}.label-success[href]:hover,.label-success[href]:focus{background-color:#449d44}.label-info{background-color:#5bc0de}.label-info[href]:hover,.label-info[href]:focus{background-color:#31b0d5}.label-warning{background-color:#f0ad4e}.label-warning[href]:hover,.label-warning[href]:focus{background-color:#ec971f}.label-danger{background-color:#d9534f}.label-danger[href]:hover,.label-danger[href]:focus{background-color:#c9302c}.badge{display:inline-block;min-width:10px;padding:3px 7px;font-size:12px;font-weight:bold;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;background-color:#999;border-radius:10px}.badge:empty{display:none}a.badge:hover,a.badge:focus{color:#fff;text-decoration:none;cursor:pointer}.btn .badge{position:relative;top:-1px}a.list-group-item.active>.badge,.nav-pills>.active>a>.badge{color:#428bca;background-color:#fff}.nav-pills>li>a>.badge{margin-left:3px}.jumbotron{padding:30px;margin-bottom:30px;font-size:21px;font-weight:200;line-height:2.1428571435;color:inherit;background-color:#eee}.jumbotron h1{line-height:1;color:inherit}.jumbotron p{line-height:1.4}.container .jumbotron{border-radius:6px}@media screen and (min-width:768px){.jumbotron{padding-top:48px;padding-bottom:48px}.container .jumbotron{padding-right:60px;padding-left:60px}.jumbotron h1{font-size:63px}}.thumbnail{display:inline-block;display:block;height:auto;max-width:100%;padding:4px;line-height:1.428571429;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.thumbnail>img{display:block;height:auto;max-width:100%}a.thumbnail:hover,a.thumbnail:focus{border-color:#428bca}.thumbnail>img{margin-right:auto;margin-left:auto}.thumbnail .caption{padding:9px;color:#333}.alert{padding:15px;margin-bottom:20px;border:1px solid transparent;border-radius:4px}.alert h4{margin-top:0;color:inherit}.alert .alert-link{font-weight:bold}.alert>p,.alert>ul{margin-bottom:0}.alert>p+p{margin-top:5px}.alert-dismissable{padding-right:35px}.alert-dismissable .close{position:relative;top:-2px;right:-21px;color:inherit}.alert-success{color:#468847;background-color:#dff0d8;border-color:#d6e9c6}.alert-success hr{border-top-color:#c9e2b3}.alert-success .alert-link{color:#356635}.alert-info{color:#3a87ad;background-color:#d9edf7;border-color:#bce8f1}.alert-info hr{border-top-color:#a6e1ec}.alert-info .alert-link{color:#2d6987}.alert-warning{color:#c09853;background-color:#fcf8e3;border-color:#fbeed5}.alert-warning hr{border-top-color:#f8e5be}.alert-warning .alert-link{color:#a47e3c}.alert-danger{color:#b94a48;background-color:#f2dede;border-color:#eed3d7}.alert-danger hr{border-top-color:#e6c1c7}.alert-danger .alert-link{color:#953b39}@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-moz-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-o-keyframes progress-bar-stripes{from{background-position:0 0}to{background-position:40px 0}}@keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}.progress{height:20px;margin-bottom:20px;overflow:hidden;background-color:#f5f5f5;border-radius:4px;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1);box-shadow:inset 0 1px 2px rgba(0,0,0,0.1)}.progress-bar{float:left;width:0;height:100%;font-size:12px;color:#fff;text-align:center;background-color:#428bca;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);-webkit-transition:width .6s ease;transition:width .6s ease}.progress-striped .progress-bar{background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-size:40px 40px}.progress.active .progress-bar{-webkit-animation:progress-bar-stripes 2s linear infinite;-moz-animation:progress-bar-stripes 2s linear infinite;-ms-animation:progress-bar-stripes 2s linear infinite;-o-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.progress-bar-success{background-color:#5cb85c}.progress-striped .progress-bar-success{background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.progress-bar-info{background-color:#5bc0de}.progress-striped .progress-bar-info{background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.progress-bar-warning{background-color:#f0ad4e}.progress-striped .progress-bar-warning{background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.progress-bar-danger{background-color:#d9534f}.progress-striped .progress-bar-danger{background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.media,.media-body{overflow:hidden;zoom:1}.media,.media .media{margin-top:15px}.media:first-child{margin-top:0}.media-object{display:block}.media-heading{margin:0 0 5px}.media>.pull-left{margin-right:10px}.media>.pull-right{margin-left:10px}.media-list{padding-left:0;list-style:none}.list-group{padding-left:0;margin-bottom:20px}.list-group-item{position:relative;display:block;padding:10px 15px;margin-bottom:-1px;background-color:#fff;border:1px solid #ddd}.list-group-item:first-child{border-top-right-radius:4px;border-top-left-radius:4px}.list-group-item:last-child{margin-bottom:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px}.list-group-item>.badge{float:right}.list-group-item>.badge+.badge{margin-right:5px}a.list-group-item{color:#555}a.list-group-item .list-group-item-heading{color:#333}a.list-group-item:hover,a.list-group-item:focus{text-decoration:none;background-color:#f5f5f5}.list-group-item.active,.list-group-item.active:hover,.list-group-item.active:focus{z-index:2;color:#fff;background-color:#428bca;border-color:#428bca}.list-group-item.active .list-group-item-heading,.list-group-item.active:hover .list-group-item-heading,.list-group-item.active:focus .list-group-item-heading{color:inherit}.list-group-item.active .list-group-item-text,.list-group-item.active:hover .list-group-item-text,.list-group-item.active:focus .list-group-item-text{color:#e1edf7}.list-group-item-heading{margin-top:0;margin-bottom:5px}.list-group-item-text{margin-bottom:0;line-height:1.3}.panel{margin-bottom:20px;background-color:#fff;border:1px solid transparent;border-radius:4px;-webkit-box-shadow:0 1px 1px rgba(0,0,0,0.05);box-shadow:0 1px 1px rgba(0,0,0,0.05)}.panel-body{padding:15px}.panel-body:before,.panel-body:after{display:table;content:" "}.panel-body:after{clear:both}.panel-body:before,.panel-body:after{display:table;content:" "}.panel-body:after{clear:both}.panel>.list-group{margin-bottom:0}.panel>.list-group .list-group-item{border-width:1px 0}.panel>.list-group .list-group-item:first-child{border-top-right-radius:0;border-top-left-radius:0}.panel>.list-group .list-group-item:last-child{border-bottom:0}.panel-heading+.list-group .list-group-item:first-child{border-top-width:0}.panel>.table{margin-bottom:0}.panel>.panel-body+.table{border-top:1px solid #ddd}.panel-heading{padding:10px 15px;border-bottom:1px solid transparent;border-top-right-radius:3px;border-top-left-radius:3px}.panel-title{margin-top:0;margin-bottom:0;font-size:16px}.panel-title>a{color:inherit}.panel-footer{padding:10px 15px;background-color:#f5f5f5;border-top:1px solid #ddd;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel-group .panel{margin-bottom:0;overflow:hidden;border-radius:4px}.panel-group .panel+.panel{margin-top:5px}.panel-group .panel-heading{border-bottom:0}.panel-group .panel-heading+.panel-collapse .panel-body{border-top:1px solid #ddd}.panel-group .panel-footer{border-top:0}.panel-group .panel-footer+.panel-collapse .panel-body{border-bottom:1px solid #ddd}.panel-default{border-color:#ddd}.panel-default>.panel-heading{color:#333;background-color:#f5f5f5;border-color:#ddd}.panel-default>.panel-heading+.panel-collapse .panel-body{border-top-color:#ddd}.panel-default>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#ddd}.panel-primary{border-color:#428bca}.panel-primary>.panel-heading{color:#fff;background-color:#428bca;border-color:#428bca}.panel-primary>.panel-heading+.panel-collapse .panel-body{border-top-color:#428bca}.panel-primary>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#428bca}.panel-success{border-color:#d6e9c6}.panel-success>.panel-heading{color:#468847;background-color:#dff0d8;border-color:#d6e9c6}.panel-success>.panel-heading+.panel-collapse .panel-body{border-top-color:#d6e9c6}.panel-success>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#d6e9c6}.panel-warning{border-color:#fbeed5}.panel-warning>.panel-heading{color:#c09853;background-color:#fcf8e3;border-color:#fbeed5}.panel-warning>.panel-heading+.panel-collapse .panel-body{border-top-color:#fbeed5}.panel-warning>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#fbeed5}.panel-danger{border-color:#eed3d7}.panel-danger>.panel-heading{color:#b94a48;background-color:#f2dede;border-color:#eed3d7}.panel-danger>.panel-heading+.panel-collapse .panel-body{border-top-color:#eed3d7}.panel-danger>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#eed3d7}.panel-info{border-color:#bce8f1}.panel-info>.panel-heading{color:#3a87ad;background-color:#d9edf7;border-color:#bce8f1}.panel-info>.panel-heading+.panel-collapse .panel-body{border-top-color:#bce8f1}.panel-info>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#bce8f1}.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.05);box-shadow:inset 0 1px 1px rgba(0,0,0,0.05)}.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,0.15)}.well-lg{padding:24px;border-radius:6px}.well-sm{padding:9px;border-radius:3px}.close{float:right;font-size:21px;font-weight:bold;line-height:1;color:#000;text-shadow:0 1px 0 #fff;opacity:.2;filter:alpha(opacity=20)}.close:hover,.close:focus{color:#000;text-decoration:none;cursor:pointer;opacity:.5;filter:alpha(opacity=50)}button.close{padding:0;cursor:pointer;background:transparent;border:0;-webkit-appearance:none}.modal-open{overflow:hidden}body.modal-open,.modal-open .navbar-fixed-top,.modal-open .navbar-fixed-bottom{margin-right:15px}.modal{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;display:none;overflow:auto;overflow-y:scroll}.modal.fade .modal-dialog{-webkit-transform:translate(0,-25%);-ms-transform:translate(0,-25%);transform:translate(0,-25%);-webkit-transition:-webkit-transform .3s ease-out;-moz-transition:-moz-transform .3s ease-out;-o-transition:-o-transform .3s ease-out;transition:transform .3s ease-out}.modal.in .modal-dialog{-webkit-transform:translate(0,0);-ms-transform:translate(0,0);transform:translate(0,0)}.modal-dialog{z-index:1050;width:auto;padding:10px;margin-right:auto;margin-left:auto}.modal-content{position:relative;background-color:#fff;border:1px solid #999;border:1px solid rgba(0,0,0,0.2);border-radius:6px;outline:0;-webkit-box-shadow:0 3px 9px rgba(0,0,0,0.5);box-shadow:0 3px 9px rgba(0,0,0,0.5);background-clip:padding-box}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1030;background-color:#000}.modal-backdrop.fade{opacity:0;filter:alpha(opacity=0)}.modal-backdrop.in{opacity:.5;filter:alpha(opacity=50)}.modal-header{min-height:16.428571429px;padding:15px;border-bottom:1px solid #e5e5e5}.modal-header .close{margin-top:-2px}.modal-title{margin:0;line-height:1.428571429}.modal-body{position:relative;padding:20px}.modal-footer{padding:19px 20px 20px;margin-top:15px;text-align:right;border-top:1px solid #e5e5e5}.modal-footer:before,.modal-footer:after{display:table;content:" "}.modal-footer:after{clear:both}.modal-footer:before,.modal-footer:after{display:table;content:" "}.modal-footer:after{clear:both}.modal-footer .btn+.btn{margin-bottom:0;margin-left:5px}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.modal-footer .btn-block+.btn-block{margin-left:0}@media screen and (min-width:768px){.modal-dialog{right:auto;left:50%;width:600px;padding-top:30px;padding-bottom:30px}.modal-content{-webkit-box-shadow:0 5px 15px rgba(0,0,0,0.5);box-shadow:0 5px 15px rgba(0,0,0,0.5)}}.tooltip{position:absolute;z-index:1030;display:block;font-size:12px;line-height:1.4;opacity:0;filter:alpha(opacity=0);visibility:visible}.tooltip.in{opacity:.9;filter:alpha(opacity=90)}.tooltip.top{padding:5px 0;margin-top:-3px}.tooltip.right{padding:0 5px;margin-left:3px}.tooltip.bottom{padding:5px 0;margin-top:3px}.tooltip.left{padding:0 5px;margin-left:-3px}.tooltip-inner{max-width:200px;padding:3px 8px;color:#fff;text-align:center;text-decoration:none;background-color:#000;border-radius:4px}.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-top-color:#000;border-width:5px 5px 0}.tooltip.top-left .tooltip-arrow{bottom:0;left:5px;border-top-color:#000;border-width:5px 5px 0}.tooltip.top-right .tooltip-arrow{right:5px;bottom:0;border-top-color:#000;border-width:5px 5px 0}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-right-color:#000;border-width:5px 5px 5px 0}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-left-color:#000;border-width:5px 0 5px 5px}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-bottom-color:#000;border-width:0 5px 5px}.tooltip.bottom-left .tooltip-arrow{top:0;left:5px;border-bottom-color:#000;border-width:0 5px 5px}.tooltip.bottom-right .tooltip-arrow{top:0;right:5px;border-bottom-color:#000;border-width:0 5px 5px}.popover{position:absolute;top:0;left:0;z-index:1010;display:none;max-width:276px;padding:1px;text-align:left;white-space:normal;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,0.2);box-shadow:0 5px 10px rgba(0,0,0,0.2);background-clip:padding-box}.popover.top{margin-top:-10px}.popover.right{margin-left:10px}.popover.bottom{margin-top:10px}.popover.left{margin-left:-10px}.popover-title{padding:8px 14px;margin:0;font-size:14px;font-weight:normal;line-height:18px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-radius:5px 5px 0 0}.popover-content{padding:9px 14px}.popover .arrow,.popover .arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.popover .arrow{border-width:11px}.popover .arrow:after{border-width:10px;content:""}.popover.top .arrow{bottom:-11px;left:50%;margin-left:-11px;border-top-color:#999;border-top-color:rgba(0,0,0,0.25);border-bottom-width:0}.popover.top .arrow:after{bottom:1px;margin-left:-10px;border-top-color:#fff;border-bottom-width:0;content:" "}.popover.right .arrow{top:50%;left:-11px;margin-top:-11px;border-right-color:#999;border-right-color:rgba(0,0,0,0.25);border-left-width:0}.popover.right .arrow:after{bottom:-10px;left:1px;border-right-color:#fff;border-left-width:0;content:" "}.popover.bottom .arrow{top:-11px;left:50%;margin-left:-11px;border-bottom-color:#999;border-bottom-color:rgba(0,0,0,0.25);border-top-width:0}.popover.bottom .arrow:after{top:1px;margin-left:-10px;border-bottom-color:#fff;border-top-width:0;content:" "}.popover.left .arrow{top:50%;right:-11px;margin-top:-11px;border-left-color:#999;border-left-color:rgba(0,0,0,0.25);border-right-width:0}.popover.left .arrow:after{right:1px;bottom:-10px;border-left-color:#fff;border-right-width:0;content:" "}.carousel{position:relative}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner>.item{position:relative;display:none;-webkit-transition:.6s ease-in-out left;transition:.6s ease-in-out left}.carousel-inner>.item>img,.carousel-inner>.item>a>img{display:block;height:auto;max-width:100%;line-height:1}.carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block}.carousel-inner>.active{left:0}.carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%}.carousel-inner>.next{left:100%}.carousel-inner>.prev{left:-100%}.carousel-inner>.next.left,.carousel-inner>.prev.right{left:0}.carousel-inner>.active.left{left:-100%}.carousel-inner>.active.right{left:100%}.carousel-control{position:absolute;top:0;bottom:0;left:0;width:15%;font-size:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,0.6);opacity:.5;filter:alpha(opacity=50)}.carousel-control.left{background-image:-webkit-gradient(linear,0 top,100% top,from(rgba(0,0,0,0.5)),to(rgba(0,0,0,0.0001)));background-image:-webkit-linear-gradient(left,color-stop(rgba(0,0,0,0.5) 0),color-stop(rgba(0,0,0,0.0001) 100%));background-image:-moz-linear-gradient(left,rgba(0,0,0,0.5) 0,rgba(0,0,0,0.0001) 100%);background-image:linear-gradient(to right,rgba(0,0,0,0.5) 0,rgba(0,0,0,0.0001) 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000',endColorstr='#00000000',GradientType=1)}.carousel-control.right{right:0;left:auto;background-image:-webkit-gradient(linear,0 top,100% top,from(rgba(0,0,0,0.0001)),to(rgba(0,0,0,0.5)));background-image:-webkit-linear-gradient(left,color-stop(rgba(0,0,0,0.0001) 0),color-stop(rgba(0,0,0,0.5) 100%));background-image:-moz-linear-gradient(left,rgba(0,0,0,0.0001) 0,rgba(0,0,0,0.5) 100%);background-image:linear-gradient(to right,rgba(0,0,0,0.0001) 0,rgba(0,0,0,0.5) 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000',endColorstr='#80000000',GradientType=1)}.carousel-control:hover,.carousel-control:focus{color:#fff;text-decoration:none;opacity:.9;filter:alpha(opacity=90)}.carousel-control .icon-prev,.carousel-control .icon-next,.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right{position:absolute;top:50%;left:50%;z-index:5;display:inline-block}.carousel-control .icon-prev,.carousel-control .icon-next{width:20px;height:20px;margin-top:-10px;margin-left:-10px;font-family:serif}.carousel-control .icon-prev:before{content:'\2039'}.carousel-control .icon-next:before{content:'\203a'}.carousel-indicators{position:absolute;bottom:10px;left:50%;z-index:15;width:60%;padding-left:0;margin-left:-30%;text-align:center;list-style:none}.carousel-indicators li{display:inline-block;width:10px;height:10px;margin:1px;text-indent:-999px;cursor:pointer;border:1px solid #fff;border-radius:10px}.carousel-indicators .active{width:12px;height:12px;margin:0;background-color:#fff}.carousel-caption{position:absolute;right:15%;bottom:20px;left:15%;z-index:10;padding-top:20px;padding-bottom:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,0.6)}.carousel-caption .btn{text-shadow:none}@media screen and (min-width:768px){.carousel-control .icon-prev,.carousel-control .icon-next{width:30px;height:30px;margin-top:-15px;margin-left:-15px;font-size:30px}.carousel-caption{right:20%;left:20%;padding-bottom:30px}.carousel-indicators{bottom:20px}}.clearfix:before,.clearfix:after{display:table;content:" "}.clearfix:after{clear:both}.pull-right{float:right!important}.pull-left{float:left!important}.hide{display:none!important}.show{display:block!important}.invisible{visibility:hidden}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.affix{position:fixed}@-ms-viewport{width:device-width}@media screen and (max-width:400px){@-ms-viewport{width:320px}}.hidden{display:none!important;visibility:hidden!important}.visible-xs{display:none!important}tr.visible-xs{display:none!important}th.visible-xs,td.visible-xs{display:none!important}@media(max-width:767px){.visible-xs{display:block!important}tr.visible-xs{display:table-row!important}th.visible-xs,td.visible-xs{display:table-cell!important}}@media(min-width:768px) and (max-width:991px){.visible-xs.visible-sm{display:block!important}tr.visible-xs.visible-sm{display:table-row!important}th.visible-xs.visible-sm,td.visible-xs.visible-sm{display:table-cell!important}}@media(min-width:992px) and (max-width:1199px){.visible-xs.visible-md{display:block!important}tr.visible-xs.visible-md{display:table-row!important}th.visible-xs.visible-md,td.visible-xs.visible-md{display:table-cell!important}}@media(min-width:1200px){.visible-xs.visible-lg{display:block!important}tr.visible-xs.visible-lg{display:table-row!important}th.visible-xs.visible-lg,td.visible-xs.visible-lg{display:table-cell!important}}.visible-sm{display:none!important}tr.visible-sm{display:none!important}th.visible-sm,td.visible-sm{display:none!important}@media(max-width:767px){.visible-sm.visible-xs{display:block!important}tr.visible-sm.visible-xs{display:table-row!important}th.visible-sm.visible-xs,td.visible-sm.visible-xs{display:table-cell!important}}@media(min-width:768px) and (max-width:991px){.visible-sm{display:block!important}tr.visible-sm{display:table-row!important}th.visible-sm,td.visible-sm{display:table-cell!important}}@media(min-width:992px) and (max-width:1199px){.visible-sm.visible-md{display:block!important}tr.visible-sm.visible-md{display:table-row!important}th.visible-sm.visible-md,td.visible-sm.visible-md{display:table-cell!important}}@media(min-width:1200px){.visible-sm.visible-lg{display:block!important}tr.visible-sm.visible-lg{display:table-row!important}th.visible-sm.visible-lg,td.visible-sm.visible-lg{display:table-cell!important}}.visible-md{display:none!important}tr.visible-md{display:none!important}th.visible-md,td.visible-md{display:none!important}@media(max-width:767px){.visible-md.visible-xs{display:block!important}tr.visible-md.visible-xs{display:table-row!important}th.visible-md.visible-xs,td.visible-md.visible-xs{display:table-cell!important}}@media(min-width:768px) and (max-width:991px){.visible-md.visible-sm{display:block!important}tr.visible-md.visible-sm{display:table-row!important}th.visible-md.visible-sm,td.visible-md.visible-sm{display:table-cell!important}}@media(min-width:992px) and (max-width:1199px){.visible-md{display:block!important}tr.visible-md{display:table-row!important}th.visible-md,td.visible-md{display:table-cell!important}}@media(min-width:1200px){.visible-md.visible-lg{display:block!important}tr.visible-md.visible-lg{display:table-row!important}th.visible-md.visible-lg,td.visible-md.visible-lg{display:table-cell!important}}.visible-lg{display:none!important}tr.visible-lg{display:none!important}th.visible-lg,td.visible-lg{display:none!important}@media(max-width:767px){.visible-lg.visible-xs{display:block!important}tr.visible-lg.visible-xs{display:table-row!important}th.visible-lg.visible-xs,td.visible-lg.visible-xs{display:table-cell!important}}@media(min-width:768px) and (max-width:991px){.visible-lg.visible-sm{display:block!important}tr.visible-lg.visible-sm{display:table-row!important}th.visible-lg.visible-sm,td.visible-lg.visible-sm{display:table-cell!important}}@media(min-width:992px) and (max-width:1199px){.visible-lg.visible-md{display:block!important}tr.visible-lg.visible-md{display:table-row!important}th.visible-lg.visible-md,td.visible-lg.visible-md{display:table-cell!important}}@media(min-width:1200px){.visible-lg{display:block!important}tr.visible-lg{display:table-row!important}th.visible-lg,td.visible-lg{display:table-cell!important}}.hidden-xs{display:block!important}tr.hidden-xs{display:table-row!important}th.hidden-xs,td.hidden-xs{display:table-cell!important}@media(max-width:767px){.hidden-xs{display:none!important}tr.hidden-xs{display:none!important}th.hidden-xs,td.hidden-xs{display:none!important}}@media(min-width:768px) and (max-width:991px){.hidden-xs.hidden-sm{display:none!important}tr.hidden-xs.hidden-sm{display:none!important}th.hidden-xs.hidden-sm,td.hidden-xs.hidden-sm{display:none!important}}@media(min-width:992px) and (max-width:1199px){.hidden-xs.hidden-md{display:none!important}tr.hidden-xs.hidden-md{display:none!important}th.hidden-xs.hidden-md,td.hidden-xs.hidden-md{display:none!important}}@media(min-width:1200px){.hidden-xs.hidden-lg{display:none!important}tr.hidden-xs.hidden-lg{display:none!important}th.hidden-xs.hidden-lg,td.hidden-xs.hidden-lg{display:none!important}}.hidden-sm{display:block!important}tr.hidden-sm{display:table-row!important}th.hidden-sm,td.hidden-sm{display:table-cell!important}@media(max-width:767px){.hidden-sm.hidden-xs{display:none!important}tr.hidden-sm.hidden-xs{display:none!important}th.hidden-sm.hidden-xs,td.hidden-sm.hidden-xs{display:none!important}}@media(min-width:768px) and (max-width:991px){.hidden-sm{display:none!important}tr.hidden-sm{display:none!important}th.hidden-sm,td.hidden-sm{display:none!important}}@media(min-width:992px) and (max-width:1199px){.hidden-sm.hidden-md{display:none!important}tr.hidden-sm.hidden-md{display:none!important}th.hidden-sm.hidden-md,td.hidden-sm.hidden-md{display:none!important}}@media(min-width:1200px){.hidden-sm.hidden-lg{display:none!important}tr.hidden-sm.hidden-lg{display:none!important}th.hidden-sm.hidden-lg,td.hidden-sm.hidden-lg{display:none!important}}.hidden-md{display:block!important}tr.hidden-md{display:table-row!important}th.hidden-md,td.hidden-md{display:table-cell!important}@media(max-width:767px){.hidden-md.hidden-xs{display:none!important}tr.hidden-md.hidden-xs{display:none!important}th.hidden-md.hidden-xs,td.hidden-md.hidden-xs{display:none!important}}@media(min-width:768px) and (max-width:991px){.hidden-md.hidden-sm{display:none!important}tr.hidden-md.hidden-sm{display:none!important}th.hidden-md.hidden-sm,td.hidden-md.hidden-sm{display:none!important}}@media(min-width:992px) and (max-width:1199px){.hidden-md{display:none!important}tr.hidden-md{display:none!important}th.hidden-md,td.hidden-md{display:none!important}}@media(min-width:1200px){.hidden-md.hidden-lg{display:none!important}tr.hidden-md.hidden-lg{display:none!important}th.hidden-md.hidden-lg,td.hidden-md.hidden-lg{display:none!important}}.hidden-lg{display:block!important}tr.hidden-lg{display:table-row!important}th.hidden-lg,td.hidden-lg{display:table-cell!important}@media(max-width:767px){.hidden-lg.hidden-xs{display:none!important}tr.hidden-lg.hidden-xs{display:none!important}th.hidden-lg.hidden-xs,td.hidden-lg.hidden-xs{display:none!important}}@media(min-width:768px) and (max-width:991px){.hidden-lg.hidden-sm{display:none!important}tr.hidden-lg.hidden-sm{display:none!important}th.hidden-lg.hidden-sm,td.hidden-lg.hidden-sm{display:none!important}}@media(min-width:992px) and (max-width:1199px){.hidden-lg.hidden-md{display:none!important}tr.hidden-lg.hidden-md{display:none!important}th.hidden-lg.hidden-md,td.hidden-lg.hidden-md{display:none!important}}@media(min-width:1200px){.hidden-lg{display:none!important}tr.hidden-lg{display:none!important}th.hidden-lg,td.hidden-lg{display:none!important}}.visible-print{display:none!important}tr.visible-print{display:none!important}th.visible-print,td.visible-print{display:none!important}@media print{.visible-print{display:block!important}tr.visible-print{display:table-row!important}th.visible-print,td.visible-print{display:table-cell!important}.hidden-print{display:none!important}tr.hidden-print{display:none!important}th.hidden-print,td.hidden-print{display:none!important}} \ No newline at end of file diff --git a/Amen/Controllers/APIController.cs b/Amen/Controllers/APIController.cs new file mode 100644 index 0000000..315e726 --- /dev/null +++ b/Amen/Controllers/APIController.cs @@ -0,0 +1,139 @@ +using System; +using System.Linq; +using System.Web.Mvc; + +namespace Amen.Controllers +{ + public class APIController : BaseController + { + /* Previous totals before initial reset + 229,412 prayers prayed before reset and 5,762,657 prayers by KTIS affiliates before migration + 13,082 prayer requests before reset and 364,224 requests by KTIS affiliates before migration + 6,211 notes sent before reset and 72,923 notes by KTIS affiliates before migration + */ + public const int CONST_PreviousPrayedCount = 229412 + 5762657; + public const int CONST_PreviousPrayerCount = 13082 + 364224; + public const int CONST_PreviousNotesSent = 6211 + 72923; + + // GET: API/Index + public JsonResult Index() + { + return Json("", JsonRequestBehavior.AllowGet); + } + + public JsonResult PraiseCount(string affiliatekey, string includeAll = "false") + { + return PrayerCount(affiliatekey, includeAll, bool.TrueString); + } + + // GET: API/PrayerCount + public JsonResult PrayerCount(string affiliatekey, string includeAll = "false", string isPraise = "false") + { + var isPraiseBool = StringToBool(isPraise); + var includeAllBool = StringToBool(includeAll); + + var affiliate = controllerHelper.GetAffiliate(affiliatekey); + + var totalCount = controllerHelper + .db.Prayers + .Count(i => (i.AffiliateId == affiliate.Id + || includeAllBool + ) + && !i.IsDeleted + && i.IsPraise == isPraiseBool); + + if (includeAllBool && !isPraiseBool) + { + totalCount += CONST_PreviousPrayerCount; + } + + var data = new + { + count = totalCount, + display = totalCount.ToString("N0") + }; + + return Json(data, JsonRequestBehavior.AllowGet); + } + + // GET: API/PrayedCount + public JsonResult PrayedCount(string affiliatekey, string includeAll = "false") + { + var includeAllBool = StringToBool(includeAll); + + var affiliate = controllerHelper.GetAffiliate(affiliatekey); + + var totalCount = controllerHelper + .db.Prayers + .Where(i => (i.AffiliateId == affiliate.Id + && !i.IsDeleted + && !i.IsPraise + ) + || includeAllBool + ) + .Select(i => i.CountPrayed).DefaultIfEmpty(0).Sum(); + + + if (includeAllBool) + { + totalCount += CONST_PreviousPrayedCount; + } + + var data = new + { + count = totalCount, + display = totalCount.ToString("N0") + }; + + return Json(data, JsonRequestBehavior.AllowGet); + } + + // GET: API/PrayedCount + public JsonResult NotesCount(string affiliatekey, string includeAll = "false") + { + var includeAllBool = StringToBool(includeAll); + + var affiliate = controllerHelper.GetAffiliate(affiliatekey); + + var totalCount = controllerHelper + .db.PrayerNotes + .Include("Prayer") + .Where(i => (i.Prayer.AffiliateId == affiliate.Id + || includeAllBool + ) + && !i.Prayer.IsDeleted + && !i.Prayer.IsPraise) + .Count(); + + + if (includeAllBool) + { + totalCount += CONST_PreviousNotesSent; + } + + + var data = new + { + count = totalCount, + display = totalCount.ToString("N0") + }; + + return Json(data, JsonRequestBehavior.AllowGet); + } + + public static bool StringToBool(string boolString) + { + if (boolString.Equals("1", StringComparison.InvariantCultureIgnoreCase) + || boolString.Equals("yes", StringComparison.InvariantCultureIgnoreCase)) + { + boolString = bool.TrueString; + } + + var boolValue = false; + bool.TryParse(boolString, out boolValue); + + return boolValue; + } + + } +} \ No newline at end of file diff --git a/Amen/Controllers/AccountController.cs b/Amen/Controllers/AccountController.cs new file mode 100644 index 0000000..755469b --- /dev/null +++ b/Amen/Controllers/AccountController.cs @@ -0,0 +1,600 @@ +using System; +using System.Linq; +using System.Threading.Tasks; +using System.Web; +using System.Web.Mvc; +using Microsoft.AspNet.Identity; +using Microsoft.AspNet.Identity.Owin; +using Microsoft.Owin.Security; +using Amen.Models; +using Facebook; +using System.Data.Entity; + +namespace Amen.Controllers +{ + [Authorize] + public class AccountController : BaseController + { + private ApplicationSignInManager _signInManager; + private ApplicationUserManager _userManager; + + public AccountController() + { + } + + public AccountController(ApplicationUserManager userManager, ApplicationSignInManager signInManager ) + { + UserManager = userManager; + SignInManager = signInManager; + } + + public ApplicationSignInManager SignInManager + { + get + { + return _signInManager ?? HttpContext.GetOwinContext().Get(); + } + private set + { + _signInManager = value; + } + } + + public ApplicationUserManager UserManager + { + get + { + return _userManager ?? HttpContext.GetOwinContext().GetUserManager(); + } + private set + { + _userManager = value; + } + } + + // + // GET: /Account/Login + [AllowAnonymous] + public ActionResult Login(string returnUrl, string affiliatekey) + { + ViewBag.ReturnUrl = returnUrl; + return View(); + } + + // + // POST: /Account/Login + [HttpPost] + [AllowAnonymous] + [ValidateAntiForgeryToken] + public async Task Login(LoginViewModel model, string returnUrl, string affiliatekey) + { + if (!ModelState.IsValid) + { + return View(model); + } + + // This doesn't count login failures towards account lockout + // To enable password failures to trigger account lockout, change to shouldLockout: true + var result = await SignInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, shouldLockout: true); + switch (result) + { + case SignInStatus.Success: + var user = controllerHelper.db.Users.Include("Affiliate").FirstOrDefault(i => i.Email == model.Email); + + if (user != null) + { + user.LastLoginDateUtc = DateTime.UtcNow; + controllerHelper.db.SaveChanges(); + affiliatekey = user.Affiliate.Key; + } + + return RedirectToLocal(returnUrl, affiliatekey); + case SignInStatus.LockedOut: + return View("Lockout"); + case SignInStatus.RequiresVerification: + return RedirectToAction("SendCode", new { ReturnUrl = returnUrl, RememberMe = model.RememberMe }); + case SignInStatus.Failure: + default: + ModelState.AddModelError("", "Invalid login attempt."); + return View(model); + } + } + + // + // GET: /Account/VerifyCode + [AllowAnonymous] + public async Task VerifyCode(string provider, string returnUrl, bool rememberMe, string affiliatekey) + { + // Require that the user has already logged in via username/password or external login + if (!await SignInManager.HasBeenVerifiedAsync()) + { + return View("Error"); + } + return View(new VerifyCodeViewModel { Provider = provider, ReturnUrl = returnUrl, RememberMe = rememberMe }); + } + + // + // POST: /Account/VerifyCode + [HttpPost] + [AllowAnonymous] + [ValidateAntiForgeryToken] + public async Task VerifyCode(VerifyCodeViewModel model, string affiliatekey) + { + if (!ModelState.IsValid) + { + return View(model); + } + + // The following code protects for brute force attacks against the two factor codes. + // If a user enters incorrect codes for a specified amount of time then the user account + // will be locked out for a specified amount of time. + // You can configure the account lockout settings in IdentityConfig + var result = await SignInManager.TwoFactorSignInAsync(model.Provider, model.Code, isPersistent: model.RememberMe, rememberBrowser: model.RememberBrowser); + switch (result) + { + case SignInStatus.Success: + return RedirectToLocal(model.ReturnUrl, affiliatekey); + case SignInStatus.LockedOut: + return View("Lockout"); + case SignInStatus.Failure: + default: + ModelState.AddModelError("", "Invalid code."); + return View(model); + } + } + + // + // GET: /Account/Register + [AllowAnonymous] + public ActionResult Register(string affiliatekey) + { + var affiliate = new ControllerHelper().GetAffiliate(affiliatekey); + var model = new RegisterViewModel() + { + EnableSmsNotifications = true, + EnableEmailNotifications = true, + AffiliateEnableShowLocation = affiliate.EnableShowLocation, + AffiliateEnableShowName = affiliate.EnableShowName, + AffiliateIsSmsCapable = affiliate.IsSmsCapable + }; + return View(model); + } + + // + // POST: /Account/Register + [HttpPost] + [AllowAnonymous] + [ValidateAntiForgeryToken] + public async Task Register(RegisterViewModel model, string affiliatekey) + { + if (ModelState.IsValid) + { + var affiliate = new ControllerHelper().GetAffiliate(affiliatekey); + + var user = new ApplicationUser { FullName = model.FullName, UserName = model.Email, Email = model.Email, AffiliateId = affiliate.Id, LastLoginDateUtc = DateTime.UtcNow, EnableSmsNotifications = model.EnableSmsNotifications, EnableEmailNotifications = model.EnableEmailNotifications, Location = model.Location, ShouldShowLocation = model.ShouldShowLocation, ShouldShowName = model.ShouldShowName }; + //return View(model); + + var result = await UserManager.CreateAsync(user, model.Password); + + if (result.Succeeded) + { + await SignInManager.SignInAsync(user, isPersistent: false, rememberBrowser: false); + + // For more information on how to enable account confirmation and password reset please visit http://go.microsoft.com/fwlink/?LinkID=320771 + // Send an email with this link + //string code = await UserManager.GenerateEmailConfirmationTokenAsync(user.Id); + //var callbackUrl = Url.Action("ConfirmEmail", "Account", new { userId = user.Id, code = code, affiliatekey = affiliatekey }, protocol: Request.Url.Scheme); + //await UserManager.SendEmailAsync(user.Id, "Confirm your account", "Please confirm your account by clicking here"); + + //TODO: redirect to note indicating confirmation email was sent + return RedirectToAction("Index", "Prayer", new { affiliatekey = affiliatekey }); + } + + //AddErrors(result); + //hack to not show the "Name [emailaddress] is already taken." error + foreach (var error in result.Errors) + { + if (error.StartsWith("Name") && error.EndsWith("is already taken.")) + continue; + + ModelState.AddModelError("", error); + } + + if (result.Errors.Count(i => i.StartsWith("Email") && i.EndsWith("is already taken.")) > 0) + ViewBag.ShowResetPassword = true; + } + + // If we got this far, something failed, redisplay form + return View(model); + } + + // + // GET: /Account/ConfirmEmail + [AllowAnonymous] + public async Task ConfirmEmail(string userId, string code, string affiliatekey) + { + if (userId == null || code == null) + { + return View("Error"); + } + var result = await UserManager.ConfirmEmailAsync(userId, code); + return View(result.Succeeded ? "ConfirmEmail" : "Error"); + } + + // + // GET: /Account/ForgotPassword + [AllowAnonymous] + public ActionResult ForgotPassword(string affiliatekey) + { + return View(); + } + + // + // POST: /Account/ForgotPassword + [HttpPost] + [AllowAnonymous] + [ValidateAntiForgeryToken] + public async Task ForgotPassword(ForgotPasswordViewModel model, string affiliatekey) + { + if (ModelState.IsValid) + { + var user = await UserManager.FindByNameAsync(model.Email); + //TODO: determine if we only send forgot password requests to confirmed users + if (user == null) // || !(await UserManager.IsEmailConfirmedAsync(user.Id))) + { + // Don't reveal that the user does not exist or is not confirmed + return View("ForgotPasswordConfirmation"); + } + + // For more information on how to enable account confirmation and password reset please visit http://go.microsoft.com/fwlink/?LinkID=320771 + // Send an email with this link + string code = await UserManager.GeneratePasswordResetTokenAsync(user.Id); + var callbackUrl = Url.Action("ResetPassword", "Account", new { userId = user.Id, code = code }, protocol: Request.Url.Scheme); + await UserManager.SendEmailAsync(user.Id, "Reset Password", "Please reset your password by clicking here"); + return RedirectToAction("ForgotPasswordConfirmation", "Account"); + } + + // If we got this far, something failed, redisplay form + return View(model); + } + + // + // GET: /Account/ForgotPasswordConfirmation + [AllowAnonymous] + public ActionResult ForgotPasswordConfirmation(string affiliatekey) + { + return View(); + } + + // + // GET: /Account/ResetPassword + [AllowAnonymous] + public ActionResult ResetPassword(string code, string affiliatekey) + { + return code == null ? View("Error") : View(); + } + + // + // POST: /Account/ResetPassword + [HttpPost] + [AllowAnonymous] + [ValidateAntiForgeryToken] + public async Task ResetPassword(ResetPasswordViewModel model, string affiliatekey) + { + if (!ModelState.IsValid) + { + return View(model); + } + var user = await UserManager.FindByNameAsync(model.Email); + if (user == null) + { + // Don't reveal that the user does not exist + return RedirectToAction("ResetPasswordConfirmation", "Account"); + } + var result = await UserManager.ResetPasswordAsync(user.Id, model.Code, model.Password); + if (result.Succeeded) + { + return RedirectToAction("ResetPasswordConfirmation", "Account"); + } + AddErrors(result); + return View(); + } + + // + // GET: /Account/ResetPasswordConfirmation + [AllowAnonymous] + public ActionResult ResetPasswordConfirmation(string affiliatekey) + { + return View(); + } + + // + // POST: /Account/ExternalLogin + [HttpPost] + [AllowAnonymous] + [ValidateAntiForgeryToken] + public ActionResult ExternalLogin(string provider, string returnUrl, string affiliatekey) + { + + + // Request a redirect to the external login provider + return new ChallengeResult(provider, Url.Action("ExternalLoginCallback", "Account", new { ReturnUrl = returnUrl, affiliatekey = (ViewBag.AffiliateKey ?? ControllerHelper.DefaultAffiliateKey) })); + } + + // + // GET: /Account/SendCode + [AllowAnonymous] + public async Task SendCode(string returnUrl, bool rememberMe, string affiliatekey) + { + var userId = await SignInManager.GetVerifiedUserIdAsync(); + if (userId == null) + { + return View("Error"); + } + var userFactors = await UserManager.GetValidTwoFactorProvidersAsync(userId); + var factorOptions = userFactors.Select(purpose => new SelectListItem { Text = purpose, Value = purpose }).ToList(); + return View(new SendCodeViewModel { Providers = factorOptions, ReturnUrl = returnUrl, RememberMe = rememberMe }); + } + + // + // POST: /Account/SendCode + [HttpPost] + [AllowAnonymous] + [ValidateAntiForgeryToken] + public async Task SendCode(SendCodeViewModel model, string affiliatekey) + { + if (!ModelState.IsValid) + { + return View(); + } + + // Generate the token and send it + if (!await SignInManager.SendTwoFactorCodeAsync(model.SelectedProvider)) + { + return View("Error"); + } + return RedirectToAction("VerifyCode", new { Provider = model.SelectedProvider, ReturnUrl = model.ReturnUrl, RememberMe = model.RememberMe }); + } + + // + // GET: /Account/ExternalLoginCallback + [AllowAnonymous] + public async Task ExternalLoginCallback(string returnUrl, string affiliatekey) + { + var loginInfo = await AuthenticationManager.GetExternalLoginInfoAsync(); + if (loginInfo == null) + { + return RedirectToAction("Login"); + } + // added the following lines + if (loginInfo.Login.LoginProvider == "Facebook") + { + var identity = AuthenticationManager.GetExternalIdentity(DefaultAuthenticationTypes.ExternalCookie); + var access_token = identity.FindFirstValue("FacebookAccessToken"); + var fb = new FacebookClient(access_token); + dynamic myInfo = fb.Get("/me?fields=email"); // specify the email field + loginInfo.Email = myInfo.email; + loginInfo.DefaultUserName = identity.Name; + } + + // Sign in the user with this external login provider if the user already has a login + var result = await SignInManager.ExternalSignInAsync(loginInfo, isPersistent: false); + switch (result) + { + case SignInStatus.Success: + + var user = controllerHelper.db.Users.Include("Affiliate").Where(i => i.Logins.Count(l => l.ProviderKey.Equals(loginInfo.Login.ProviderKey)) > 0).FirstOrDefault(); + if (user != null) + { + user.LastLoginDateUtc = DateTime.UtcNow; + controllerHelper.db.SaveChanges(); + affiliatekey = user.Affiliate.Key; + } + + return RedirectToLocal(returnUrl, affiliatekey); + case SignInStatus.LockedOut: + return View("Lockout"); + case SignInStatus.RequiresVerification: + return RedirectToAction("SendCode", new { ReturnUrl = returnUrl, RememberMe = false }); + case SignInStatus.Failure: + default: + if (await TryCreateOrAssocaiateUser(loginInfo, affiliatekey)) + { + var user2 = controllerHelper.db.Users.Include("Affiliate").FirstOrDefault(i => i.Email == loginInfo.Email); + if (user2 != null) + { + affiliatekey = user2.Affiliate.Key; + } + + return RedirectToLocal(returnUrl, affiliatekey); + } + + // If the user does not have an account, then prompt the user to create an account + ViewBag.ReturnUrl = returnUrl; + ViewBag.LoginProvider = loginInfo.Login.LoginProvider; + return View("ExternalLoginConfirmation", new ExternalLoginConfirmationViewModel { Email = loginInfo.Email, FullName = loginInfo.DefaultUserName }); + } + } + + private async Task TryCreateOrAssocaiateUser( ExternalLoginInfo info, string affiliatekey) + { + var affiliate = new ControllerHelper().GetAffiliate(affiliatekey); + + var user = controllerHelper.db.Users.FirstOrDefault(i => i.Email.Equals(info.Email)); + var result = new IdentityResult(); + + if (user == null) + { + user = new ApplicationUser { UserName = info.Email, FullName = info.DefaultUserName, Email = info.Email, AffiliateId = affiliate.Id, EmailConfirmed = true, LastLoginDateUtc = DateTime.UtcNow, EnableEmailNotifications = true, EnableSmsNotifications = true }; + result = await UserManager.CreateAsync(user); + } + + if (result.Succeeded || result.Errors.Count() == 0) + { + result = await UserManager.AddLoginAsync(user.Id, info.Login); + if (result.Succeeded) + { + await SignInManager.SignInAsync(user, isPersistent: false, rememberBrowser: false); + } + } + else + { + return false; + } + + return true; + } + + // + // POST: /Account/ExternalLoginConfirmation + [HttpPost] + [AllowAnonymous] + [ValidateAntiForgeryToken] + public async Task ExternalLoginConfirmation(ExternalLoginConfirmationViewModel model, string returnUrl, string affiliatekey) + { + if (User.Identity.IsAuthenticated) + { + return RedirectToAction("Index", "Manage"); + } + + if (ModelState.IsValid) + { + // Get the information about the user from the external login provider + var info = await AuthenticationManager.GetExternalLoginInfoAsync(); + if (info == null) + { + return View("ExternalLoginFailure"); + } + + var affiliate = new ControllerHelper().GetAffiliate(affiliatekey); + + var user = controllerHelper.db.Users.FirstOrDefault(i => i.Email.Equals(model.Email)); + var result = new IdentityResult(); + + if (user == null) + { + user = new ApplicationUser { UserName = model.Email, FullName = model.FullName, Email = model.Email, AffiliateId = affiliate.Id, LastLoginDateUtc = DateTime.UtcNow, EnableSmsNotifications = true, EnableEmailNotifications = true }; + result = await UserManager.CreateAsync(user); + } + + if (result.Succeeded || result.Errors.Count() == 0) + { + result = await UserManager.AddLoginAsync(user.Id, info.Login); + if (result.Succeeded) + { + await SignInManager.SignInAsync(user, isPersistent: false, rememberBrowser: false); + return RedirectToLocal(returnUrl, affiliatekey); + } + } + AddErrors(result); + } + + ViewBag.ReturnUrl = returnUrl; + return View(model); + } + + // + // POST: /Account/LogOff + [HttpPost] + [ValidateAntiForgeryToken] + public ActionResult LogOff(string affiliatekey) + { + AuthenticationManager.SignOut(); + return RedirectToAction("Index", "Prayer", new { affiliatekey = affiliatekey }); + } + + // + // GET: /Account/ExternalLoginFailure + [AllowAnonymous] + public ActionResult ExternalLoginFailure(string affiliatekey) + { + return View(); + } + + protected override void Dispose(bool disposing) + { + if (disposing) + { + if (_userManager != null) + { + _userManager.Dispose(); + _userManager = null; + } + + if (_signInManager != null) + { + _signInManager.Dispose(); + _signInManager = null; + } + } + + base.Dispose(disposing); + } + + #region Helpers + // Used for XSRF protection when adding external logins + private const string XsrfKey = "XsrfId"; + + private IAuthenticationManager AuthenticationManager + { + get + { + return HttpContext.GetOwinContext().Authentication; + } + } + + private void AddErrors(IdentityResult result) + { + foreach (var error in result.Errors) + { + ModelState.AddModelError("", error); + } + } + + private ActionResult RedirectToLocal(string returnUrl, string affiliatekey) + { + if (Url.IsLocalUrl(returnUrl)) + { + return Redirect(returnUrl); + } + return RedirectToAction("Index", "Prayer", new { affiliatekey = affiliatekey }); + } + + internal class ChallengeResult : HttpUnauthorizedResult + { + public ChallengeResult(string provider, string redirectUri) + : this(provider, redirectUri, null) + { + } + + public ChallengeResult(string provider, string redirectUri, string userId) + { + LoginProvider = provider; + RedirectUri = redirectUri; + UserId = userId; + } + + public string LoginProvider { get; set; } + public string RedirectUri { get; set; } + public string UserId { get; set; } + + public override void ExecuteResult(ControllerContext context) + { + + //context.HttpContext.Session["WAKEUP"] = "NOW!"; + //context.HttpContext.Session.RemoveAll(); + + //// this line fixed the problem with returing null + //context.RequestContext.HttpContext.Response.SuppressFormsAuthenticationRedirect = true; + + var properties = new AuthenticationProperties { RedirectUri = RedirectUri }; + if (UserId != null) + { + properties.Dictionary[XsrfKey] = UserId; + } + context.HttpContext.GetOwinContext().Authentication.Challenge(properties, LoginProvider); + } + } + #endregion + } +} \ No newline at end of file diff --git a/Amen/Controllers/AffiliateController.Extended.cs b/Amen/Controllers/AffiliateController.Extended.cs new file mode 100644 index 0000000..71a62d1 --- /dev/null +++ b/Amen/Controllers/AffiliateController.Extended.cs @@ -0,0 +1,816 @@ +using Amen.Models; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web.Mvc; +using Microsoft.AspNet.Identity; +using System.Configuration; +using System.Text; +using System.Data.Entity; +using OfficeOpenXml; +using System.IO; +using PagedList; + +namespace Amen.Controllers +{ + [Authorize(Roles = ControllerHelper.Role_Administrator + "," + ControllerHelper.Role_AffiliateAdministrator)] + public partial class AffiliateController : BaseController + { + [AllowAnonymous] + public ActionResult Select(string affiliatekey) + { + var prayerSource = PrayerSource.DeterminePrayerSource(this.Request.UserAgent); + + var model = controllerHelper.db + .Affiliates + .Where(i => i.IsActive && i.SubscriptionTypeId != (int)SubscriptionTypeEnum.Demo) + .OrderByDescending(i => i.Key == ControllerHelper.DefaultAffiliateKey) + .ThenBy(i => i.Name) + .Select(i => new AffiliateSelectViewModel() + { + Name = i.Name, + Key = i.Key, + UrlLogo = i.UrlLogo, + SubscriptionTypeId = i.SubscriptionTypeId + }) + .ToList(); + + if (prayerSource == (int)PrayerSourceEnum.iOS) + { + model = model.Where(i => i.Key == ControllerHelper.DefaultAffiliateKey || i.SubscriptionTypeId == (int)SubscriptionTypeEnum.BasicPlus).ToList(); + } + + foreach (var item in model) + { + item.NavigateUrl = Url.Action("Index", "Prayer", new { affiliatekey = item.Key }, null); + } + + return View(model); + } + + + [AllowAnonymous] + public ActionResult NavigateToWebsite(string affiliatekey) + { + var affiliate = controllerHelper.GetAffiliate(affiliatekey); + if (affiliate != null && !string.IsNullOrEmpty(affiliate.UrlWebsite)) + return Redirect(affiliate.UrlWebsite); + + return Redirect(Url.Action("Index", "Prayer", new { affiliatekey = affiliate.Key })); + } + + bool ValidateAccess(string affiliatekey) + { + if (User.IsInRole(ControllerHelper.Role_Administrator)) + return true; + + if (User.IsInRole(ControllerHelper.Role_AffiliateAdministrator)) + { + var appUserId = User.Identity.GetUserId(); + return controllerHelper.db.AffiliateAdmins.Include("Affiliate").Count(i => i.Affiliate.Key.Equals(affiliatekey) && i.ApplicationUserId == appUserId) > 0; + } + + return false; + } + + public ActionResult Users(int id, string affiliatekey) + { + Affiliate affiliate = db.Affiliates.Find(id); + if (!ValidateAccess(affiliate.Key)) + return new EmptyResult(); + + var adminRoles = db.Roles.Where(i => i.Name == ControllerHelper.Role_Administrator || i.Name == ControllerHelper.Role_AffiliateAdministrator).Select(i => i.Id).ToList(); + var admins = db.Users.Where(i => i.AffiliateId == id && i.Roles.Count(r => adminRoles.Contains(r.RoleId)) > 0).Select(i => i.Id).ToList(); + + var offset = controllerHelper.GetTimeZoneOffsetFromClient(); + + //TODO: add case where user does not have default affiliate of current affiliate, but is an admin for the affiliate (when 1 person is an admin for multiple affiliates) + var model = new AffiliateUsersViewModel(); + model.Id = id; + model.Users = controllerHelper.db.Users + .Include("Affiliate") + .Where(i => i.AffiliateId == id) + .Select(i => new AffiliateUsersViewModel.AffiliateUserViewModel() + { + Id = i.Id, + FullName = i.FullName, + Email = i.Email, + //LastLoginDate = i.LastLoginDateUtc, + OffsetMinutes = offset, + IsAdmin = i.Roles.Count(r => admins.Contains(r.UserId)) > 0 + }) + .OrderByDescending(i => i.IsAdmin) + .ThenBy(i => i.FullName) + .ToList(); + + return View(model); + } + + [Authorize(Roles = ControllerHelper.Role_Administrator)] + public ActionResult UserMakeAdmin(int id, string userId) + { + Affiliate affiliate = db.Affiliates.Find(id); + if (!ValidateAccess(affiliate.Key)) + return new EmptyResult(); + + var adminRoleId = db.Roles.First(i => i.Name == ControllerHelper.Role_AffiliateAdministrator).Id; + var user = db.Users.Include("Roles").FirstOrDefault(i => i.Id == userId); + if (user != null) + { + if (user.Roles.Count(i => i.RoleId == adminRoleId) == 0) + { + user.Roles.Add(new Microsoft.AspNet.Identity.EntityFramework.IdentityUserRole() { RoleId = adminRoleId, UserId = user.Id }); + db.SaveChanges(); + } + + if (db.AffiliateAdmins.Count(i => i.ApplicationUserId == userId && i.AffiliateId == id) == 0) + { + db.AffiliateAdmins.Add(new AffiliateAdmin() + { + AffiliateId = id, + ApplicationUserId = userId, + CreatedUTC = DateTime.UtcNow + + }); + db.SaveChanges(); + } + } + + return RedirectToAction("Users", new { id = id, affiliatekey = ViewBag.AffiliateKey ?? Amen.Controllers.ControllerHelper.DefaultAffiliateKey }); + } + + [Authorize(Roles = ControllerHelper.Role_Administrator)] + public ActionResult UserRemoveAdmin(int id, string userId) + { + Affiliate affiliate = db.Affiliates.Find(id); + if (!ValidateAccess(affiliate.Key)) + return new EmptyResult(); + + var adminRoleId = db.Roles.First(i => i.Name == ControllerHelper.Role_AffiliateAdministrator).Id; + var user = db.Users.Include("Roles").FirstOrDefault(i => i.Id == userId); + if (user != null) + { + var role = user.Roles.FirstOrDefault(i => i.RoleId == adminRoleId); + if (role != null) + { + user.Roles.Remove(role); + db.SaveChanges(); + } + + var affAdmin = db.AffiliateAdmins.FirstOrDefault(i => i.ApplicationUserId == userId && i.AffiliateId == id); + if (affAdmin != null) + { + db.AffiliateAdmins.Remove(affAdmin); + db.SaveChanges(); + } + } + + return RedirectToAction("Users", new { id = id, affiliatekey = ViewBag.AffiliateKey ?? Amen.Controllers.ControllerHelper.DefaultAffiliateKey }); + } + + public ActionResult Prayers(int id, string affiliatekey, int page = 1) + { + Affiliate affiliate = db.Affiliates.Find(id); + if (!ValidateAccess(affiliate.Key)) + return new EmptyResult(); + + var pageSize = 100; + + var model = new AffiliatePrayersViewModel() { Id = id, PageSize = pageSize, Page = page }; + model.Prayers = controllerHelper.db + .Prayers + .Include("ApplicationUser") + .Where(i => i.AffiliateId == id + && !i.IsPraise + && !i.IsDeleted) + .OrderByDescending(i => i.CreatedUTC) + .ToPagedList(page, pageSize); + + return View(model); + } + + public ActionResult Praise(int id, string affiliatekey, int page = 1) + { + Affiliate affiliate = db.Affiliates.Find(id); + if (!ValidateAccess(affiliate.Key)) + return new EmptyResult(); + + var pageSize = 100; + + var model = new AffiliatePrayersViewModel() { Id = id, PageSize = pageSize, Page = page }; + model.Prayers = controllerHelper.db + .Prayers + .Include("ApplicationUser") + .Where(i => i.AffiliateId == id + && i.IsPraise + && !i.IsDeleted) + .OrderByDescending(i => i.CreatedUTC) + .ToPagedList(page, pageSize); + + return View(model); + } + + public void ExportPrayers(int id, string affiliatekey, int days = 0) + { + Affiliate affiliate = db.Affiliates.Find(id); + if (!ValidateAccess(affiliate.Key)) + return; + + if (days <= 0) + { + days = 20 * 365; + } + + var startDate = DateTime.UtcNow.AddDays(-days); + + var data = controllerHelper.db + .Prayers + .Include("ApplicationUser") + .Include("PrayerSource") + .Where(i => i.AffiliateId == id + && !i.IsPraise + && !i.IsDeleted + && i.CreatedUTC >= startDate) + .OrderByDescending(i => i.Id) + //.OrderByDescending(i => i.CreatedUTC) + .ToList(); + + ExcelPackage excel = new ExcelPackage(); + var workSheet = excel.Workbook.Worksheets.Add("Prayers"); + var filename = string.Format("{0}-Prayers", affiliatekey); + + var row = 1; + var col = 1; + //headers first + workSheet.Cells[row, col++].Value = "Id"; + workSheet.Cells[row, col++].Value = "IsActive"; + workSheet.Cells[row, col++].Value = "Title"; + workSheet.Cells[row, col++].Value = "Content"; + workSheet.Cells[row, col++].Value = "CountPrayed"; + workSheet.Cells[row, col++].Value = "CountFlagged"; + workSheet.Cells[row, col++].Value = "EnableEmailNote"; + workSheet.Cells[row, col++].Value = "EnableEmailNotification"; + workSheet.Cells[row, col++].Value = "EnableTextNotification"; + workSheet.Cells[row, col++].Value = "FullName"; + workSheet.Cells[row, col++].Value = "Email"; + workSheet.Cells[row, col++].Value = "IPAddress"; + workSheet.Cells[row, col++].Value = "UserAgent"; + workSheet.Cells[row, col++].Value = "Source"; + workSheet.Cells[row, col++].Value = "CreatedUTC"; + workSheet.Column(col - 1).Style.Numberformat.Format = "m/d/yyyy HH:mm"; + + foreach (var item in data) + { + col = 1; + row++; + workSheet.Cells[row, col++].Value = item.Id; + workSheet.Cells[row, col++].Value = item.IsActive; + workSheet.Cells[row, col++].Value = item.Summary; + workSheet.Cells[row, col++].Value = item.Content; + workSheet.Cells[row, col++].Value = item.CountPrayed; + workSheet.Cells[row, col++].Value = item.CountFlagged; + workSheet.Cells[row, col++].Value = item.EnableEmailNote; + workSheet.Cells[row, col++].Value = item.EnableEmailNotification; + workSheet.Cells[row, col++].Value = item.EnableTextNotification; + + if (item.ApplicationUser != null) + { + workSheet.Cells[row, col++].Value = item.ApplicationUser.FullName; + workSheet.Cells[row, col++].Value = item.ApplicationUser.Email; + } + else + { + workSheet.Cells[row, col++].Value = item.AnonymousName; + workSheet.Cells[row, col++].Value = item.AnonymousEmail; + } + + workSheet.Cells[row, col++].Value = item.AnonymousPhone; + workSheet.Cells[row, col++].Value = item.IPAddress; + workSheet.Cells[row, col++].Value = item.UserAgent; + workSheet.Cells[row, col++].Value = item.PrayerSource.EnumValue.ToString(); + workSheet.Cells[row, col++].Value = item.CreatedUTC; + + } + + for (int i = 1; i <= workSheet.Dimension.End.Column; i++) + { + workSheet.Column(i).AutoFit(0, 300); + } + + using (var memoryStream = new MemoryStream()) + { + Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"; + Response.AddHeader("content-disposition", "attachment; filename=" + filename + ".xlsx"); + excel.SaveAs(memoryStream); + memoryStream.WriteTo(Response.OutputStream); + Response.Flush(); + Response.End(); + } + } + + public void ExportPraise(int id, string affiliatekey, int days = 0) + { + Affiliate affiliate = db.Affiliates.Find(id); + if (!ValidateAccess(affiliate.Key)) + return; + + if (days <= 0) + { + days = 20 * 365; + } + + var startDate = DateTime.UtcNow.AddDays(-days); + + var data = controllerHelper.db + .Prayers + .Include("ApplicationUser") + .Include("PrayerSource") + .Where(i => i.AffiliateId == id + && i.IsPraise + && !i.IsDeleted + && i.CreatedUTC >= startDate) + .OrderByDescending(i => i.Id) + //.OrderByDescending(i => i.CreatedUTC) + .ToList(); + + ExcelPackage excel = new ExcelPackage(); + var workSheet = excel.Workbook.Worksheets.Add("Praise"); + var filename = string.Format("{0}-Praise", affiliatekey); + + var row = 1; + var col = 1; + //headers first + workSheet.Cells[row, col++].Value = "Id"; + workSheet.Cells[row, col++].Value = "IsActive"; + workSheet.Cells[row, col++].Value = "Title"; + workSheet.Cells[row, col++].Value = "Content"; + workSheet.Cells[row, col++].Value = "CountFlagged"; + workSheet.Cells[row, col++].Value = "FullName"; + workSheet.Cells[row, col++].Value = "Email"; + workSheet.Cells[row, col++].Value = "IPAddress"; + workSheet.Cells[row, col++].Value = "UserAgent"; + workSheet.Cells[row, col++].Value = "Source"; + workSheet.Cells[row, col++].Value = "CreatedUTC"; + workSheet.Column(col - 1).Style.Numberformat.Format = "m/d/yyyy HH:mm"; + + foreach (var item in data) + { + col = 1; + row++; + workSheet.Cells[row, col++].Value = item.Id; + workSheet.Cells[row, col++].Value = item.IsActive; + workSheet.Cells[row, col++].Value = item.Summary; + workSheet.Cells[row, col++].Value = item.Content; + workSheet.Cells[row, col++].Value = item.CountFlagged; + + if (item.ApplicationUser != null) + { + workSheet.Cells[row, col++].Value = item.ApplicationUser.FullName; + workSheet.Cells[row, col++].Value = item.ApplicationUser.Email; + } + else + { + workSheet.Cells[row, col++].Value = item.AnonymousName; + workSheet.Cells[row, col++].Value = item.AnonymousEmail; + } + + workSheet.Cells[row, col++].Value = item.IPAddress; + workSheet.Cells[row, col++].Value = item.UserAgent; + workSheet.Cells[row, col++].Value = item.PrayerSource.EnumValue.ToString(); + workSheet.Cells[row, col++].Value = item.CreatedUTC; + + } + + for (int i = 1; i <= workSheet.Dimension.End.Column; i++) + { + workSheet.Column(i).AutoFit(0, 300); + } + + using (var memoryStream = new MemoryStream()) + { + Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"; + Response.AddHeader("content-disposition", "attachment; filename=" + filename + ".xlsx"); + excel.SaveAs(memoryStream); + memoryStream.WriteTo(Response.OutputStream); + Response.Flush(); + Response.End(); + } + } + + public ActionResult PrayerEdit(int id, string affiliatekey) + { + var prayer = db.Prayers.Include("Affiliate").FirstOrDefault(i => i.Id == id); + if (!ValidateAccess(prayer.Affiliate.Key)) + return new EmptyResult(); + + var model = controllerHelper.db.Prayers + .Include("ApplicationUser") + .FirstOrDefault(i => i.Id == id && !i.IsDeleted); + + ViewBag.PrayerSourceId = new SelectList(db.PrayerSources, "Id", "Label", model.PrayerSourceId); + + return View(model); + } + + [HttpPost] + [ValidateAntiForgeryToken] + public ActionResult PrayerEdit([Bind(Include = "Id,PWId,AffiliateId,ApplicationUserId,IsActive,IsDeleted,EnableTextNotification,EnableEmailNotification,EnableEmailNote,Summary,Content,IsPraise,AnonymousName,AnonymousEmail,AnonymousPhone,AgreeTermsOfUse,IPAddress,UserAgent,ModifiedUTC,CreatedUTC,CountPrayed,CountFlagged,PrayerSourceId")] Prayer prayer, string affiliatekey) + //public ActionResult PrayerEdit([Bind(Include = "Id,IsActive,EnableTextNotification")] Prayer prayer, string affiliatekey) + { + Affiliate affiliate = db.Affiliates.Find(prayer.AffiliateId); + if (!ValidateAccess(affiliate.Key)) + return new EmptyResult(); + + if (ModelState.IsValid) + { + prayer.ModifiedUTC = DateTime.UtcNow; + db.Entry(prayer).State = EntityState.Modified; + db.SaveChanges(); + + if (prayer.IsPraise) + return RedirectToAction("Praise", new { id = prayer.AffiliateId, affiliatekey = affiliatekey }); + else + return RedirectToAction("Prayers", new { id = prayer.AffiliateId, affiliatekey = affiliatekey }); + } + + ViewBag.PrayerSourceId = new SelectList(db.PrayerSources, "Id", "Label", prayer.PrayerSourceId); + return View(prayer); + } + + public ActionResult PrayerDelete(int id, string affiliatekey) + { + var prayer = controllerHelper.db.Prayers.Include("Affiliate").FirstOrDefault(i => i.Id == id); + if (!ValidateAccess(prayer.Affiliate.Key)) + return new EmptyResult(); + + prayer.IsDeleted = true; + prayer.ModifiedUTC = DateTime.UtcNow; + controllerHelper.db.SaveChanges(); + + if (prayer.IsPraise) + return RedirectToAction("Praise", new { id = prayer.AffiliateId, affiliatekey = affiliatekey }); + else + return RedirectToAction("Prayers", new { id = prayer.AffiliateId, affiliatekey = affiliatekey }); + } + + public ActionResult PrayerActivate(int id, string affiliatekey) + { + var prayer = controllerHelper.db.Prayers.Include("Affiliate").FirstOrDefault(i => i.Id == id); + if (!ValidateAccess(prayer.Affiliate.Key)) + return new EmptyResult(); + + prayer.IsActive = true; + prayer.ModifiedUTC = DateTime.UtcNow; + controllerHelper.db.SaveChanges(); + + if (prayer.IsPraise) + return RedirectToAction("Praise", new { id = prayer.AffiliateId, affiliatekey = affiliatekey }); + else + return RedirectToAction("Prayers", new { id = prayer.AffiliateId, affiliatekey = affiliatekey }); + } + + // GET: Affiliate + public ActionResult Index() + { + var affiliates = new List(); + if (!User.IsInRole(ControllerHelper.Role_Administrator)) + { + var appUserId = User.Identity.GetUserId() ?? "none"; + affiliates = db.AffiliateAdmins + .Include("Affiliate") + .Include("Affiliate.SubscriptionType") + .Where(i => i.ApplicationUserId == appUserId) + .Select(i => i.Affiliate) + .ToList(); + + if (affiliates.Count == 1) + return RedirectToAction("Details", new { id = affiliates.First().Id, affiliatekey = affiliates.First().Key }); + + } + else + { + affiliates = db.Affiliates + .Include("SubscriptionType") + .ToList(); + } + + affiliates = affiliates + .OrderByDescending(i => i.Key == ControllerHelper.DefaultAffiliateKey) + .ThenByDescending(i => i.IsActive) + .ThenBy(i => i.Name) + .ToList(); + + return View(affiliates); + } + + public ActionResult Stats(int id, string affiliatekey) + { + Affiliate affiliate = db.Affiliates.Find(id); + if (!ValidateAccess(affiliate.Key)) + return new EmptyResult(); + + var model = new AffiliateStatsViewModel(); + model.Id = id; + + var recentStart = DateTime.UtcNow.AddDays(-30); + + model.TotalRequests = db.Prayers.Count(i => i.AffiliateId == id && !i.IsDeleted && !i.IsPraise); + model.RecentRequests = db.Prayers.Count(i => i.AffiliateId == id && !i.IsDeleted && !i.IsPraise && i.CreatedUTC > recentStart); + + model.TotalPraise = db.Prayers.Count(i => i.AffiliateId == id && !i.IsDeleted && i.IsPraise); + model.RecentPraise = db.Prayers.Count(i => i.AffiliateId == id && !i.IsDeleted && i.IsPraise && i.CreatedUTC > recentStart); + + model.TotalNotesSent = db.PrayerNotes.Include("Prayer").Count(i => i.Prayer.AffiliateId == id && !i.Prayer.IsDeleted); + model.RecentNotesSent = db.PrayerNotes.Include("Prayer").Count(i => i.Prayer.AffiliateId == id && !i.Prayer.IsDeleted && i.CreatedUTC > recentStart); + + //TODO look at prayer rather than PrayerItems + //model.TotalPrayersPrayed = db.PrayerItems.Include("Prayer").Count(i => i.Prayer.AffiliateId == id && !i.Prayer.IsDeleted); + //model.RecentPrayersPrayed = db.PrayerItems.Include("Prayer").Count(i => i.Prayer.AffiliateId == id && !i.Prayer.IsDeleted && i.CreatedUTC > recentStart); + model.TotalPrayersPrayed = db.Prayers.Where(i => !i.IsDeleted && i.AffiliateId == id).Select(i => i.CountPrayed).DefaultIfEmpty(0).Sum(); + model.RecentPrayersPrayed = db.Prayers.Where(i => !i.IsDeleted && i.AffiliateId == id && i.CreatedUTC > recentStart).Select(i => i.CountPrayed).DefaultIfEmpty(0).Sum(); + + //TODO look at prayer.CountFlagged rather than PrayerFlags + //model.TotalFlagsIndicated = db.PrayerFlags.Include("Prayer").Count(i => i.Prayer.AffiliateId == id && !i.Prayer.IsDeleted); + //model.RecentFlagsIndicated = db.PrayerFlags.Include("Prayer").Count(i => i.Prayer.AffiliateId == id && !i.Prayer.IsDeleted && i.CreatedUTC > recentStart); + model.TotalFlagsIndicated = db.Prayers.Where(i => !i.IsDeleted && i.AffiliateId == id).Select(i => i.CountFlagged).DefaultIfEmpty(0).Sum(); + model.RecentFlagsIndicated = db.Prayers.Where(i => !i.IsDeleted && i.AffiliateId == id && i.CreatedUTC > recentStart).Select(i => i.CountFlagged).DefaultIfEmpty(0).Sum(); + + return View(model); + } + + public string UploadImage(string affiliatekey) + { + if (!ValidateAccess(affiliatekey)) + return string.Empty; + + var returnImage = ""; + + if (this.Request.Files.AllKeys.Any()) + { + // Get the uploaded image from the Files collection + var httpPostedFile = this.Request.Files["UploadedImage"]; + + var fileName = httpPostedFile.FileName; + var contentType = httpPostedFile.ContentType; + var fileExtension = fileName.Substring(fileName.LastIndexOf('.') + 1); + fileName = fileName.Substring(0, fileName.LastIndexOf('.')); + + var imageName = string.Format("{0}-{1}-{2}.{3}", affiliatekey, fileName, DateTime.UtcNow.Ticks, fileExtension).ToLower(); + + foreach (char c in System.IO.Path.GetInvalidFileNameChars()) + { + imageName = imageName.Replace(c, '-'); + } + + var azureFolder = ConfigurationManager.AppSettings["AzureBlobStorageLogoFolder"]; + + if (httpPostedFile != null) + { + returnImage = ControllerHelper.ResizeAndSaveStreamToBlobStorage(httpPostedFile.InputStream, azureFolder, imageName, contentType, new ImageResizer.ResizeSettings(200, 200, ImageResizer.FitMode.Max, fileExtension)); + + //httpPostedFile.InputStream.Position = 0; + //returnImage = BlobStorageHelper.SaveToBlobStorage(azureFolder, imageName, contentType, httpPostedFile.InputStream); + } + } + return returnImage; + } + + public ActionResult Style(int id, string affiliatekey) + { + Affiliate affiliate = db.Affiliates.Find(id); + if (!ValidateAccess(affiliate.Key)) + return new EmptyResult(); + + var builder = new StringBuilder(); + var styles = controllerHelper.db.AffiliateStyles.Where(i => i.AffiliateId == id).Select(i => i.StyleSheet); + foreach (var style in styles) + { + builder.Append(style); + builder.AppendLine(); + } + + var template = System.IO.File.ReadAllText(Server.MapPath(@"~/Content/SiteCustom.css")).Trim(); + var model = new AffiliateStyleViewModel() + { + Id = id, + Template = template, + StyleContent = builder.ToString(), + Key = affiliatekey + }; + + return View(model); + } + + [HttpPost] + [ValidateAntiForgeryToken] + public ActionResult Style(AffiliateStyleViewModel affiliateStyle, string affiliatekey) + { + if (!ValidateAccess(affiliateStyle.Key)) + return new EmptyResult(); + + if (ModelState.IsValid) + { + var styleItem = db.AffiliateStyles.FirstOrDefault(i => i.AffiliateId == affiliateStyle.Id); + var hasNewContent = !string.IsNullOrWhiteSpace(affiliateStyle.StyleContent); + var hasExistingStyle = styleItem != null; + + if (!hasNewContent && hasExistingStyle)//need to clear out style + { + db.AffiliateStyles.Remove(styleItem); + } + else if (hasNewContent && !hasExistingStyle) // need to add new style + { + db.AffiliateStyles.Add(new AffiliateStyle() + { + AffiliateId = affiliateStyle.Id, + StyleSheet = affiliateStyle.StyleContent.Trim(), + CreatedUTC = DateTime.UtcNow + }); + } + else if (hasNewContent && hasExistingStyle) // need to update existing style + { + styleItem.StyleSheet = affiliateStyle.StyleContent.Trim(); + } + + db.SaveChanges(); + + } + + return View(affiliateStyle); + } + + + public ActionResult FlagWords(int id, string affiliatekey) + { + Affiliate affiliate = db.Affiliates.Include("AutoFlagItems").FirstOrDefault(i => i.Id == id); + if (!ValidateAccess(affiliate.Key)) + return new EmptyResult(); + + var model = new AffiliateFlagItemsViewModel() + { + Id = id, + Key = affiliatekey, + FlagItems = string.Join(",", affiliate.AutoFlagItems.Select(i => i.Text).ToArray()) + }; + + return View(model); + } + + + [HttpPost] + [ValidateAntiForgeryToken] + public ActionResult FlagWords(AffiliateFlagItemsViewModel model, string affiliatekey) + { + if (!ValidateAccess(model.Key)) + return new EmptyResult(); + + if (ModelState.IsValid) + { + var affiliate = db.Affiliates.Include("AutoFlagItems").FirstOrDefault(i => i.Key.Equals(model.Key)); + + var newList = (model.FlagItems ?? "").Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(i => i.Trim()).ToList(); + var existingList = affiliate.AutoFlagItems.Select(i => i.Text.Trim()).ToList(); + + var added = newList.Except(existingList); + var deleted = existingList.Except(newList); + + foreach (var item in added) + { + db.AutoFlagItems.Add(new AutoFlagItem() + { + AffiliateId = affiliate.Id, + Text = item + }); + } + + var dbItems = affiliate.AutoFlagItems.ToList(); + foreach (var item in dbItems) + { + if (deleted.Contains(item.Text)) + db.AutoFlagItems.Remove(item); + } + + db.SaveChanges(); + + } + + return View(model); + } + + + public ActionResult FlagIPs(int id, string affiliatekey) + { + Affiliate affiliate = db.Affiliates.Include("BlacklistIPs").FirstOrDefault(i => i.Id == id); + if (!ValidateAccess(affiliate.Key)) + return new EmptyResult(); + + var model = new AffiliateFlagItemsViewModel() + { + Id = id, + Key = affiliatekey, + FlagItems = string.Join(",", affiliate.BlacklistIPs.Select(i => i.IP).ToArray()) + }; + + return View(model); + } + + + [HttpPost] + [ValidateAntiForgeryToken] + public ActionResult FlagIPs(AffiliateFlagItemsViewModel model, string affiliatekey) + { + if (!ValidateAccess(model.Key)) + return new EmptyResult(); + + if (ModelState.IsValid) + { + var affiliate = db.Affiliates.Include("BlacklistIPs").FirstOrDefault(i => i.Key.Equals(model.Key)); + + var newList = (model.FlagItems ?? "").Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(i => i.Trim()).ToList(); + var existingList = affiliate.BlacklistIPs.Select(i => i.IP.Trim()).ToList(); + + var added = newList.Except(existingList); + var deleted = existingList.Except(newList); + + foreach (var item in added) + { + db.BlacklistIPs.Add(new BlacklistIP() + { + AffiliateId = affiliate.Id, + IP = item + }); + } + + var dbItems = affiliate.BlacklistIPs.ToList(); + foreach (var item in dbItems) + { + if (deleted.Contains(item.IP)) + db.BlacklistIPs.Remove(item); + } + + db.SaveChanges(); + + } + + return View(model); + } + + + public ActionResult FlagEmails(int id, string affiliatekey) + { + Affiliate affiliate = db.Affiliates.Include("BlacklistEmails").FirstOrDefault(i => i.Id == id); + if (!ValidateAccess(affiliate.Key)) + return new EmptyResult(); + + var model = new AffiliateFlagItemsViewModel() + { + Id = id, + Key = affiliatekey, + FlagItems = string.Join(",", affiliate.BlacklistEmails.Select(i => i.Email).ToArray()) + }; + + return View(model); + } + + + [HttpPost] + [ValidateAntiForgeryToken] + public ActionResult FlagEmails(AffiliateFlagItemsViewModel model, string affiliatekey) + { + if (!ValidateAccess(model.Key)) + return new EmptyResult(); + + if (ModelState.IsValid) + { + var affiliate = db.Affiliates.Include("BlacklistEmails").FirstOrDefault(i => i.Key.Equals(model.Key)); + + var newList = (model.FlagItems ?? "").Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(i => i.Trim()).ToList(); + var existingList = affiliate.BlacklistEmails.Select(i => i.Email.Trim()).ToList(); + + var added = newList.Except(existingList); + var deleted = existingList.Except(newList); + + foreach (var item in added) + { + db.BlacklistEmails.Add(new BlacklistEmail() + { + AffiliateId = affiliate.Id, + Email = item + }); + } + + var dbItems = affiliate.BlacklistEmails.ToList(); + foreach (var item in dbItems) + { + if (deleted.Contains(item.Email)) + db.BlacklistEmails.Remove(item); + } + + db.SaveChanges(); + + } + + return View(model); + } + } +} \ No newline at end of file diff --git a/Amen/Controllers/AffiliateController.cs b/Amen/Controllers/AffiliateController.cs new file mode 100644 index 0000000..2b4a496 --- /dev/null +++ b/Amen/Controllers/AffiliateController.cs @@ -0,0 +1,146 @@ +using System.Data.Entity; +using System.Linq; +using System.Net; +using System.Web.Mvc; +using Amen.Models; + +namespace Amen.Controllers +{ + public partial class AffiliateController : BaseController + { + private ApplicationDbContext db = new ApplicationDbContext(); + + + // GET: Affiliate/Details/5 + public ActionResult Details(int? id, string affiliatekey) + { + if (id == null) + { + return new HttpStatusCodeResult(HttpStatusCode.BadRequest); + } + + Affiliate affiliate = db.Affiliates.Find(id); + + if (!ValidateAccess(affiliate.Key)) + return new EmptyResult(); + + affiliate = db.Affiliates.Include("SubscriptionType").FirstOrDefault(i => i.Id == id); + if (affiliate == null) + { + return HttpNotFound(); + } + return View(affiliate); + } + + // GET: Affiliate/Create + [Authorize(Roles = ControllerHelper.Role_Administrator)] + public ActionResult Create() + { + ViewBag.SubscriptionTypeId = new SelectList(db.SubscriptionTypes, "Id", "Label"); + return View(); + } + + // POST: Affiliate/Create + // To protect from overposting attacks, please enable the specific properties you want to bind to, for + // more details see http://go.microsoft.com/fwlink/?LinkId=317598. + [HttpPost] + [ValidateAntiForgeryToken] + [Authorize(Roles = ControllerHelper.Role_Administrator)] + public ActionResult Create([Bind(Include = "Id,PWId,Key,IncludeInUniversal,IsActive,Name,Instructions,InstructionsAddPrayer,UrlWebsite,UrlLogo,EmailAdmin,EmailBilling,EmailFlag,SendMessagePrayed,SendMessageNote,PrayerDaysThreshold,FlagThreshold,TwilioSID,TwilioAuthToken,TwilioPhoneNumber,ShouldSendPrayerNotificationAdmin,ShouldSendPraiseNotificationAdmin,EnableNotes,RequireModeration,SubscriptionTypeId,RequireLoginForNoticiations,EnableShowLocation,EnableShowName")] Affiliate affiliate) + { + if (ModelState.IsValid) + { + db.Affiliates.Add(affiliate); + db.SaveChanges(); + return RedirectToAction("Details", new { id = affiliate.Id, affiliatekey = ViewBag.AffiliateKey ?? Amen.Controllers.ControllerHelper.DefaultAffiliateKey }); + } + + ViewBag.SubscriptionTypeId = new SelectList(db.SubscriptionTypes, "Id", "Label", affiliate.SubscriptionTypeId); + return View(affiliate); + } + + // GET: Affiliate/Edit/5 + public ActionResult Edit(int? id) + { + if (id == null) + { + return new HttpStatusCodeResult(HttpStatusCode.BadRequest); + } + Affiliate affiliate = db.Affiliates.Find(id); + if (affiliate == null) + { + return HttpNotFound(); + } + + if (!ValidateAccess(affiliate.Key)) + return new EmptyResult(); + + ViewBag.SubscriptionTypeId = new SelectList(db.SubscriptionTypes, "Id", "Label", affiliate.SubscriptionTypeId); + return View(affiliate); + } + + // POST: Affiliate/Edit/5 + // To protect from overposting attacks, please enable the specific properties you want to bind to, for + // more details see http://go.microsoft.com/fwlink/?LinkId=317598. + [HttpPost] + [ValidateAntiForgeryToken] + public ActionResult Edit([Bind(Include = "Id,PWId,Key,IncludeInUniversal,IsActive,Name,Instructions,InstructionsPraise,InstructionsAddPrayer,InstructionsAddPraise,InstructionsNote,UrlWebsite,UrlLogo,EmailAdmin,EmailBilling,EmailFlag,SendMessagePrayed,SendMessageNote,PrayerDaysThreshold,FlagThreshold,TwilioSID,TwilioAuthToken,TwilioPhoneNumber,ShouldSendPrayerNotificationAdmin,ShouldSendPraiseNotificationAdmin,EnableNotes,RequireModeration,SubscriptionTypeId,RequireLoginForNoticiations,EnableShowLocation,EnableShowName")] Affiliate affiliate) + { + if (!ValidateAccess(affiliate.Key)) + return new EmptyResult(); + + var extraValid = true; + if (affiliate.PrayerDaysThreshold <= 0 || affiliate.FlagThreshold <= 0) + { + extraValid = false; + } + + if (ModelState.IsValid && extraValid) + { + db.Entry(affiliate).State = EntityState.Modified; + db.SaveChanges(); + return RedirectToAction("Details", new { id = affiliate.Id, affiliatekey = ViewBag.AffiliateKey ?? Amen.Controllers.ControllerHelper.DefaultAffiliateKey }); + } + + ViewBag.SubscriptionTypeId = new SelectList(db.SubscriptionTypes, "Id", "Label", affiliate.SubscriptionTypeId); + return View(affiliate); + } + + // GET: Affiliate/Delete/5 + [Authorize(Roles = ControllerHelper.Role_Administrator)] + public ActionResult Delete(int? id) + { + if (id == null) + { + return new HttpStatusCodeResult(HttpStatusCode.BadRequest); + } + Affiliate affiliate = db.Affiliates.Find(id); + if (affiliate == null) + { + return HttpNotFound(); + } + return View(affiliate); + } + + // POST: Affiliate/Delete/5 + [HttpPost, ActionName("Delete")] + [ValidateAntiForgeryToken] + [Authorize(Roles = ControllerHelper.Role_Administrator)] + public ActionResult DeleteConfirmed(int id) + { + Affiliate affiliate = db.Affiliates.Find(id); + db.Affiliates.Remove(affiliate); + db.SaveChanges(); + return RedirectToAction("Index", new { affiliatekey = ViewBag.AffiliateKey ?? Amen.Controllers.ControllerHelper.DefaultAffiliateKey }); + } + + protected override void Dispose(bool disposing) + { + if (disposing) + { + db.Dispose(); + } + base.Dispose(disposing); + } + } +} diff --git a/Amen/Controllers/BaseController.cs b/Amen/Controllers/BaseController.cs new file mode 100644 index 0000000..20822e8 --- /dev/null +++ b/Amen/Controllers/BaseController.cs @@ -0,0 +1,46 @@ +using System.Collections.Generic; +using System.Configuration; +using System.Web.Mvc; +using System.Web.Routing; + +namespace Amen.Controllers +{ + public class BaseController : Controller + { + public ControllerHelper controllerHelper = new ControllerHelper(); + + protected override void OnActionExecuting(ActionExecutingContext filterContext) + { + //ViewBag.AffiliateKey = filterContext.ActionParameters["affiliatekey"]; + + ViewBag.AffiliateKey = filterContext.RouteData.Values["affiliatekey"]; + var isAdmin = filterContext.HttpContext.User.IsInRole(ControllerHelper.Role_Administrator); + ViewBag.IsAdministrator = isAdmin; + + string controller = (filterContext.RouteData.Values["controller"] as string ?? "").ToLower(); + string action = (filterContext.RouteData.Values["action"] as string ?? "").ToLower(); + var isUpgrade = false; + bool.TryParse(ConfigurationManager.AppSettings["IsUpgradeInProgress"], out isUpgrade); + + var allowControllers = new List() { "account", "css" }; + var allowActions = new List() { "upgradeinprogress" }; + + ViewBag.IsUpgradeInProgress = isUpgrade; + + if (isUpgrade + && !isAdmin + && !allowControllers.Contains(controller) + && !allowActions.Contains(action)) + { + filterContext.Result = new RedirectToRouteResult( + new RouteValueDictionary { + { "controller", "Home" }, + { "action", "UpgradeInProgress" }, + { "affiliatekey", ViewBag.AffiliateKey } + }); + } + + base.OnActionExecuting(filterContext); + } + } +} \ No newline at end of file diff --git a/Amen/Controllers/CSSController.cs b/Amen/Controllers/CSSController.cs new file mode 100644 index 0000000..4fa4f81 --- /dev/null +++ b/Amen/Controllers/CSSController.cs @@ -0,0 +1,36 @@ +using System.Linq; +using System.Text; +using System.Web.Mvc; + +namespace Amen.Controllers +{ + public class CssController : BaseController + { + public ContentResult GetTheme(string affiliatekey) + { + var builder = new StringBuilder(); + + var affiliate = controllerHelper.GetAffiliate(affiliatekey); + var styles = controllerHelper.db.AffiliateStyles.Where(i => i.AffiliateId == affiliate.Id).Select(i => i.StyleSheet); + + foreach (var style in styles) + { + builder.Append(style); + builder.AppendLine(); + } + + return Content(builder.ToString(), "text/css"); + } + + public ActionResult AffiliateLogo(string affiliatekey) + { + var path = controllerHelper.Absolute(Url, Url.Content("~/Content/Images/Blank.png")); + + var affiliate = controllerHelper.GetAffiliate(affiliatekey); + if (affiliate != null && !string.IsNullOrEmpty(affiliate.UrlLogo)) + path = affiliate.UrlLogo; + + return Redirect(path); + } + } +} \ No newline at end of file diff --git a/Amen/Controllers/ControllerHelper.cs b/Amen/Controllers/ControllerHelper.cs new file mode 100644 index 0000000..f9b5b76 --- /dev/null +++ b/Amen/Controllers/ControllerHelper.cs @@ -0,0 +1,195 @@ +using Amen.Models; +using System; +using System.Linq; +using System.Web; +using Microsoft.AspNet.Identity; +using System.Web.Mvc; +using System.IO; +using System.Web.Routing; +using System.Data.Entity; +using Amen.Helpers; +using Microsoft.Crm.Sdk.Messages; + +namespace Amen.Controllers +{ + public class ControllerHelper + { + public const string DefaultAffiliateKey = "Amen"; + public const string Role_SuperAdministrator = "Super Administrator"; + public const string Role_Administrator = "Administrator"; + public const string Role_AffiliateAdministrator = "Affiliate Administrator"; + + public ApplicationDbContext db = new ApplicationDbContext(); + + public static string ToAbsolute(HttpContext context, string relativeUrl) + { + var request = context.Request; + + return string.Format("{0}://{1}{2}", + (request.IsSecureConnection) ? "https" : "http", + request.Headers["Host"], + VirtualPathUtility.ToAbsolute(relativeUrl)); + } + + public string Absolute(UrlHelper url, string relativeUrl) + { + var request = url.RequestContext.HttpContext.Request; + + return string.Format("{0}://{1}{2}", + (request.IsSecureConnection) ? "https" : "http", + request.Headers["Host"], + VirtualPathUtility.ToAbsolute(relativeUrl)); + } + + private Affiliate _currentAffiliate; + public Affiliate GetAffiliate(string key, bool returnInactive = false) + { + if (_currentAffiliate != null) + return _currentAffiliate; + + var aff = db.Affiliates.FirstOrDefault(i => i.Key == key); + + if (aff != null && !aff.IsActive && returnInactive) + { + return aff; + } + + if (aff == null || !aff.IsActive) + { + aff = db.Affiliates.FirstOrDefault(i => i.Key.Equals(DefaultAffiliateKey, StringComparison.InvariantCultureIgnoreCase)); + } + + _currentAffiliate = aff; + + return _currentAffiliate; + } + + public ApplicationUser GetLoggedInUser() + { + if (HttpContext.Current == null || !HttpContext.Current.User.Identity.IsAuthenticated) + return null; + + var userIdentity = HttpContext.Current.User.Identity.GetUserId(); + return db.Users.Include("Affiliate").FirstOrDefault(i => i.Id.Equals(userIdentity)); + } + + public int GetTimeZoneOffsetFromClient() + { + var cookieVal = GetCookieValue("TZOffset"); + var offset = 0; + int.TryParse(cookieVal, out offset); + + return offset; + } + + + private void SetCookie(string cName, string cValue) + { + HttpCookie cookie = new HttpCookie(cName); + cookie.Value = cValue; + cookie.Path = "/"; + HttpContext.Current.Response.Cookies.Add(cookie); + } + + private string GetCookieValue(string cName) + { + var cookie = HttpContext.Current.Request.Cookies.Get(cName); + return cookie == null ? "" : cookie.Value; + } + + private void RemoveCookie(string cName) + { + var cookie = HttpContext.Current.Request.Cookies.Get(cName); + + if (cookie == null) + return; + + HttpContext.Current.Response.Cookies.Remove(cookie.Name); + + cookie.Expires = DateTime.Now.AddDays(-1); + cookie.Value = null; + cookie.Path = "/"; + + HttpContext.Current.Response.Cookies.Set(cookie); + } + + public static string RenderViewToString(ControllerContext context, + string viewPath, + object model = null, + bool partial = false) + { + // first find the ViewEngine for this view + ViewEngineResult viewEngineResult = null; + if (partial) + viewEngineResult = ViewEngines.Engines.FindPartialView(context, viewPath); + else + viewEngineResult = ViewEngines.Engines.FindView(context, viewPath, null); + + if (viewEngineResult == null) + throw new FileNotFoundException("View cannot be found."); + + // get the view and attach the model to view data + var view = viewEngineResult.View; + context.Controller.ViewData.Model = model; + + string result = null; + + using (var sw = new StringWriter()) + { + var ctx = new ViewContext(context, view, + context.Controller.ViewData, + context.Controller.TempData, + sw); + view.Render(ctx, sw); + result = sw.ToString(); + } + + return result; + } + + public static T CreateController(RouteData routeData = null) + where T : Controller, new() + { + // create a disconnected controller instance + T controller = new T(); + + // get context wrapper from HttpContext if available + HttpContextBase wrapper; + if (System.Web.HttpContext.Current != null) + wrapper = new HttpContextWrapper(System.Web.HttpContext.Current); + else + throw new InvalidOperationException( + "Can't create Controller Context if no " + + "active HttpContext instance is available."); + + if (routeData == null) + routeData = new RouteData(); + + // add the controller routing if not existing + if (!routeData.Values.ContainsKey("controller") && + !routeData.Values.ContainsKey("Controller")) + routeData.Values.Add("controller", + controller.GetType() + .Name.ToLower().Replace("controller", "")); + + controller.ControllerContext = new ControllerContext(wrapper, routeData, controller); + return controller; + } + + static internal string ResizeAndSaveStreamToBlobStorage(Stream inputStream, string azureFolder, string fileName, string contentType, ImageResizer.ResizeSettings settings) + { + using (var outstream = new MemoryStream()) + { + inputStream.Position = 0; + + //resize with settings + ImageResizer.ImageBuilder.Current.Build(inputStream, outstream, settings, false); + + //reset the outstream back to the initial position + outstream.Position = 0; + + return BlobStorageHelper.SaveToBlobStorage(azureFolder, fileName, contentType, outstream); + } + } + } +} \ No newline at end of file diff --git a/Amen/Controllers/HomeController.cs b/Amen/Controllers/HomeController.cs new file mode 100644 index 0000000..fc0d0bc --- /dev/null +++ b/Amen/Controllers/HomeController.cs @@ -0,0 +1,12 @@ +using System.Web.Mvc; + +namespace Amen.Controllers +{ + public class HomeController : Controller + { + public ActionResult UpgradeInProgress() + { + return View(); + } + } +} \ No newline at end of file diff --git a/Amen/Controllers/ManageController.cs b/Amen/Controllers/ManageController.cs new file mode 100644 index 0000000..b6c6c86 --- /dev/null +++ b/Amen/Controllers/ManageController.cs @@ -0,0 +1,425 @@ +using System.Linq; +using System.Threading.Tasks; +using System.Web; +using System.Web.Mvc; +using Microsoft.AspNet.Identity; +using Microsoft.AspNet.Identity.Owin; +using Microsoft.Owin.Security; +using Amen.Models; +using System.Net; + +namespace Amen.Controllers +{ + [Authorize] + public class ManageController : BaseController + { + private ApplicationSignInManager _signInManager; + private ApplicationUserManager _userManager; + + public ManageController() + { + } + + public ManageController(ApplicationUserManager userManager, ApplicationSignInManager signInManager) + { + UserManager = userManager; + SignInManager = signInManager; + } + + public ApplicationSignInManager SignInManager + { + get + { + return _signInManager ?? HttpContext.GetOwinContext().Get(); + } + private set + { + _signInManager = value; + } + } + + public ApplicationUserManager UserManager + { + get + { + return _userManager ?? HttpContext.GetOwinContext().GetUserManager(); + } + private set + { + _userManager = value; + } + } + + // + // GET: /Manage/Index + public async Task Index(ManageMessageId? message, string affiliatekey) + { + ViewBag.StatusMessage = + message == ManageMessageId.ChangePasswordSuccess ? "Your password has been changed." + : message == ManageMessageId.SetPasswordSuccess ? "Your password has been set." + : message == ManageMessageId.SetTwoFactorSuccess ? "Your two-factor authentication provider has been set." + : message == ManageMessageId.Error ? "An error has occurred." + : message == ManageMessageId.AddPhoneSuccess ? "Your phone number was added." + : message == ManageMessageId.RemovePhoneSuccess ? "Your phone number was removed." + : ""; + + var userId = User.Identity.GetUserId(); + var user = controllerHelper.GetLoggedInUser(); + var model = new IndexViewModel + { + FullName = user.FullName, + EnableEmailNotifications = user.EnableEmailNotifications, + EnableSmsNotifications = user.EnableSmsNotifications, + HasPassword = HasPassword(), + PhoneNumber = await UserManager.GetPhoneNumberAsync(userId), + TwoFactor = await UserManager.GetTwoFactorEnabledAsync(userId), + Logins = await UserManager.GetLoginsAsync(userId), + BrowserRemembered = await AuthenticationManager.TwoFactorBrowserRememberedAsync(userId), + AffiliateSmsCapable = user.Affiliate.IsSmsCapable, + AffiliateEnableShowLocation = user.Affiliate.EnableShowLocation, + AffiliateEnableShowName = user.Affiliate.EnableShowName, + ShouldShowLocation = user.ShouldShowLocation, + ShouldShowName = user.ShouldShowName, + Location = user.Location + }; + return View(model); + } + + [HttpPost] + public JsonResult SaveProfile(SaveProfileViewModel model, string affiliatekey) + { + if (!User.Identity.IsAuthenticated) + return Json(false, JsonRequestBehavior.AllowGet); + + var user = controllerHelper.GetLoggedInUser(); + user.FullName = model.FullName; + user.Location = model.Location; + user.EnableEmailNotifications = model.EnableEmailNotifications; + user.EnableSmsNotifications = model.EnableSmsNotifications; + user.ShouldShowName = model.ShouldShowName; + user.ShouldShowLocation = model.ShouldShowLocation; + + + controllerHelper.db.SaveChanges(); + + return Json(true, JsonRequestBehavior.AllowGet); + } + + // + // POST: /Manage/RemoveLogin + [HttpPost] + [ValidateAntiForgeryToken] + public async Task RemoveLogin(string loginProvider, string providerKey, string affiliatekey) + { + ManageMessageId? message; + var result = await UserManager.RemoveLoginAsync(User.Identity.GetUserId(), new UserLoginInfo(loginProvider, providerKey)); + if (result.Succeeded) + { + var user = await UserManager.FindByIdAsync(User.Identity.GetUserId()); + if (user != null) + { + await SignInManager.SignInAsync(user, isPersistent: false, rememberBrowser: false); + } + message = ManageMessageId.RemoveLoginSuccess; + } + else + { + message = ManageMessageId.Error; + } + return RedirectToAction("ManageLogins", new { Message = message, affiliatekey = affiliatekey }); + } + + // + // GET: /Manage/AddPhoneNumber + public ActionResult AddPhoneNumber(string affiliatekey) + { + return View(); + } + + // + // POST: /Manage/AddPhoneNumber + [HttpPost] + [ValidateAntiForgeryToken] + public async Task AddPhoneNumber(AddPhoneNumberViewModel model, string affiliatekey) + { + if (!ModelState.IsValid) + { + return View(model); + } + // Generate the token and send it + var code = await UserManager.GenerateChangePhoneNumberTokenAsync(User.Identity.GetUserId(), model.Number); + if (UserManager.SmsService != null) + { + ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12; + var affiliate = controllerHelper.GetAffiliate(affiliatekey); + var message = new SmsIdentityMessage + { + Destination = model.Number, + Body = "Your security code is: " + code, + TwilioSID = affiliate.TwilioSID, + TwilioAuthToken = affiliate.TwilioAuthToken, + TwilioPhoneNumber = affiliate.TwilioPhoneNumber + }; + await UserManager.SmsService.SendAsync(message); + } + return RedirectToAction("VerifyPhoneNumber", new { PhoneNumber = model.Number, affiliatekey = affiliatekey }); + } + + // + // POST: /Manage/EnableTwoFactorAuthentication + [HttpPost] + [ValidateAntiForgeryToken] + public async Task EnableTwoFactorAuthentication(string affiliatekey) + { + await UserManager.SetTwoFactorEnabledAsync(User.Identity.GetUserId(), true); + var user = await UserManager.FindByIdAsync(User.Identity.GetUserId()); + if (user != null) + { + await SignInManager.SignInAsync(user, isPersistent: false, rememberBrowser: false); + } + return RedirectToAction("Index", "Manage", new { affiliatekey = affiliatekey }); + } + + // + // POST: /Manage/DisableTwoFactorAuthentication + [HttpPost] + [ValidateAntiForgeryToken] + public async Task DisableTwoFactorAuthentication(string affiliatekey) + { + await UserManager.SetTwoFactorEnabledAsync(User.Identity.GetUserId(), false); + var user = await UserManager.FindByIdAsync(User.Identity.GetUserId()); + if (user != null) + { + await SignInManager.SignInAsync(user, isPersistent: false, rememberBrowser: false); + } + return RedirectToAction("Index", "Manage", new {affiliatekey = affiliatekey }); + } + + // + // GET: /Manage/VerifyPhoneNumber + public async Task VerifyPhoneNumber(string phoneNumber, string affiliatekey) + { + var code = await UserManager.GenerateChangePhoneNumberTokenAsync(User.Identity.GetUserId(), phoneNumber); + + // Send an SMS through the SMS provider to verify the phone number + //controllerHelper.SendSmsMessage(affiliatekey, phoneNumber, code); + + return phoneNumber == null ? View("Error") : View(new VerifyPhoneNumberViewModel { PhoneNumber = phoneNumber }); + } + + // + // POST: /Manage/VerifyPhoneNumber + [HttpPost] + [ValidateAntiForgeryToken] + public async Task VerifyPhoneNumber(VerifyPhoneNumberViewModel model, string affiliatekey) + { + if (!ModelState.IsValid) + { + return View(model); + } + var result = await UserManager.ChangePhoneNumberAsync(User.Identity.GetUserId(), model.PhoneNumber, model.Code); + if (result.Succeeded) + { + var user = await UserManager.FindByIdAsync(User.Identity.GetUserId()); + if (user != null) + { + await SignInManager.SignInAsync(user, isPersistent: false, rememberBrowser: false); + } + return RedirectToAction("Index", new { Message = ManageMessageId.AddPhoneSuccess, affiliatekey = affiliatekey }); + } + // If we got this far, something failed, redisplay form + ModelState.AddModelError("", "Failed to verify phone"); + return View(model); + } + + // + // GET: /Manage/RemovePhoneNumber + public async Task RemovePhoneNumber(string affiliatekey) + { + var result = await UserManager.SetPhoneNumberAsync(User.Identity.GetUserId(), null); + if (!result.Succeeded) + { + return RedirectToAction("Index", new { Message = ManageMessageId.Error, affiliatekey = affiliatekey }); + } + var user = await UserManager.FindByIdAsync(User.Identity.GetUserId()); + if (user != null) + { + await SignInManager.SignInAsync(user, isPersistent: false, rememberBrowser: false); + } + return RedirectToAction("Index", new { Message = ManageMessageId.RemovePhoneSuccess, affiliatekey = affiliatekey }); + } + + // + // GET: /Manage/ChangePassword + public ActionResult ChangePassword(string affiliatekey) + { + return View(); + } + + // + // POST: /Manage/ChangePassword + [HttpPost] + [ValidateAntiForgeryToken] + public async Task ChangePassword(ChangePasswordViewModel model, string affiliatekey) + { + if (!ModelState.IsValid) + { + return View(model); + } + var result = await UserManager.ChangePasswordAsync(User.Identity.GetUserId(), model.OldPassword, model.NewPassword); + if (result.Succeeded) + { + var user = await UserManager.FindByIdAsync(User.Identity.GetUserId()); + if (user != null) + { + await SignInManager.SignInAsync(user, isPersistent: false, rememberBrowser: false); + } + return RedirectToAction("Index", new { Message = ManageMessageId.ChangePasswordSuccess, affiliatekey = affiliatekey }); + } + AddErrors(result); + return View(model); + } + + // + // GET: /Manage/SetPassword + public ActionResult SetPassword(string affiliatekey) + { + return View(); + } + + // + // POST: /Manage/SetPassword + [HttpPost] + [ValidateAntiForgeryToken] + public async Task SetPassword(SetPasswordViewModel model, string affiliatekey) + { + if (ModelState.IsValid) + { + var result = await UserManager.AddPasswordAsync(User.Identity.GetUserId(), model.NewPassword); + if (result.Succeeded) + { + var user = await UserManager.FindByIdAsync(User.Identity.GetUserId()); + if (user != null) + { + await SignInManager.SignInAsync(user, isPersistent: false, rememberBrowser: false); + } + return RedirectToAction("Index", new { Message = ManageMessageId.SetPasswordSuccess, affiliatekey = affiliatekey }); + } + AddErrors(result); + } + + // If we got this far, something failed, redisplay form + return View(model); + } + + // + // GET: /Manage/ManageLogins + public async Task ManageLogins(ManageMessageId? message, string affiliatekey) + { + ViewBag.StatusMessage = + message == ManageMessageId.RemoveLoginSuccess ? "The external login was removed." + : message == ManageMessageId.Error ? "An error has occurred." + : ""; + var user = await UserManager.FindByIdAsync(User.Identity.GetUserId()); + if (user == null) + { + return View("Error"); + } + var userLogins = await UserManager.GetLoginsAsync(User.Identity.GetUserId()); + var otherLogins = AuthenticationManager.GetExternalAuthenticationTypes().Where(auth => userLogins.All(ul => auth.AuthenticationType != ul.LoginProvider)).ToList(); + ViewBag.ShowRemoveButton = user.PasswordHash != null || userLogins.Count > 1; + return View(new ManageLoginsViewModel + { + CurrentLogins = userLogins, + OtherLogins = otherLogins + }); + } + + // + // POST: /Manage/LinkLogin + [HttpPost] + [ValidateAntiForgeryToken] + public ActionResult LinkLogin(string provider, string affiliatekey) + { + // Request a redirect to the external login provider to link a login for the current user + return new AccountController.ChallengeResult(provider, Url.Action("LinkLoginCallback", "Manage", new {affiliatekey = affiliatekey}), User.Identity.GetUserId()); + } + + // + // GET: /Manage/LinkLoginCallback + public async Task LinkLoginCallback(string affiliatekey) + { + var loginInfo = await AuthenticationManager.GetExternalLoginInfoAsync(XsrfKey, User.Identity.GetUserId()); + if (loginInfo == null) + { + return RedirectToAction("ManageLogins", new { Message = ManageMessageId.Error, affiliatekey = affiliatekey }); + } + var result = await UserManager.AddLoginAsync(User.Identity.GetUserId(), loginInfo.Login); + return result.Succeeded ? RedirectToAction("ManageLogins", new { affiliatekey = affiliatekey }) : RedirectToAction("ManageLogins", new { Message = ManageMessageId.Error, affiliatekey = affiliatekey }); + } + + protected override void Dispose(bool disposing) + { + if (disposing && _userManager != null) + { + _userManager.Dispose(); + _userManager = null; + } + + base.Dispose(disposing); + } + +#region Helpers + // Used for XSRF protection when adding external logins + private const string XsrfKey = "XsrfId"; + + private IAuthenticationManager AuthenticationManager + { + get + { + return HttpContext.GetOwinContext().Authentication; + } + } + + private void AddErrors(IdentityResult result) + { + foreach (var error in result.Errors) + { + ModelState.AddModelError("", error); + } + } + + private bool HasPassword() + { + var user = UserManager.FindById(User.Identity.GetUserId()); + if (user != null) + { + return user.PasswordHash != null; + } + return false; + } + + private bool HasPhoneNumber() + { + var user = UserManager.FindById(User.Identity.GetUserId()); + if (user != null) + { + return user.PhoneNumber != null; + } + return false; + } + + public enum ManageMessageId + { + AddPhoneSuccess, + ChangePasswordSuccess, + SetTwoFactorSuccess, + SetPasswordSuccess, + RemoveLoginSuccess, + RemovePhoneSuccess, + Error + } + +#endregion + } +} \ No newline at end of file diff --git a/Amen/Controllers/NotificationController.cs b/Amen/Controllers/NotificationController.cs new file mode 100644 index 0000000..2b736dd --- /dev/null +++ b/Amen/Controllers/NotificationController.cs @@ -0,0 +1,366 @@ +using Amen.Models; +using System; +using System.Configuration; +using System.Diagnostics; +using System.Linq; +using System.Net; +using System.Net.Http; +using System.Net.Mail; +using System.Web.Mvc; +using System.Web.Routing; +using System.Xml; +using Twilio; + +namespace Amen.Controllers +{ + public class NotificationController : BaseController + { + + public enum EmailSendType + { + Account, + Notify + } + + public ActionResult PreviewPrayed(int id) + { + var prayer = controllerHelper.db.Prayers.Include("Affiliate").FirstOrDefault(i => i.Id == id); + var model = new PrayerEmailViewModel() + { + To = "", + Subject = "", + Title = prayer.Summary, + DetailUrl = controllerHelper.Absolute(this.Url, Url.Action("Detail", "Prayer", new { id = prayer.Id, affiliatekey = prayer.Affiliate.Key })), + ManageUrl = controllerHelper.Absolute(this.Url, Url.Action("Index", "Manage", new { affiliatekey = prayer.Affiliate.Key })) + }; + ViewBag.LogoUrl = controllerHelper.Absolute(this.Url, Url.Content("~/Content/Images/amen-logo-flyin.gif")); + + return View("~/Views/Email/Prayed.cshtml", model); + } + + public ActionResult PreviewPrayerSubmitted(int id) + { + var prayer = controllerHelper.db.Prayers.Include("Affiliate").FirstOrDefault(i => i.Id == id); + var model = new PrayerEmailViewModel() + { + To = "", + Subject = "", + Title = prayer.Summary, + DetailUrl = controllerHelper.Absolute(this.Url, Url.Action("Detail", "Prayer", new { id = prayer.Id, affiliatekey = prayer.Affiliate.Key })), + ManageUrl = controllerHelper.Absolute(this.Url, Url.Action("Index", "Manage", new { affiliatekey = prayer.Affiliate.Key })) + }; + ViewBag.LogoUrl = controllerHelper.Absolute(this.Url, Url.Content("~/Content/Images/amen-logo-flyin.gif")); + + return View("~/Views/Email/PrayerSubmitted.cshtml", model); + } + + + public ActionResult PreviewNoteSent(int id) + { + var prayer = controllerHelper.db.Prayers.Include("Affiliate").FirstOrDefault(i => i.Id == id); + var model = new PrayerEmailViewModel() + { + To = "", + Subject = "", + Title = prayer.Summary, + NoteText = "This is preview text for the note of encouragement", + DetailUrl = controllerHelper.Absolute(this.Url, Url.Action("Detail", "Prayer", new { id = prayer.Id, affiliatekey = prayer.Affiliate.Key })), + ManageUrl = controllerHelper.Absolute(this.Url, Url.Action("Index", "Manage", new { affiliatekey = prayer.Affiliate.Key })) + }; + ViewBag.LogoUrl = controllerHelper.Absolute(this.Url, Url.Content("~/Content/Images/amen-logo-flyin.gif")); + + return View("~/Views/Email/NoteSent.cshtml", model); + } + + + public ActionResult PreviewAdminNotification(int id) + { + var prayer = controllerHelper.db.Prayers.Include("Affiliate").FirstOrDefault(i => i.Id == id); + var model = new AdminEmailViewModel() + { + To = "", + Subject = "", + PrayerTitle = prayer.Summary, + PrayerContent = prayer.Content, + DetailUrl = controllerHelper.Absolute(this.Url, Url.Action("Detail", "Prayer", new { id = prayer.Id, affiliatekey = prayer.Affiliate.Key, isPraise = prayer.IsPraise })), + ManageUrl = controllerHelper.Absolute(this.Url, Url.Action("Index", "Group", new { affiliatekey = prayer.Affiliate.Key })), + NotificationTypeMessage = string.Format("A new {0} has been submitted.", prayer.IsPraise ? "Praise" : "Prayer") + }; + ViewBag.LogoUrl = controllerHelper.Absolute(this.Url, Url.Content("~/Content/Images/amen-logo-flyin.gif")); + + return View("~/Views/Email/AdminNotification.cshtml", model); + } + + public static void SendSmsMessage(string twilioSID, string twilioAuthToken, string twilioPhoneNumber, string phoneNumber, string message) + { + var overrideToNumber = ConfigurationManager.AppSettings["SmsOverrideToNumber"]; + if (!string.IsNullOrEmpty(overrideToNumber)) + phoneNumber = overrideToNumber; + + if (string.IsNullOrEmpty(twilioSID) || string.IsNullOrEmpty(twilioAuthToken) || string.IsNullOrEmpty(twilioPhoneNumber) || string.IsNullOrEmpty(phoneNumber) || string.IsNullOrEmpty(message)) + return; + + try + { + ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12; + var twilio = new TwilioRestClient(twilioSID, twilioAuthToken); + var msg = twilio.SendMessage(twilioPhoneNumber, phoneNumber, message); + + //TODO: log success + } + catch (Exception) + { + //TODO: log failure + } + } + + public static void SendEmailMessage(string to, string subject, string body, EmailSendType sendType = EmailSendType.Notify) + { + var overrideToAddress = ConfigurationManager.AppSettings["EmailOverrideToAddress"]; + if (!string.IsNullOrEmpty(overrideToAddress)) + to = overrideToAddress; + + //sender info + var from = ConfigurationManager.AppSettings[sendType.ToString() + "EmailFromAccount"]; + var fromName = ConfigurationManager.AppSettings[sendType.ToString() + "EmailFromAccountName"]; + //var password = ConfigurationManager.AppSettings[sendType.ToString() + "EmailFromPassword"]; + + //mail server + var smtpServer = ConfigurationManager.AppSettings["EmailServer"]; + int smtpPort = 587; + int.TryParse(ConfigurationManager.AppSettings["EmailServerPort"] ?? "587", out smtpPort); + bool smtpEnableSsl = false; + bool.TryParse(ConfigurationManager.AppSettings["EmailServerEnableSsl"], out smtpEnableSsl); + var smtpUsername = ConfigurationManager.AppSettings["EmailServerUsername"]; + var smtpPassword = ConfigurationManager.AppSettings["EmailServerPassword"]; + + try + { + var client = new SmtpClient(smtpServer, smtpPort) + { + Credentials = new NetworkCredential(smtpUsername, smtpPassword), + EnableSsl = smtpEnableSsl + }; + var message = new MailMessage(from, to, subject, body); + message.From = new MailAddress(from, fromName); + message.IsBodyHtml = true; + client.Send(message); + + //TODO: log success + } + catch (Exception) + { + //TODO: log failure + } + } + + static bool CanSendText(Affiliate affiliate, ApplicationUser appUser, Prayer prayer) + { + //if we don't have what we need then return + if (affiliate == null || appUser == null || prayer == null) + return false; + + //if user opted not to recieve text notifications then return + if (!appUser.IsSmsCapable || !prayer.EnableTextNotification || !affiliate.IsSmsCapable) + return false; + + return true; + } + + static bool CanSendEmail(Affiliate affiliate, ref ApplicationUser appUser, Prayer prayer, bool noteCheck = false, bool submitCheck = false) + { + //if we don't have what we need then return + if (affiliate == null || prayer == null) + return false; + + if (appUser == null) + { + // log in is no longer required + //if (!affiliate.RequireLoginForNoticiations) + //{ + //if login not required, then set the user with anonymous email and name + appUser = new ApplicationUser() + { + Email = prayer.AnonymousEmail, + PhoneNumber = prayer.AnonymousPhone, + FullName = prayer.AnonymousName, + EnableEmailNotifications = true + }; + //} + //else + //{ + // return false; + //} + } + + //this indicates that someone submitted a prayer, so we should check if the user allows notifications, and then send them an email regarless of whether they sellected to allow prayed for notifications + if (appUser.EnableEmailNotifications && submitCheck) + return true; + + //if doing a noteCheck, then ignore the prayer.EnableEmailNotification flag as they explicitly chose to allow notes of encouragement but not necessarily to be notified when someone prays. + if (appUser.EnableEmailNotifications && noteCheck && prayer.EnableEmailNote) + return true; + + //if user opted not to recieve notifications then return + if (!appUser.EnableEmailNotifications || !prayer.EnableEmailNotification) + return false; + + return true; + } + + static BaseController GetBaseController(Affiliate affiliate) + { + var routeData = new RouteData(); + routeData.Values.Add("affiliatekey", affiliate.Key); + + return ControllerHelper.CreateController(routeData); + } + + public static void NotifyPrayerRequest(UrlHelper urlHelper, Affiliate affiliate, ApplicationUser appUser, Prayer prayer) + { + var controller = GetBaseController(affiliate); + controller.ViewBag.LogoUrl = controller.controllerHelper.Absolute(urlHelper, urlHelper.Content("~/Content/Images/amen-logo-flyin.gif")); + var model = new PrayerEmailViewModel(); + model.Title = prayer.Summary; + model.Subject = "We are praying for you!"; + if (appUser != null) + { + model.To = appUser.Email; + } + else + { + model.To = prayer.AnonymousEmail; + } + model.DetailUrl = controller.controllerHelper.Absolute(urlHelper, urlHelper.Action("Detail", "Prayer", new { id = prayer.Id, affiliatekey = affiliate.Key })); + model.ManageUrl = controller.controllerHelper.Absolute(urlHelper, urlHelper.Action("Index", "Manage", new { affiliatekey = affiliate.Key })); + model.IsUserLoggedIn = !string.IsNullOrEmpty(prayer.ApplicationUserId); + model.IsPraise = prayer.IsPraise; + + if (CanSendEmail(affiliate, ref appUser, prayer, false, true)) + { + if (prayer.ContactPreference == "email" || prayer.ContactPreference == "any") + { + var body = ControllerHelper.RenderViewToString(controller.ControllerContext, "~/Views/Email/PrayerSubmitted.cshtml", model); + SendEmailMessage(model.To, model.Subject, body); + } + } + + if (CanSendText(affiliate, appUser, prayer)) + { + if (prayer.ContactPreference == "phone" || prayer.ContactPreference == "any") + { + SendSmsMessage(affiliate.TwilioSID, affiliate.TwilioAuthToken, affiliate.TwilioPhoneNumber, appUser.PhoneNumber, string.Format("We are praying for you! {0}", model.DetailUrl)); + } + } + + if (affiliate != null + && !string.IsNullOrEmpty(affiliate.EmailAdmin) + && ( + (affiliate.ShouldSendPrayerNotificationAdmin && !prayer.IsPraise) + || + (affiliate.ShouldSendPraiseNotificationAdmin && prayer.IsPraise) + ) + ) + { + var controller2 = GetBaseController(affiliate); + controller2.ViewBag.LogoUrl = controller2.controllerHelper.Absolute(urlHelper, urlHelper.Content("~/Content/Images/amen-logo-flyin.gif")); + + var adminModel = new AdminEmailViewModel(); + + adminModel.PrayerTitle = prayer.Summary; + adminModel.PrayerContent = prayer.Content; + adminModel.Subject = string.Format("Admin Notification: {0} Requested", prayer.IsPraise ? "Praise" : "Prayer"); + adminModel.To = affiliate.EmailAdmin; + adminModel.NotificationTypeMessage = string.Format("A new {0} has been submitted.", prayer.IsPraise ? "Praise" : "Prayer"); + if (affiliate.RequireModeration) + { + adminModel.NotificationTypeMessage = "** MODERATION REQUIRED ** " + adminModel.NotificationTypeMessage; + } + adminModel.DetailUrl = controller2.controllerHelper.Absolute(urlHelper, urlHelper.Action("Detail", "Prayer", new { id = prayer.Id, affiliatekey = affiliate.Key, isPraise = prayer.IsPraise })); + adminModel.ManageUrl = controller2.controllerHelper.Absolute(urlHelper, urlHelper.Action("Index", "Group")); + + var body = ControllerHelper.RenderViewToString(controller2.ControllerContext, "~/Views/Email/AdminNotification.cshtml", adminModel); + + SendEmailMessage(adminModel.To, adminModel.Subject, body); + } + } + + public static void NotifyPrayed(UrlHelper urlHelper, Affiliate affiliate, ApplicationUser appUser, Prayer prayer) + { + var model = new PrayerEmailViewModel(); + var controller = GetBaseController(affiliate); + model.DetailUrl = controller.controllerHelper.Absolute(urlHelper, urlHelper.Action("Detail", "Prayer", new { id = prayer.Id, affiliatekey = affiliate.Key })); + model.ManageUrl = controller.controllerHelper.Absolute(urlHelper, urlHelper.Action("Index", "Manage", new { affiliatekey = affiliate.Key })); + + if (CanSendText(affiliate, appUser, prayer)) + { + if (prayer.ContactPreference == "phone" || prayer.ContactPreference == "any") + { + SendSmsMessage(affiliate.TwilioSID, affiliate.TwilioAuthToken, affiliate.TwilioPhoneNumber, appUser.PhoneNumber, string.Format("Someone just prayed for you! {0}", model.DetailUrl)); + } + } + + if (CanSendEmail(affiliate, ref appUser, prayer)) + { + if (prayer.ContactPreference == "email" || prayer.ContactPreference == "any") + { + controller.ViewBag.LogoUrl = controller.controllerHelper.Absolute(urlHelper, urlHelper.Content("~/Content/Images/amen-logo-flyin.gif")); + + model.Title = prayer.Summary; + model.Subject = !string.IsNullOrEmpty(affiliate.SendMessagePrayed) ? affiliate.SendMessagePrayed : "Someone just prayed for you!"; + model.To = appUser.Email; + + var body = ControllerHelper.RenderViewToString(controller.ControllerContext, "~/Views/Email/Prayed.cshtml", model); + + SendEmailMessage(model.To, model.Subject, body); + } + } + } + + public static void NotifyNoteSent(UrlHelper urlHelper, Affiliate affiliate, ApplicationUser appUser, Prayer prayer, PrayerNote note) + { + if (!CanSendEmail(affiliate, ref appUser, prayer, true) || !prayer.EnableEmailNote) + return; + + var controller = GetBaseController(affiliate); + controller.ViewBag.LogoUrl = controller.controllerHelper.Absolute(urlHelper, urlHelper.Content("~/Content/Images/amen-logo-flyin.gif")); + + var model = new PrayerEmailViewModel(); + model.Title = prayer.Summary; + model.NoteText = note.NoteText; + model.Subject = !string.IsNullOrEmpty(affiliate.SendMessagePrayed) ? affiliate.SendMessageNote : "A note from Amen"; + model.To = appUser.Email; + model.DetailUrl = controller.controllerHelper.Absolute(urlHelper, urlHelper.Action("Detail", "Prayer", new { id = prayer.Id, affiliatekey = affiliate.Key })); + model.ManageUrl = controller.controllerHelper.Absolute(urlHelper, urlHelper.Action("Index", "Manage", new { affiliatekey = affiliate.Key })); + + var body = ControllerHelper.RenderViewToString(controller.ControllerContext, "~/Views/Email/NoteSent.cshtml", model); + + SendEmailMessage(model.To, model.Subject, body); + } + + public static void NotifyPrayerFlagged(UrlHelper urlHelper, Affiliate affiliate, Prayer prayer, PrayerFlag flag) + { + if (affiliate != null && !string.IsNullOrEmpty(affiliate.EmailFlag)) + { + var controller = GetBaseController(affiliate); + controller.ViewBag.LogoUrl = controller.controllerHelper.Absolute(urlHelper, urlHelper.Content("~/Content/Images/amen-logo-flyin.gif")); + + var model = new AdminEmailViewModel(); + model.NotificationTypeMessage = "Prayer Flagged"; + model.PrayerTitle = prayer.Summary; + if (!string.IsNullOrEmpty(flag.Reason)) + { + model.PrayerContent = "Has been flagged for the following reason: " + flag.Reason; + } + model.Subject = "An Amen Prayer Has Been Flagged"; + model.To = affiliate.EmailFlag; + model.DetailUrl = controller.controllerHelper.Absolute(urlHelper, urlHelper.Action("Detail", "Prayer", new { id = prayer.Id, affiliatekey = affiliate.Key })); + model.ManageUrl = controller.controllerHelper.Absolute(urlHelper, urlHelper.Action("Index", "Group", new { affiliatekey = affiliate.Key })); + + var body = ControllerHelper.RenderViewToString(controller.ControllerContext, "~/Views/Email/AdminNotification.cshtml", model); + + SendEmailMessage(model.To, model.Subject, body); + } + } + } +} \ No newline at end of file diff --git a/Amen/Controllers/PrayerController.cs b/Amen/Controllers/PrayerController.cs new file mode 100644 index 0000000..97eace2 --- /dev/null +++ b/Amen/Controllers/PrayerController.cs @@ -0,0 +1,682 @@ +using Amen.Models; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web.Mvc; +using Microsoft.AspNet.Identity; +using Amen.Helpers; +using System.Data.SqlClient; +using System.Text.RegularExpressions; +using System.Net.Http; +using System.Net.Http.Headers; +using System.Threading.Tasks; + +namespace Amen.Controllers +{ + public class PrayerController : BaseController + { + + // GET: Prayer + public ActionResult Index(string affiliatekey, bool isPraise = false, string sort = "newest") + { + ViewBag.IsPraise = isPraise; + var affiliate = controllerHelper.GetAffiliate(affiliatekey, true); + if (!affiliate.IsActive) + { + ViewBag.ShowInactiveAffiliateMessage = true; + affiliate = controllerHelper.GetAffiliate(affiliatekey); + } + + if(!affiliate.Key.Equals(affiliatekey, StringComparison.InvariantCultureIgnoreCase)) + { + //TODO: Log this since a different affiliate was requested + } + + var user = controllerHelper.GetLoggedInUser(); + ViewBag.AffiliateKey = affiliate.Key; + + ViewBag.Title = string.Format("{0} {1}", affiliate.Name, isPraise ? "Praise" : "Prayers"); + + var model = new PrayersViewModel(); + model.IsUserAuthenticated = User.Identity.IsAuthenticated; + if (model.IsUserAuthenticated) + { + model.AuthenticatedUserEmail = user.Email; + } + model.EnableNotifications = true; //model.IsUserAuthenticated || !affiliate.RequireLoginForNoticiations; + model.IsAffiliateNotesEnabled = affiliate.EnableNotes; + model.IsAffiliateSmsCapable = affiliate.IsSmsCapable; + model.IsUserSmsCapable = user != null && user.IsSmsCapable; + model.IsPraise = isPraise; + model.Prayers = FetchPrayerItems(affiliate.Id, affiliatekey, affiliate.PrayerDaysThreshold, isPraise, 0, sort); + model.IsDetail = false; + model.Instructions = affiliate.Instructions; + model.InstructionsPraise = affiliate.InstructionsPraise; + model.InstructionsAddPrayer = affiliate.InstructionsAddPrayer; + model.InstructionsAddPraise = affiliate.InstructionsAddPraise; + model.InstructionsNote = affiliate.InstructionsNote; + + return View(model); + } + + public ActionResult Pray(string affiliatekey, bool isPraise = false, string sort = "newest") + { + ViewBag.IsPraise = isPraise; + var affiliate = controllerHelper.GetAffiliate(affiliatekey); + var user = controllerHelper.GetLoggedInUser(); + ViewBag.Title = string.Format("{0} {1}", affiliate.Name, isPraise ? "Praise" : "Prayers"); + ViewBag.ShowInactiveAffiliateMessage = !affiliate.Key.Equals(affiliatekey, StringComparison.InvariantCultureIgnoreCase); + + var model = new PrayersViewModel(); + model.ShouldOpenSubmit = true; + model.IsUserAuthenticated = User.Identity.IsAuthenticated; + if (model.IsUserAuthenticated) + { + model.AuthenticatedUserEmail = user.Email; + } + model.EnableNotifications = true; //model.IsUserAuthenticated || !affiliate.RequireLoginForNoticiations; + model.IsAffiliateNotesEnabled = affiliate.EnableNotes; + model.IsAffiliateSmsCapable = affiliate.IsSmsCapable; + model.IsUserSmsCapable = user != null && user.IsSmsCapable; + model.IsPraise = isPraise; + model.Prayers = FetchPrayerItems(affiliate.Id, affiliatekey, affiliate.PrayerDaysThreshold, isPraise, 0, sort); + model.IsDetail = false; + + return View("Index", model); + } + + public ActionResult Detail(int id, string affiliatekey, bool isPraise = false, bool returnToUserPage = false) + { + var affiliate = controllerHelper.GetAffiliate(affiliatekey); + var user = controllerHelper.GetLoggedInUser(); + + var model = new PrayersViewModel(); + model.ShouldReturnToUserPage = returnToUserPage; + model.IsDetail = true; + model.IsUserAuthenticated = User.Identity.IsAuthenticated; + if (model.IsUserAuthenticated) + { + model.AuthenticatedUserEmail = user.Email; + } + model.EnableNotifications = true; //model.IsUserAuthenticated || !affiliate.RequireLoginForNoticiations; + model.IsAffiliateNotesEnabled = affiliate.EnableNotes; + model.IsAffiliateSmsCapable = affiliate.IsSmsCapable; + model.IsUserSmsCapable = user != null && user.IsSmsCapable; + model.Prayers = FetchPrayerItems(affiliate.Id, affiliatekey, affiliate.PrayerDaysThreshold, isPraise, 0, null, 1, id); + + if (model.Prayers.Count == 1) + { + model.IsPraise = model.Prayers.First().IsPraise; + } + else + model.IsPraise = false; + + ViewBag.Title = string.Format("{0} {1}", affiliate.Name, model.IsPraise ? "Praise" : "Prayers"); + + + return View("Index", model); + } + + public ActionResult PrayerItems(string affiliatekey, bool isPraise = false, int lastPrayerId = 0, string sort = "newest") + { + var affiliate = controllerHelper.GetAffiliate(affiliatekey); + return PartialView("_PrayerItems", FetchPrayerItems(affiliate.Id, affiliatekey, affiliate.PrayerDaysThreshold, isPraise, lastPrayerId, sort)); + } + + public PartialViewResult EditPrayer(string affiliatekey) + { + //Thread.Sleep(3000); + + return PartialView("_EditPrayer"); + } + + public PartialViewResult MyPrayerItems(string affiliatekey, bool isPraise = false, bool isSubmitted = false, bool isBookmarked = false, bool isPrayedFor = false) + { + var affiliate = controllerHelper.GetAffiliate(affiliatekey); + + var threshold = affiliate.PrayerDaysThreshold; + if (isSubmitted || isBookmarked) + { + threshold = 365; + } + + ViewBag.HideAction = true; + return PartialView("_PrayerItems", FetchPrayerItems(affiliate.Id, affiliatekey, threshold, isPraise, lastPrayerId: 0, takeCount: int.MaxValue, isSubmitted: isSubmitted, isBookmarked: isBookmarked, isPrayedFor: isPrayedFor)); + } + + private List FetchPrayerItems(int affiliateId, string affiliatekey, int includeDays, bool isPraise, int lastPrayerId, string sort = "newest", int takeCount = 10, int? prayerId = null, bool isSubmitted = false, bool isBookmarked = false, bool isPrayedFor = false) + { + //var universalAffiliateId = 1; + var appUserId = User.Identity.GetUserId() ?? "none"; + var affiliate = controllerHelper.GetAffiliate(affiliatekey); + + var offset = controllerHelper.GetTimeZoneOffsetFromClient(); + var now = DateTime.Now; + var dateThreshold = now.AddDays(-includeDays); + + var parms = new List(); + parms.Add(new SqlParameter() + { + ParameterName = "affiliateId", + SqlDbType = System.Data.SqlDbType.Int, + Value = affiliateId + }); + parms.Add(new SqlParameter() + { + ParameterName = "fetchCount", + SqlDbType = System.Data.SqlDbType.Int, + Value = takeCount + }); + parms.Add(new SqlParameter() + { + ParameterName = "skipCount", + SqlDbType = System.Data.SqlDbType.Int, + Value = 0 + }); + parms.Add(new SqlParameter() + { + ParameterName = "days", + SqlDbType = System.Data.SqlDbType.Int, + Value = includeDays + }); + parms.Add(new SqlParameter() + { + ParameterName = "userId", + SqlDbType = System.Data.SqlDbType.NVarChar, + Size = 255, + Value = appUserId + }); + parms.Add(new SqlParameter() + { + ParameterName = "orderBy", + SqlDbType = System.Data.SqlDbType.NVarChar, + Size = 255, + Value = sort ?? "newest" + }); + parms.Add(new SqlParameter() + { + ParameterName = "skipToPrayerId", + SqlDbType = System.Data.SqlDbType.Int, + Value = lastPrayerId + }); + parms.Add(new SqlParameter() + { + ParameterName = "isPraise", + SqlDbType = System.Data.SqlDbType.Bit, + Value = isPraise + }); + + if (prayerId.HasValue) + parms.Add(new SqlParameter() + { + ParameterName = "prayerId", + SqlDbType = System.Data.SqlDbType.Int, + Value = prayerId.Value + }); + else + parms.Add(new SqlParameter() + { + ParameterName = "prayerId", + SqlDbType = System.Data.SqlDbType.Int, + Value = DBNull.Value + }); + + parms.Add(new SqlParameter() + { + ParameterName = "isSubmitted", + SqlDbType = System.Data.SqlDbType.Bit, + Value = isSubmitted + }); + parms.Add(new SqlParameter() + { + ParameterName = "isBookmarked", + SqlDbType = System.Data.SqlDbType.Bit, + Value = isBookmarked + }); + parms.Add(new SqlParameter() + { + ParameterName = "isPrayedFor", + SqlDbType = System.Data.SqlDbType.Bit, + Value = isPrayedFor + }); + + var fetchItems = controllerHelper.db.Database.SqlQuery("GetPrayers @affiliateId, @fetchCount, @skipCount, @days, @userId, @orderBy, @skipToPrayerId, @isPraise, @prayerId, @isSubmitted, @isBookmarked, @isPrayedFor", parms.ToArray()) .ToList(); + + foreach (var item in fetchItems) + { + item.DetailUrl = controllerHelper.Absolute(this.Url, Url.Action("Detail", "Prayer", new { id = item.Id, affiliatekey = affiliatekey })); + //item.IsUserAuthenticated = User.Identity.IsAuthenticated; + //item.EnableNotifications = item.IsUserAuthenticated || !affiliate.RequireLoginForNoticiations; + item.IsAffiliateNotesEnabled = affiliate.EnableNotes; + item.EnableNotifications = affiliate.EnableNotes; + item.OffsetMinutes = offset; + + if (!affiliate.EnableShowName) + item.UserName = ""; + + if (!affiliate.EnableShowLocation) + item.UserLocation = ""; + } + return fetchItems; + } + + public JsonResult Subscribe(int prayerId, string affiliatekey) + { + var userIdentity = this.User.Identity.GetUserId(); + if (string.IsNullOrEmpty(userIdentity)) + return Json(false, JsonRequestBehavior.AllowGet); + + var subscription = controllerHelper.db.PrayerSubscriptions.FirstOrDefault(i => i.PrayerId == prayerId && i.ApplicationUserId == userIdentity); + + if (subscription == null) + { + controllerHelper.db.PrayerSubscriptions.Add(new PrayerSubscription() + { + ApplicationUserId = userIdentity, + PrayerId = prayerId, + CreatedUTC = DateTime.UtcNow + }); + controllerHelper.db.SaveChanges(); + } + + return Json(true, JsonRequestBehavior.AllowGet); + } + + public JsonResult Unsubscribe(int prayerId, string affiliatekey) + { + var userIdentity = this.User.Identity.GetUserId(); + if (string.IsNullOrEmpty(userIdentity)) + return Json(false, JsonRequestBehavior.AllowGet); + + var subscription = controllerHelper.db.PrayerSubscriptions.FirstOrDefault(i => i.PrayerId == prayerId && i.ApplicationUserId == userIdentity); + + if (subscription != null) + { + controllerHelper.db.PrayerSubscriptions.Remove(subscription); + controllerHelper.db.SaveChanges(); + } + + return Json(true, JsonRequestBehavior.AllowGet); + } + + public JsonResult Bookmark(int prayerId, string affiliatekey) + { + var userIdentity = this.User.Identity.GetUserId(); + if (string.IsNullOrEmpty(userIdentity)) + return Json(false, JsonRequestBehavior.AllowGet); + + var bookmark = controllerHelper.db.PrayerBookmarks.FirstOrDefault(i => i.PrayerId == prayerId && i.ApplicationUserId == userIdentity); + + if (bookmark == null) + { + controllerHelper.db.PrayerBookmarks.Add(new PrayerBookmark() + { + ApplicationUserId = userIdentity, + PrayerId = prayerId, + CreatedUTC = DateTime.UtcNow + }); + controllerHelper.db.SaveChanges(); + } + + return Json(true, JsonRequestBehavior.AllowGet); + } + + public JsonResult RemoveBookmark(int prayerId, string affiliatekey) + { + var userIdentity = this.User.Identity.GetUserId(); + if (string.IsNullOrEmpty(userIdentity)) + return Json(false, JsonRequestBehavior.AllowGet); + + var bookmark = controllerHelper.db.PrayerBookmarks.FirstOrDefault(i => i.PrayerId == prayerId && i.ApplicationUserId == userIdentity); + + if (bookmark != null) + { + controllerHelper.db.PrayerBookmarks.Remove(bookmark); + controllerHelper.db.SaveChanges(); + } + + return Json(true, JsonRequestBehavior.AllowGet); + } + + + public JsonResult Prayed(int prayerId, string affiliatekey) + { + var prayer = controllerHelper.db.Prayers.Include("ApplicationUser").FirstOrDefault(i => i.Id == prayerId && i.IsActive && !i.IsDeleted); + + if (prayer == null) + return Json(false, JsonRequestBehavior.AllowGet); + + var user = controllerHelper.GetLoggedInUser(); + var ipAddress = RequestHelper.GetClientIpAddress(this.Request); + var userAgent = this.Request.UserAgent ?? ""; + + controllerHelper.db.PrayerItems.Add(new PrayerItem() + { + PrayerId = prayerId, + ApplicationUserId = user != null ? user.Id : null, + CreatedUTC = DateTime.UtcNow, + IPAddress = ipAddress, + UserAgent = userAgent + }); + + controllerHelper.db.SaveChanges(); + + var dbPrayedCount = controllerHelper.db.PrayerItems.Count(i => i.PrayerId == prayerId); + prayer.CountPrayed = Math.Max(prayer.CountPrayed + 1, dbPrayedCount); + controllerHelper.db.SaveChanges(); + + var affiliate = controllerHelper.GetAffiliate(affiliatekey); + + NotificationController.NotifyPrayed(this.Url, affiliate, prayer.ApplicationUser, prayer); + + var data = new + { + id = prayer.Id, + count = prayer.CountPrayed + }; + + return Json(data, JsonRequestBehavior.AllowGet); + } + + public JsonResult SendNote(int prayerId, string content, string affiliatekey) + { + var prayer = controllerHelper.db.Prayers.Include("ApplicationUser").FirstOrDefault(i => i.Id == prayerId && i.IsActive && !i.IsDeleted); + + if (prayer == null) + return Json(new { success = false, message = "Prayer doesn't exist." }, JsonRequestBehavior.AllowGet); + + var user = controllerHelper.GetLoggedInUser(); + var ipAddress = RequestHelper.GetClientIpAddress(this.Request); + var userAgent = this.Request.UserAgent ?? ""; + + var validationMessage = ""; + if (!ValidatePrayerSubmission(affiliatekey, "note of encouragement", content, "", ipAddress, out validationMessage)) + { + return Json(new { success = false, message = validationMessage }, JsonRequestBehavior.AllowGet); + } + + var note = controllerHelper.db.PrayerNotes.Add(new PrayerNote() + { + PrayerId = prayerId, + ApplicationUserId = user != null ? user.Id : null, + NoteText = content, + CreatedUTC = DateTime.UtcNow, + IPAddress = ipAddress, + UserAgent = userAgent + }); + + controllerHelper.db.SaveChanges(); + + var affiliate = controllerHelper.GetAffiliate(affiliatekey); + NotificationController.NotifyNoteSent(this.Url, affiliate, prayer.ApplicationUser, prayer, note); + + return Json(new { success = true, message = "" }, JsonRequestBehavior.AllowGet); + } + + public JsonResult Flag(int prayerId, string reason, string name, string email, string affiliatekey) + { + var prayer = controllerHelper.db.Prayers.FirstOrDefault(i => i.Id == prayerId && i.IsActive && !i.IsDeleted); + + if (prayer != null) + { + var user = controllerHelper.GetLoggedInUser(); + string userid = null; + if (user != null) + { + userid = user.Id; + name = user.UserName; + email = user.Email; + } + + var flag = new PrayerFlag() + { + PrayerId = prayerId, + ApplicationUserId = userid, + Reason = reason, + AnonymousName = name, + AnonymousEmail = email, + CreatedUTC = DateTime.UtcNow + }; + + controllerHelper.db.PrayerFlags.Add(flag); + controllerHelper.db.SaveChanges(); + + var dbFlagCount = controllerHelper.db.PrayerFlags.Count(i => i.PrayerId == prayerId); + prayer.CountFlagged = Math.Max(prayer.CountFlagged + 1, dbFlagCount); + controllerHelper.db.SaveChanges(); + + var affiliate = controllerHelper.GetAffiliate(affiliatekey); + NotificationController.NotifyPrayerFlagged(this.Url, affiliate, prayer, flag); + + var data = new + { + id = prayer.Id, + hide = prayer.CountFlagged >= affiliate.FlagThreshold + }; + + return Json(data, JsonRequestBehavior.AllowGet); + } + else + { + return Json(false, JsonRequestBehavior.AllowGet); + } + } + + public bool Delete(int id, string affiliatekey) + { + if (!User.Identity.IsAuthenticated) + { + return false; + } + + var prayer = controllerHelper.db.Prayers.Include("Affiliate").FirstOrDefault(i => i.Id == id); + var userIdentity = User.Identity.GetUserId(); + + if (prayer.ApplicationUserId != userIdentity) + { + return false; + } + + prayer.IsDeleted = true; + prayer.ModifiedUTC = DateTime.UtcNow; + controllerHelper.db.SaveChanges(); + + return true; + } + + private bool ValidatePrayerSubmission(string affiliatekey, string subject, string content, string emailAddress, string ipAddress, out string message) + { + message = ""; + if (string.IsNullOrEmpty(subject) || string.IsNullOrEmpty(content)) + { + message = "Prayer Request cannot be empty"; + return false; + } + + emailAddress = (emailAddress ?? "").Trim(); + ipAddress = (ipAddress ?? "").Trim(); + + var affiliate = controllerHelper.db.Affiliates.Include("BlacklistEmails").Include("BlacklistIPs").Include("AutoFlagItems").FirstOrDefault(i => i.Key == affiliatekey && i.IsActive); + + if (affiliate == null) + { + affiliate = controllerHelper.db.Affiliates.Include("BlacklistEmails").Include("BlacklistIPs").Include("AutoFlagItems").FirstOrDefault(i => i.Key.Equals(ControllerHelper.DefaultAffiliateKey, StringComparison.InvariantCultureIgnoreCase)); + } + + //ensure not a blacklist email address + if (affiliate.BlacklistEmails.Count(i => i.Email.Equals(emailAddress, StringComparison.InvariantCultureIgnoreCase)) > 0) + { + message = "Email address has been blocked"; + return false; + } + + //ensure not a blacklist ip address + if (affiliate.BlacklistIPs.Count(i => i.IP.Equals(ipAddress, StringComparison.InvariantCultureIgnoreCase)) > 0) + { + message = "IP address has been blocked"; + return false; + } + + if (affiliate.AutoFlagItems.Count > 0) + { + subject = subject.StripPunctuation().ToLower(); + content = content.StripPunctuation().ToLower(); + + var flagWords = @"\b(" + string.Join("|", affiliate.AutoFlagItems.Select(i => i.Text.ToLower()).ToArray()) + @")\b"; + var subjectMatch = Regex.IsMatch(subject, flagWords); + var contentMatch = Regex.IsMatch(content, flagWords); + + if (contentMatch || subjectMatch) + { + message = "Title or Content contains inappropriate word or phrase."; + return false; + } + } + return true; + } + + public JsonResult Edit(PrayerEditViewModel model, string affiliatekey) + { + var user = controllerHelper.GetLoggedInUser(); + var appUserId = User.Identity.GetUserId() ?? "none"; + var ipAddress = RequestHelper.GetClientIpAddress(this.Request); + var userAgent = this.Request.UserAgent ?? ""; + + var email = model.AnonymousEmail ?? "none"; + var phone = model.AnonymousPhone ?? "none"; + + if (user != null) + { + email = user.Email ?? email; + phone = user.PhoneNumber ?? phone; + } + + //if (User.Identity.IsAuthenticated) + //{ + // model.AnonymousName = null; + // model.AnonymousEmail = null; + //} + + model.ContactPreference = model.ContactPreference ?? "email"; + + var validationMessage = ""; + if (!ValidatePrayerSubmission(affiliatekey, model.Summary, model.Content, email, ipAddress, out validationMessage)) + { + return Json(new { success = false, message = validationMessage }, JsonRequestBehavior.AllowGet); + } + + var prayer = controllerHelper.db.Prayers.FirstOrDefault(i => i.Id == model.Id && i.IsActive && !i.IsDeleted && i.ApplicationUserId == appUserId); + + if (model.IsNew) + { + var affiliate = controllerHelper.GetAffiliate(affiliatekey); + prayer = controllerHelper.db.Prayers.Add(new Prayer() + { + AffiliateId = affiliate.Id, + IsPraise = model.IsPraise, + CreatedUTC = DateTime.UtcNow, + AgreeTermsOfUse = model.AgreeTermsOfUse, + IsActive = true, + ApplicationUserId = User.Identity.IsAuthenticated ? appUserId : null, + EnableEmailNotification = model.EnableEmailNotification, + EnableTextNotification = model.EnableTextNotification, + EnableEmailNote = model.EnableEmailNote, + AnonymousEmail = email, + AnonymousPhone = phone, + AnonymousName = model.AnonymousName.Trim(), + ShareThis = model.ShareThis, + ContactPreference = model.ContactPreference, + UserAgent = userAgent, + IPAddress = ipAddress, + PrayerSourceId = PrayerSource.DeterminePrayerSource(userAgent), + Summary = model.Summary.Trim(), + Content = model.Content.Trim(), + ModifiedUTC = DateTime.UtcNow + }); + + if (!model.IsPraise && affiliate.RequireModeration) + { + prayer.IsActive = false; + } + + controllerHelper.db.SaveChanges(); + + //send info to Dataverse for select affiliates + //National: 293 + //West: 356 + //East: 357 + //South: 358 + //Way Nation: 350 + //KSBJ: 17 + //NGEN: 19 + //Vida: 352 + int[] aryAffliates = { 293, 356, 357, 358, 350, 17, 19, 352, 1 }; //TODO: remove 1, it's for testing + if (aryAffliates.Contains(prayer.AffiliateId)) + { + _ = SyncDataverseAsync("add_prayer", prayer.AffiliateId, prayer.Content, prayer.AnonymousName, prayer.AnonymousEmail, prayer.AnonymousPhone); + } + + NotificationController.NotifyPrayerRequest(this.Url, affiliate, user, prayer); + } + + if (prayer == null) + return Json(new { success = false, message = "Prayer does not exist" }, JsonRequestBehavior.AllowGet); + + if (!model.IsNew) + { + prayer.Summary = model.Summary; + prayer.Content = model.Content; + + prayer.EnableEmailNotification = model.EnableEmailNotification; + prayer.EnableTextNotification = model.EnableTextNotification; + prayer.EnableEmailNote = model.EnableEmailNote; + + prayer.ModifiedUTC = DateTime.UtcNow; + + controllerHelper.db.SaveChanges(); + } + + return Json(new { success = true, message = "Success" }, JsonRequestBehavior.AllowGet); + } + + public async Task SyncDataverseAsync(string task, int affiliateId, string prayer_request, string name, string email, string phone) + { + // have to get Affiliate name by Id + ApplicationDbContext db = new ApplicationDbContext(); + Affiliate affiliate = db.Affiliates.Find(affiliateId); + + //string APIUrl = "http://localhost:7157/api/AmenDataSync"; + string APIUrl = "https://amendatasync.azurewebsites.net/api/AmenDataSync"; + APIUrl += "?task=" + task + + "&brand=" + affiliate.Name + + "&prayer_request=" + prayer_request + + "&name=" + name + + "&email=" + email + + "&phone=" + phone; + + try + { + using (var client = new HttpClient()) + { + client.BaseAddress = new Uri(APIUrl); + client.DefaultRequestHeaders.Accept.Clear(); + client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); + HttpResponseMessage response = await client.GetAsync(APIUrl); + //var result = client.GetAsync(APIUrl).Result; + + if (response.IsSuccessStatusCode) + { + var readTask = response.Content.ReadAsStringAsync().ConfigureAwait(false); + var rawResponse = readTask.GetAwaiter().GetResult(); + } + } + } + catch + { + + } + + + } + } +} \ No newline at end of file diff --git a/Amen/Global.asax b/Amen/Global.asax new file mode 100644 index 0000000..1ba8282 --- /dev/null +++ b/Amen/Global.asax @@ -0,0 +1 @@ +<%@ Application Codebehind="Global.asax.cs" Inherits="Amen.MvcApplication" Language="C#" %> diff --git a/Amen/Global.asax.cs b/Amen/Global.asax.cs new file mode 100644 index 0000000..bb8063f --- /dev/null +++ b/Amen/Global.asax.cs @@ -0,0 +1,29 @@ +using Amen.Models; +using System; +using System.Collections.Generic; +using System.Data.Entity; +using System.Linq; +using System.Web; +using System.Web.Http; +using System.Web.Mvc; +using System.Web.Optimization; +using System.Web.Routing; + +namespace Amen +{ + public class MvcApplication : System.Web.HttpApplication + { + protected void Application_Start() + { + AreaRegistration.RegisterAllAreas(); + //GlobalConfiguration.Configure(WebApiConfig.Register); + FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); + RouteConfig.RegisterRoutes(RouteTable.Routes); + BundleConfig.RegisterBundles(BundleTable.Bundles); + +#if DEBUG + //Database.SetInitializer(new ApplicationDbContextInitializer()); +#endif + } + } +} diff --git a/Amen/Helpers/BlobStorageHelper.cs b/Amen/Helpers/BlobStorageHelper.cs new file mode 100644 index 0000000..4a51e03 --- /dev/null +++ b/Amen/Helpers/BlobStorageHelper.cs @@ -0,0 +1,77 @@ +using Microsoft.WindowsAzure.Storage; +using Microsoft.WindowsAzure.Storage.Auth; +using Microsoft.WindowsAzure.Storage.Blob; +using System; +using System.Collections.Generic; +using System.Configuration; +using System.IO; +using System.Linq; +using System.Web; + +namespace Amen.Helpers +{ + public class BlobStorageHelper + { + + //public static string SaveToBlobStorage(string containerName, string blobName, string contentType, byte[] bytes) + public static string SaveToBlobStorage(string containerName, string blobName, string contentType, Stream stream) + { + var accountName = ConfigurationManager.AppSettings["AzureBlobStorageAccount"]; + var accountKey = ConfigurationManager.AppSettings["AzureBlobStorageAccountKey"]; + + CloudStorageAccount storageAccount = new CloudStorageAccount(new StorageCredentials(accountName, accountKey), true); + CloudBlobClient cloudBlobClient = storageAccount.CreateCloudBlobClient(); + CloudBlobContainer container = cloudBlobClient.GetContainerReference(containerName); + + container.CreateIfNotExists(); + var permission = container.GetPermissions(); + permission.PublicAccess = BlobContainerPublicAccessType.Container; + container.SetPermissions(permission); + + CloudBlockBlob blob = container.GetBlockBlobReference(blobName); + + blob.UploadFromStream(stream); + //blob.UploadFromByteArray(bytes, 0, bytes.Length); + blob.Properties.ContentType = contentType; + blob.SetProperties(); + + return blob.Uri.AbsoluteUri; + } + + public static string RenameBlobStorageItem(string containerName, string oldBlobName, string newBlobName) + { + var accountName = ConfigurationManager.AppSettings["AzureBlobStorageAccount"]; + var accountKey = ConfigurationManager.AppSettings["AzureBlobStorageAccountKey"]; + + CloudStorageAccount storageAccount = new CloudStorageAccount(new StorageCredentials(accountName, accountKey), true); + CloudBlobClient cloudBlobClient = storageAccount.CreateCloudBlobClient(); + CloudBlobContainer container = cloudBlobClient.GetContainerReference(containerName); + + container.CreateIfNotExists(); + + CloudBlockBlob oldBlob = container.GetBlockBlobReference(oldBlobName); + + if (!oldBlob.Exists()) + return string.Empty; + + CloudBlockBlob newBlob = container.GetBlockBlobReference(newBlobName); + + //newBlob.StartCopyFromBlob(oldBlob.Uri); + newBlob.StartCopy(oldBlob); + while (true) + { + newBlob.FetchAttributes(); + if (newBlob.CopyState.Status != CopyStatus.Pending) + { + break; + } + //Sleep for a second may be + System.Threading.Thread.Sleep(100); + } + oldBlob.Delete(); + + return newBlob.Uri.AbsoluteUri; + } + } + +} \ No newline at end of file diff --git a/Amen/Helpers/RequestHelper.cs b/Amen/Helpers/RequestHelper.cs new file mode 100644 index 0000000..6293131 --- /dev/null +++ b/Amen/Helpers/RequestHelper.cs @@ -0,0 +1,64 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Web; + +namespace Amen.Helpers +{ + public class RequestHelper + { + public static string GetClientIpAddress(HttpRequestBase request) + { + try + { + var userHostAddress = request.UserHostAddress; + + // Attempt to parse. If it fails, we catch below and return "0.0.0.0" + // Could use TryParse instead, but I wanted to catch all exceptions + IPAddress.Parse(userHostAddress); + + var xForwardedFor = request.ServerVariables["X_FORWARDED_FOR"]; + + if (string.IsNullOrEmpty(xForwardedFor)) + return userHostAddress; + + // Get a list of public ip addresses in the X_FORWARDED_FOR variable + var publicForwardingIps = xForwardedFor.Split(',').Where(ip => !IsPrivateIpAddress(ip)).ToList(); + + // If we found any, return the last one, otherwise return the user host address + return publicForwardingIps.Any() ? publicForwardingIps.Last() : userHostAddress; + } + catch (Exception) + { + // Always return all zeroes for any failure (my calling code expects it) + return "0.0.0.0"; + } + } + + private static bool IsPrivateIpAddress(string ipAddress) + { + // http://en.wikipedia.org/wiki/Private_network + // Private IP Addresses are: + // 24-bit block: 10.0.0.0 through 10.255.255.255 + // 20-bit block: 172.16.0.0 through 172.31.255.255 + // 16-bit block: 192.168.0.0 through 192.168.255.255 + // Link-local addresses: 169.254.0.0 through 169.254.255.255 (http://en.wikipedia.org/wiki/Link-local_address) + + var ip = IPAddress.Parse(ipAddress); + var octets = ip.GetAddressBytes(); + + var is24BitBlock = octets[0] == 10; + if (is24BitBlock) return true; // Return to prevent further processing + + var is20BitBlock = octets[0] == 172 && octets[1] >= 16 && octets[1] <= 31; + if (is20BitBlock) return true; // Return to prevent further processing + + var is16BitBlock = octets[0] == 192 && octets[1] == 168; + if (is16BitBlock) return true; // Return to prevent further processing + + var isLinkLocalAddress = octets[0] == 169 && octets[1] == 254; + return isLinkLocalAddress; + } + } +} \ No newline at end of file diff --git a/Amen/Helpers/StringHelper.cs b/Amen/Helpers/StringHelper.cs new file mode 100644 index 0000000..fc3f4c4 --- /dev/null +++ b/Amen/Helpers/StringHelper.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Web; + +namespace Amen.Helpers +{ + public static class StringExtension + { + public static string StripPunctuation(this string s) + { + var sb = new StringBuilder(); + foreach (char c in s) + { + if (!char.IsPunctuation(c)) + sb.Append(c); + } + return sb.ToString(); + } + } + + public class StringHelper + { + + } +} \ No newline at end of file diff --git a/Amen/Helpers/UserHelper.cs b/Amen/Helpers/UserHelper.cs new file mode 100644 index 0000000..b7b971b --- /dev/null +++ b/Amen/Helpers/UserHelper.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Security.Claims; +using System.Web; + +namespace Amen.Helpers +{ + public static class UserHelper + { + public static string GetFullName(this System.Security.Principal.IPrincipal usr) + { + var fullNameClaim = ((ClaimsIdentity)usr.Identity).FindFirst("FullName"); + if (fullNameClaim != null) + return fullNameClaim.Value; + + return ""; + } + } +} \ No newline at end of file diff --git a/Amen/Migrations/201701031255563_AddCreatedUTCColumns.Designer.cs b/Amen/Migrations/201701031255563_AddCreatedUTCColumns.Designer.cs new file mode 100644 index 0000000..f91830d --- /dev/null +++ b/Amen/Migrations/201701031255563_AddCreatedUTCColumns.Designer.cs @@ -0,0 +1,29 @@ +// +namespace Amen.Migrations +{ + using System.CodeDom.Compiler; + using System.Data.Entity.Migrations; + using System.Data.Entity.Migrations.Infrastructure; + using System.Resources; + + [GeneratedCode("EntityFramework.Migrations", "6.1.1-30610")] + public sealed partial class AddCreatedUTCColumns : IMigrationMetadata + { + private readonly ResourceManager Resources = new ResourceManager(typeof(AddCreatedUTCColumns)); + + string IMigrationMetadata.Id + { + get { return "201701031255563_AddCreatedUTCColumns"; } + } + + string IMigrationMetadata.Source + { + get { return Resources.GetString("Source"); } + } + + string IMigrationMetadata.Target + { + get { return Resources.GetString("Target"); } + } + } +} diff --git a/Amen/Migrations/201701031255563_AddCreatedUTCColumns.cs b/Amen/Migrations/201701031255563_AddCreatedUTCColumns.cs new file mode 100644 index 0000000..47a2b40 --- /dev/null +++ b/Amen/Migrations/201701031255563_AddCreatedUTCColumns.cs @@ -0,0 +1,30 @@ +namespace Amen.Migrations +{ + using System; + using System.Data.Entity.Migrations; + + public partial class AddCreatedUTCColumns : DbMigration + { + public override void Up() + { + AddColumn("dbo.AffiliateAdmin", "CreatedUTC", c => c.DateTime(nullable: false, defaultValueSql: "GETUTCDATE()")); + AddColumn("dbo.AffiliateStyle", "CreatedUTC", c => c.DateTime(nullable: false, defaultValueSql: "GETUTCDATE()")); + AddColumn("dbo.PrayerBookmark", "CreatedUTC", c => c.DateTime(nullable: false, defaultValueSql: "GETUTCDATE()")); + AddColumn("dbo.PrayerFlag", "CreatedUTC", c => c.DateTime(nullable: false, defaultValueSql: "GETUTCDATE()")); + AddColumn("dbo.PrayerItem", "CreatedUTC", c => c.DateTime(nullable: false, defaultValueSql: "GETUTCDATE()")); + AddColumn("dbo.PrayerNote", "CreatedUTC", c => c.DateTime(nullable: false, defaultValueSql: "GETUTCDATE()")); + AddColumn("dbo.PrayerSubscription", "CreatedUTC", c => c.DateTime(nullable: false, defaultValueSql: "GETUTCDATE()")); + } + + public override void Down() + { + DropColumn("dbo.PrayerSubscription", "CreatedUTC"); + DropColumn("dbo.PrayerNote", "CreatedUTC"); + DropColumn("dbo.PrayerItem", "CreatedUTC"); + DropColumn("dbo.PrayerFlag", "CreatedUTC"); + DropColumn("dbo.PrayerBookmark", "CreatedUTC"); + DropColumn("dbo.AffiliateStyle", "CreatedUTC"); + DropColumn("dbo.AffiliateAdmin", "CreatedUTC"); + } + } +} diff --git a/Amen/Migrations/201701031255563_AddCreatedUTCColumns.resx b/Amen/Migrations/201701031255563_AddCreatedUTCColumns.resx new file mode 100644 index 0000000..dfc9332 --- /dev/null +++ b/Amen/Migrations/201701031255563_AddCreatedUTCColumns.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 + + + 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 + + + dbo + + \ No newline at end of file diff --git a/Amen/Migrations/201708042356577_AddAffiliateIntructions.Designer.cs b/Amen/Migrations/201708042356577_AddAffiliateIntructions.Designer.cs new file mode 100644 index 0000000..0a76732 --- /dev/null +++ b/Amen/Migrations/201708042356577_AddAffiliateIntructions.Designer.cs @@ -0,0 +1,29 @@ +// +namespace Amen.Migrations +{ + using System.CodeDom.Compiler; + using System.Data.Entity.Migrations; + using System.Data.Entity.Migrations.Infrastructure; + using System.Resources; + + [GeneratedCode("EntityFramework.Migrations", "6.1.1-30610")] + public sealed partial class AddAffiliateIntructions : IMigrationMetadata + { + private readonly ResourceManager Resources = new ResourceManager(typeof(AddAffiliateIntructions)); + + string IMigrationMetadata.Id + { + get { return "201708042356577_AddAffiliateIntructions"; } + } + + string IMigrationMetadata.Source + { + get { return Resources.GetString("Source"); } + } + + string IMigrationMetadata.Target + { + get { return Resources.GetString("Target"); } + } + } +} diff --git a/Amen/Migrations/201708042356577_AddAffiliateIntructions.cs b/Amen/Migrations/201708042356577_AddAffiliateIntructions.cs new file mode 100644 index 0000000..b4a5b2a --- /dev/null +++ b/Amen/Migrations/201708042356577_AddAffiliateIntructions.cs @@ -0,0 +1,22 @@ +namespace Amen.Migrations +{ + using System; + using System.Data.Entity.Migrations; + + public partial class AddAffiliateIntructions : DbMigration + { + public override void Up() + { + AddColumn("dbo.Affiliate", "InstructionsPraise", c => c.String()); + AddColumn("dbo.Affiliate", "InstructionsAddPraise", c => c.String()); + AddColumn("dbo.Affiliate", "InstructionsNote", c => c.String()); + } + + public override void Down() + { + DropColumn("dbo.Affiliate", "InstructionsNote"); + DropColumn("dbo.Affiliate", "InstructionsAddPraise"); + DropColumn("dbo.Affiliate", "InstructionsPraise"); + } + } +} diff --git a/Amen/Migrations/201708042356577_AddAffiliateIntructions.resx b/Amen/Migrations/201708042356577_AddAffiliateIntructions.resx new file mode 100644 index 0000000..00cf5cb --- /dev/null +++ b/Amen/Migrations/201708042356577_AddAffiliateIntructions.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 + + + 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 + + + dbo + + \ No newline at end of file diff --git a/Amen/Migrations/201708050049099_AddFieldsToSupportShowingUserNameAndLocation.Designer.cs b/Amen/Migrations/201708050049099_AddFieldsToSupportShowingUserNameAndLocation.Designer.cs new file mode 100644 index 0000000..52744ad --- /dev/null +++ b/Amen/Migrations/201708050049099_AddFieldsToSupportShowingUserNameAndLocation.Designer.cs @@ -0,0 +1,29 @@ +// +namespace Amen.Migrations +{ + using System.CodeDom.Compiler; + using System.Data.Entity.Migrations; + using System.Data.Entity.Migrations.Infrastructure; + using System.Resources; + + [GeneratedCode("EntityFramework.Migrations", "6.1.1-30610")] + public sealed partial class AddFieldsToSupportShowingUserNameAndLocation : IMigrationMetadata + { + private readonly ResourceManager Resources = new ResourceManager(typeof(AddFieldsToSupportShowingUserNameAndLocation)); + + string IMigrationMetadata.Id + { + get { return "201708050049099_AddFieldsToSupportShowingUserNameAndLocation"; } + } + + string IMigrationMetadata.Source + { + get { return null; } + } + + string IMigrationMetadata.Target + { + get { return Resources.GetString("Target"); } + } + } +} diff --git a/Amen/Migrations/201708050049099_AddFieldsToSupportShowingUserNameAndLocation.cs b/Amen/Migrations/201708050049099_AddFieldsToSupportShowingUserNameAndLocation.cs new file mode 100644 index 0000000..5fce406 --- /dev/null +++ b/Amen/Migrations/201708050049099_AddFieldsToSupportShowingUserNameAndLocation.cs @@ -0,0 +1,26 @@ +namespace Amen.Migrations +{ + using System; + using System.Data.Entity.Migrations; + + public partial class AddFieldsToSupportShowingUserNameAndLocation : DbMigration + { + public override void Up() + { + AddColumn("dbo.Affiliate", "EnableShowLocation", c => c.Boolean(nullable: false)); + AddColumn("dbo.Affiliate", "EnableShowName", c => c.Boolean(nullable: false)); + AddColumn("dbo.AspNetUsers", "Location", c => c.String()); + AddColumn("dbo.AspNetUsers", "ShouldShowLocation", c => c.Boolean(nullable: false)); + AddColumn("dbo.AspNetUsers", "ShouldShowName", c => c.Boolean(nullable: false)); + } + + public override void Down() + { + DropColumn("dbo.AspNetUsers", "ShouldShowName"); + DropColumn("dbo.AspNetUsers", "ShouldShowLocation"); + DropColumn("dbo.AspNetUsers", "Location"); + DropColumn("dbo.Affiliate", "EnableShowName"); + DropColumn("dbo.Affiliate", "EnableShowLocation"); + } + } +} diff --git a/Amen/Migrations/201708050049099_AddFieldsToSupportShowingUserNameAndLocation.resx b/Amen/Migrations/201708050049099_AddFieldsToSupportShowingUserNameAndLocation.resx new file mode 100644 index 0000000..3a36d69 --- /dev/null +++ b/Amen/Migrations/201708050049099_AddFieldsToSupportShowingUserNameAndLocation.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 + + + 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 + + + dbo + + \ No newline at end of file diff --git a/Amen/Migrations/Configuration.cs b/Amen/Migrations/Configuration.cs new file mode 100644 index 0000000..e28ce61 --- /dev/null +++ b/Amen/Migrations/Configuration.cs @@ -0,0 +1,116 @@ +namespace Amen.Migrations +{ + using Amen.Controllers; + using Amen.Models; + using System; + using System.Data.Entity; + using System.Data.Entity.Migrations; + using System.Linq; + using System.Web.Security; + + internal sealed class Configuration : DbMigrationsConfiguration + { + public Configuration() + { + AutomaticMigrationsEnabled = true; + ContextKey = "Amen.Models.ApplicationDbContext"; + AutomaticMigrationDataLossAllowed = true; + + /* + * Add-Migration [MigrationName] + * Update-Database -Script -SourceMigration: $InitialDatabase -TargetMigration: [MigrationName] + * + * Update-Database -ConnectionStringName: AmenPrayerDev + * Update-Database -ConnectionStringName: AmenPrayerProd + * + * */ + } + + protected override void Seed(Amen.Models.ApplicationDbContext context) + { + // This method will be called after migrating to the latest version. + + // You can use the DbSet.AddOrUpdate() helper extension method + // to avoid creating duplicate seed data. E.g. + // + // context.People.AddOrUpdate( + // p => p.FullName, + // new Person { FullName = "Andrew Peters" }, + // new Person { FullName = "Brice Lambson" }, + // new Person { FullName = "Rowan Miller" } + // ); + // + + context.PrayerSources.AddOrUpdate(i => i.Label, + new PrayerSource() { Label = "Web", Description = "Requests made via the web site." }, + new PrayerSource() { Label = "iOS", Description = "Requests made via the iOS app." } + ); + context.SaveChanges(); + + context.SubscriptionTypes.AddOrUpdate(i => i.Label, + new SubscriptionType() { Label = "Basic", Description = "Basic subscription with web access." }, + new SubscriptionType() { Label = "BasicPlus", Description = "Basic Plus access to iOS app." }, + new SubscriptionType() { Label = "Demo", Description = "Try it out, but does not show up in the affiliate list." } + ); + context.SaveChanges(); + + var noSource = context.Prayers.Where(i => !i.PrayerSourceId.HasValue).ToList(); + //var noSource = context.Prayers.ToList(); + foreach (var item in noSource) + { + item.PrayerSourceId = PrayerSource.DeterminePrayerSource(item.UserAgent); + } + context.SaveChanges(); + + if (context.Roles.Count(i => i.Name == ControllerHelper.Role_SuperAdministrator) == 0) + { + context.Roles.Add(new Microsoft.AspNet.Identity.EntityFramework.IdentityRole(ControllerHelper.Role_SuperAdministrator)); + context.SaveChanges(); + } + + if (context.Roles.Count(i => i.Name == ControllerHelper.Role_Administrator) == 0) + { + context.Roles.Add(new Microsoft.AspNet.Identity.EntityFramework.IdentityRole(ControllerHelper.Role_Administrator)); + context.SaveChanges(); + } + + if (context.Roles.Count(i => i.Name == ControllerHelper.Role_AffiliateAdministrator) == 0) + { + context.Roles.Add(new Microsoft.AspNet.Identity.EntityFramework.IdentityRole(ControllerHelper.Role_AffiliateAdministrator)); + context.SaveChanges(); + } + + var than = context.Users.Include(i => i.Roles).FirstOrDefault(i => i.Email == "thannap@hotmail.com"); + if (than != null) + { + var adminRole = context.Roles.FirstOrDefault(i => i.Name == ControllerHelper.Role_Administrator); + if (than.Roles.Count(i => i.RoleId == adminRole.Id) == 0) + { + than.Roles.Add(new Microsoft.AspNet.Identity.EntityFramework.IdentityUserRole() { RoleId = adminRole.Id, UserId = than.Id }); + context.SaveChanges(); + } + + var superAdminRole = context.Roles.FirstOrDefault(i => i.Name == ControllerHelper.Role_SuperAdministrator); + if (than.Roles.Count(i => i.RoleId == superAdminRole.Id) == 0) + { + than.Roles.Add(new Microsoft.AspNet.Identity.EntityFramework.IdentityUserRole() { RoleId = superAdminRole.Id, UserId = than.Id }); + context.SaveChanges(); + } + } + + var thangmail = context.Users.Include(i => i.Roles).FirstOrDefault(i => i.Email == "thannap@gmail.com"); + if (thangmail != null) + { + var adminRole = context.Roles.FirstOrDefault(i => i.Name == ControllerHelper.Role_AffiliateAdministrator); + if (thangmail.Roles.Count(i => i.RoleId == adminRole.Id) == 0) + { + thangmail.Roles.Add(new Microsoft.AspNet.Identity.EntityFramework.IdentityUserRole() { RoleId = adminRole.Id, UserId = thangmail.Id }); + context.SaveChanges(); + } + } + + //RoleManager = new RoleManager(new RoleStore(new MyDbContext())); + //var roleresult = RoleManager.Create(new IdentityRole(roleName)); + } + } +} diff --git a/Amen/Models/AccountViewModels.cs b/Amen/Models/AccountViewModels.cs new file mode 100644 index 0000000..10b529e --- /dev/null +++ b/Amen/Models/AccountViewModels.cs @@ -0,0 +1,140 @@ +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; + +namespace Amen.Models +{ + public class ExternalLoginConfirmationViewModel + { + [Required] + [Display(Name = "Email")] + public string Email { get; set; } + + [Required] + [Display(Name = "Full Name")] + public string FullName { get; set; } + } + + public class ExternalLoginListViewModel + { + public string ReturnUrl { get; set; } + } + + public class SendCodeViewModel + { + public string SelectedProvider { get; set; } + public ICollection Providers { get; set; } + public string ReturnUrl { get; set; } + public bool RememberMe { get; set; } + } + + public class VerifyCodeViewModel + { + [Required] + public string Provider { get; set; } + + [Required] + [Display(Name = "Code")] + public string Code { get; set; } + public string ReturnUrl { get; set; } + + [Display(Name = "Remember this browser?")] + public bool RememberBrowser { get; set; } + + public bool RememberMe { get; set; } + } + + public class ForgotViewModel + { + [Required] + [Display(Name = "Email")] + public string Email { get; set; } + } + + public class LoginViewModel + { + [Required] + [Display(Name = "Email")] + [EmailAddress] + public string Email { get; set; } + + [Required] + [DataType(DataType.Password)] + [Display(Name = "Password")] + public string Password { get; set; } + + [Display(Name = "Remember me?")] + public bool RememberMe { get; set; } + } + + public class RegisterViewModel + { + + [Required] + [Display(Name = "Full Name")] + public string FullName { get; set; } + + [Required] + [EmailAddress] + [Display(Name = "Email")] + public string Email { get; set; } + + [Display(Name = "Location")] + public string Location { get; set; } + + [Display(Name = "Enable Text Notifications")] + public bool EnableSmsNotifications { get; set; } + + [Display(Name = "Enable Email Notifications")] + public bool EnableEmailNotifications { get; set; } + + [Display(Name = "Allow My Name To Be Shown When Posting")] + public bool ShouldShowName { get; set; } + + [Display(Name = "Allow My Location To Be Shown When Posting")] + public bool ShouldShowLocation { get; set; } + + [Required] + [StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)] + [DataType(DataType.Password)] + [Display(Name = "Password")] + public string Password { get; set; } + + [DataType(DataType.Password)] + [Display(Name = "Confirm password")] + [Compare("Password", ErrorMessage = "The password and confirmation password do not match.")] + public string ConfirmPassword { get; set; } + + public bool AffiliateEnableShowLocation { get; set; } + public bool AffiliateEnableShowName { get; set; } + public bool AffiliateIsSmsCapable { get; set; } + } + + public class ResetPasswordViewModel + { + [Required] + [EmailAddress] + [Display(Name = "Email")] + public string Email { get; set; } + + [Required] + [StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)] + [DataType(DataType.Password)] + [Display(Name = "Password")] + public string Password { get; set; } + + [DataType(DataType.Password)] + [Display(Name = "Confirm password")] + [Compare("Password", ErrorMessage = "The password and confirmation password do not match.")] + public string ConfirmPassword { get; set; } + + public string Code { get; set; } + } + + public class ForgotPasswordViewModel + { + [Required] + [EmailAddress] + [Display(Name = "Email")] + public string Email { get; set; } + } +} diff --git a/Amen/Models/Affiliate.cs b/Amen/Models/Affiliate.cs new file mode 100644 index 0000000..0263d96 --- /dev/null +++ b/Amen/Models/Affiliate.cs @@ -0,0 +1,137 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using System.Linq; +using System.Web; +using System.Web.Mvc; + +namespace Amen.Models +{ + public class Affiliate + { + public int Id { get; set; } + + [ScaffoldColumn(false)] + public int PWId { get; set; } + + [Index(IsUnique = true)] + [StringLength(64)] + [Required] + public string Key { get; set; } + + [Display(Name = "Include prayers in Amen universal list?", Description = "Increases visibility of prayers")] + public bool IncludeInUniversal { get; set; } + + + [Display(Name = "Is Active?")] + public bool IsActive { get; set; } + + [Required] + public string Name { get; set; } + + [AllowHtml] + [DataType(DataType.MultilineText)] + [Display(Name = "Instructions for Prayer List")] + public string Instructions { get; set; } + + [AllowHtml] + [DataType(DataType.MultilineText)] + [Display(Name = "Instructions for Praise List")] + public string InstructionsPraise { get; set; } + + [AllowHtml] + [DataType(DataType.MultilineText)] + [Display(Name = "Instructions for Submitting Individual Prayers")] + public string InstructionsAddPrayer { get; set; } + + [AllowHtml] + [DataType(DataType.MultilineText)] + [Display(Name = "Instructions for Submitting Individual Praise")] + public string InstructionsAddPraise { get; set; } + + [AllowHtml] + [DataType(DataType.MultilineText)] + [Display(Name = "Instructions for Notes of Encouragement")] + public string InstructionsNote { get; set; } + + [Display(Name = "Website Url")] + public string UrlWebsite { get; set; } + [Display(Name = "Logo Url")] + public string UrlLogo { get; set; } + + [Display(Name = "Email Address of Admin Contact")] + public string EmailAdmin { get; set; } + [Display(Name = "Email Address of Billing Contact")] + public string EmailBilling { get; set; } + [Display(Name = "Email Address of Flag Contact")] + public string EmailFlag { get; set; } + + [Display(Name = "Email Subject Line For Prayed Notification")] + public string SendMessagePrayed { get; set; } + [Display(Name = "Email Subject Line For Note of Encouragement Notification")] + public string SendMessageNote { get; set; } + + [Display(Name = "How many days of prayers to include")] + public int PrayerDaysThreshold { get; set; } + + [Display(Name = "How many flags to disable a prayer")] + public int FlagThreshold { get; set; } + + public string TwilioSID { get; set; } + public string TwilioAuthToken { get; set; } + public string TwilioPhoneNumber { get; set; } + + + [Display(Name = "Send notification to admin when someone submits prayer request")] + public bool ShouldSendPrayerNotificationAdmin { get; set; } + + [Display(Name = "Send notification to admin when someone submits praise")] + public bool ShouldSendPraiseNotificationAdmin { get; set; } + + [Display(Name = "Allow users to send notes of encouragement")] + public bool EnableNotes { get; set; } + + [Display(Name = "Require admin moderation in order for prayers to become 'active'")] + public bool RequireModeration { get; set; } + + public int? SubscriptionTypeId { get; set; } + public SubscriptionType SubscriptionType { get; set; } + + [Display(Name = "Require users to create and log into an account to use notification features (recommended)")] + public bool RequireLoginForNoticiations { get; set; } + + [Display(Name = "Allow users to opt in to show their location")] + public bool EnableShowLocation { get; set; } + + [Display(Name = "Allow users to opt in to show their name")] + public bool EnableShowName { get; set; } + + //TODO: implement something new + //public int Level { get; set; } + //public int Status { get; set; } + //public bool ShouldUseBlacklist { get; set; } + //public string BlacklistEmails { get; set; } + //public string BlacklistIPs { get; set; } + + //public int MaxLengthPrayer { get; set; } + //public int MaxLengthStory { get; set; } + + public virtual IList Styles { get; set; } + public virtual IList BlacklistEmails { get; set; } + public virtual IList BlacklistIPs { get; set; } + public virtual IList AutoFlagItems { get; set; } + public virtual IList AffiliateAdmins { get; set; } + + [NotMapped] + public bool IsSmsCapable + { + get + { + return !string.IsNullOrEmpty(this.TwilioSID) + && !string.IsNullOrEmpty(this.TwilioAuthToken) + && !string.IsNullOrEmpty(this.TwilioPhoneNumber); + } + } + } +} \ No newline at end of file diff --git a/Amen/Models/AffiliateAdmin.cs b/Amen/Models/AffiliateAdmin.cs new file mode 100644 index 0000000..f53bae2 --- /dev/null +++ b/Amen/Models/AffiliateAdmin.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using System.Linq; +using System.Web; + +namespace Amen.Models +{ + public class AffiliateAdmin + { + [Key, Column(Order = 0)] + [ForeignKey("ApplicationUser")] + public string ApplicationUserId { get; set; } + public ApplicationUser ApplicationUser { get; set; } + + [Key, Column(Order = 1)] + public int AffiliateId { get; set; } + public Affiliate Affiliate { get; set; } + + public DateTime CreatedUTC { get; set; } + } +} \ No newline at end of file diff --git a/Amen/Models/AffiliateStyle.cs b/Amen/Models/AffiliateStyle.cs new file mode 100644 index 0000000..e5e6e52 --- /dev/null +++ b/Amen/Models/AffiliateStyle.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; + +namespace Amen.Models +{ + public class AffiliateStyle + { + public int Id { get; set; } + + public int AffiliateId { get; set; } + public Affiliate Affiliate { get; set; } + + public string StyleSheet { get; set; } + + public DateTime CreatedUTC { get; set; } + } +} \ No newline at end of file diff --git a/Amen/Models/AffiliateViewModels.cs b/Amen/Models/AffiliateViewModels.cs new file mode 100644 index 0000000..3f5826e --- /dev/null +++ b/Amen/Models/AffiliateViewModels.cs @@ -0,0 +1,127 @@ +using PagedList; +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using System.Web; + +namespace Amen.Models +{ + public class AffiliateSelectViewModel + { + public int Id { get; set; } + public string Name { get; set; } + public string Key { get; set; } + public string UrlLogo { get; set; } + public string NavigateUrl { get; set; } + + public int? SubscriptionTypeId { get; set; } + } + + public class AffiliateTabsViewModel + { + public int Id { get; set; } + public string Key { get; set; } + public string Selected { get; set; } + } + + public class AffiliateStyleViewModel + { + public int Id { get; set; } + public string Key { get; set; } + + [DataType(DataType.MultilineText)] + public string StyleContent { get; set; } + public string Template { get; set; } + } + + public class AffiliateFlagItemsViewModel + { + public int Id { get; set; } + public string Key { get; set; } + + //[DataType(DataType.MultilineText)] + public string FlagItems { get; set; } + } + + public class AffiliatePrayersViewModel + { + public int Id { get; set; } + public int Page { get; set; } + public int PageSize { get; set; } + public IPagedList Prayers { get; set; } + } + + public class AffiliateStatsViewModel + { + public int Id { get; set; } + + [Display(Name = "Total Requests")] + public int TotalRequests { get; set; } + [Display(Name = "Total Praise")] + public int TotalPraise { get; set; } + [Display(Name = "Total Notes Sent")] + public int TotalNotesSent { get; set; } + [Display(Name = "Total Prayers Prayed")] + public int TotalPrayersPrayed { get; set; } + [Display(Name = "Total Flags")] + public int TotalFlagsIndicated { get; set; } + + [Display(Name = "Recent Requests")] + public int RecentRequests { get; set; } + [Display(Name = "Recent Praise")] + public int RecentPraise { get; set; } + [Display(Name = "Recent Notes Sent")] + public int RecentNotesSent { get; set; } + [Display(Name = "Recent Prayers Prayed")] + public int RecentPrayersPrayed { get; set; } + [Display(Name = "Recent Flags")] + public int RecentFlagsIndicated { get; set; } + + [Display(Name="Recent Requests %")] + [DisplayFormat(DataFormatString = "{0:N2}")] + public double RecentRequestsPercentage { get { if (this.TotalRequests == 0) return 0; return (double)this.RecentRequests / (double)this.TotalRequests * 100.0; } } + [Display(Name = "Recent Praise %")] + [DisplayFormat(DataFormatString = "{0:N2}")] + public double RecentPraisePercentage { get { if (this.TotalPraise == 0) return 0; return (double)this.RecentPraise / (double)this.TotalPraise * 100.0; } } + [Display(Name = "Recent Notes %")] + [DisplayFormat(DataFormatString = "{0:N2}")] + public double RecentNotesSentPercentage { get { if (this.TotalNotesSent == 0) return 0; return (double)this.RecentNotesSent / (double)this.TotalNotesSent * 100.0; } } + [Display(Name = "Recent Prayed %")] + [DisplayFormat(DataFormatString = "{0:N2}")] + public double RecentPrayersPrayedPercentage { get { if (this.TotalPrayersPrayed == 0) return 0; return (double)this.RecentPrayersPrayed / (double)this.TotalPrayersPrayed * 100.0; } } + [Display(Name = "Recent Flags %")] + [DisplayFormat(DataFormatString = "{0:N2}")] + public double RecentFlagsIndicatedPercentage { get { if (this.TotalFlagsIndicated == 0) return 0; return (double)this.RecentFlagsIndicated / (double)this.TotalFlagsIndicated * 100.0; } } + } + + public class AffiliateUsersViewModel + { + public int Id { get; set; } + public List Users { get; set; } + + public class AffiliateUserViewModel + { + public string Id { get; set; } + public string FullName { get; set; } + public string Email { get; set; } + + public DateTime? LastLoginDate { get; set; } + public bool IsAdmin { get; set; } + public int OffsetMinutes { get; set; } + + public string DisplayLoginDate + { + get + { + if (!this.LastLoginDate.HasValue) + return ""; + + return this.LastLoginDate.Value.AddMinutes(OffsetMinutes).ToShortDateString(); + } + } + } + } + + +} \ No newline at end of file diff --git a/Amen/Models/AutoFlagItem.cs b/Amen/Models/AutoFlagItem.cs new file mode 100644 index 0000000..01b8490 --- /dev/null +++ b/Amen/Models/AutoFlagItem.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; + +namespace Amen.Models +{ + public class AutoFlagItem + { + public int Id { get; set; } + + public int AffiliateId { get; set; } + public Affiliate Affiliate { get; set; } + + public string Text { get; set; } + } +} \ No newline at end of file diff --git a/Amen/Models/BlacklistEmail.cs b/Amen/Models/BlacklistEmail.cs new file mode 100644 index 0000000..f277b39 --- /dev/null +++ b/Amen/Models/BlacklistEmail.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; + +namespace Amen.Models +{ + public class BlacklistEmail + { + public int Id { get; set; } + + public int AffiliateId { get; set; } + public Affiliate Affiliate { get; set; } + + public string Email { get; set; } + } +} \ No newline at end of file diff --git a/Amen/Models/BlacklistIP.cs b/Amen/Models/BlacklistIP.cs new file mode 100644 index 0000000..70465ac --- /dev/null +++ b/Amen/Models/BlacklistIP.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; + +namespace Amen.Models +{ + public class BlacklistIP + { + public int Id { get; set; } + + public int AffiliateId { get; set; } + public Affiliate Affiliate { get; set; } + + public string IP { get; set; } + } +} \ No newline at end of file diff --git a/Amen/Models/EmailViewModels.cs b/Amen/Models/EmailViewModels.cs new file mode 100644 index 0000000..0e14f2a --- /dev/null +++ b/Amen/Models/EmailViewModels.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; + +namespace Amen.Models +{ + public class EmailViewModel + { + public string To { get; set; } + public string Subject { get; set; } + } + + public class PrayerEmailViewModel : EmailViewModel + { + public string Title { get; set; } + public string NoteText { get; set; } + public string DetailUrl { get; set; } + public string ManageUrl { get; set; } + public bool IsUserLoggedIn { get; set; } + public bool IsPraise { get; set; } + } + + + public class AdminEmailViewModel : EmailViewModel + { + public string PrayerTitle { get; set; } + public string PrayerContent { get; set; } + public string NotificationTypeMessage { get; set; } + public string DetailUrl { get; set; } + public string ManageUrl { get; set; } + } +} \ No newline at end of file diff --git a/Amen/Models/FacebookAuthModels.cs b/Amen/Models/FacebookAuthModels.cs new file mode 100644 index 0000000..dcaaea2 --- /dev/null +++ b/Amen/Models/FacebookAuthModels.cs @@ -0,0 +1,44 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Net.Http; +using System.Web; + +namespace Amen.Models +{ + public class FacebookOauthResponse + { + public string access_token { get; set; } + public string token_type { get; set; } + public int expires_in { get; set; } + } + + public class FacebookBackChannelHandler : HttpClientHandler + { + protected override async System.Threading.Tasks.Task SendAsync(HttpRequestMessage request, System.Threading.CancellationToken cancellationToken) + { + var result = await base.SendAsync(request, cancellationToken); + if (!request.RequestUri.AbsolutePath.Contains("access_token")) + return result; + + // For the access token we need to now deal with the fact that the response is now in JSON format, not form values. Owin looks for form values. + var content = await result.Content.ReadAsStringAsync(); + var facebookOauthResponse = JsonConvert.DeserializeObject(content); + + var outgoingQueryString = HttpUtility.ParseQueryString(string.Empty); + outgoingQueryString.Add("access_token", facebookOauthResponse.access_token); + outgoingQueryString.Add("expires_in", facebookOauthResponse.expires_in + string.Empty); + outgoingQueryString.Add("token_type", facebookOauthResponse.token_type); + var postdata = outgoingQueryString.ToString(); + + var modifiedResult = new HttpResponseMessage(HttpStatusCode.OK) + { + Content = new StringContent(postdata) + }; + + return modifiedResult; + } + } +} \ No newline at end of file diff --git a/Amen/Models/IdentityModels.cs b/Amen/Models/IdentityModels.cs new file mode 100644 index 0000000..870740a --- /dev/null +++ b/Amen/Models/IdentityModels.cs @@ -0,0 +1,217 @@ +using System.Data.Entity; +using System.Security.Claims; +using System.Threading.Tasks; +using Microsoft.AspNet.Identity; +using Microsoft.AspNet.Identity.EntityFramework; +using System.Data.Entity.ModelConfiguration.Conventions; +using System.Collections.Generic; +using System; +using Amen.Controllers; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Amen.Models +{ + + // You can add profile data for the user by adding more properties to your ApplicationUser class, please visit http://go.microsoft.com/fwlink/?LinkID=317594 to learn more. + public class ApplicationUser : IdentityUser + { + public int AffiliateId { get; set; } + public Affiliate Affiliate { get; set; } + + [Display(Name = "Name")] + public string FullName { get; set; } + + + public bool EnableSmsNotifications { get; set; } + public bool EnableEmailNotifications { get; set; } + + public DateTime? LastLoginDateUtc { get; set; } + + public string Location { get; set; } + public bool ShouldShowLocation { get; set; } + public bool ShouldShowName { get; set; } + + [NotMapped] + public bool IsSmsCapable + { + get + { + return !string.IsNullOrEmpty(this.PhoneNumber) && this.EnableSmsNotifications; + } + } + + public virtual IList Prayers { get; set; } + + public async Task GenerateUserIdentityAsync(UserManager manager) + { + // Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType + var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie); + + userIdentity.AddClaim(new Claim("FullName", this.FullName)); + // Add custom user claims here + return userIdentity; + } + } + + public class ApplicationDbContext : IdentityDbContext + { + public DbSet Prayers { get; set; } + public DbSet Affiliates { get; set; } + public DbSet PrayerBookmarks { get; set; } + public DbSet PrayerSubscriptions { get; set; } + public DbSet PrayerFlags { get; set; } + public DbSet PrayerItems { get; set; } + public DbSet BlacklistEmails { get; set; } + public DbSet BlacklistIPs { get; set; } + public DbSet AutoFlagItems { get; set; } + public DbSet PrayerNotes { get; set; } + public DbSet AffiliateStyles { get; set; } + public DbSet AffiliateAdmins { get; set; } + public DbSet PrayerSources { get; set; } + public DbSet SubscriptionTypes { get; set; } + + public ApplicationDbContext() + : base("AmenPrayer", throwIfV1Schema: false) + { + this.Database.CommandTimeout = 300; + } + + public static ApplicationDbContext Create() + { + return new ApplicationDbContext(); + } + + + protected override void OnModelCreating(DbModelBuilder modelBuilder) + { + base.OnModelCreating(modelBuilder); + + //keep table names singular + modelBuilder.Conventions.Remove(); + + //turn off cascade delete + modelBuilder.Conventions.Remove(); + modelBuilder.Conventions.Remove(); + } + + } + + public class ApplicationDbContextInitializer : DropCreateDatabaseIfModelChanges + { + private void SeedMembership(ApplicationDbContext db) + { + //var roles = Roles.Provider; + //var membership = Membership.Provider; + + //if (!roles.RoleExists("Administrator")) + //{ + // roles.CreateRole("Administrator"); + //} + //if (membership.GetUser("thannap", false) == null) + //{ + // MembershipCreateStatus status; + // membership.CreateUser("thannap", "password", "thannap@hotmail.com", "pass?", "password", true, null, out status); + // //membership.CreateUserAndAccount("sallen", "imalittleteapot"); + //} + //if (!roles.GetRolesForUser("thannap").Contains("Admin")) + //{ + // roles.AddUsersToRoles(new[] { "thannap" }, new[] { "Admin" }); + //} + } + + protected override void Seed(ApplicationDbContext db) + { + var aff = db.Affiliates.Add(new Affiliate() + { + Key = ControllerHelper.DefaultAffiliateKey, + IsActive = true, + Name = "Amen", + Instructions = "Amen: A prayer app", + //Status = 0, + //Level = 0, + PrayerDaysThreshold = 30, + //BlacklistEmails = "", + //BlacklistIPs = "", + EmailAdmin = "than@effectivepixels.net", + EmailBilling = "than@effectivepixels.net", + EmailFlag = "than@effectivepixels.net", + FlagThreshold = 3, + //HasCustomCSS = false, + //MaxLengthPrayer = 1024, + //MaxLengthStory = 1024, + SendMessageNote = "Someone has sent you a note!", + SendMessagePrayed = "Someone has prayed for you!", + InstructionsAddPrayer = "This is text that shows up before the add prayer button", + ShouldSendPrayerNotificationAdmin = true, + ShouldSendPraiseNotificationAdmin = true, + //ShouldUseBlacklist = true, + TwilioAuthToken = "480bcbad18cd89e11ab5627532549c18", + TwilioPhoneNumber = "2064296488", + TwilioSID = "ACffd3ffac5601e6ee480e3ff6855d3b54", + UrlLogo = "https://amen.blob.core.windows.net/logos/amen-logo.png", + UrlWebsite = "http://www.amenprayer.com", + IncludeInUniversal = true + }); + + var aff2 = db.Affiliates.Add(new Affiliate() + { + Key = "joyfm", + IsActive = true, + Name = "Joy FM", + Instructions = "Nap: There's a Nap for that", + //Status = 0, + //Level = 0, + PrayerDaysThreshold = 30, + //BlacklistEmails = "", + //BlacklistIPs = "", + EmailAdmin = "than@napclan.com", + EmailBilling = "than@napclan.com", + EmailFlag = "than@napclan.com", + FlagThreshold = 3, + //HasCustomCSS = false, + //MaxLengthPrayer = 1024, + //MaxLengthStory = 1024, + SendMessageNote = "Someone has sent you a note!", + SendMessagePrayed = "Someone has prayed for you!", + InstructionsAddPrayer = "This is text that shows up before the add prayer button", + ShouldSendPrayerNotificationAdmin = true, + ShouldSendPraiseNotificationAdmin = true, + //ShouldUseBlacklist = true, + TwilioAuthToken = "480bcbad18cd89e11ab5627532549c18", + TwilioPhoneNumber = "2064296488", + TwilioSID = "ACffd3ffac5601e6ee480e3ff6855d3b54", + UrlLogo = "https://amen.blob.core.windows.net/logos/joy-logo.gif", + UrlWebsite = "http://www.napclan.com", + IncludeInUniversal = false + }); + db.SaveChanges(); + + for (int i = 0; i < 100; i++) + { + db.Prayers.Add(new Prayer() + { + Summary = "Prayer Summary " + i.ToString(), + Content = i.ToString() + " - Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum gravida fringilla dui mattis consequat.\r\rDonec ultrices facilisis metus, et ultrices erat efficitur non. Nunc viverra id nulla id pulvinar. Donec posuere, nibh a pretium tempus, leo enim bibendum metus, eu efficitur justo tellus ullamcorper purus. Mauris mi dui, porta quis pellentesque laoreet, finibus sollicitudin elit. Cras maximus dui lorem, at tincidunt metus egestas ac. Nam vitae neque tincidunt, pulvinar nibh id, molestie nisl. Aliquam nec libero faucibus, aliquet urna ut, ultrices diam. Aenean purus tortor, pulvinar sit amet arcu a, lacinia tristique est.", + CreatedUTC = System.DateTime.UtcNow, + AffiliateId = i % 2 == 0 ? aff.Id : aff2.Id, + AgreeTermsOfUse = true, + AnonymousEmail = "thannap@gmail.com", + AnonymousName = "Annon Than", + //AnonymousPhone = "2067550211", + EnableEmailNote = i % 3 == 0, + EnableEmailNotification = i % 4 == 0, + EnableTextNotification = i % 5 == 0, + IsActive = true, + IsPraise = i % 5 == 0, + CountFlagged = 0, + CountPrayed = (int)Math.Floor((double)i % 5), + PrayerSourceId = (int)PrayerSourceEnum.Web + }); + db.SaveChanges(); + } + + SeedMembership(db); + } + } +} \ No newline at end of file diff --git a/Amen/Models/ManageViewModels.cs b/Amen/Models/ManageViewModels.cs new file mode 100644 index 0000000..04c3700 --- /dev/null +++ b/Amen/Models/ManageViewModels.cs @@ -0,0 +1,115 @@ +using Microsoft.AspNet.Identity; +using Microsoft.Owin.Security; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; + +namespace Amen.Models +{ + public class SaveProfileViewModel + { + public string FullName { get; set; } + public string Location { get; set; } + public bool EnableEmailNotifications { get; set; } + public bool EnableSmsNotifications { get; set; } + public bool ShouldShowName { get; set; } + public bool ShouldShowLocation { get; set; } + } + + public class IndexViewModel + { + public bool HasPassword { get; set; } + + public IList Logins { get; set; } + public string PhoneNumber { get; set; } + public bool TwoFactor { get; set; } + public bool BrowserRemembered { get; set; } + public string FullName { get; set; } + + public string Location { get; set; } + + [Display(Name="Enable Text Notifications")] + public bool EnableSmsNotifications { get; set; } + [Display(Name = "Enable Email Notifications")] + public bool EnableEmailNotifications { get; set; } + + [Display(Name = "Allow My Name To Be Shown When Posting")] + public bool ShouldShowName { get; set; } + + [Display(Name = "Allow My Location To Be Shown When Posting")] + public bool ShouldShowLocation { get; set; } + + public bool AffiliateSmsCapable { get; set; } + public bool AffiliateEnableShowLocation { get; set; } + public bool AffiliateEnableShowName { get; set; } + } + + public class ManageLoginsViewModel + { + public IList CurrentLogins { get; set; } + public IList OtherLogins { get; set; } + } + + public class FactorViewModel + { + public string Purpose { get; set; } + } + + public class SetPasswordViewModel + { + [Required] + [StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)] + [DataType(DataType.Password)] + [Display(Name = "New password")] + public string NewPassword { get; set; } + + [DataType(DataType.Password)] + [Display(Name = "Confirm new password")] + [Compare("NewPassword", ErrorMessage = "The new password and confirmation password do not match.")] + public string ConfirmPassword { get; set; } + } + + public class ChangePasswordViewModel + { + [Required] + [DataType(DataType.Password)] + [Display(Name = "Current password")] + public string OldPassword { get; set; } + + [Required] + [StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)] + [DataType(DataType.Password)] + [Display(Name = "New password")] + public string NewPassword { get; set; } + + [DataType(DataType.Password)] + [Display(Name = "Confirm new password")] + [Compare("NewPassword", ErrorMessage = "The new password and confirmation password do not match.")] + public string ConfirmPassword { get; set; } + } + + public class AddPhoneNumberViewModel + { + [Required] + [Phone] + [Display(Name = "Phone Number")] + public string Number { get; set; } + } + + public class VerifyPhoneNumberViewModel + { + [Required] + [Display(Name = "Code")] + public string Code { get; set; } + + [Required] + [Phone] + [Display(Name = "Phone Number")] + public string PhoneNumber { get; set; } + } + + public class ConfigureTwoFactorViewModel + { + public string SelectedProvider { get; set; } + public ICollection Providers { get; set; } + } +} \ No newline at end of file diff --git a/Amen/Models/Prayer.cs b/Amen/Models/Prayer.cs new file mode 100644 index 0000000..bad3cd2 --- /dev/null +++ b/Amen/Models/Prayer.cs @@ -0,0 +1,142 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using System.Linq; +using System.Web; + +namespace Amen.Models +{ + public class Prayer + { + public int Id { get; set; } + + public int PWId { get; set; } + + public int AffiliateId { get; set; } + + public Affiliate Affiliate { get; set; } + + [ForeignKey("ApplicationUser")] + public string ApplicationUserId { get; set; } + + public ApplicationUser ApplicationUser { get; set; } + + [Display(Name = "Active?")] + public bool IsActive { get; set; } + + public bool IsDeleted { get; set; } + + [Display(Name = "Enable Text Notifications?")] + public bool EnableTextNotification { get; set; } + + [Display(Name = "Enable Email Notifications?")] + public bool EnableEmailNotification { get; set; } + + [Display(Name = "Enable Note of Encouragement?")] + public bool EnableEmailNote { get; set; } + + [Display(Name = "Title")] + public string Summary { get; set; } + + [DataType(DataType.MultilineText)] + public string Content { get; set; } + + public bool IsPraise { get; set; } + + [Display(Name = "Anonymous Name")] + public string AnonymousName { get; set; } + + [Display(Name = "Anonymous Email")] + public string AnonymousEmail { get; set; } + + [Display(Name = "Phone")] + public string AnonymousPhone { get; set; } + + [Display(Name = "Share this?")] + public string ShareThis { get; set; } + + [Display(Name = "Contact Preference")] + public string ContactPreference { get; set; } + + [Display(Name="Terms?")] + public bool AgreeTermsOfUse { get; set; } + + [Display(Name = "IP")] + public string IPAddress { get; set; } + + public string UserAgent { get; set; } + + public DateTime? ModifiedUTC { get; set; } + + [DisplayFormat(DataFormatString="{0:MMM d, yyyy}")] + [Display(Name = "Created")] + public DateTime CreatedUTC { get; set; } + + [Display(Name = "Prayed")] + public int CountPrayed { get; set; } + + [Display(Name="Flagged")] + public int CountFlagged { get; set; } + + public int? PrayerSourceId { get; set; } + + public PrayerSource PrayerSource { get; set; } + + public virtual IList PrayerItems { get; set; } + + public virtual IList PrayerFlags { get; set; } + + public virtual IList PrayerNotes { get; set; } + + public virtual IList PrayerBookmarks { get; set; } + + public virtual IList PrayerSubscriptions { get; set; } + + + [ForeignKey("ParentPrayer")] + public int? ParentPrayerId { get; set; } + + public virtual Prayer ParentPrayer { get; set; } + + public virtual ICollection ChildPrayers { get; set; } + + [NotMapped] + public string ContentElipsis + { + get + { + if (string.IsNullOrEmpty(this.Content) || this.Content.Length <= 50) + return this.Content; + + else + return this.Content.Substring(0, Math.Min(100, this.Content.Length)) + "..."; + } + } + + [NotMapped] + public string DisplayUserName + { + get + { + if (this.ApplicationUser != null) + return this.ApplicationUser.FullName; + else + return this.AnonymousName; + } + } + + [NotMapped] + public string DisplayUserEmail + { + get + { + if (this.ApplicationUser != null) + return this.ApplicationUser.Email; + else + return this.AnonymousEmail; + } + } + } +} \ No newline at end of file diff --git a/Amen/Models/PrayerBookmark.cs b/Amen/Models/PrayerBookmark.cs new file mode 100644 index 0000000..942eda2 --- /dev/null +++ b/Amen/Models/PrayerBookmark.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations.Schema; +using System.Linq; +using System.Web; + +namespace Amen.Models +{ + public class PrayerBookmark + { + public int Id { get; set; } + + public int PrayerId { get; set; } + public Prayer Prayer { get; set; } + + [ForeignKey("ApplicationUser")] + public string ApplicationUserId { get; set; } + public ApplicationUser ApplicationUser { get; set; } + + public DateTime CreatedUTC { get; set; } + } +} \ No newline at end of file diff --git a/Amen/Models/PrayerFlag.cs b/Amen/Models/PrayerFlag.cs new file mode 100644 index 0000000..5f2ad41 --- /dev/null +++ b/Amen/Models/PrayerFlag.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations.Schema; +using System.Linq; +using System.Web; + +namespace Amen.Models +{ + public class PrayerFlag + { + public int Id { get; set; } + + public int PrayerId { get; set; } + public Prayer Prayer { get; set; } + + [ForeignKey("ApplicationUser")] + public string ApplicationUserId { get; set; } + public ApplicationUser ApplicationUser { get; set; } + + public string AnonymousName { get; set; } + public string AnonymousEmail { get; set; } + + public string Reason { get; set; } + + public DateTime CreatedUTC { get; set; } + + } +} \ No newline at end of file diff --git a/Amen/Models/PrayerItem.cs b/Amen/Models/PrayerItem.cs new file mode 100644 index 0000000..8a363c7 --- /dev/null +++ b/Amen/Models/PrayerItem.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations.Schema; +using System.Linq; +using System.Web; + +namespace Amen.Models +{ + public class PrayerItem + { + public int Id { get; set; } + + public int PrayerId { get; set; } + public Prayer Prayer { get; set; } + + [ForeignKey("ApplicationUser")] + public string ApplicationUserId { get; set; } + public ApplicationUser ApplicationUser { get; set; } + + public string IPAddress { get; set; } + public string UserAgent { get; set; } + + public DateTime CreatedUTC { get; set; } + } +} \ No newline at end of file diff --git a/Amen/Models/PrayerNote.cs b/Amen/Models/PrayerNote.cs new file mode 100644 index 0000000..e099ca7 --- /dev/null +++ b/Amen/Models/PrayerNote.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations.Schema; +using System.Linq; +using System.Web; + +namespace Amen.Models +{ + public class PrayerNote + { + public int Id { get; set; } + + public int PrayerId { get; set; } + public Prayer Prayer { get; set; } + + [ForeignKey("ApplicationUser")] + public string ApplicationUserId { get; set; } + public ApplicationUser ApplicationUser { get; set; } + + public string NoteText { get; set; } + + public string IPAddress { get; set; } + public string UserAgent { get; set; } + + public DateTime CreatedUTC { get; set; } + } +} \ No newline at end of file diff --git a/Amen/Models/PrayerSource.cs b/Amen/Models/PrayerSource.cs new file mode 100644 index 0000000..77e671e --- /dev/null +++ b/Amen/Models/PrayerSource.cs @@ -0,0 +1,52 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations.Schema; +using System.Linq; +using System.Text.RegularExpressions; +using System.Web; + +namespace Amen.Models +{ + public enum PrayerSourceEnum + { + Web = 1, + iOS = 2 + } + + public class PrayerSource + { + public int Id { get; set; } + public string Label { get; set; } + public string Description { get; set; } + + [NotMapped] + public PrayerSourceEnum EnumValue + { + get + { + return (PrayerSourceEnum)this.Id; + } + set + { + this.Id = (int)value; + } + } + + public static int DeterminePrayerSource(string userAgent) + { + userAgent = userAgent ?? ""; + var isWebView = Regex.IsMatch(userAgent, "((iPhone|iPod|iPad).*AppleWebKit(?!.*(Safari|CriOS)))", RegexOptions.IgnoreCase); + isWebView = isWebView || userAgent.Contains("AmenPrayer iOS"); + + if (isWebView) + { + return (int)PrayerSourceEnum.iOS; + } + else + { + return (int)PrayerSourceEnum.Web; + } + } + } + +} \ No newline at end of file diff --git a/Amen/Models/PrayerSubscription.cs b/Amen/Models/PrayerSubscription.cs new file mode 100644 index 0000000..b75e0f0 --- /dev/null +++ b/Amen/Models/PrayerSubscription.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations.Schema; +using System.Linq; +using System.Web; + +namespace Amen.Models +{ + public class PrayerSubscription + { + public int Id { get; set; } + + public int PrayerId { get; set; } + public Prayer Prayer { get; set; } + + [ForeignKey("ApplicationUser")] + public string ApplicationUserId { get; set; } + public ApplicationUser ApplicationUser { get; set; } + + public DateTime CreatedUTC { get; set; } + } +} \ No newline at end of file diff --git a/Amen/Models/PrayerViewModels.cs b/Amen/Models/PrayerViewModels.cs new file mode 100644 index 0000000..37875ca --- /dev/null +++ b/Amen/Models/PrayerViewModels.cs @@ -0,0 +1,214 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; + +namespace Amen.Models +{ + public class PrayersViewModel + { + public string Instructions { get; set; } + public string InstructionsPraise { get; set; } + public string InstructionsAddPrayer { get; set; } + public string InstructionsAddPraise { get; set; } + public string InstructionsNote { get; set; } + public bool ShouldOpenSubmit { get; set; } + public bool IsDetail { get; set; } + public bool IsPraise { get; set; } + public bool IsUserAuthenticated { get; set; } + public string AuthenticatedUserEmail { get; set; } + public bool IsAffiliateSmsCapable { get; set; } + public bool IsUserSmsCapable { get; set; } + public bool EnableNotifications { get; set; } + public bool IsAffiliateNotesEnabled { get; set; } + public bool ShouldReturnToUserPage { get; set; } + public IList Prayers { get; set; } + + public bool ShowPraiseListInstructions + { + get + { + return !this.IsDetail && this.IsPraise && !string.IsNullOrEmpty(InstructionsPraise); + } + } + + public bool ShowPrayerListInstructions + { + get + { + return !this.IsDetail && !this.IsPraise && !string.IsNullOrEmpty(Instructions); + } + } + + public bool ShowAddPraiseInstructions + { + get + { + return this.IsPraise && !string.IsNullOrEmpty(InstructionsAddPraise); + } + } + + public bool ShowAddPrayerInstructions + { + get + { + return !this.IsPraise && !string.IsNullOrEmpty(InstructionsAddPrayer); + } + } + } + + public class PrayerItemViewModel + { + public int Id { get; set; } + public string UserName { get; set; } + public string UserLocation { get; set; } + public string Summary { get; set; } + public string Content { get; set; } + public string ContentElipsis + { + get + { + if (string.IsNullOrEmpty(this.Content) || this.Content.Length <= 50) + return this.Content; + + else + return this.Content.Substring(0, Math.Min(100, this.Content.Length)) + "..."; + } + } + public bool IsPraise { get; set; } + public int CountPrayed { get; set; } + public bool EnableEmailNote { get; set; } + + //public bool IsUserAuthenticated { get; set; } + public string ShareThis { get; set; } + public bool EnableNotifications { get; set; } + public bool IsAffiliateNotesEnabled { get; set; } + public bool IsUserSubscribed { get; set; } + public bool IsUserBookmarked { get; set; } + public bool EnableEdit { get; set; } + public DateTime CreatedUTC { get; set; } + public int OffsetMinutes { get; set; } + public string DetailUrl { get; set; } + public string UrlLogo { get; set; } + + public string DisplaySubmittedDate + { + get + { + var now = DateTime.UtcNow.AddMinutes(-this.OffsetMinutes); + var created = this.CreatedUTC.AddMinutes(-this.OffsetMinutes); + var diffMinutes = Math.Round((now - created).TotalMinutes); + var hours = Math.Round( diffMinutes / 60); + + if (diffMinutes <= 1) + return "1 minute ago"; + else if (diffMinutes < 60) + return string.Format("{0} minutes ago", diffMinutes); + else if (hours == 1) + return "1 hour ago"; + else if (hours <= 12) + return string.Format("{0} hours ago", hours); + else if (created.DayOfYear != now.DayOfYear) + return string.Format("{0:MMM d, yyyy}", created); + else + return string.Format("{0} hours ago", hours); + } + } + + public string DisplaySubscribeText + { + get + { + return this.IsUserSubscribed ? "Unsubscribe" : "Subscribe"; + } + } + + public string DisplayBookmarkText + { + get + { + return this.IsUserBookmarked ? "Remove Bookmark" : "Bookmark"; + } + } + + public string ShareFacebookUrl + { + get + { + return string.Format("https://www.facebook.com/sharer/sharer.php?u={0}", HttpUtility.UrlEncode(DetailUrl)); + } + } + + public string ShareTwitterUrl + { + get + { + return string.Format("https://twitter.com/home?status={0}", HttpUtility.UrlEncode(DetailUrl)); + } + } + + public string ShareEmailUrl + { + get + { + return string.Format("mailto:?&subject={0}&body={1}", HttpUtility.UrlPathEncode("Amen Prayer - " + this.Summary), HttpUtility.UrlPathEncode("Please pray with me - " + this.DetailUrl)); + } + } + + public bool HasUserName + { + get { return !string.IsNullOrEmpty(this.UserName); } + } + + public bool HasUserLocation + { + get { return !string.IsNullOrEmpty(this.UserLocation); } + } + + public bool HasUserNameAndLocation + { + get { return HasUserName && HasUserLocation; } + } + + } + + + //public class PrayerFlagViewModel + //{ + // public int Id { get; set; } + // public string Reason { get; set; } + // public string Name { get; set; } + // public string Email { get; set; } + //} + + public class PrayerEditViewModel + { + public int Id { get; set; } + + public string Summary { get; set; } + + public string Content { get; set; } + + public bool IsNew { get; set; } + + public bool IsPraise { get; set; } + + public bool AgreeTermsOfUse { get; set; } + + public string AnonymousName { get; set; } + + public string AnonymousEmail { get; set; } + + public string AnonymousPhone { get; set; } + + public string ShareThis { get; set; } + + public string ContactPreference { get; set; } + + public bool EnableEmailNote { get; set; } + + public bool EnableEmailNotification { get; set; } + + public bool EnableTextNotification { get; set; } + } +} \ No newline at end of file diff --git a/Amen/Models/RelatedPrayer.cs b/Amen/Models/RelatedPrayer.cs new file mode 100644 index 0000000..0350d2b --- /dev/null +++ b/Amen/Models/RelatedPrayer.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using System.Linq; +using System.Web; + +namespace Amen.Models +{ + //public class RelatedPrayer + //{ + // [Key, Column(Order = 0)] + // [ForeignKey("Prayer")] + // public string ParentPrayerId { get; set; } + // public Prayer ParentPrayer { get; set; } + + // [Key, Column(Order = 1)] + // [ForeignKey("Prayer")] + // public int ChildPrayerId { get; set; } + // public Prayer ChildPrayer { get; set; } + + // public DateTime CreatedUTC { get; set; } + //} +} \ No newline at end of file diff --git a/Amen/Models/SubscriptionType.cs b/Amen/Models/SubscriptionType.cs new file mode 100644 index 0000000..2f2f6bc --- /dev/null +++ b/Amen/Models/SubscriptionType.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using System.Linq; +using System.Web; + +namespace Amen.Models +{ + public enum SubscriptionTypeEnum + { + Basic = 1, + BasicPlus = 2, + Demo = 3 + } + + public class SubscriptionType + { + public int Id { get; set; } + [Display(Name = "Subscription Type")] + public string Label { get; set; } + public string Description { get; set; } + + [NotMapped] + public SubscriptionTypeEnum EnumValue + { + get + { + return (SubscriptionTypeEnum)this.Id; + } + set + { + this.Id = (int)value; + } + } + } +} \ No newline at end of file diff --git a/Amen/Project_Readme.html b/Amen/Project_Readme.html new file mode 100644 index 0000000..4bb6760 --- /dev/null +++ b/Amen/Project_Readme.html @@ -0,0 +1,151 @@ + + + + + Your ASP.NET application + + + + + + +
+
+

This application consists of:

+
    +
  • Sample pages showing basic nav between Home, About, and Contact
  • +
  • Theming using Bootstrap
  • +
  • Authentication, if selected, shows how to register and sign in
  • +
  • ASP.NET features managed using NuGet
  • +
+
+ + + + + +
+

Get help

+ +
+
+ + + \ No newline at end of file diff --git a/Amen/Properties/AssemblyInfo.cs b/Amen/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..0036321 --- /dev/null +++ b/Amen/Properties/AssemblyInfo.cs @@ -0,0 +1,35 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Amen")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Amen")] +[assembly: AssemblyCopyright("Copyright © 2016")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("4699afe3-6d5c-43bd-b9e6-4c06583eae1f")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Revision and Build Numbers +// by using the '*' as shown below: +[assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyFileVersion("1.0.*")] diff --git a/Amen/Scripts/_references.js b/Amen/Scripts/_references.js new file mode 100644 index 0000000..ae3e38d Binary files /dev/null and b/Amen/Scripts/_references.js differ diff --git a/Amen/Scripts/bootstrap-tagsinput-angular.js b/Amen/Scripts/bootstrap-tagsinput-angular.js new file mode 100644 index 0000000..b849848 --- /dev/null +++ b/Amen/Scripts/bootstrap-tagsinput-angular.js @@ -0,0 +1,92 @@ +/* + * bootstrap-tagsinput v0.8.0 + * + */ + +angular.module('bootstrap-tagsinput', []) +.directive('bootstrapTagsinput', [function() { + + function getItemProperty(scope, property) { + if (!property) + return undefined; + + if (angular.isFunction(scope.$parent[property])) + return scope.$parent[property]; + + return function(item) { + return item[property]; + }; + } + + return { + restrict: 'EA', + scope: { + model: '=ngModel' + }, + template: '', + replace: false, + link: function(scope, element, attrs) { + $(function() { + if (!angular.isArray(scope.model)) + scope.model = []; + + var select = $('select', element); + var typeaheadSourceArray = attrs.typeaheadSource ? attrs.typeaheadSource.split('.') : null; + var typeaheadSource = typeaheadSourceArray ? + (typeaheadSourceArray.length > 1 ? + scope.$parent[typeaheadSourceArray[0]][typeaheadSourceArray[1]] + : scope.$parent[typeaheadSourceArray[0]]) + : null; + + select.tagsinput(scope.$parent[attrs.options || ''] || { + typeahead : { + source : angular.isFunction(typeaheadSource) ? typeaheadSource : null + }, + itemValue: getItemProperty(scope, attrs.itemvalue), + itemText : getItemProperty(scope, attrs.itemtext), + confirmKeys : getItemProperty(scope, attrs.confirmkeys) ? JSON.parse(attrs.confirmkeys) : [13], + tagClass : angular.isFunction(scope.$parent[attrs.tagclass]) ? scope.$parent[attrs.tagclass] : function(item) { return attrs.tagclass; } + }); + + for (var i = 0; i < scope.model.length; i++) { + select.tagsinput('add', scope.model[i]); + } + + select.on('itemAdded', function(event) { + if (scope.model.indexOf(event.item) === -1) + scope.model.push(event.item); + }); + + select.on('itemRemoved', function(event) { + var idx = scope.model.indexOf(event.item); + if (idx !== -1) + scope.model.splice(idx, 1); + }); + + // create a shallow copy of model's current state, needed to determine + // diff when model changes + var prev = scope.model.slice(); + scope.$watch("model", function() { + var added = scope.model.filter(function(i) {return prev.indexOf(i) === -1;}), + removed = prev.filter(function(i) {return scope.model.indexOf(i) === -1;}), + i; + + prev = scope.model.slice(); + + // Remove tags no longer in binded model + for (i = 0; i < removed.length; i++) { + select.tagsinput('remove', removed[i]); + } + + // Refresh remaining tags + select.tagsinput('refresh'); + + // Add new items in model as tags + for (i = 0; i < added.length; i++) { + select.tagsinput('add', added[i]); + } + }, true); + }); + } + }; +}]); diff --git a/Amen/Scripts/bootstrap-tagsinput-angular.min.js b/Amen/Scripts/bootstrap-tagsinput-angular.min.js new file mode 100644 index 0000000..02ed4fd --- /dev/null +++ b/Amen/Scripts/bootstrap-tagsinput-angular.min.js @@ -0,0 +1,7 @@ +/* + * bootstrap-tagsinput v0.8.0 + * + */ + +angular.module("bootstrap-tagsinput",[]).directive("bootstrapTagsinput",[function(){function a(a,b){return b?angular.isFunction(a.$parent[b])?a.$parent[b]:function(a){return a[b]}:void 0}return{restrict:"EA",scope:{model:"=ngModel"},template:"",replace:!1,link:function(b,c,d){$(function(){angular.isArray(b.model)||(b.model=[]);var e=$("select",c),f=d.typeaheadSource?d.typeaheadSource.split("."):null,g=f?f.length>1?b.$parent[f[0]][f[1]]:b.$parent[f[0]]:null;e.tagsinput(b.$parent[d.options||""]||{typeahead:{source:angular.isFunction(g)?g:null},itemValue:a(b,d.itemvalue),itemText:a(b,d.itemtext),confirmKeys:a(b,d.confirmkeys)?JSON.parse(d.confirmkeys):[13],tagClass:angular.isFunction(b.$parent[d.tagclass])?b.$parent[d.tagclass]:function(a){return d.tagclass}});for(var h=0;h'); + this.$input = $('').appendTo(this.$container); + + this.$element.before(this.$container); + + this.build(options); + this.isInit = false; + } + + TagsInput.prototype = { + constructor: TagsInput, + + /** + * Adds the given item as a new tag. Pass true to dontPushVal to prevent + * updating the elements val() + */ + add: function(item, dontPushVal, options) { + var self = this; + + if (self.options.maxTags && self.itemsArray.length >= self.options.maxTags) + return; + + // Ignore falsey values, except false + if (item !== false && !item) + return; + + // Trim value + if (typeof item === "string" && self.options.trimValue) { + item = $.trim(item); + } + + // Throw an error when trying to add an object while the itemValue option was not set + if (typeof item === "object" && !self.objectItems) + throw("Can't add objects when itemValue option is not set"); + + // Ignore strings only containg whitespace + if (item.toString().match(/^\s*$/)) + return; + + // If SELECT but not multiple, remove current tag + if (self.isSelect && !self.multiple && self.itemsArray.length > 0) + self.remove(self.itemsArray[0]); + + if (typeof item === "string" && this.$element[0].tagName === 'INPUT') { + var delimiter = (self.options.delimiterRegex) ? self.options.delimiterRegex : self.options.delimiter; + var items = item.split(delimiter); + if (items.length > 1) { + for (var i = 0; i < items.length; i++) { + this.add(items[i], true); + } + + if (!dontPushVal) + self.pushVal(self.options.triggerChange); + return; + } + } + + var itemValue = self.options.itemValue(item), + itemText = self.options.itemText(item), + tagClass = self.options.tagClass(item), + itemTitle = self.options.itemTitle(item); + + // Ignore items allready added + var existing = $.grep(self.itemsArray, function(item) { return self.options.itemValue(item) === itemValue; } )[0]; + if (existing && !self.options.allowDuplicates) { + // Invoke onTagExists + if (self.options.onTagExists) { + var $existingTag = $(".tag", self.$container).filter(function() { return $(this).data("item") === existing; }); + self.options.onTagExists(item, $existingTag); + } + return; + } + + // if length greater than limit + if (self.items().toString().length + item.length + 1 > self.options.maxInputLength) + return; + + // raise beforeItemAdd arg + var beforeItemAddEvent = $.Event('beforeItemAdd', { item: item, cancel: false, options: options}); + self.$element.trigger(beforeItemAddEvent); + if (beforeItemAddEvent.cancel) + return; + + // register item in internal array and map + self.itemsArray.push(item); + + // add a tag element + + var $tag = $('' + htmlEncode(itemText) + ''); + $tag.data('item', item); + self.findInputWrapper().before($tag); + $tag.after(' '); + + // Check to see if the tag exists in its raw or uri-encoded form + var optionExists = ( + $('option[value="' + encodeURIComponent(itemValue) + '"]', self.$element).length || + $('option[value="' + htmlEncode(itemValue) + '"]', self.$element).length + ); + + // add