diff --git a/samples/xamarin/.DS_Store b/samples/xamarin/.DS_Store new file mode 100644 index 0000000..6978a76 Binary files /dev/null and b/samples/xamarin/.DS_Store differ diff --git a/samples/xamarin/UserItems/.DS_Store b/samples/xamarin/UserItems/.DS_Store new file mode 100644 index 0000000..220bb57 Binary files /dev/null and b/samples/xamarin/UserItems/.DS_Store differ diff --git a/samples/xamarin/UserItems/ResourceTokenBroker/.DS_Store b/samples/xamarin/UserItems/ResourceTokenBroker/.DS_Store new file mode 100644 index 0000000..c2e40ad Binary files /dev/null and b/samples/xamarin/UserItems/ResourceTokenBroker/.DS_Store differ diff --git a/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker.sln b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker.sln new file mode 100755 index 0000000..a8df47e --- /dev/null +++ b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker.sln @@ -0,0 +1,28 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.25420.1 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ResourceTokenBroker", "ResourceTokenBroker\ResourceTokenBroker.csproj", "{C4233D06-E76E-4459-8D44-B9DDBEB4369C}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "test", "test\test.csproj", "{1832596A-95EE-4941-8973-62BD197CDB5A}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {C4233D06-E76E-4459-8D44-B9DDBEB4369C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C4233D06-E76E-4459-8D44-B9DDBEB4369C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C4233D06-E76E-4459-8D44-B9DDBEB4369C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C4233D06-E76E-4459-8D44-B9DDBEB4369C}.Release|Any CPU.Build.0 = Release|Any CPU + {1832596A-95EE-4941-8973-62BD197CDB5A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1832596A-95EE-4941-8973-62BD197CDB5A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1832596A-95EE-4941-8973-62BD197CDB5A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1832596A-95EE-4941-8973-62BD197CDB5A}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/.DS_Store b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/.DS_Store new file mode 100644 index 0000000..13fc1e2 Binary files /dev/null and b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/.DS_Store differ diff --git a/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/App_Start/BundleConfig.cs b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/App_Start/BundleConfig.cs new file mode 100755 index 0000000..865986b --- /dev/null +++ b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/App_Start/BundleConfig.cs @@ -0,0 +1,28 @@ +using System.Web; +using System.Web.Optimization; + +namespace ResourceTokenBroker +{ + 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")); + + // 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/respond.js")); + + bundles.Add(new StyleBundle("~/Content/css").Include( + "~/Content/bootstrap.css", + "~/Content/site.css")); + } + } +} diff --git a/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/App_Start/FilterConfig.cs b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/App_Start/FilterConfig.cs new file mode 100755 index 0000000..44b85e2 --- /dev/null +++ b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/App_Start/FilterConfig.cs @@ -0,0 +1,13 @@ +using System.Web; +using System.Web.Mvc; + +namespace ResourceTokenBroker +{ + public class FilterConfig + { + public static void RegisterGlobalFilters(GlobalFilterCollection filters) + { + filters.Add(new HandleErrorAttribute()); + } + } +} diff --git a/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/App_Start/IdentityConfig.cs b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/App_Start/IdentityConfig.cs new file mode 100755 index 0000000..87fd9de --- /dev/null +++ b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/App_Start/IdentityConfig.cs @@ -0,0 +1,45 @@ +using System.Threading.Tasks; +using Microsoft.AspNet.Identity; +using Microsoft.AspNet.Identity.EntityFramework; +using Microsoft.AspNet.Identity.Owin; +using Microsoft.Owin; +using ResourceTokenBroker.Models; + +namespace ResourceTokenBroker +{ + // 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, + }; + var dataProtectionProvider = options.DataProtectionProvider; + if (dataProtectionProvider != null) + { + manager.UserTokenProvider = new DataProtectorTokenProvider(dataProtectionProvider.Create("ASP.NET Identity")); + } + return manager; + } + } +} diff --git a/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/App_Start/RouteConfig.cs b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/App_Start/RouteConfig.cs new file mode 100755 index 0000000..fc1a2a8 --- /dev/null +++ b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/App_Start/RouteConfig.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; +using System.Web.Mvc; +using System.Web.Routing; + +namespace ResourceTokenBroker +{ + public class RouteConfig + { + public static void RegisterRoutes(RouteCollection routes) + { + routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); + + routes.MapRoute( + name: "Default", + url: "{controller}/{action}/{id}", + defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional } + ); + } + } +} diff --git a/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/App_Start/Startup.Auth.cs b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/App_Start/Startup.Auth.cs new file mode 100755 index 0000000..b21eb50 --- /dev/null +++ b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/App_Start/Startup.Auth.cs @@ -0,0 +1,69 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Microsoft.AspNet.Identity; +using Microsoft.AspNet.Identity.EntityFramework; +using Microsoft.Owin; +using Microsoft.Owin.Security.Cookies; +using Microsoft.Owin.Security.Google; +using Microsoft.Owin.Security.OAuth; +using Owin; +using ResourceTokenBroker.Providers; +using ResourceTokenBroker.Models; + +namespace ResourceTokenBroker +{ + public partial class Startup + { + public static OAuthAuthorizationServerOptions OAuthOptions { get; private set; } + + public static string PublicClientId { get; private set; } + + // For more information on configuring authentication, please visit http://go.microsoft.com/fwlink/?LinkId=301864 + public void ConfigureAuth(IAppBuilder app) + { + // Configure the db context and user manager to use a single instance per request + app.CreatePerOwinContext(ApplicationDbContext.Create); + app.CreatePerOwinContext(ApplicationUserManager.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 + app.UseCookieAuthentication(new CookieAuthenticationOptions()); + app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie); + + // Configure the application for OAuth based flow + PublicClientId = "self"; + OAuthOptions = new OAuthAuthorizationServerOptions + { + TokenEndpointPath = new PathString("/Token"), + Provider = new ApplicationOAuthProvider(PublicClientId), + AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin"), + AccessTokenExpireTimeSpan = TimeSpan.FromDays(14), + // In production mode set AllowInsecureHttp = false + AllowInsecureHttp = true + }; + + // Enable the application to use bearer tokens to authenticate users + app.UseOAuthBearerTokens(OAuthOptions); + + // Uncomment the following lines to enable logging in with third party login providers + //app.UseMicrosoftAccountAuthentication( + // clientId: "", + // clientSecret: ""); + + //app.UseTwitterAuthentication( + // consumerKey: "", + // consumerSecret: ""); + + //app.UseFacebookAuthentication( + // appId: "", + // appSecret: ""); + + //app.UseGoogleAuthentication(new GoogleOAuth2AuthenticationOptions() + //{ + // ClientId = "", + // ClientSecret = "" + //}); + } + } +} diff --git a/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/App_Start/WebApiConfig.cs b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/App_Start/WebApiConfig.cs new file mode 100755 index 0000000..4212e74 --- /dev/null +++ b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/App_Start/WebApiConfig.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net.Http; +using System.Web.Http; +using Microsoft.Owin.Security.OAuth; +using Newtonsoft.Json.Serialization; + +namespace ResourceTokenBroker +{ + public static class WebApiConfig + { + public static void Register(HttpConfiguration config) + { + // Web API configuration and services + // Configure Web API to use only bearer token authentication. + config.SuppressDefaultHostAuthentication(); + config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType)); + + // Web API routes + config.MapHttpAttributeRoutes(); + + config.Routes.MapHttpRoute( + name: "DefaultApi", + routeTemplate: "api/{controller}/{id}", + defaults: new { id = RouteParameter.Optional } + ); + } + } +} diff --git a/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/ApiDescriptionExtensions.cs b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/ApiDescriptionExtensions.cs new file mode 100755 index 0000000..59d3c3c --- /dev/null +++ b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/ApiDescriptionExtensions.cs @@ -0,0 +1,39 @@ +using System; +using System.Text; +using System.Web; +using System.Web.Http.Description; + +namespace ResourceTokenBroker.Areas.HelpPage +{ + public static class ApiDescriptionExtensions + { + /// + /// Generates an URI-friendly ID for the . E.g. "Get-Values-id_name" instead of "GetValues/{id}?name={name}" + /// + /// The . + /// The ID as a string. + public static string GetFriendlyId(this ApiDescription description) + { + string path = description.RelativePath; + string[] urlParts = path.Split('?'); + string localPath = urlParts[0]; + string queryKeyString = null; + if (urlParts.Length > 1) + { + string query = urlParts[1]; + string[] queryKeys = HttpUtility.ParseQueryString(query).AllKeys; + queryKeyString = String.Join("_", queryKeys); + } + + StringBuilder friendlyPath = new StringBuilder(); + friendlyPath.AppendFormat("{0}-{1}", + description.HttpMethod.Method, + localPath.Replace("/", "-").Replace("{", String.Empty).Replace("}", String.Empty)); + if (queryKeyString != null) + { + friendlyPath.AppendFormat("_{0}", queryKeyString.Replace('.', '-')); + } + return friendlyPath.ToString(); + } + } +} \ No newline at end of file diff --git a/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/App_Start/HelpPageConfig.cs b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/App_Start/HelpPageConfig.cs new file mode 100755 index 0000000..c34c595 --- /dev/null +++ b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/App_Start/HelpPageConfig.cs @@ -0,0 +1,113 @@ +// Uncomment the following to provide samples for PageResult. Must also add the Microsoft.AspNet.WebApi.OData +// package to your project. +////#define Handle_PageResultOfT + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Net.Http.Headers; +using System.Reflection; +using System.Web; +using System.Web.Http; +#if Handle_PageResultOfT +using System.Web.Http.OData; +#endif + +namespace ResourceTokenBroker.Areas.HelpPage +{ + /// + /// Use this class to customize the Help Page. + /// For example you can set a custom to supply the documentation + /// or you can provide the samples for the requests/responses. + /// + public static class HelpPageConfig + { + [SuppressMessage("Microsoft.Globalization", "CA1303:Do not pass literals as localized parameters", + MessageId = "ResourceTokenBroker.Areas.HelpPage.TextSample.#ctor(System.String)", + Justification = "End users may choose to merge this string with existing localized resources.")] + [SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", + MessageId = "bsonspec", + Justification = "Part of a URI.")] + public static void Register(HttpConfiguration config) + { + //// Uncomment the following to use the documentation from XML documentation file. + //config.SetDocumentationProvider(new XmlDocumentationProvider(HttpContext.Current.Server.MapPath("~/App_Data/XmlDocument.xml"))); + + //// Uncomment the following to use "sample string" as the sample for all actions that have string as the body parameter or return type. + //// Also, the string arrays will be used for IEnumerable. The sample objects will be serialized into different media type + //// formats by the available formatters. + //config.SetSampleObjects(new Dictionary + //{ + // {typeof(string), "sample string"}, + // {typeof(IEnumerable), new string[]{"sample 1", "sample 2"}} + //}); + + // Extend the following to provide factories for types not handled automatically (those lacking parameterless + // constructors) or for which you prefer to use non-default property values. Line below provides a fallback + // since automatic handling will fail and GeneratePageResult handles only a single type. +#if Handle_PageResultOfT + config.GetHelpPageSampleGenerator().SampleObjectFactories.Add(GeneratePageResult); +#endif + + // Extend the following to use a preset object directly as the sample for all actions that support a media + // type, regardless of the body parameter or return type. The lines below avoid display of binary content. + // The BsonMediaTypeFormatter (if available) is not used to serialize the TextSample object. + config.SetSampleForMediaType( + new TextSample("Binary JSON content. See http://bsonspec.org for details."), + new MediaTypeHeaderValue("application/bson")); + + //// Uncomment the following to use "[0]=foo&[1]=bar" directly as the sample for all actions that support form URL encoded format + //// and have IEnumerable as the body parameter or return type. + //config.SetSampleForType("[0]=foo&[1]=bar", new MediaTypeHeaderValue("application/x-www-form-urlencoded"), typeof(IEnumerable)); + + //// Uncomment the following to use "1234" directly as the request sample for media type "text/plain" on the controller named "Values" + //// and action named "Put". + //config.SetSampleRequest("1234", new MediaTypeHeaderValue("text/plain"), "Values", "Put"); + + //// Uncomment the following to use the image on "../images/aspNetHome.png" directly as the response sample for media type "image/png" + //// on the controller named "Values" and action named "Get" with parameter "id". + //config.SetSampleResponse(new ImageSample("../images/aspNetHome.png"), new MediaTypeHeaderValue("image/png"), "Values", "Get", "id"); + + //// Uncomment the following to correct the sample request when the action expects an HttpRequestMessage with ObjectContent. + //// The sample will be generated as if the controller named "Values" and action named "Get" were having string as the body parameter. + //config.SetActualRequestType(typeof(string), "Values", "Get"); + + //// Uncomment the following to correct the sample response when the action returns an HttpResponseMessage with ObjectContent. + //// The sample will be generated as if the controller named "Values" and action named "Post" were returning a string. + //config.SetActualResponseType(typeof(string), "Values", "Post"); + } + +#if Handle_PageResultOfT + private static object GeneratePageResult(HelpPageSampleGenerator sampleGenerator, Type type) + { + if (type.IsGenericType) + { + Type openGenericType = type.GetGenericTypeDefinition(); + if (openGenericType == typeof(PageResult<>)) + { + // Get the T in PageResult + Type[] typeParameters = type.GetGenericArguments(); + Debug.Assert(typeParameters.Length == 1); + + // Create an enumeration to pass as the first parameter to the PageResult constuctor + Type itemsType = typeof(List<>).MakeGenericType(typeParameters); + object items = sampleGenerator.GetSampleObject(itemsType); + + // Fill in the other information needed to invoke the PageResult constuctor + Type[] parameterTypes = new Type[] { itemsType, typeof(Uri), typeof(long?), }; + object[] parameters = new object[] { items, null, (long)ObjectGenerator.DefaultCollectionSize, }; + + // Call PageResult(IEnumerable items, Uri nextPageLink, long? count) constructor + ConstructorInfo constructor = type.GetConstructor(parameterTypes); + return constructor.Invoke(parameters); + } + } + + return null; + } +#endif + } +} \ No newline at end of file diff --git a/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/Controllers/HelpController.cs b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/Controllers/HelpController.cs new file mode 100755 index 0000000..aa29f54 --- /dev/null +++ b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/Controllers/HelpController.cs @@ -0,0 +1,63 @@ +using System; +using System.Web.Http; +using System.Web.Mvc; +using ResourceTokenBroker.Areas.HelpPage.ModelDescriptions; +using ResourceTokenBroker.Areas.HelpPage.Models; + +namespace ResourceTokenBroker.Areas.HelpPage.Controllers +{ + /// + /// The controller that will handle requests for the help page. + /// + public class HelpController : Controller + { + private const string ErrorViewName = "Error"; + + public HelpController() + : this(GlobalConfiguration.Configuration) + { + } + + public HelpController(HttpConfiguration config) + { + Configuration = config; + } + + public HttpConfiguration Configuration { get; private set; } + + public ActionResult Index() + { + ViewBag.DocumentationProvider = Configuration.Services.GetDocumentationProvider(); + return View(Configuration.Services.GetApiExplorer().ApiDescriptions); + } + + public ActionResult Api(string apiId) + { + if (!String.IsNullOrEmpty(apiId)) + { + HelpPageApiModel apiModel = Configuration.GetHelpPageApiModel(apiId); + if (apiModel != null) + { + return View(apiModel); + } + } + + return View(ErrorViewName); + } + + public ActionResult ResourceModel(string modelName) + { + if (!String.IsNullOrEmpty(modelName)) + { + ModelDescriptionGenerator modelDescriptionGenerator = Configuration.GetModelDescriptionGenerator(); + ModelDescription modelDescription; + if (modelDescriptionGenerator.GeneratedModels.TryGetValue(modelName, out modelDescription)) + { + return View(modelDescription); + } + } + + return View(ErrorViewName); + } + } +} \ No newline at end of file diff --git a/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/HelpPage.css b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/HelpPage.css new file mode 100755 index 0000000..aff2230 --- /dev/null +++ b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/HelpPage.css @@ -0,0 +1,134 @@ +.help-page h1, +.help-page .h1, +.help-page h2, +.help-page .h2, +.help-page h3, +.help-page .h3, +#body.help-page, +.help-page-table th, +.help-page-table pre, +.help-page-table p { + font-family: "Segoe UI Light", Frutiger, "Frutiger Linotype", "Dejavu Sans", "Helvetica Neue", Arial, sans-serif; +} + +.help-page pre.wrapped { + white-space: -moz-pre-wrap; + white-space: -pre-wrap; + white-space: -o-pre-wrap; + white-space: pre-wrap; +} + +.help-page .warning-message-container { + margin-top: 20px; + padding: 0 10px; + color: #525252; + background: #EFDCA9; + border: 1px solid #CCCCCC; +} + +.help-page-table { + width: 100%; + border-collapse: collapse; + text-align: left; + margin: 0px 0px 20px 0px; + border-top: 1px solid #D4D4D4; +} + +.help-page-table th { + text-align: left; + font-weight: bold; + border-bottom: 1px solid #D4D4D4; + padding: 5px 6px 5px 6px; +} + +.help-page-table td { + border-bottom: 1px solid #D4D4D4; + padding: 10px 8px 10px 8px; + vertical-align: top; +} + +.help-page-table pre, +.help-page-table p { + margin: 0px; + padding: 0px; + font-family: inherit; + font-size: 100%; +} + +.help-page-table tbody tr:hover td { + background-color: #F3F3F3; +} + +.help-page a:hover { + background-color: transparent; +} + +.help-page .sample-header { + border: 2px solid #D4D4D4; + background: #00497E; + color: #FFFFFF; + padding: 8px 15px; + border-bottom: none; + display: inline-block; + margin: 10px 0px 0px 0px; +} + +.help-page .sample-content { + display: block; + border-width: 0; + padding: 15px 20px; + background: #FFFFFF; + border: 2px solid #D4D4D4; + margin: 0px 0px 10px 0px; +} + +.help-page .api-name { + width: 40%; +} + +.help-page .api-documentation { + width: 60%; +} + +.help-page .parameter-name { + width: 20%; +} + +.help-page .parameter-documentation { + width: 40%; +} + +.help-page .parameter-type { + width: 20%; +} + +.help-page .parameter-annotations { + width: 20%; +} + +.help-page h1, +.help-page .h1 { + font-size: 36px; + line-height: normal; +} + +.help-page h2, +.help-page .h2 { + font-size: 24px; +} + +.help-page h3, +.help-page .h3 { + font-size: 20px; +} + +#body.help-page { + font-size: 14px; + line-height: 143%; + color: #333; +} + +.help-page a { + color: #0000EE; + text-decoration: none; +} diff --git a/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/HelpPageAreaRegistration.cs b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/HelpPageAreaRegistration.cs new file mode 100755 index 0000000..b558b00 --- /dev/null +++ b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/HelpPageAreaRegistration.cs @@ -0,0 +1,26 @@ +using System.Web.Http; +using System.Web.Mvc; + +namespace ResourceTokenBroker.Areas.HelpPage +{ + public class HelpPageAreaRegistration : AreaRegistration + { + public override string AreaName + { + get + { + return "HelpPage"; + } + } + + public override void RegisterArea(AreaRegistrationContext context) + { + context.MapRoute( + "HelpPage_Default", + "Help/{action}/{apiId}", + new { controller = "Help", action = "Index", apiId = UrlParameter.Optional }); + + HelpPageConfig.Register(GlobalConfiguration.Configuration); + } + } +} \ No newline at end of file diff --git a/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/HelpPageConfigurationExtensions.cs b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/HelpPageConfigurationExtensions.cs new file mode 100755 index 0000000..09cf2da --- /dev/null +++ b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/HelpPageConfigurationExtensions.cs @@ -0,0 +1,467 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.ComponentModel; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Globalization; +using System.Linq; +using System.Net.Http; +using System.Net.Http.Headers; +using System.Web.Http; +using System.Web.Http.Controllers; +using System.Web.Http.Description; +using ResourceTokenBroker.Areas.HelpPage.ModelDescriptions; +using ResourceTokenBroker.Areas.HelpPage.Models; + +namespace ResourceTokenBroker.Areas.HelpPage +{ + public static class HelpPageConfigurationExtensions + { + private const string ApiModelPrefix = "MS_HelpPageApiModel_"; + + /// + /// Sets the documentation provider for help page. + /// + /// The . + /// The documentation provider. + public static void SetDocumentationProvider(this HttpConfiguration config, IDocumentationProvider documentationProvider) + { + config.Services.Replace(typeof(IDocumentationProvider), documentationProvider); + } + + /// + /// Sets the objects that will be used by the formatters to produce sample requests/responses. + /// + /// The . + /// The sample objects. + public static void SetSampleObjects(this HttpConfiguration config, IDictionary sampleObjects) + { + config.GetHelpPageSampleGenerator().SampleObjects = sampleObjects; + } + + /// + /// Sets the sample request directly for the specified media type and action. + /// + /// The . + /// The sample request. + /// The media type. + /// Name of the controller. + /// Name of the action. + public static void SetSampleRequest(this HttpConfiguration config, object sample, MediaTypeHeaderValue mediaType, string controllerName, string actionName) + { + config.GetHelpPageSampleGenerator().ActionSamples.Add(new HelpPageSampleKey(mediaType, SampleDirection.Request, controllerName, actionName, new[] { "*" }), sample); + } + + /// + /// Sets the sample request directly for the specified media type and action with parameters. + /// + /// The . + /// The sample request. + /// The media type. + /// Name of the controller. + /// Name of the action. + /// The parameter names. + public static void SetSampleRequest(this HttpConfiguration config, object sample, MediaTypeHeaderValue mediaType, string controllerName, string actionName, params string[] parameterNames) + { + config.GetHelpPageSampleGenerator().ActionSamples.Add(new HelpPageSampleKey(mediaType, SampleDirection.Request, controllerName, actionName, parameterNames), sample); + } + + /// + /// Sets the sample request directly for the specified media type of the action. + /// + /// The . + /// The sample response. + /// The media type. + /// Name of the controller. + /// Name of the action. + public static void SetSampleResponse(this HttpConfiguration config, object sample, MediaTypeHeaderValue mediaType, string controllerName, string actionName) + { + config.GetHelpPageSampleGenerator().ActionSamples.Add(new HelpPageSampleKey(mediaType, SampleDirection.Response, controllerName, actionName, new[] { "*" }), sample); + } + + /// + /// Sets the sample response directly for the specified media type of the action with specific parameters. + /// + /// The . + /// The sample response. + /// The media type. + /// Name of the controller. + /// Name of the action. + /// The parameter names. + public static void SetSampleResponse(this HttpConfiguration config, object sample, MediaTypeHeaderValue mediaType, string controllerName, string actionName, params string[] parameterNames) + { + config.GetHelpPageSampleGenerator().ActionSamples.Add(new HelpPageSampleKey(mediaType, SampleDirection.Response, controllerName, actionName, parameterNames), sample); + } + + /// + /// Sets the sample directly for all actions with the specified media type. + /// + /// The . + /// The sample. + /// The media type. + public static void SetSampleForMediaType(this HttpConfiguration config, object sample, MediaTypeHeaderValue mediaType) + { + config.GetHelpPageSampleGenerator().ActionSamples.Add(new HelpPageSampleKey(mediaType), sample); + } + + /// + /// Sets the sample directly for all actions with the specified type and media type. + /// + /// The . + /// The sample. + /// The media type. + /// The parameter type or return type of an action. + public static void SetSampleForType(this HttpConfiguration config, object sample, MediaTypeHeaderValue mediaType, Type type) + { + config.GetHelpPageSampleGenerator().ActionSamples.Add(new HelpPageSampleKey(mediaType, type), sample); + } + + /// + /// Specifies the actual type of passed to the in an action. + /// The help page will use this information to produce more accurate request samples. + /// + /// The . + /// The type. + /// Name of the controller. + /// Name of the action. + public static void SetActualRequestType(this HttpConfiguration config, Type type, string controllerName, string actionName) + { + config.GetHelpPageSampleGenerator().ActualHttpMessageTypes.Add(new HelpPageSampleKey(SampleDirection.Request, controllerName, actionName, new[] { "*" }), type); + } + + /// + /// Specifies the actual type of passed to the in an action. + /// The help page will use this information to produce more accurate request samples. + /// + /// The . + /// The type. + /// Name of the controller. + /// Name of the action. + /// The parameter names. + public static void SetActualRequestType(this HttpConfiguration config, Type type, string controllerName, string actionName, params string[] parameterNames) + { + config.GetHelpPageSampleGenerator().ActualHttpMessageTypes.Add(new HelpPageSampleKey(SampleDirection.Request, controllerName, actionName, parameterNames), type); + } + + /// + /// Specifies the actual type of returned as part of the in an action. + /// The help page will use this information to produce more accurate response samples. + /// + /// The . + /// The type. + /// Name of the controller. + /// Name of the action. + public static void SetActualResponseType(this HttpConfiguration config, Type type, string controllerName, string actionName) + { + config.GetHelpPageSampleGenerator().ActualHttpMessageTypes.Add(new HelpPageSampleKey(SampleDirection.Response, controllerName, actionName, new[] { "*" }), type); + } + + /// + /// Specifies the actual type of returned as part of the in an action. + /// The help page will use this information to produce more accurate response samples. + /// + /// The . + /// The type. + /// Name of the controller. + /// Name of the action. + /// The parameter names. + public static void SetActualResponseType(this HttpConfiguration config, Type type, string controllerName, string actionName, params string[] parameterNames) + { + config.GetHelpPageSampleGenerator().ActualHttpMessageTypes.Add(new HelpPageSampleKey(SampleDirection.Response, controllerName, actionName, parameterNames), type); + } + + /// + /// Gets the help page sample generator. + /// + /// The . + /// The help page sample generator. + public static HelpPageSampleGenerator GetHelpPageSampleGenerator(this HttpConfiguration config) + { + return (HelpPageSampleGenerator)config.Properties.GetOrAdd( + typeof(HelpPageSampleGenerator), + k => new HelpPageSampleGenerator()); + } + + /// + /// Sets the help page sample generator. + /// + /// The . + /// The help page sample generator. + public static void SetHelpPageSampleGenerator(this HttpConfiguration config, HelpPageSampleGenerator sampleGenerator) + { + config.Properties.AddOrUpdate( + typeof(HelpPageSampleGenerator), + k => sampleGenerator, + (k, o) => sampleGenerator); + } + + /// + /// Gets the model description generator. + /// + /// The configuration. + /// The + public static ModelDescriptionGenerator GetModelDescriptionGenerator(this HttpConfiguration config) + { + return (ModelDescriptionGenerator)config.Properties.GetOrAdd( + typeof(ModelDescriptionGenerator), + k => InitializeModelDescriptionGenerator(config)); + } + + /// + /// Gets the model that represents an API displayed on the help page. The model is initialized on the first call and cached for subsequent calls. + /// + /// The . + /// The ID. + /// + /// An + /// + public static HelpPageApiModel GetHelpPageApiModel(this HttpConfiguration config, string apiDescriptionId) + { + object model; + string modelId = ApiModelPrefix + apiDescriptionId; + if (!config.Properties.TryGetValue(modelId, out model)) + { + Collection apiDescriptions = config.Services.GetApiExplorer().ApiDescriptions; + ApiDescription apiDescription = apiDescriptions.FirstOrDefault(api => String.Equals(api.GetFriendlyId(), apiDescriptionId, StringComparison.OrdinalIgnoreCase)); + if (apiDescription != null) + { + model = GenerateApiModel(apiDescription, config); + config.Properties.TryAdd(modelId, model); + } + } + + return (HelpPageApiModel)model; + } + + private static HelpPageApiModel GenerateApiModel(ApiDescription apiDescription, HttpConfiguration config) + { + HelpPageApiModel apiModel = new HelpPageApiModel() + { + ApiDescription = apiDescription, + }; + + ModelDescriptionGenerator modelGenerator = config.GetModelDescriptionGenerator(); + HelpPageSampleGenerator sampleGenerator = config.GetHelpPageSampleGenerator(); + GenerateUriParameters(apiModel, modelGenerator); + GenerateRequestModelDescription(apiModel, modelGenerator, sampleGenerator); + GenerateResourceDescription(apiModel, modelGenerator); + GenerateSamples(apiModel, sampleGenerator); + + return apiModel; + } + + private static void GenerateUriParameters(HelpPageApiModel apiModel, ModelDescriptionGenerator modelGenerator) + { + ApiDescription apiDescription = apiModel.ApiDescription; + foreach (ApiParameterDescription apiParameter in apiDescription.ParameterDescriptions) + { + if (apiParameter.Source == ApiParameterSource.FromUri) + { + HttpParameterDescriptor parameterDescriptor = apiParameter.ParameterDescriptor; + Type parameterType = null; + ModelDescription typeDescription = null; + ComplexTypeModelDescription complexTypeDescription = null; + if (parameterDescriptor != null) + { + parameterType = parameterDescriptor.ParameterType; + typeDescription = modelGenerator.GetOrCreateModelDescription(parameterType); + complexTypeDescription = typeDescription as ComplexTypeModelDescription; + } + + // Example: + // [TypeConverter(typeof(PointConverter))] + // public class Point + // { + // public Point(int x, int y) + // { + // X = x; + // Y = y; + // } + // public int X { get; set; } + // public int Y { get; set; } + // } + // Class Point is bindable with a TypeConverter, so Point will be added to UriParameters collection. + // + // public class Point + // { + // public int X { get; set; } + // public int Y { get; set; } + // } + // Regular complex class Point will have properties X and Y added to UriParameters collection. + if (complexTypeDescription != null + && !IsBindableWithTypeConverter(parameterType)) + { + foreach (ParameterDescription uriParameter in complexTypeDescription.Properties) + { + apiModel.UriParameters.Add(uriParameter); + } + } + else if (parameterDescriptor != null) + { + ParameterDescription uriParameter = + AddParameterDescription(apiModel, apiParameter, typeDescription); + + if (!parameterDescriptor.IsOptional) + { + uriParameter.Annotations.Add(new ParameterAnnotation() { Documentation = "Required" }); + } + + object defaultValue = parameterDescriptor.DefaultValue; + if (defaultValue != null) + { + uriParameter.Annotations.Add(new ParameterAnnotation() { Documentation = "Default value is " + Convert.ToString(defaultValue, CultureInfo.InvariantCulture) }); + } + } + else + { + Debug.Assert(parameterDescriptor == null); + + // If parameterDescriptor is null, this is an undeclared route parameter which only occurs + // when source is FromUri. Ignored in request model and among resource parameters but listed + // as a simple string here. + ModelDescription modelDescription = modelGenerator.GetOrCreateModelDescription(typeof(string)); + AddParameterDescription(apiModel, apiParameter, modelDescription); + } + } + } + } + + private static bool IsBindableWithTypeConverter(Type parameterType) + { + if (parameterType == null) + { + return false; + } + + return TypeDescriptor.GetConverter(parameterType).CanConvertFrom(typeof(string)); + } + + private static ParameterDescription AddParameterDescription(HelpPageApiModel apiModel, + ApiParameterDescription apiParameter, ModelDescription typeDescription) + { + ParameterDescription parameterDescription = new ParameterDescription + { + Name = apiParameter.Name, + Documentation = apiParameter.Documentation, + TypeDescription = typeDescription, + }; + + apiModel.UriParameters.Add(parameterDescription); + return parameterDescription; + } + + private static void GenerateRequestModelDescription(HelpPageApiModel apiModel, ModelDescriptionGenerator modelGenerator, HelpPageSampleGenerator sampleGenerator) + { + ApiDescription apiDescription = apiModel.ApiDescription; + foreach (ApiParameterDescription apiParameter in apiDescription.ParameterDescriptions) + { + if (apiParameter.Source == ApiParameterSource.FromBody) + { + Type parameterType = apiParameter.ParameterDescriptor.ParameterType; + apiModel.RequestModelDescription = modelGenerator.GetOrCreateModelDescription(parameterType); + apiModel.RequestDocumentation = apiParameter.Documentation; + } + else if (apiParameter.ParameterDescriptor != null && + apiParameter.ParameterDescriptor.ParameterType == typeof(HttpRequestMessage)) + { + Type parameterType = sampleGenerator.ResolveHttpRequestMessageType(apiDescription); + + if (parameterType != null) + { + apiModel.RequestModelDescription = modelGenerator.GetOrCreateModelDescription(parameterType); + } + } + } + } + + private static void GenerateResourceDescription(HelpPageApiModel apiModel, ModelDescriptionGenerator modelGenerator) + { + ResponseDescription response = apiModel.ApiDescription.ResponseDescription; + Type responseType = response.ResponseType ?? response.DeclaredType; + if (responseType != null && responseType != typeof(void)) + { + apiModel.ResourceDescription = modelGenerator.GetOrCreateModelDescription(responseType); + } + } + + [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "The exception is recorded as ErrorMessages.")] + private static void GenerateSamples(HelpPageApiModel apiModel, HelpPageSampleGenerator sampleGenerator) + { + try + { + foreach (var item in sampleGenerator.GetSampleRequests(apiModel.ApiDescription)) + { + apiModel.SampleRequests.Add(item.Key, item.Value); + LogInvalidSampleAsError(apiModel, item.Value); + } + + foreach (var item in sampleGenerator.GetSampleResponses(apiModel.ApiDescription)) + { + apiModel.SampleResponses.Add(item.Key, item.Value); + LogInvalidSampleAsError(apiModel, item.Value); + } + } + catch (Exception e) + { + apiModel.ErrorMessages.Add(String.Format(CultureInfo.CurrentCulture, + "An exception has occurred while generating the sample. Exception message: {0}", + HelpPageSampleGenerator.UnwrapException(e).Message)); + } + } + + private static bool TryGetResourceParameter(ApiDescription apiDescription, HttpConfiguration config, out ApiParameterDescription parameterDescription, out Type resourceType) + { + parameterDescription = apiDescription.ParameterDescriptions.FirstOrDefault( + p => p.Source == ApiParameterSource.FromBody || + (p.ParameterDescriptor != null && p.ParameterDescriptor.ParameterType == typeof(HttpRequestMessage))); + + if (parameterDescription == null) + { + resourceType = null; + return false; + } + + resourceType = parameterDescription.ParameterDescriptor.ParameterType; + + if (resourceType == typeof(HttpRequestMessage)) + { + HelpPageSampleGenerator sampleGenerator = config.GetHelpPageSampleGenerator(); + resourceType = sampleGenerator.ResolveHttpRequestMessageType(apiDescription); + } + + if (resourceType == null) + { + parameterDescription = null; + return false; + } + + return true; + } + + private static ModelDescriptionGenerator InitializeModelDescriptionGenerator(HttpConfiguration config) + { + ModelDescriptionGenerator modelGenerator = new ModelDescriptionGenerator(config); + Collection apis = config.Services.GetApiExplorer().ApiDescriptions; + foreach (ApiDescription api in apis) + { + ApiParameterDescription parameterDescription; + Type parameterType; + if (TryGetResourceParameter(api, config, out parameterDescription, out parameterType)) + { + modelGenerator.GetOrCreateModelDescription(parameterType); + } + } + return modelGenerator; + } + + private static void LogInvalidSampleAsError(HelpPageApiModel apiModel, object sample) + { + InvalidSample invalidSample = sample as InvalidSample; + if (invalidSample != null) + { + apiModel.ErrorMessages.Add(invalidSample.ErrorMessage); + } + } + } +} diff --git a/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/ModelDescriptions/CollectionModelDescription.cs b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/ModelDescriptions/CollectionModelDescription.cs new file mode 100755 index 0000000..1494555 --- /dev/null +++ b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/ModelDescriptions/CollectionModelDescription.cs @@ -0,0 +1,7 @@ +namespace ResourceTokenBroker.Areas.HelpPage.ModelDescriptions +{ + public class CollectionModelDescription : ModelDescription + { + public ModelDescription ElementDescription { get; set; } + } +} \ No newline at end of file diff --git a/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/ModelDescriptions/ComplexTypeModelDescription.cs b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/ModelDescriptions/ComplexTypeModelDescription.cs new file mode 100755 index 0000000..f17aec6 --- /dev/null +++ b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/ModelDescriptions/ComplexTypeModelDescription.cs @@ -0,0 +1,14 @@ +using System.Collections.ObjectModel; + +namespace ResourceTokenBroker.Areas.HelpPage.ModelDescriptions +{ + public class ComplexTypeModelDescription : ModelDescription + { + public ComplexTypeModelDescription() + { + Properties = new Collection(); + } + + public Collection Properties { get; private set; } + } +} \ No newline at end of file diff --git a/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/ModelDescriptions/DictionaryModelDescription.cs b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/ModelDescriptions/DictionaryModelDescription.cs new file mode 100755 index 0000000..95504df --- /dev/null +++ b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/ModelDescriptions/DictionaryModelDescription.cs @@ -0,0 +1,6 @@ +namespace ResourceTokenBroker.Areas.HelpPage.ModelDescriptions +{ + public class DictionaryModelDescription : KeyValuePairModelDescription + { + } +} \ No newline at end of file diff --git a/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/ModelDescriptions/EnumTypeModelDescription.cs b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/ModelDescriptions/EnumTypeModelDescription.cs new file mode 100755 index 0000000..9cdb644 --- /dev/null +++ b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/ModelDescriptions/EnumTypeModelDescription.cs @@ -0,0 +1,15 @@ +using System.Collections.Generic; +using System.Collections.ObjectModel; + +namespace ResourceTokenBroker.Areas.HelpPage.ModelDescriptions +{ + public class EnumTypeModelDescription : ModelDescription + { + public EnumTypeModelDescription() + { + Values = new Collection(); + } + + public Collection Values { get; private set; } + } +} \ No newline at end of file diff --git a/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/ModelDescriptions/EnumValueDescription.cs b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/ModelDescriptions/EnumValueDescription.cs new file mode 100755 index 0000000..cc0051b --- /dev/null +++ b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/ModelDescriptions/EnumValueDescription.cs @@ -0,0 +1,11 @@ +namespace ResourceTokenBroker.Areas.HelpPage.ModelDescriptions +{ + public class EnumValueDescription + { + public string Documentation { get; set; } + + public string Name { get; set; } + + public string Value { get; set; } + } +} \ No newline at end of file diff --git a/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/ModelDescriptions/IModelDocumentationProvider.cs b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/ModelDescriptions/IModelDocumentationProvider.cs new file mode 100755 index 0000000..d7ddfa0 --- /dev/null +++ b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/ModelDescriptions/IModelDocumentationProvider.cs @@ -0,0 +1,12 @@ +using System; +using System.Reflection; + +namespace ResourceTokenBroker.Areas.HelpPage.ModelDescriptions +{ + public interface IModelDocumentationProvider + { + string GetDocumentation(MemberInfo member); + + string GetDocumentation(Type type); + } +} \ No newline at end of file diff --git a/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/ModelDescriptions/KeyValuePairModelDescription.cs b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/ModelDescriptions/KeyValuePairModelDescription.cs new file mode 100755 index 0000000..b638af5 --- /dev/null +++ b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/ModelDescriptions/KeyValuePairModelDescription.cs @@ -0,0 +1,9 @@ +namespace ResourceTokenBroker.Areas.HelpPage.ModelDescriptions +{ + public class KeyValuePairModelDescription : ModelDescription + { + public ModelDescription KeyModelDescription { get; set; } + + public ModelDescription ValueModelDescription { get; set; } + } +} \ No newline at end of file diff --git a/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/ModelDescriptions/ModelDescription.cs b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/ModelDescriptions/ModelDescription.cs new file mode 100755 index 0000000..dc80c64 --- /dev/null +++ b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/ModelDescriptions/ModelDescription.cs @@ -0,0 +1,16 @@ +using System; + +namespace ResourceTokenBroker.Areas.HelpPage.ModelDescriptions +{ + /// + /// Describes a type model. + /// + public abstract class ModelDescription + { + public string Documentation { get; set; } + + public Type ModelType { get; set; } + + public string Name { get; set; } + } +} \ No newline at end of file diff --git a/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/ModelDescriptions/ModelDescriptionGenerator.cs b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/ModelDescriptions/ModelDescriptionGenerator.cs new file mode 100755 index 0000000..469a240 --- /dev/null +++ b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/ModelDescriptions/ModelDescriptionGenerator.cs @@ -0,0 +1,451 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.ComponentModel.DataAnnotations; +using System.Globalization; +using System.Reflection; +using System.Runtime.Serialization; +using System.Web.Http; +using System.Web.Http.Description; +using System.Xml.Serialization; +using Newtonsoft.Json; + +namespace ResourceTokenBroker.Areas.HelpPage.ModelDescriptions +{ + /// + /// Generates model descriptions for given types. + /// + public class ModelDescriptionGenerator + { + // Modify this to support more data annotation attributes. + private readonly IDictionary> AnnotationTextGenerator = new Dictionary> + { + { typeof(RequiredAttribute), a => "Required" }, + { typeof(RangeAttribute), a => + { + RangeAttribute range = (RangeAttribute)a; + return String.Format(CultureInfo.CurrentCulture, "Range: inclusive between {0} and {1}", range.Minimum, range.Maximum); + } + }, + { typeof(MaxLengthAttribute), a => + { + MaxLengthAttribute maxLength = (MaxLengthAttribute)a; + return String.Format(CultureInfo.CurrentCulture, "Max length: {0}", maxLength.Length); + } + }, + { typeof(MinLengthAttribute), a => + { + MinLengthAttribute minLength = (MinLengthAttribute)a; + return String.Format(CultureInfo.CurrentCulture, "Min length: {0}", minLength.Length); + } + }, + { typeof(StringLengthAttribute), a => + { + StringLengthAttribute strLength = (StringLengthAttribute)a; + return String.Format(CultureInfo.CurrentCulture, "String length: inclusive between {0} and {1}", strLength.MinimumLength, strLength.MaximumLength); + } + }, + { typeof(DataTypeAttribute), a => + { + DataTypeAttribute dataType = (DataTypeAttribute)a; + return String.Format(CultureInfo.CurrentCulture, "Data type: {0}", dataType.CustomDataType ?? dataType.DataType.ToString()); + } + }, + { typeof(RegularExpressionAttribute), a => + { + RegularExpressionAttribute regularExpression = (RegularExpressionAttribute)a; + return String.Format(CultureInfo.CurrentCulture, "Matching regular expression pattern: {0}", regularExpression.Pattern); + } + }, + }; + + // Modify this to add more default documentations. + private readonly IDictionary DefaultTypeDocumentation = new Dictionary + { + { typeof(Int16), "integer" }, + { typeof(Int32), "integer" }, + { typeof(Int64), "integer" }, + { typeof(UInt16), "unsigned integer" }, + { typeof(UInt32), "unsigned integer" }, + { typeof(UInt64), "unsigned integer" }, + { typeof(Byte), "byte" }, + { typeof(Char), "character" }, + { typeof(SByte), "signed byte" }, + { typeof(Uri), "URI" }, + { typeof(Single), "decimal number" }, + { typeof(Double), "decimal number" }, + { typeof(Decimal), "decimal number" }, + { typeof(String), "string" }, + { typeof(Guid), "globally unique identifier" }, + { typeof(TimeSpan), "time interval" }, + { typeof(DateTime), "date" }, + { typeof(DateTimeOffset), "date" }, + { typeof(Boolean), "boolean" }, + }; + + private Lazy _documentationProvider; + + public ModelDescriptionGenerator(HttpConfiguration config) + { + if (config == null) + { + throw new ArgumentNullException("config"); + } + + _documentationProvider = new Lazy(() => config.Services.GetDocumentationProvider() as IModelDocumentationProvider); + GeneratedModels = new Dictionary(StringComparer.OrdinalIgnoreCase); + } + + public Dictionary GeneratedModels { get; private set; } + + private IModelDocumentationProvider DocumentationProvider + { + get + { + return _documentationProvider.Value; + } + } + + public ModelDescription GetOrCreateModelDescription(Type modelType) + { + if (modelType == null) + { + throw new ArgumentNullException("modelType"); + } + + Type underlyingType = Nullable.GetUnderlyingType(modelType); + if (underlyingType != null) + { + modelType = underlyingType; + } + + ModelDescription modelDescription; + string modelName = ModelNameHelper.GetModelName(modelType); + if (GeneratedModels.TryGetValue(modelName, out modelDescription)) + { + if (modelType != modelDescription.ModelType) + { + throw new InvalidOperationException( + String.Format( + CultureInfo.CurrentCulture, + "A model description could not be created. Duplicate model name '{0}' was found for types '{1}' and '{2}'. " + + "Use the [ModelName] attribute to change the model name for at least one of the types so that it has a unique name.", + modelName, + modelDescription.ModelType.FullName, + modelType.FullName)); + } + + return modelDescription; + } + + if (DefaultTypeDocumentation.ContainsKey(modelType)) + { + return GenerateSimpleTypeModelDescription(modelType); + } + + if (modelType.IsEnum) + { + return GenerateEnumTypeModelDescription(modelType); + } + + if (modelType.IsGenericType) + { + Type[] genericArguments = modelType.GetGenericArguments(); + + if (genericArguments.Length == 1) + { + Type enumerableType = typeof(IEnumerable<>).MakeGenericType(genericArguments); + if (enumerableType.IsAssignableFrom(modelType)) + { + return GenerateCollectionModelDescription(modelType, genericArguments[0]); + } + } + if (genericArguments.Length == 2) + { + Type dictionaryType = typeof(IDictionary<,>).MakeGenericType(genericArguments); + if (dictionaryType.IsAssignableFrom(modelType)) + { + return GenerateDictionaryModelDescription(modelType, genericArguments[0], genericArguments[1]); + } + + Type keyValuePairType = typeof(KeyValuePair<,>).MakeGenericType(genericArguments); + if (keyValuePairType.IsAssignableFrom(modelType)) + { + return GenerateKeyValuePairModelDescription(modelType, genericArguments[0], genericArguments[1]); + } + } + } + + if (modelType.IsArray) + { + Type elementType = modelType.GetElementType(); + return GenerateCollectionModelDescription(modelType, elementType); + } + + if (modelType == typeof(NameValueCollection)) + { + return GenerateDictionaryModelDescription(modelType, typeof(string), typeof(string)); + } + + if (typeof(IDictionary).IsAssignableFrom(modelType)) + { + return GenerateDictionaryModelDescription(modelType, typeof(object), typeof(object)); + } + + if (typeof(IEnumerable).IsAssignableFrom(modelType)) + { + return GenerateCollectionModelDescription(modelType, typeof(object)); + } + + return GenerateComplexTypeModelDescription(modelType); + } + + // Change this to provide different name for the member. + private static string GetMemberName(MemberInfo member, bool hasDataContractAttribute) + { + JsonPropertyAttribute jsonProperty = member.GetCustomAttribute(); + if (jsonProperty != null && !String.IsNullOrEmpty(jsonProperty.PropertyName)) + { + return jsonProperty.PropertyName; + } + + if (hasDataContractAttribute) + { + DataMemberAttribute dataMember = member.GetCustomAttribute(); + if (dataMember != null && !String.IsNullOrEmpty(dataMember.Name)) + { + return dataMember.Name; + } + } + + return member.Name; + } + + private static bool ShouldDisplayMember(MemberInfo member, bool hasDataContractAttribute) + { + JsonIgnoreAttribute jsonIgnore = member.GetCustomAttribute(); + XmlIgnoreAttribute xmlIgnore = member.GetCustomAttribute(); + IgnoreDataMemberAttribute ignoreDataMember = member.GetCustomAttribute(); + NonSerializedAttribute nonSerialized = member.GetCustomAttribute(); + ApiExplorerSettingsAttribute apiExplorerSetting = member.GetCustomAttribute(); + + bool hasMemberAttribute = member.DeclaringType.IsEnum ? + member.GetCustomAttribute() != null : + member.GetCustomAttribute() != null; + + // Display member only if all the followings are true: + // no JsonIgnoreAttribute + // no XmlIgnoreAttribute + // no IgnoreDataMemberAttribute + // no NonSerializedAttribute + // no ApiExplorerSettingsAttribute with IgnoreApi set to true + // no DataContractAttribute without DataMemberAttribute or EnumMemberAttribute + return jsonIgnore == null && + xmlIgnore == null && + ignoreDataMember == null && + nonSerialized == null && + (apiExplorerSetting == null || !apiExplorerSetting.IgnoreApi) && + (!hasDataContractAttribute || hasMemberAttribute); + } + + private string CreateDefaultDocumentation(Type type) + { + string documentation; + if (DefaultTypeDocumentation.TryGetValue(type, out documentation)) + { + return documentation; + } + if (DocumentationProvider != null) + { + documentation = DocumentationProvider.GetDocumentation(type); + } + + return documentation; + } + + private void GenerateAnnotations(MemberInfo property, ParameterDescription propertyModel) + { + List annotations = new List(); + + IEnumerable attributes = property.GetCustomAttributes(); + foreach (Attribute attribute in attributes) + { + Func textGenerator; + if (AnnotationTextGenerator.TryGetValue(attribute.GetType(), out textGenerator)) + { + annotations.Add( + new ParameterAnnotation + { + AnnotationAttribute = attribute, + Documentation = textGenerator(attribute) + }); + } + } + + // Rearrange the annotations + annotations.Sort((x, y) => + { + // Special-case RequiredAttribute so that it shows up on top + if (x.AnnotationAttribute is RequiredAttribute) + { + return -1; + } + if (y.AnnotationAttribute is RequiredAttribute) + { + return 1; + } + + // Sort the rest based on alphabetic order of the documentation + return String.Compare(x.Documentation, y.Documentation, StringComparison.OrdinalIgnoreCase); + }); + + foreach (ParameterAnnotation annotation in annotations) + { + propertyModel.Annotations.Add(annotation); + } + } + + private CollectionModelDescription GenerateCollectionModelDescription(Type modelType, Type elementType) + { + ModelDescription collectionModelDescription = GetOrCreateModelDescription(elementType); + if (collectionModelDescription != null) + { + return new CollectionModelDescription + { + Name = ModelNameHelper.GetModelName(modelType), + ModelType = modelType, + ElementDescription = collectionModelDescription + }; + } + + return null; + } + + private ModelDescription GenerateComplexTypeModelDescription(Type modelType) + { + ComplexTypeModelDescription complexModelDescription = new ComplexTypeModelDescription + { + Name = ModelNameHelper.GetModelName(modelType), + ModelType = modelType, + Documentation = CreateDefaultDocumentation(modelType) + }; + + GeneratedModels.Add(complexModelDescription.Name, complexModelDescription); + bool hasDataContractAttribute = modelType.GetCustomAttribute() != null; + PropertyInfo[] properties = modelType.GetProperties(BindingFlags.Public | BindingFlags.Instance); + foreach (PropertyInfo property in properties) + { + if (ShouldDisplayMember(property, hasDataContractAttribute)) + { + ParameterDescription propertyModel = new ParameterDescription + { + Name = GetMemberName(property, hasDataContractAttribute) + }; + + if (DocumentationProvider != null) + { + propertyModel.Documentation = DocumentationProvider.GetDocumentation(property); + } + + GenerateAnnotations(property, propertyModel); + complexModelDescription.Properties.Add(propertyModel); + propertyModel.TypeDescription = GetOrCreateModelDescription(property.PropertyType); + } + } + + FieldInfo[] fields = modelType.GetFields(BindingFlags.Public | BindingFlags.Instance); + foreach (FieldInfo field in fields) + { + if (ShouldDisplayMember(field, hasDataContractAttribute)) + { + ParameterDescription propertyModel = new ParameterDescription + { + Name = GetMemberName(field, hasDataContractAttribute) + }; + + if (DocumentationProvider != null) + { + propertyModel.Documentation = DocumentationProvider.GetDocumentation(field); + } + + complexModelDescription.Properties.Add(propertyModel); + propertyModel.TypeDescription = GetOrCreateModelDescription(field.FieldType); + } + } + + return complexModelDescription; + } + + private DictionaryModelDescription GenerateDictionaryModelDescription(Type modelType, Type keyType, Type valueType) + { + ModelDescription keyModelDescription = GetOrCreateModelDescription(keyType); + ModelDescription valueModelDescription = GetOrCreateModelDescription(valueType); + + return new DictionaryModelDescription + { + Name = ModelNameHelper.GetModelName(modelType), + ModelType = modelType, + KeyModelDescription = keyModelDescription, + ValueModelDescription = valueModelDescription + }; + } + + private EnumTypeModelDescription GenerateEnumTypeModelDescription(Type modelType) + { + EnumTypeModelDescription enumDescription = new EnumTypeModelDescription + { + Name = ModelNameHelper.GetModelName(modelType), + ModelType = modelType, + Documentation = CreateDefaultDocumentation(modelType) + }; + bool hasDataContractAttribute = modelType.GetCustomAttribute() != null; + foreach (FieldInfo field in modelType.GetFields(BindingFlags.Public | BindingFlags.Static)) + { + if (ShouldDisplayMember(field, hasDataContractAttribute)) + { + EnumValueDescription enumValue = new EnumValueDescription + { + Name = field.Name, + Value = field.GetRawConstantValue().ToString() + }; + if (DocumentationProvider != null) + { + enumValue.Documentation = DocumentationProvider.GetDocumentation(field); + } + enumDescription.Values.Add(enumValue); + } + } + GeneratedModels.Add(enumDescription.Name, enumDescription); + + return enumDescription; + } + + private KeyValuePairModelDescription GenerateKeyValuePairModelDescription(Type modelType, Type keyType, Type valueType) + { + ModelDescription keyModelDescription = GetOrCreateModelDescription(keyType); + ModelDescription valueModelDescription = GetOrCreateModelDescription(valueType); + + return new KeyValuePairModelDescription + { + Name = ModelNameHelper.GetModelName(modelType), + ModelType = modelType, + KeyModelDescription = keyModelDescription, + ValueModelDescription = valueModelDescription + }; + } + + private ModelDescription GenerateSimpleTypeModelDescription(Type modelType) + { + SimpleTypeModelDescription simpleModelDescription = new SimpleTypeModelDescription + { + Name = ModelNameHelper.GetModelName(modelType), + ModelType = modelType, + Documentation = CreateDefaultDocumentation(modelType) + }; + GeneratedModels.Add(simpleModelDescription.Name, simpleModelDescription); + + return simpleModelDescription; + } + } +} \ No newline at end of file diff --git a/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/ModelDescriptions/ModelNameAttribute.cs b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/ModelDescriptions/ModelNameAttribute.cs new file mode 100755 index 0000000..b776c08 --- /dev/null +++ b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/ModelDescriptions/ModelNameAttribute.cs @@ -0,0 +1,18 @@ +using System; + +namespace ResourceTokenBroker.Areas.HelpPage.ModelDescriptions +{ + /// + /// Use this attribute to change the name of the generated for a type. + /// + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum, AllowMultiple = false, Inherited = false)] + public sealed class ModelNameAttribute : Attribute + { + public ModelNameAttribute(string name) + { + Name = name; + } + + public string Name { get; private set; } + } +} \ No newline at end of file diff --git a/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/ModelDescriptions/ModelNameHelper.cs b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/ModelDescriptions/ModelNameHelper.cs new file mode 100755 index 0000000..4176e8f --- /dev/null +++ b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/ModelDescriptions/ModelNameHelper.cs @@ -0,0 +1,36 @@ +using System; +using System.Globalization; +using System.Linq; +using System.Reflection; + +namespace ResourceTokenBroker.Areas.HelpPage.ModelDescriptions +{ + internal static class ModelNameHelper + { + // Modify this to provide custom model name mapping. + public static string GetModelName(Type type) + { + ModelNameAttribute modelNameAttribute = type.GetCustomAttribute(); + if (modelNameAttribute != null && !String.IsNullOrEmpty(modelNameAttribute.Name)) + { + return modelNameAttribute.Name; + } + + string modelName = type.Name; + if (type.IsGenericType) + { + // Format the generic type name to something like: GenericOfAgurment1AndArgument2 + Type genericType = type.GetGenericTypeDefinition(); + Type[] genericArguments = type.GetGenericArguments(); + string genericTypeName = genericType.Name; + + // Trim the generic parameter counts from the name + genericTypeName = genericTypeName.Substring(0, genericTypeName.IndexOf('`')); + string[] argumentTypeNames = genericArguments.Select(t => GetModelName(t)).ToArray(); + modelName = String.Format(CultureInfo.InvariantCulture, "{0}Of{1}", genericTypeName, String.Join("And", argumentTypeNames)); + } + + return modelName; + } + } +} \ No newline at end of file diff --git a/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/ModelDescriptions/ParameterAnnotation.cs b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/ModelDescriptions/ParameterAnnotation.cs new file mode 100755 index 0000000..1b71b1a --- /dev/null +++ b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/ModelDescriptions/ParameterAnnotation.cs @@ -0,0 +1,11 @@ +using System; + +namespace ResourceTokenBroker.Areas.HelpPage.ModelDescriptions +{ + public class ParameterAnnotation + { + public Attribute AnnotationAttribute { get; set; } + + public string Documentation { get; set; } + } +} \ No newline at end of file diff --git a/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/ModelDescriptions/ParameterDescription.cs b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/ModelDescriptions/ParameterDescription.cs new file mode 100755 index 0000000..34716e6 --- /dev/null +++ b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/ModelDescriptions/ParameterDescription.cs @@ -0,0 +1,21 @@ +using System.Collections.Generic; +using System.Collections.ObjectModel; + +namespace ResourceTokenBroker.Areas.HelpPage.ModelDescriptions +{ + public class ParameterDescription + { + public ParameterDescription() + { + Annotations = new Collection(); + } + + public Collection Annotations { get; private set; } + + public string Documentation { get; set; } + + public string Name { get; set; } + + public ModelDescription TypeDescription { get; set; } + } +} \ No newline at end of file diff --git a/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/ModelDescriptions/SimpleTypeModelDescription.cs b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/ModelDescriptions/SimpleTypeModelDescription.cs new file mode 100755 index 0000000..f66d893 --- /dev/null +++ b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/ModelDescriptions/SimpleTypeModelDescription.cs @@ -0,0 +1,6 @@ +namespace ResourceTokenBroker.Areas.HelpPage.ModelDescriptions +{ + public class SimpleTypeModelDescription : ModelDescription + { + } +} \ No newline at end of file diff --git a/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/Models/HelpPageApiModel.cs b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/Models/HelpPageApiModel.cs new file mode 100755 index 0000000..acdfbda --- /dev/null +++ b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/Models/HelpPageApiModel.cs @@ -0,0 +1,108 @@ +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Net.Http.Headers; +using System.Web.Http.Description; +using ResourceTokenBroker.Areas.HelpPage.ModelDescriptions; + +namespace ResourceTokenBroker.Areas.HelpPage.Models +{ + /// + /// The model that represents an API displayed on the help page. + /// + public class HelpPageApiModel + { + /// + /// Initializes a new instance of the class. + /// + public HelpPageApiModel() + { + UriParameters = new Collection(); + SampleRequests = new Dictionary(); + SampleResponses = new Dictionary(); + ErrorMessages = new Collection(); + } + + /// + /// Gets or sets the that describes the API. + /// + public ApiDescription ApiDescription { get; set; } + + /// + /// Gets or sets the collection that describes the URI parameters for the API. + /// + public Collection UriParameters { get; private set; } + + /// + /// Gets or sets the documentation for the request. + /// + public string RequestDocumentation { get; set; } + + /// + /// Gets or sets the that describes the request body. + /// + public ModelDescription RequestModelDescription { get; set; } + + /// + /// Gets the request body parameter descriptions. + /// + public IList RequestBodyParameters + { + get + { + return GetParameterDescriptions(RequestModelDescription); + } + } + + /// + /// Gets or sets the that describes the resource. + /// + public ModelDescription ResourceDescription { get; set; } + + /// + /// Gets the resource property descriptions. + /// + public IList ResourceProperties + { + get + { + return GetParameterDescriptions(ResourceDescription); + } + } + + /// + /// Gets the sample requests associated with the API. + /// + public IDictionary SampleRequests { get; private set; } + + /// + /// Gets the sample responses associated with the API. + /// + public IDictionary SampleResponses { get; private set; } + + /// + /// Gets the error messages associated with this model. + /// + public Collection ErrorMessages { get; private set; } + + private static IList GetParameterDescriptions(ModelDescription modelDescription) + { + ComplexTypeModelDescription complexTypeModelDescription = modelDescription as ComplexTypeModelDescription; + if (complexTypeModelDescription != null) + { + return complexTypeModelDescription.Properties; + } + + CollectionModelDescription collectionModelDescription = modelDescription as CollectionModelDescription; + if (collectionModelDescription != null) + { + complexTypeModelDescription = collectionModelDescription.ElementDescription as ComplexTypeModelDescription; + if (complexTypeModelDescription != null) + { + return complexTypeModelDescription.Properties; + } + } + + return null; + } + } +} \ No newline at end of file diff --git a/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/SampleGeneration/HelpPageSampleGenerator.cs b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/SampleGeneration/HelpPageSampleGenerator.cs new file mode 100755 index 0000000..00e0260 --- /dev/null +++ b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/SampleGeneration/HelpPageSampleGenerator.cs @@ -0,0 +1,444 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.ComponentModel; +using System.Diagnostics.CodeAnalysis; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Net.Http; +using System.Net.Http.Formatting; +using System.Net.Http.Headers; +using System.Web.Http.Description; +using System.Xml.Linq; +using Newtonsoft.Json; + +namespace ResourceTokenBroker.Areas.HelpPage +{ + /// + /// This class will generate the samples for the help page. + /// + public class HelpPageSampleGenerator + { + /// + /// Initializes a new instance of the class. + /// + public HelpPageSampleGenerator() + { + ActualHttpMessageTypes = new Dictionary(); + ActionSamples = new Dictionary(); + SampleObjects = new Dictionary(); + SampleObjectFactories = new List> + { + DefaultSampleObjectFactory, + }; + } + + /// + /// Gets CLR types that are used as the content of or . + /// + public IDictionary ActualHttpMessageTypes { get; internal set; } + + /// + /// Gets the objects that are used directly as samples for certain actions. + /// + public IDictionary ActionSamples { get; internal set; } + + /// + /// Gets the objects that are serialized as samples by the supported formatters. + /// + public IDictionary SampleObjects { get; internal set; } + + /// + /// Gets factories for the objects that the supported formatters will serialize as samples. Processed in order, + /// stopping when the factory successfully returns a non- object. + /// + /// + /// Collection includes just initially. Use + /// SampleObjectFactories.Insert(0, func) to provide an override and + /// SampleObjectFactories.Add(func) to provide a fallback. + [SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", + Justification = "This is an appropriate nesting of generic types")] + public IList> SampleObjectFactories { get; private set; } + + /// + /// Gets the request body samples for a given . + /// + /// The . + /// The samples keyed by media type. + public IDictionary GetSampleRequests(ApiDescription api) + { + return GetSample(api, SampleDirection.Request); + } + + /// + /// Gets the response body samples for a given . + /// + /// The . + /// The samples keyed by media type. + public IDictionary GetSampleResponses(ApiDescription api) + { + return GetSample(api, SampleDirection.Response); + } + + /// + /// Gets the request or response body samples. + /// + /// The . + /// The value indicating whether the sample is for a request or for a response. + /// The samples keyed by media type. + public virtual IDictionary GetSample(ApiDescription api, SampleDirection sampleDirection) + { + if (api == null) + { + throw new ArgumentNullException("api"); + } + string controllerName = api.ActionDescriptor.ControllerDescriptor.ControllerName; + string actionName = api.ActionDescriptor.ActionName; + IEnumerable parameterNames = api.ParameterDescriptions.Select(p => p.Name); + Collection formatters; + Type type = ResolveType(api, controllerName, actionName, parameterNames, sampleDirection, out formatters); + var samples = new Dictionary(); + + // Use the samples provided directly for actions + var actionSamples = GetAllActionSamples(controllerName, actionName, parameterNames, sampleDirection); + foreach (var actionSample in actionSamples) + { + samples.Add(actionSample.Key.MediaType, WrapSampleIfString(actionSample.Value)); + } + + // Do the sample generation based on formatters only if an action doesn't return an HttpResponseMessage. + // Here we cannot rely on formatters because we don't know what's in the HttpResponseMessage, it might not even use formatters. + if (type != null && !typeof(HttpResponseMessage).IsAssignableFrom(type)) + { + object sampleObject = GetSampleObject(type); + foreach (var formatter in formatters) + { + foreach (MediaTypeHeaderValue mediaType in formatter.SupportedMediaTypes) + { + if (!samples.ContainsKey(mediaType)) + { + object sample = GetActionSample(controllerName, actionName, parameterNames, type, formatter, mediaType, sampleDirection); + + // If no sample found, try generate sample using formatter and sample object + if (sample == null && sampleObject != null) + { + sample = WriteSampleObjectUsingFormatter(formatter, sampleObject, type, mediaType); + } + + samples.Add(mediaType, WrapSampleIfString(sample)); + } + } + } + } + + return samples; + } + + /// + /// Search for samples that are provided directly through . + /// + /// Name of the controller. + /// Name of the action. + /// The parameter names. + /// The CLR type. + /// The formatter. + /// The media type. + /// The value indicating whether the sample is for a request or for a response. + /// The sample that matches the parameters. + public virtual object GetActionSample(string controllerName, string actionName, IEnumerable parameterNames, Type type, MediaTypeFormatter formatter, MediaTypeHeaderValue mediaType, SampleDirection sampleDirection) + { + object sample; + + // First, try to get the sample provided for the specified mediaType, sampleDirection, controllerName, actionName and parameterNames. + // If not found, try to get the sample provided for the specified mediaType, sampleDirection, controllerName and actionName regardless of the parameterNames. + // If still not found, try to get the sample provided for the specified mediaType and type. + // Finally, try to get the sample provided for the specified mediaType. + if (ActionSamples.TryGetValue(new HelpPageSampleKey(mediaType, sampleDirection, controllerName, actionName, parameterNames), out sample) || + ActionSamples.TryGetValue(new HelpPageSampleKey(mediaType, sampleDirection, controllerName, actionName, new[] { "*" }), out sample) || + ActionSamples.TryGetValue(new HelpPageSampleKey(mediaType, type), out sample) || + ActionSamples.TryGetValue(new HelpPageSampleKey(mediaType), out sample)) + { + return sample; + } + + return null; + } + + /// + /// Gets the sample object that will be serialized by the formatters. + /// First, it will look at the . If no sample object is found, it will try to create + /// one using (which wraps an ) and other + /// factories in . + /// + /// The type. + /// The sample object. + [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", + Justification = "Even if all items in SampleObjectFactories throw, problem will be visible as missing sample.")] + public virtual object GetSampleObject(Type type) + { + object sampleObject; + + if (!SampleObjects.TryGetValue(type, out sampleObject)) + { + // No specific object available, try our factories. + foreach (Func factory in SampleObjectFactories) + { + if (factory == null) + { + continue; + } + + try + { + sampleObject = factory(this, type); + if (sampleObject != null) + { + break; + } + } + catch + { + // Ignore any problems encountered in the factory; go on to the next one (if any). + } + } + } + + return sampleObject; + } + + /// + /// Resolves the actual type of passed to the in an action. + /// + /// The . + /// The type. + public virtual Type ResolveHttpRequestMessageType(ApiDescription api) + { + string controllerName = api.ActionDescriptor.ControllerDescriptor.ControllerName; + string actionName = api.ActionDescriptor.ActionName; + IEnumerable parameterNames = api.ParameterDescriptions.Select(p => p.Name); + Collection formatters; + return ResolveType(api, controllerName, actionName, parameterNames, SampleDirection.Request, out formatters); + } + + /// + /// Resolves the type of the action parameter or return value when or is used. + /// + /// The . + /// Name of the controller. + /// Name of the action. + /// The parameter names. + /// The value indicating whether the sample is for a request or a response. + /// The formatters. + [SuppressMessage("Microsoft.Design", "CA1021:AvoidOutParameters", Justification = "This is only used in advanced scenarios.")] + public virtual Type ResolveType(ApiDescription api, string controllerName, string actionName, IEnumerable parameterNames, SampleDirection sampleDirection, out Collection formatters) + { + if (!Enum.IsDefined(typeof(SampleDirection), sampleDirection)) + { + throw new InvalidEnumArgumentException("sampleDirection", (int)sampleDirection, typeof(SampleDirection)); + } + if (api == null) + { + throw new ArgumentNullException("api"); + } + Type type; + if (ActualHttpMessageTypes.TryGetValue(new HelpPageSampleKey(sampleDirection, controllerName, actionName, parameterNames), out type) || + ActualHttpMessageTypes.TryGetValue(new HelpPageSampleKey(sampleDirection, controllerName, actionName, new[] { "*" }), out type)) + { + // Re-compute the supported formatters based on type + Collection newFormatters = new Collection(); + foreach (var formatter in api.ActionDescriptor.Configuration.Formatters) + { + if (IsFormatSupported(sampleDirection, formatter, type)) + { + newFormatters.Add(formatter); + } + } + formatters = newFormatters; + } + else + { + switch (sampleDirection) + { + case SampleDirection.Request: + ApiParameterDescription requestBodyParameter = api.ParameterDescriptions.FirstOrDefault(p => p.Source == ApiParameterSource.FromBody); + type = requestBodyParameter == null ? null : requestBodyParameter.ParameterDescriptor.ParameterType; + formatters = api.SupportedRequestBodyFormatters; + break; + case SampleDirection.Response: + default: + type = api.ResponseDescription.ResponseType ?? api.ResponseDescription.DeclaredType; + formatters = api.SupportedResponseFormatters; + break; + } + } + + return type; + } + + /// + /// Writes the sample object using formatter. + /// + /// The formatter. + /// The value. + /// The type. + /// Type of the media. + /// + [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "The exception is recorded as InvalidSample.")] + public virtual object WriteSampleObjectUsingFormatter(MediaTypeFormatter formatter, object value, Type type, MediaTypeHeaderValue mediaType) + { + if (formatter == null) + { + throw new ArgumentNullException("formatter"); + } + if (mediaType == null) + { + throw new ArgumentNullException("mediaType"); + } + + object sample = String.Empty; + MemoryStream ms = null; + HttpContent content = null; + try + { + if (formatter.CanWriteType(type)) + { + ms = new MemoryStream(); + content = new ObjectContent(type, value, formatter, mediaType); + formatter.WriteToStreamAsync(type, value, ms, content, null).Wait(); + ms.Position = 0; + StreamReader reader = new StreamReader(ms); + string serializedSampleString = reader.ReadToEnd(); + if (mediaType.MediaType.ToUpperInvariant().Contains("XML")) + { + serializedSampleString = TryFormatXml(serializedSampleString); + } + else if (mediaType.MediaType.ToUpperInvariant().Contains("JSON")) + { + serializedSampleString = TryFormatJson(serializedSampleString); + } + + sample = new TextSample(serializedSampleString); + } + else + { + sample = new InvalidSample(String.Format( + CultureInfo.CurrentCulture, + "Failed to generate the sample for media type '{0}'. Cannot use formatter '{1}' to write type '{2}'.", + mediaType, + formatter.GetType().Name, + type.Name)); + } + } + catch (Exception e) + { + sample = new InvalidSample(String.Format( + CultureInfo.CurrentCulture, + "An exception has occurred while using the formatter '{0}' to generate sample for media type '{1}'. Exception message: {2}", + formatter.GetType().Name, + mediaType.MediaType, + UnwrapException(e).Message)); + } + finally + { + if (ms != null) + { + ms.Dispose(); + } + if (content != null) + { + content.Dispose(); + } + } + + return sample; + } + + internal static Exception UnwrapException(Exception exception) + { + AggregateException aggregateException = exception as AggregateException; + if (aggregateException != null) + { + return aggregateException.Flatten().InnerException; + } + return exception; + } + + // Default factory for sample objects + private static object DefaultSampleObjectFactory(HelpPageSampleGenerator sampleGenerator, Type type) + { + // Try to create a default sample object + ObjectGenerator objectGenerator = new ObjectGenerator(); + return objectGenerator.GenerateObject(type); + } + + [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Handling the failure by returning the original string.")] + private static string TryFormatJson(string str) + { + try + { + object parsedJson = JsonConvert.DeserializeObject(str); + return JsonConvert.SerializeObject(parsedJson, Formatting.Indented); + } + catch + { + // can't parse JSON, return the original string + return str; + } + } + + [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Handling the failure by returning the original string.")] + private static string TryFormatXml(string str) + { + try + { + XDocument xml = XDocument.Parse(str); + return xml.ToString(); + } + catch + { + // can't parse XML, return the original string + return str; + } + } + + private static bool IsFormatSupported(SampleDirection sampleDirection, MediaTypeFormatter formatter, Type type) + { + switch (sampleDirection) + { + case SampleDirection.Request: + return formatter.CanReadType(type); + case SampleDirection.Response: + return formatter.CanWriteType(type); + } + return false; + } + + private IEnumerable> GetAllActionSamples(string controllerName, string actionName, IEnumerable parameterNames, SampleDirection sampleDirection) + { + HashSet parameterNamesSet = new HashSet(parameterNames, StringComparer.OrdinalIgnoreCase); + foreach (var sample in ActionSamples) + { + HelpPageSampleKey sampleKey = sample.Key; + if (String.Equals(controllerName, sampleKey.ControllerName, StringComparison.OrdinalIgnoreCase) && + String.Equals(actionName, sampleKey.ActionName, StringComparison.OrdinalIgnoreCase) && + (sampleKey.ParameterNames.SetEquals(new[] { "*" }) || parameterNamesSet.SetEquals(sampleKey.ParameterNames)) && + sampleDirection == sampleKey.SampleDirection) + { + yield return sample; + } + } + } + + private static object WrapSampleIfString(object sample) + { + string stringSample = sample as string; + if (stringSample != null) + { + return new TextSample(stringSample); + } + + return sample; + } + } +} \ No newline at end of file diff --git a/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/SampleGeneration/HelpPageSampleKey.cs b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/SampleGeneration/HelpPageSampleKey.cs new file mode 100755 index 0000000..3c89694 --- /dev/null +++ b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/SampleGeneration/HelpPageSampleKey.cs @@ -0,0 +1,172 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Net.Http.Headers; + +namespace ResourceTokenBroker.Areas.HelpPage +{ + /// + /// This is used to identify the place where the sample should be applied. + /// + public class HelpPageSampleKey + { + /// + /// Creates a new based on media type. + /// + /// The media type. + public HelpPageSampleKey(MediaTypeHeaderValue mediaType) + { + if (mediaType == null) + { + throw new ArgumentNullException("mediaType"); + } + + ActionName = String.Empty; + ControllerName = String.Empty; + MediaType = mediaType; + ParameterNames = new HashSet(StringComparer.OrdinalIgnoreCase); + } + + /// + /// Creates a new based on media type and CLR type. + /// + /// The media type. + /// The CLR type. + public HelpPageSampleKey(MediaTypeHeaderValue mediaType, Type type) + : this(mediaType) + { + if (type == null) + { + throw new ArgumentNullException("type"); + } + + ParameterType = type; + } + + /// + /// Creates a new based on , controller name, action name and parameter names. + /// + /// The . + /// Name of the controller. + /// Name of the action. + /// The parameter names. + public HelpPageSampleKey(SampleDirection sampleDirection, string controllerName, string actionName, IEnumerable parameterNames) + { + if (!Enum.IsDefined(typeof(SampleDirection), sampleDirection)) + { + throw new InvalidEnumArgumentException("sampleDirection", (int)sampleDirection, typeof(SampleDirection)); + } + if (controllerName == null) + { + throw new ArgumentNullException("controllerName"); + } + if (actionName == null) + { + throw new ArgumentNullException("actionName"); + } + if (parameterNames == null) + { + throw new ArgumentNullException("parameterNames"); + } + + ControllerName = controllerName; + ActionName = actionName; + ParameterNames = new HashSet(parameterNames, StringComparer.OrdinalIgnoreCase); + SampleDirection = sampleDirection; + } + + /// + /// Creates a new based on media type, , controller name, action name and parameter names. + /// + /// The media type. + /// The . + /// Name of the controller. + /// Name of the action. + /// The parameter names. + public HelpPageSampleKey(MediaTypeHeaderValue mediaType, SampleDirection sampleDirection, string controllerName, string actionName, IEnumerable parameterNames) + : this(sampleDirection, controllerName, actionName, parameterNames) + { + if (mediaType == null) + { + throw new ArgumentNullException("mediaType"); + } + + MediaType = mediaType; + } + + /// + /// Gets the name of the controller. + /// + /// + /// The name of the controller. + /// + public string ControllerName { get; private set; } + + /// + /// Gets the name of the action. + /// + /// + /// The name of the action. + /// + public string ActionName { get; private set; } + + /// + /// Gets the media type. + /// + /// + /// The media type. + /// + public MediaTypeHeaderValue MediaType { get; private set; } + + /// + /// Gets the parameter names. + /// + public HashSet ParameterNames { get; private set; } + + public Type ParameterType { get; private set; } + + /// + /// Gets the . + /// + public SampleDirection? SampleDirection { get; private set; } + + public override bool Equals(object obj) + { + HelpPageSampleKey otherKey = obj as HelpPageSampleKey; + if (otherKey == null) + { + return false; + } + + return String.Equals(ControllerName, otherKey.ControllerName, StringComparison.OrdinalIgnoreCase) && + String.Equals(ActionName, otherKey.ActionName, StringComparison.OrdinalIgnoreCase) && + (MediaType == otherKey.MediaType || (MediaType != null && MediaType.Equals(otherKey.MediaType))) && + ParameterType == otherKey.ParameterType && + SampleDirection == otherKey.SampleDirection && + ParameterNames.SetEquals(otherKey.ParameterNames); + } + + public override int GetHashCode() + { + int hashCode = ControllerName.ToUpperInvariant().GetHashCode() ^ ActionName.ToUpperInvariant().GetHashCode(); + if (MediaType != null) + { + hashCode ^= MediaType.GetHashCode(); + } + if (SampleDirection != null) + { + hashCode ^= SampleDirection.GetHashCode(); + } + if (ParameterType != null) + { + hashCode ^= ParameterType.GetHashCode(); + } + foreach (string parameterName in ParameterNames) + { + hashCode ^= parameterName.ToUpperInvariant().GetHashCode(); + } + + return hashCode; + } + } +} diff --git a/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/SampleGeneration/ImageSample.cs b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/SampleGeneration/ImageSample.cs new file mode 100755 index 0000000..2a8c9a1 --- /dev/null +++ b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/SampleGeneration/ImageSample.cs @@ -0,0 +1,41 @@ +using System; + +namespace ResourceTokenBroker.Areas.HelpPage +{ + /// + /// This represents an image sample on the help page. There's a display template named ImageSample associated with this class. + /// + public class ImageSample + { + /// + /// Initializes a new instance of the class. + /// + /// The URL of an image. + public ImageSample(string src) + { + if (src == null) + { + throw new ArgumentNullException("src"); + } + Src = src; + } + + public string Src { get; private set; } + + public override bool Equals(object obj) + { + ImageSample other = obj as ImageSample; + return other != null && Src == other.Src; + } + + public override int GetHashCode() + { + return Src.GetHashCode(); + } + + public override string ToString() + { + return Src; + } + } +} \ No newline at end of file diff --git a/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/SampleGeneration/InvalidSample.cs b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/SampleGeneration/InvalidSample.cs new file mode 100755 index 0000000..76e8535 --- /dev/null +++ b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/SampleGeneration/InvalidSample.cs @@ -0,0 +1,37 @@ +using System; + +namespace ResourceTokenBroker.Areas.HelpPage +{ + /// + /// This represents an invalid sample on the help page. There's a display template named InvalidSample associated with this class. + /// + public class InvalidSample + { + public InvalidSample(string errorMessage) + { + if (errorMessage == null) + { + throw new ArgumentNullException("errorMessage"); + } + ErrorMessage = errorMessage; + } + + public string ErrorMessage { get; private set; } + + public override bool Equals(object obj) + { + InvalidSample other = obj as InvalidSample; + return other != null && ErrorMessage == other.ErrorMessage; + } + + public override int GetHashCode() + { + return ErrorMessage.GetHashCode(); + } + + public override string ToString() + { + return ErrorMessage; + } + } +} \ No newline at end of file diff --git a/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/SampleGeneration/ObjectGenerator.cs b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/SampleGeneration/ObjectGenerator.cs new file mode 100755 index 0000000..10d6513 --- /dev/null +++ b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/SampleGeneration/ObjectGenerator.cs @@ -0,0 +1,456 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Globalization; +using System.Linq; +using System.Reflection; + +namespace ResourceTokenBroker.Areas.HelpPage +{ + /// + /// This class will create an object of a given type and populate it with sample data. + /// + public class ObjectGenerator + { + internal const int DefaultCollectionSize = 2; + private readonly SimpleTypeObjectGenerator SimpleObjectGenerator = new SimpleTypeObjectGenerator(); + + /// + /// Generates an object for a given type. The type needs to be public, have a public default constructor and settable public properties/fields. Currently it supports the following types: + /// Simple types: , , , , , etc. + /// Complex types: POCO types. + /// Nullables: . + /// Arrays: arrays of simple types or complex types. + /// Key value pairs: + /// Tuples: , , etc + /// Dictionaries: or anything deriving from . + /// Collections: , , , , , or anything deriving from or . + /// Queryables: , . + /// + /// The type. + /// An object of the given type. + public object GenerateObject(Type type) + { + return GenerateObject(type, new Dictionary()); + } + + [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Here we just want to return null if anything goes wrong.")] + private object GenerateObject(Type type, Dictionary createdObjectReferences) + { + try + { + if (SimpleTypeObjectGenerator.CanGenerateObject(type)) + { + return SimpleObjectGenerator.GenerateObject(type); + } + + if (type.IsArray) + { + return GenerateArray(type, DefaultCollectionSize, createdObjectReferences); + } + + if (type.IsGenericType) + { + return GenerateGenericType(type, DefaultCollectionSize, createdObjectReferences); + } + + if (type == typeof(IDictionary)) + { + return GenerateDictionary(typeof(Hashtable), DefaultCollectionSize, createdObjectReferences); + } + + if (typeof(IDictionary).IsAssignableFrom(type)) + { + return GenerateDictionary(type, DefaultCollectionSize, createdObjectReferences); + } + + if (type == typeof(IList) || + type == typeof(IEnumerable) || + type == typeof(ICollection)) + { + return GenerateCollection(typeof(ArrayList), DefaultCollectionSize, createdObjectReferences); + } + + if (typeof(IList).IsAssignableFrom(type)) + { + return GenerateCollection(type, DefaultCollectionSize, createdObjectReferences); + } + + if (type == typeof(IQueryable)) + { + return GenerateQueryable(type, DefaultCollectionSize, createdObjectReferences); + } + + if (type.IsEnum) + { + return GenerateEnum(type); + } + + if (type.IsPublic || type.IsNestedPublic) + { + return GenerateComplexObject(type, createdObjectReferences); + } + } + catch + { + // Returns null if anything fails + return null; + } + + return null; + } + + private static object GenerateGenericType(Type type, int collectionSize, Dictionary createdObjectReferences) + { + Type genericTypeDefinition = type.GetGenericTypeDefinition(); + if (genericTypeDefinition == typeof(Nullable<>)) + { + return GenerateNullable(type, createdObjectReferences); + } + + if (genericTypeDefinition == typeof(KeyValuePair<,>)) + { + return GenerateKeyValuePair(type, createdObjectReferences); + } + + if (IsTuple(genericTypeDefinition)) + { + return GenerateTuple(type, createdObjectReferences); + } + + Type[] genericArguments = type.GetGenericArguments(); + if (genericArguments.Length == 1) + { + if (genericTypeDefinition == typeof(IList<>) || + genericTypeDefinition == typeof(IEnumerable<>) || + genericTypeDefinition == typeof(ICollection<>)) + { + Type collectionType = typeof(List<>).MakeGenericType(genericArguments); + return GenerateCollection(collectionType, collectionSize, createdObjectReferences); + } + + if (genericTypeDefinition == typeof(IQueryable<>)) + { + return GenerateQueryable(type, collectionSize, createdObjectReferences); + } + + Type closedCollectionType = typeof(ICollection<>).MakeGenericType(genericArguments[0]); + if (closedCollectionType.IsAssignableFrom(type)) + { + return GenerateCollection(type, collectionSize, createdObjectReferences); + } + } + + if (genericArguments.Length == 2) + { + if (genericTypeDefinition == typeof(IDictionary<,>)) + { + Type dictionaryType = typeof(Dictionary<,>).MakeGenericType(genericArguments); + return GenerateDictionary(dictionaryType, collectionSize, createdObjectReferences); + } + + Type closedDictionaryType = typeof(IDictionary<,>).MakeGenericType(genericArguments[0], genericArguments[1]); + if (closedDictionaryType.IsAssignableFrom(type)) + { + return GenerateDictionary(type, collectionSize, createdObjectReferences); + } + } + + if (type.IsPublic || type.IsNestedPublic) + { + return GenerateComplexObject(type, createdObjectReferences); + } + + return null; + } + + private static object GenerateTuple(Type type, Dictionary createdObjectReferences) + { + Type[] genericArgs = type.GetGenericArguments(); + object[] parameterValues = new object[genericArgs.Length]; + bool failedToCreateTuple = true; + ObjectGenerator objectGenerator = new ObjectGenerator(); + for (int i = 0; i < genericArgs.Length; i++) + { + parameterValues[i] = objectGenerator.GenerateObject(genericArgs[i], createdObjectReferences); + failedToCreateTuple &= parameterValues[i] == null; + } + if (failedToCreateTuple) + { + return null; + } + object result = Activator.CreateInstance(type, parameterValues); + return result; + } + + private static bool IsTuple(Type genericTypeDefinition) + { + return genericTypeDefinition == typeof(Tuple<>) || + genericTypeDefinition == typeof(Tuple<,>) || + genericTypeDefinition == typeof(Tuple<,,>) || + genericTypeDefinition == typeof(Tuple<,,,>) || + genericTypeDefinition == typeof(Tuple<,,,,>) || + genericTypeDefinition == typeof(Tuple<,,,,,>) || + genericTypeDefinition == typeof(Tuple<,,,,,,>) || + genericTypeDefinition == typeof(Tuple<,,,,,,,>); + } + + private static object GenerateKeyValuePair(Type keyValuePairType, Dictionary createdObjectReferences) + { + Type[] genericArgs = keyValuePairType.GetGenericArguments(); + Type typeK = genericArgs[0]; + Type typeV = genericArgs[1]; + ObjectGenerator objectGenerator = new ObjectGenerator(); + object keyObject = objectGenerator.GenerateObject(typeK, createdObjectReferences); + object valueObject = objectGenerator.GenerateObject(typeV, createdObjectReferences); + if (keyObject == null && valueObject == null) + { + // Failed to create key and values + return null; + } + object result = Activator.CreateInstance(keyValuePairType, keyObject, valueObject); + return result; + } + + private static object GenerateArray(Type arrayType, int size, Dictionary createdObjectReferences) + { + Type type = arrayType.GetElementType(); + Array result = Array.CreateInstance(type, size); + bool areAllElementsNull = true; + ObjectGenerator objectGenerator = new ObjectGenerator(); + for (int i = 0; i < size; i++) + { + object element = objectGenerator.GenerateObject(type, createdObjectReferences); + result.SetValue(element, i); + areAllElementsNull &= element == null; + } + + if (areAllElementsNull) + { + return null; + } + + return result; + } + + private static object GenerateDictionary(Type dictionaryType, int size, Dictionary createdObjectReferences) + { + Type typeK = typeof(object); + Type typeV = typeof(object); + if (dictionaryType.IsGenericType) + { + Type[] genericArgs = dictionaryType.GetGenericArguments(); + typeK = genericArgs[0]; + typeV = genericArgs[1]; + } + + object result = Activator.CreateInstance(dictionaryType); + MethodInfo addMethod = dictionaryType.GetMethod("Add") ?? dictionaryType.GetMethod("TryAdd"); + MethodInfo containsMethod = dictionaryType.GetMethod("Contains") ?? dictionaryType.GetMethod("ContainsKey"); + ObjectGenerator objectGenerator = new ObjectGenerator(); + for (int i = 0; i < size; i++) + { + object newKey = objectGenerator.GenerateObject(typeK, createdObjectReferences); + if (newKey == null) + { + // Cannot generate a valid key + return null; + } + + bool containsKey = (bool)containsMethod.Invoke(result, new object[] { newKey }); + if (!containsKey) + { + object newValue = objectGenerator.GenerateObject(typeV, createdObjectReferences); + addMethod.Invoke(result, new object[] { newKey, newValue }); + } + } + + return result; + } + + private static object GenerateEnum(Type enumType) + { + Array possibleValues = Enum.GetValues(enumType); + if (possibleValues.Length > 0) + { + return possibleValues.GetValue(0); + } + return null; + } + + private static object GenerateQueryable(Type queryableType, int size, Dictionary createdObjectReferences) + { + bool isGeneric = queryableType.IsGenericType; + object list; + if (isGeneric) + { + Type listType = typeof(List<>).MakeGenericType(queryableType.GetGenericArguments()); + list = GenerateCollection(listType, size, createdObjectReferences); + } + else + { + list = GenerateArray(typeof(object[]), size, createdObjectReferences); + } + if (list == null) + { + return null; + } + if (isGeneric) + { + Type argumentType = typeof(IEnumerable<>).MakeGenericType(queryableType.GetGenericArguments()); + MethodInfo asQueryableMethod = typeof(Queryable).GetMethod("AsQueryable", new[] { argumentType }); + return asQueryableMethod.Invoke(null, new[] { list }); + } + + return Queryable.AsQueryable((IEnumerable)list); + } + + private static object GenerateCollection(Type collectionType, int size, Dictionary createdObjectReferences) + { + Type type = collectionType.IsGenericType ? + collectionType.GetGenericArguments()[0] : + typeof(object); + object result = Activator.CreateInstance(collectionType); + MethodInfo addMethod = collectionType.GetMethod("Add"); + bool areAllElementsNull = true; + ObjectGenerator objectGenerator = new ObjectGenerator(); + for (int i = 0; i < size; i++) + { + object element = objectGenerator.GenerateObject(type, createdObjectReferences); + addMethod.Invoke(result, new object[] { element }); + areAllElementsNull &= element == null; + } + + if (areAllElementsNull) + { + return null; + } + + return result; + } + + private static object GenerateNullable(Type nullableType, Dictionary createdObjectReferences) + { + Type type = nullableType.GetGenericArguments()[0]; + ObjectGenerator objectGenerator = new ObjectGenerator(); + return objectGenerator.GenerateObject(type, createdObjectReferences); + } + + private static object GenerateComplexObject(Type type, Dictionary createdObjectReferences) + { + object result = null; + + if (createdObjectReferences.TryGetValue(type, out result)) + { + // The object has been created already, just return it. This will handle the circular reference case. + return result; + } + + if (type.IsValueType) + { + result = Activator.CreateInstance(type); + } + else + { + ConstructorInfo defaultCtor = type.GetConstructor(Type.EmptyTypes); + if (defaultCtor == null) + { + // Cannot instantiate the type because it doesn't have a default constructor + return null; + } + + result = defaultCtor.Invoke(new object[0]); + } + createdObjectReferences.Add(type, result); + SetPublicProperties(type, result, createdObjectReferences); + SetPublicFields(type, result, createdObjectReferences); + return result; + } + + private static void SetPublicProperties(Type type, object obj, Dictionary createdObjectReferences) + { + PropertyInfo[] properties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance); + ObjectGenerator objectGenerator = new ObjectGenerator(); + foreach (PropertyInfo property in properties) + { + if (property.CanWrite) + { + object propertyValue = objectGenerator.GenerateObject(property.PropertyType, createdObjectReferences); + property.SetValue(obj, propertyValue, null); + } + } + } + + private static void SetPublicFields(Type type, object obj, Dictionary createdObjectReferences) + { + FieldInfo[] fields = type.GetFields(BindingFlags.Public | BindingFlags.Instance); + ObjectGenerator objectGenerator = new ObjectGenerator(); + foreach (FieldInfo field in fields) + { + object fieldValue = objectGenerator.GenerateObject(field.FieldType, createdObjectReferences); + field.SetValue(obj, fieldValue); + } + } + + private class SimpleTypeObjectGenerator + { + private long _index = 0; + private static readonly Dictionary> DefaultGenerators = InitializeGenerators(); + + [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity", Justification = "These are simple type factories and cannot be split up.")] + private static Dictionary> InitializeGenerators() + { + return new Dictionary> + { + { typeof(Boolean), index => true }, + { typeof(Byte), index => (Byte)64 }, + { typeof(Char), index => (Char)65 }, + { typeof(DateTime), index => DateTime.Now }, + { typeof(DateTimeOffset), index => new DateTimeOffset(DateTime.Now) }, + { typeof(DBNull), index => DBNull.Value }, + { typeof(Decimal), index => (Decimal)index }, + { typeof(Double), index => (Double)(index + 0.1) }, + { typeof(Guid), index => Guid.NewGuid() }, + { typeof(Int16), index => (Int16)(index % Int16.MaxValue) }, + { typeof(Int32), index => (Int32)(index % Int32.MaxValue) }, + { typeof(Int64), index => (Int64)index }, + { typeof(Object), index => new object() }, + { typeof(SByte), index => (SByte)64 }, + { typeof(Single), index => (Single)(index + 0.1) }, + { + typeof(String), index => + { + return String.Format(CultureInfo.CurrentCulture, "sample string {0}", index); + } + }, + { + typeof(TimeSpan), index => + { + return TimeSpan.FromTicks(1234567); + } + }, + { typeof(UInt16), index => (UInt16)(index % UInt16.MaxValue) }, + { typeof(UInt32), index => (UInt32)(index % UInt32.MaxValue) }, + { typeof(UInt64), index => (UInt64)index }, + { + typeof(Uri), index => + { + return new Uri(String.Format(CultureInfo.CurrentCulture, "http://webapihelppage{0}.com", index)); + } + }, + }; + } + + public static bool CanGenerateObject(Type type) + { + return DefaultGenerators.ContainsKey(type); + } + + public object GenerateObject(Type type) + { + return DefaultGenerators[type](++_index); + } + } + } +} \ No newline at end of file diff --git a/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/SampleGeneration/SampleDirection.cs b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/SampleGeneration/SampleDirection.cs new file mode 100755 index 0000000..f7f407c --- /dev/null +++ b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/SampleGeneration/SampleDirection.cs @@ -0,0 +1,11 @@ +namespace ResourceTokenBroker.Areas.HelpPage +{ + /// + /// Indicates whether the sample is used for request or response + /// + public enum SampleDirection + { + Request = 0, + Response + } +} \ No newline at end of file diff --git a/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/SampleGeneration/TextSample.cs b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/SampleGeneration/TextSample.cs new file mode 100755 index 0000000..c111d4e --- /dev/null +++ b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/SampleGeneration/TextSample.cs @@ -0,0 +1,37 @@ +using System; + +namespace ResourceTokenBroker.Areas.HelpPage +{ + /// + /// This represents a preformatted text sample on the help page. There's a display template named TextSample associated with this class. + /// + public class TextSample + { + public TextSample(string text) + { + if (text == null) + { + throw new ArgumentNullException("text"); + } + Text = text; + } + + public string Text { get; private set; } + + public override bool Equals(object obj) + { + TextSample other = obj as TextSample; + return other != null && Text == other.Text; + } + + public override int GetHashCode() + { + return Text.GetHashCode(); + } + + public override string ToString() + { + return Text; + } + } +} \ No newline at end of file diff --git a/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/Views/Help/Api.cshtml b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/Views/Help/Api.cshtml new file mode 100755 index 0000000..9dfa3f9 --- /dev/null +++ b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/Views/Help/Api.cshtml @@ -0,0 +1,22 @@ +@using System.Web.Http +@using ResourceTokenBroker.Areas.HelpPage.Models +@model HelpPageApiModel + +@{ + var description = Model.ApiDescription; + ViewBag.Title = description.HttpMethod.Method + " " + description.RelativePath; +} + + +
+ +
+ @Html.DisplayForModel() +
+
diff --git a/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/Views/Help/DisplayTemplates/ApiGroup.cshtml b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/Views/Help/DisplayTemplates/ApiGroup.cshtml new file mode 100755 index 0000000..0eb1608 --- /dev/null +++ b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/Views/Help/DisplayTemplates/ApiGroup.cshtml @@ -0,0 +1,41 @@ +@using System.Web.Http +@using System.Web.Http.Controllers +@using System.Web.Http.Description +@using ResourceTokenBroker.Areas.HelpPage +@using ResourceTokenBroker.Areas.HelpPage.Models +@model IGrouping + +@{ + var controllerDocumentation = ViewBag.DocumentationProvider != null ? + ViewBag.DocumentationProvider.GetDocumentation(Model.Key) : + null; +} + +

@Model.Key.ControllerName

+@if (!String.IsNullOrEmpty(controllerDocumentation)) +{ +

@controllerDocumentation

+} + + + + + + @foreach (var api in Model) + { + + + + + } + +
APIDescription
@api.HttpMethod.Method @api.RelativePath + @if (api.Documentation != null) + { +

@api.Documentation

+ } + else + { +

No documentation available.

+ } +
\ No newline at end of file diff --git a/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/Views/Help/DisplayTemplates/CollectionModelDescription.cshtml b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/Views/Help/DisplayTemplates/CollectionModelDescription.cshtml new file mode 100755 index 0000000..add00af --- /dev/null +++ b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/Views/Help/DisplayTemplates/CollectionModelDescription.cshtml @@ -0,0 +1,6 @@ +@using ResourceTokenBroker.Areas.HelpPage.ModelDescriptions +@model CollectionModelDescription +@if (Model.ElementDescription is ComplexTypeModelDescription) +{ + @Html.DisplayFor(m => m.ElementDescription) +} \ No newline at end of file diff --git a/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/Views/Help/DisplayTemplates/ComplexTypeModelDescription.cshtml b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/Views/Help/DisplayTemplates/ComplexTypeModelDescription.cshtml new file mode 100755 index 0000000..6fbba90 --- /dev/null +++ b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/Views/Help/DisplayTemplates/ComplexTypeModelDescription.cshtml @@ -0,0 +1,3 @@ +@using ResourceTokenBroker.Areas.HelpPage.ModelDescriptions +@model ComplexTypeModelDescription +@Html.DisplayFor(m => m.Properties, "Parameters") \ No newline at end of file diff --git a/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/Views/Help/DisplayTemplates/DictionaryModelDescription.cshtml b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/Views/Help/DisplayTemplates/DictionaryModelDescription.cshtml new file mode 100755 index 0000000..fdfb877 --- /dev/null +++ b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/Views/Help/DisplayTemplates/DictionaryModelDescription.cshtml @@ -0,0 +1,4 @@ +@using ResourceTokenBroker.Areas.HelpPage.ModelDescriptions +@model DictionaryModelDescription +Dictionary of @Html.DisplayFor(m => Model.KeyModelDescription.ModelType, "ModelDescriptionLink", new { modelDescription = Model.KeyModelDescription }) [key] +and @Html.DisplayFor(m => Model.ValueModelDescription.ModelType, "ModelDescriptionLink", new { modelDescription = Model.ValueModelDescription }) [value] \ No newline at end of file diff --git a/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/Views/Help/DisplayTemplates/EnumTypeModelDescription.cshtml b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/Views/Help/DisplayTemplates/EnumTypeModelDescription.cshtml new file mode 100755 index 0000000..7f5d507 --- /dev/null +++ b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/Views/Help/DisplayTemplates/EnumTypeModelDescription.cshtml @@ -0,0 +1,24 @@ +@using ResourceTokenBroker.Areas.HelpPage.ModelDescriptions +@model EnumTypeModelDescription + +

Possible enumeration values:

+ + + + + + + @foreach (EnumValueDescription value in Model.Values) + { + + + + + + } + +
NameValueDescription
@value.Name +

@value.Value

+
+

@value.Documentation

+
\ No newline at end of file diff --git a/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/Views/Help/DisplayTemplates/HelpPageApiModel.cshtml b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/Views/Help/DisplayTemplates/HelpPageApiModel.cshtml new file mode 100755 index 0000000..78b75eb --- /dev/null +++ b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/Views/Help/DisplayTemplates/HelpPageApiModel.cshtml @@ -0,0 +1,67 @@ +@using System.Web.Http +@using System.Web.Http.Description +@using ResourceTokenBroker.Areas.HelpPage.Models +@using ResourceTokenBroker.Areas.HelpPage.ModelDescriptions +@model HelpPageApiModel + +@{ + ApiDescription description = Model.ApiDescription; +} +

@description.HttpMethod.Method @description.RelativePath

+
+

@description.Documentation

+ +

Request Information

+ +

URI Parameters

+ @Html.DisplayFor(m => m.UriParameters, "Parameters") + +

Body Parameters

+ +

@Model.RequestDocumentation

+ + @if (Model.RequestModelDescription != null) + { + @Html.DisplayFor(m => m.RequestModelDescription.ModelType, "ModelDescriptionLink", new { modelDescription = Model.RequestModelDescription }) + if (Model.RequestBodyParameters != null) + { + @Html.DisplayFor(m => m.RequestBodyParameters, "Parameters") + } + } + else + { +

None.

+ } + + @if (Model.SampleRequests.Count > 0) + { +

Request Formats

+ @Html.DisplayFor(m => m.SampleRequests, "Samples") + } + +

Response Information

+ +

Resource Description

+ +

@description.ResponseDescription.Documentation

+ + @if (Model.ResourceDescription != null) + { + @Html.DisplayFor(m => m.ResourceDescription.ModelType, "ModelDescriptionLink", new { modelDescription = Model.ResourceDescription }) + if (Model.ResourceProperties != null) + { + @Html.DisplayFor(m => m.ResourceProperties, "Parameters") + } + } + else + { +

None.

+ } + + @if (Model.SampleResponses.Count > 0) + { +

Response Formats

+ @Html.DisplayFor(m => m.SampleResponses, "Samples") + } + +
\ No newline at end of file diff --git a/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/Views/Help/DisplayTemplates/ImageSample.cshtml b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/Views/Help/DisplayTemplates/ImageSample.cshtml new file mode 100755 index 0000000..defb167 --- /dev/null +++ b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/Views/Help/DisplayTemplates/ImageSample.cshtml @@ -0,0 +1,4 @@ +@using ResourceTokenBroker.Areas.HelpPage +@model ImageSample + + \ No newline at end of file diff --git a/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/Views/Help/DisplayTemplates/InvalidSample.cshtml b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/Views/Help/DisplayTemplates/InvalidSample.cshtml new file mode 100755 index 0000000..134cd2f --- /dev/null +++ b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/Views/Help/DisplayTemplates/InvalidSample.cshtml @@ -0,0 +1,13 @@ +@using ResourceTokenBroker.Areas.HelpPage +@model InvalidSample + +@if (HttpContext.Current.IsDebuggingEnabled) +{ +
+

@Model.ErrorMessage

+
+} +else +{ +

Sample not available.

+} \ No newline at end of file diff --git a/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/Views/Help/DisplayTemplates/KeyValuePairModelDescription.cshtml b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/Views/Help/DisplayTemplates/KeyValuePairModelDescription.cshtml new file mode 100755 index 0000000..adc7e51 --- /dev/null +++ b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/Views/Help/DisplayTemplates/KeyValuePairModelDescription.cshtml @@ -0,0 +1,4 @@ +@using ResourceTokenBroker.Areas.HelpPage.ModelDescriptions +@model KeyValuePairModelDescription +Pair of @Html.DisplayFor(m => Model.KeyModelDescription.ModelType, "ModelDescriptionLink", new { modelDescription = Model.KeyModelDescription }) [key] +and @Html.DisplayFor(m => Model.ValueModelDescription.ModelType, "ModelDescriptionLink", new { modelDescription = Model.ValueModelDescription }) [value] \ No newline at end of file diff --git a/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/Views/Help/DisplayTemplates/ModelDescriptionLink.cshtml b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/Views/Help/DisplayTemplates/ModelDescriptionLink.cshtml new file mode 100755 index 0000000..4cecac9 --- /dev/null +++ b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/Views/Help/DisplayTemplates/ModelDescriptionLink.cshtml @@ -0,0 +1,26 @@ +@using ResourceTokenBroker.Areas.HelpPage.ModelDescriptions +@model Type +@{ + ModelDescription modelDescription = ViewBag.modelDescription; + if (modelDescription is ComplexTypeModelDescription || modelDescription is EnumTypeModelDescription) + { + if (Model == typeof(Object)) + { + @:Object + } + else + { + @Html.ActionLink(modelDescription.Name, "ResourceModel", "Help", new { modelName = modelDescription.Name }, null) + } + } + else if (modelDescription is CollectionModelDescription) + { + var collectionDescription = modelDescription as CollectionModelDescription; + var elementDescription = collectionDescription.ElementDescription; + @:Collection of @Html.DisplayFor(m => elementDescription.ModelType, "ModelDescriptionLink", new { modelDescription = elementDescription }) + } + else + { + @Html.DisplayFor(m => modelDescription) + } +} \ No newline at end of file diff --git a/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/Views/Help/DisplayTemplates/Parameters.cshtml b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/Views/Help/DisplayTemplates/Parameters.cshtml new file mode 100755 index 0000000..e2220c4 --- /dev/null +++ b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/Views/Help/DisplayTemplates/Parameters.cshtml @@ -0,0 +1,48 @@ +@using System.Collections.Generic +@using System.Collections.ObjectModel +@using System.Web.Http.Description +@using System.Threading +@using ResourceTokenBroker.Areas.HelpPage.ModelDescriptions +@model IList + +@if (Model.Count > 0) +{ + + + + + + @foreach (ParameterDescription parameter in Model) + { + ModelDescription modelDescription = parameter.TypeDescription; + + + + + + + } + +
NameDescriptionTypeAdditional information
@parameter.Name +

@parameter.Documentation

+
+ @Html.DisplayFor(m => modelDescription.ModelType, "ModelDescriptionLink", new { modelDescription = modelDescription }) + + @if (parameter.Annotations.Count > 0) + { + foreach (var annotation in parameter.Annotations) + { +

@annotation.Documentation

+ } + } + else + { +

None.

+ } +
+} +else +{ +

None.

+} + diff --git a/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/Views/Help/DisplayTemplates/Samples.cshtml b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/Views/Help/DisplayTemplates/Samples.cshtml new file mode 100755 index 0000000..c19596f --- /dev/null +++ b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/Views/Help/DisplayTemplates/Samples.cshtml @@ -0,0 +1,30 @@ +@using System.Net.Http.Headers +@model Dictionary + +@{ + // Group the samples into a single tab if they are the same. + Dictionary samples = Model.GroupBy(pair => pair.Value).ToDictionary( + pair => String.Join(", ", pair.Select(m => m.Key.ToString()).ToArray()), + pair => pair.Key); + var mediaTypes = samples.Keys; +} +
+ @foreach (var mediaType in mediaTypes) + { +

@mediaType

+
+ Sample: + @{ + var sample = samples[mediaType]; + if (sample == null) + { +

Sample not available.

+ } + else + { + @Html.DisplayFor(s => sample); + } + } +
+ } +
\ No newline at end of file diff --git a/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/Views/Help/DisplayTemplates/SimpleTypeModelDescription.cshtml b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/Views/Help/DisplayTemplates/SimpleTypeModelDescription.cshtml new file mode 100755 index 0000000..939ddb7 --- /dev/null +++ b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/Views/Help/DisplayTemplates/SimpleTypeModelDescription.cshtml @@ -0,0 +1,3 @@ +@using ResourceTokenBroker.Areas.HelpPage.ModelDescriptions +@model SimpleTypeModelDescription +@Model.Documentation \ No newline at end of file diff --git a/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/Views/Help/DisplayTemplates/TextSample.cshtml b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/Views/Help/DisplayTemplates/TextSample.cshtml new file mode 100755 index 0000000..4e77b9b --- /dev/null +++ b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/Views/Help/DisplayTemplates/TextSample.cshtml @@ -0,0 +1,6 @@ +@using ResourceTokenBroker.Areas.HelpPage +@model TextSample + +
+@Model.Text
+
\ No newline at end of file diff --git a/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/Views/Help/Index.cshtml b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/Views/Help/Index.cshtml new file mode 100755 index 0000000..0ea2e87 --- /dev/null +++ b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/Views/Help/Index.cshtml @@ -0,0 +1,38 @@ +@using System.Web.Http +@using System.Web.Http.Controllers +@using System.Web.Http.Description +@using System.Collections.ObjectModel +@using ResourceTokenBroker.Areas.HelpPage.Models +@model Collection + +@{ + ViewBag.Title = "ASP.NET Web API Help Page"; + + // Group APIs by controller + ILookup apiGroups = Model.ToLookup(api => api.ActionDescriptor.ControllerDescriptor); +} + + +
+
+
+

@ViewBag.Title

+
+
+
+
+ +
+ @foreach (var group in apiGroups) + { + @Html.DisplayFor(m => group, "ApiGroup") + } +
+
diff --git a/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/Views/Help/ResourceModel.cshtml b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/Views/Help/ResourceModel.cshtml new file mode 100755 index 0000000..373b869 --- /dev/null +++ b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/Views/Help/ResourceModel.cshtml @@ -0,0 +1,19 @@ +@using System.Web.Http +@using ResourceTokenBroker.Areas.HelpPage.ModelDescriptions +@model ModelDescription + + +
+ +

@Model.Name

+

@Model.Documentation

+
+ @Html.DisplayFor(m => Model) +
+
diff --git a/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/Views/Shared/_Layout.cshtml b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/Views/Shared/_Layout.cshtml new file mode 100755 index 0000000..896c833 --- /dev/null +++ b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/Views/Shared/_Layout.cshtml @@ -0,0 +1,12 @@ + + + + + + @ViewBag.Title + @RenderSection("scripts", required: false) + + + @RenderBody() + + \ No newline at end of file diff --git a/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/Views/Web.config b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/Views/Web.config new file mode 100755 index 0000000..0971732 --- /dev/null +++ b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/Views/Web.config @@ -0,0 +1,41 @@ + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/Views/_ViewStart.cshtml b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/Views/_ViewStart.cshtml new file mode 100755 index 0000000..d735b1c --- /dev/null +++ b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/Views/_ViewStart.cshtml @@ -0,0 +1,4 @@ +@{ + // Change the Layout path below to blend the look and feel of the help page with your existing web pages + Layout = "~/Views/Shared/_Layout.cshtml"; +} \ No newline at end of file diff --git a/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/XmlDocumentationProvider.cs b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/XmlDocumentationProvider.cs new file mode 100755 index 0000000..99f705b --- /dev/null +++ b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Areas/HelpPage/XmlDocumentationProvider.cs @@ -0,0 +1,161 @@ +using System; +using System.Globalization; +using System.Linq; +using System.Reflection; +using System.Web.Http.Controllers; +using System.Web.Http.Description; +using System.Xml.XPath; +using ResourceTokenBroker.Areas.HelpPage.ModelDescriptions; + +namespace ResourceTokenBroker.Areas.HelpPage +{ + /// + /// A custom that reads the API documentation from an XML documentation file. + /// + public class XmlDocumentationProvider : IDocumentationProvider, IModelDocumentationProvider + { + private XPathNavigator _documentNavigator; + private const string TypeExpression = "/doc/members/member[@name='T:{0}']"; + private const string MethodExpression = "/doc/members/member[@name='M:{0}']"; + private const string PropertyExpression = "/doc/members/member[@name='P:{0}']"; + private const string FieldExpression = "/doc/members/member[@name='F:{0}']"; + private const string ParameterExpression = "param[@name='{0}']"; + + /// + /// Initializes a new instance of the class. + /// + /// The physical path to XML document. + public XmlDocumentationProvider(string documentPath) + { + if (documentPath == null) + { + throw new ArgumentNullException("documentPath"); + } + XPathDocument xpath = new XPathDocument(documentPath); + _documentNavigator = xpath.CreateNavigator(); + } + + public string GetDocumentation(HttpControllerDescriptor controllerDescriptor) + { + XPathNavigator typeNode = GetTypeNode(controllerDescriptor.ControllerType); + return GetTagValue(typeNode, "summary"); + } + + public virtual string GetDocumentation(HttpActionDescriptor actionDescriptor) + { + XPathNavigator methodNode = GetMethodNode(actionDescriptor); + return GetTagValue(methodNode, "summary"); + } + + public virtual string GetDocumentation(HttpParameterDescriptor parameterDescriptor) + { + ReflectedHttpParameterDescriptor reflectedParameterDescriptor = parameterDescriptor as ReflectedHttpParameterDescriptor; + if (reflectedParameterDescriptor != null) + { + XPathNavigator methodNode = GetMethodNode(reflectedParameterDescriptor.ActionDescriptor); + if (methodNode != null) + { + string parameterName = reflectedParameterDescriptor.ParameterInfo.Name; + XPathNavigator parameterNode = methodNode.SelectSingleNode(String.Format(CultureInfo.InvariantCulture, ParameterExpression, parameterName)); + if (parameterNode != null) + { + return parameterNode.Value.Trim(); + } + } + } + + return null; + } + + public string GetResponseDocumentation(HttpActionDescriptor actionDescriptor) + { + XPathNavigator methodNode = GetMethodNode(actionDescriptor); + return GetTagValue(methodNode, "returns"); + } + + public string GetDocumentation(MemberInfo member) + { + string memberName = String.Format(CultureInfo.InvariantCulture, "{0}.{1}", GetTypeName(member.DeclaringType), member.Name); + string expression = member.MemberType == MemberTypes.Field ? FieldExpression : PropertyExpression; + string selectExpression = String.Format(CultureInfo.InvariantCulture, expression, memberName); + XPathNavigator propertyNode = _documentNavigator.SelectSingleNode(selectExpression); + return GetTagValue(propertyNode, "summary"); + } + + public string GetDocumentation(Type type) + { + XPathNavigator typeNode = GetTypeNode(type); + return GetTagValue(typeNode, "summary"); + } + + private XPathNavigator GetMethodNode(HttpActionDescriptor actionDescriptor) + { + ReflectedHttpActionDescriptor reflectedActionDescriptor = actionDescriptor as ReflectedHttpActionDescriptor; + if (reflectedActionDescriptor != null) + { + string selectExpression = String.Format(CultureInfo.InvariantCulture, MethodExpression, GetMemberName(reflectedActionDescriptor.MethodInfo)); + return _documentNavigator.SelectSingleNode(selectExpression); + } + + return null; + } + + private static string GetMemberName(MethodInfo method) + { + string name = String.Format(CultureInfo.InvariantCulture, "{0}.{1}", GetTypeName(method.DeclaringType), method.Name); + ParameterInfo[] parameters = method.GetParameters(); + if (parameters.Length != 0) + { + string[] parameterTypeNames = parameters.Select(param => GetTypeName(param.ParameterType)).ToArray(); + name += String.Format(CultureInfo.InvariantCulture, "({0})", String.Join(",", parameterTypeNames)); + } + + return name; + } + + private static string GetTagValue(XPathNavigator parentNode, string tagName) + { + if (parentNode != null) + { + XPathNavigator node = parentNode.SelectSingleNode(tagName); + if (node != null) + { + return node.Value.Trim(); + } + } + + return null; + } + + private XPathNavigator GetTypeNode(Type type) + { + string controllerTypeName = GetTypeName(type); + string selectExpression = String.Format(CultureInfo.InvariantCulture, TypeExpression, controllerTypeName); + return _documentNavigator.SelectSingleNode(selectExpression); + } + + private static string GetTypeName(Type type) + { + string name = type.FullName; + if (type.IsGenericType) + { + // Format the generic type name to something like: Generic{System.Int32,System.String} + Type genericType = type.GetGenericTypeDefinition(); + Type[] genericArguments = type.GetGenericArguments(); + string genericTypeName = genericType.FullName; + + // Trim the generic parameter counts from the name + genericTypeName = genericTypeName.Substring(0, genericTypeName.IndexOf('`')); + string[] argumentTypeNames = genericArguments.Select(t => GetTypeName(t)).ToArray(); + name = String.Format(CultureInfo.InvariantCulture, "{0}{{{1}}}", genericTypeName, String.Join(",", argumentTypeNames)); + } + if (type.IsNested) + { + // Changing the nested type name from OuterType+InnerType to OuterType.InnerType to match the XML documentation syntax. + name = name.Replace("+", "."); + } + + return name; + } + } +} diff --git a/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Content/Site.css b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Content/Site.css new file mode 100755 index 0000000..d825a52 --- /dev/null +++ b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Content/Site.css @@ -0,0 +1,17 @@ +body { + padding-top: 50px; + padding-bottom: 20px; +} + +/* Set padding to keep content from hitting the edges */ +.body-content { + padding-left: 15px; + padding-right: 15px; +} + +/* Set width on the form input elements since they're 100% wide by default */ +input, +select, +textarea { + max-width: 280px; +} diff --git a/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Content/bootstrap.css b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Content/bootstrap.css new file mode 100755 index 0000000..6d6e682 --- /dev/null +++ b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/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/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Content/bootstrap.min.css b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Content/bootstrap.min.css new file mode 100755 index 0000000..df89a50 --- /dev/null +++ b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/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/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Controllers/ResourceTokenController.cs b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Controllers/ResourceTokenController.cs new file mode 100755 index 0000000..ba8c021 --- /dev/null +++ b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Controllers/ResourceTokenController.cs @@ -0,0 +1,202 @@ +using Microsoft.Azure.Documents; +using Microsoft.Azure.Documents.Client; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using System; +using System.Collections.Generic; +using System.Configuration; +using System.Linq; +using System.Net; +using System.Net.Http; +using System.Runtime.Serialization; +using System.Threading; +using System.Threading.Tasks; +using System.Web.Http; + +namespace ResourceTokenBroker.Controllers +{ + + + public class ResourceTokenController : ApiController + { + private static DocumentClient _client = null; + private string databaseId = ConfigurationManager.AppSettings["databaseId"]; + private string collectionId = ConfigurationManager.AppSettings["collectionId"]; + private string permissionId = ConfigurationManager.AppSettings["collectionId"] + "PK"; // needs to be unique per user + private string hostURL = ConfigurationManager.AppSettings["hostURL"]; + + private static DateTime BeginningOfTime = new DateTime(2017, 1, 1); + public static DocumentClient Client + { + get + { + if (_client == null) + { + _client = new DocumentClient(new System.Uri(ConfigurationManager.AppSettings["accountUrl"]), ConfigurationManager.AppSettings["accountKey"]); + } + return _client; + } + } + + public ResourceTokenController() + { + + } + + public async Task Get() + { + string userId = null; + + var token = this.Request.Headers.GetValues("x-zumo-auth").First(); + userId = await GetUserId(token); + + if (userId == null) return this.BadRequest("Request was authorized, but unable to fetch the user ID"); + + return await Get(userId); + } + private async Task GetUserId(string appserviceToken) + { + try + { + using (var http = new HttpClient()) + { + http.DefaultRequestHeaders.Add("x-zumo-auth", appserviceToken); + var response = await http.GetAsync(hostURL + "/.auth/me"); + string rs = await response.Content.ReadAsStringAsync(); + var rj = JsonConvert.DeserializeObject(rs); + return rj.Children().FirstOrDefault().Children().FirstOrDefault(x => x.Name == "user_id").Value.ToString(); + } + } + catch (Exception ex) + { + Console.WriteLine("Error: {0}", ex.ToString()); + return null; + } + } + + public async Task Get(string userId) + { + try + { + var permissionToken = await GetPermission(userId); + Console.WriteLine(" returned token " + permissionToken.Token + " with expires " + permissionToken.Expires); + return Ok(permissionToken); + } + catch (Exception ex) + { + return BadRequest(ex.Message); + } + + } + + private async Task GetPermission(string userId) + { + PermissionToken permissionToken = null; + + try + { + permissionToken = await GetCachedUserPermission(userId); + if (permissionToken != null) return permissionToken; + } + catch (DocumentClientException e) + { + if (e.StatusCode != System.Net.HttpStatusCode.NotFound) throw e; + } + //not cached or expired, get a new permission + permissionToken = await GetNewPermission(userId); + + //cache it + await CacheUserPermission(permissionToken); + + return permissionToken; + } + + private async Task GetCachedUserPermission(string userId) + { + Document permissionDocument = await Client.ReadDocumentAsync( + UriFactory.CreateDocumentUri(databaseId, collectionId, userId + "permission"), + new RequestOptions() { PartitionKey = new PartitionKey(userId) }); + int expires = permissionDocument.GetPropertyValue("expires"); + int fiveMinAgo = Convert.ToInt32(DateTime.UtcNow.AddMinutes(-5).Subtract(BeginningOfTime).TotalSeconds); + if (expires > fiveMinAgo) + { + return new PermissionToken() + { + Token = permissionDocument.GetPropertyValue("token"), + Expires = expires, + UserId = userId + }; + } + return null; + } + + private async Task CacheUserPermission(PermissionToken permissionToken) + { + permissionToken.Id = permissionToken.UserId + "permission"; + await Client.UpsertDocumentAsync(UriFactory.CreateDocumentCollectionUri(databaseId, collectionId), + permissionToken); + } + + private async Task GetNewPermission(string userId) + { + Permission permission = null; + try + { + permission = await Client.ReadPermissionAsync(UriFactory.CreatePermissionUri(databaseId, userId, permissionId)); + + } + catch (DocumentClientException e) + { + if (e.StatusCode == System.Net.HttpStatusCode.NotFound) + { + DocumentCollection collection = await Client.ReadDocumentCollectionAsync(UriFactory.CreateDocumentCollectionUri(databaseId, collectionId)); + Permission p = new Permission + { + PermissionMode = PermissionMode.All, + ResourceLink = collection.SelfLink, + ResourcePartitionKey = new PartitionKey(userId), + Id = permissionId //needs to be unique for a given user + }; + await CreateUserIfNotExistAsync(userId); + permission = await Client.CreatePermissionAsync(UriFactory.CreateUserUri(databaseId, userId), p); + } + else throw e; + } + var expires = Convert.ToInt32(DateTime.UtcNow.Subtract(BeginningOfTime).TotalSeconds) + 3600; // expires in 1h + return new PermissionToken() + { + Token = permission.Token, + Expires = expires, + UserId = userId + }; + } + private async Task CreateUserIfNotExistAsync(string userId) + { + try + { + await Client.ReadUserAsync(UriFactory.CreateUserUri(databaseId, userId)); + } + catch (DocumentClientException e) + { + if (e.StatusCode == System.Net.HttpStatusCode.NotFound) + { + await Client.CreateUserAsync(UriFactory.CreateDatabaseUri(databaseId), new User { Id = userId }); + } + } + + } + + + } + public class PermissionToken + { + [JsonProperty(PropertyName = "id")] + public string Id { get; set; } + [JsonProperty(PropertyName = "token")] + public string Token { get; set; } + [JsonProperty(PropertyName = "expires")] + public int Expires { get; set; } + [JsonProperty(PropertyName = "userid")] + public string UserId { get; set; } + } +} diff --git a/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Global.asax b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Global.asax new file mode 100755 index 0000000..3eb4b24 --- /dev/null +++ b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Global.asax @@ -0,0 +1 @@ +<%@ Application Codebehind="Global.asax.cs" Inherits="ResourceTokenBroker.WebApiApplication" Language="C#" %> diff --git a/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Global.asax.cs b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Global.asax.cs new file mode 100755 index 0000000..3fb9fd2 --- /dev/null +++ b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Global.asax.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; +using System.Web.Http; +using System.Web.Mvc; +using System.Web.Optimization; +using System.Web.Routing; + +namespace ResourceTokenBroker +{ + public class WebApiApplication : 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); + } + } +} diff --git a/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Models/AccountBindingModels.cs b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Models/AccountBindingModels.cs new file mode 100755 index 0000000..eee6136 --- /dev/null +++ b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Models/AccountBindingModels.cs @@ -0,0 +1,84 @@ +using System; +using System.ComponentModel.DataAnnotations; +using Newtonsoft.Json; + +namespace ResourceTokenBroker.Models +{ + // Models used as parameters to AccountController actions. + + public class AddExternalLoginBindingModel + { + [Required] + [Display(Name = "External access token")] + public string ExternalAccessToken { get; set; } + } + + public class ChangePasswordBindingModel + { + [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 RegisterBindingModel + { + [Required] + [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 class RegisterExternalBindingModel + { + [Required] + [Display(Name = "Email")] + public string Email { get; set; } + } + + public class RemoveLoginBindingModel + { + [Required] + [Display(Name = "Login provider")] + public string LoginProvider { get; set; } + + [Required] + [Display(Name = "Provider key")] + public string ProviderKey { get; set; } + } + + public class SetPasswordBindingModel + { + [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; } + } +} diff --git a/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Models/AccountViewModels.cs b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Models/AccountViewModels.cs new file mode 100755 index 0000000..f76e7e6 --- /dev/null +++ b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Models/AccountViewModels.cs @@ -0,0 +1,43 @@ +using System; +using System.Collections.Generic; + +namespace ResourceTokenBroker.Models +{ + // Models returned by AccountController actions. + + public class ExternalLoginViewModel + { + public string Name { get; set; } + + public string Url { get; set; } + + public string State { get; set; } + } + + public class ManageInfoViewModel + { + public string LocalLoginProvider { get; set; } + + public string Email { get; set; } + + public IEnumerable Logins { get; set; } + + public IEnumerable ExternalLoginProviders { get; set; } + } + + public class UserInfoViewModel + { + public string Email { get; set; } + + public bool HasRegistered { get; set; } + + public string LoginProvider { get; set; } + } + + public class UserLoginInfoViewModel + { + public string LoginProvider { get; set; } + + public string ProviderKey { get; set; } + } +} diff --git a/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Models/IdentityModels.cs b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Models/IdentityModels.cs new file mode 100755 index 0000000..cbc1b0d --- /dev/null +++ b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Models/IdentityModels.cs @@ -0,0 +1,33 @@ +using System.Security.Claims; +using System.Threading.Tasks; +using Microsoft.AspNet.Identity; +using Microsoft.AspNet.Identity.EntityFramework; +using Microsoft.AspNet.Identity.Owin; + +namespace ResourceTokenBroker.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 async Task GenerateUserIdentityAsync(UserManager manager, string authenticationType) + { + // Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType + var userIdentity = await manager.CreateIdentityAsync(this, authenticationType); + // Add custom user claims here + return userIdentity; + } + } + + public class ApplicationDbContext : IdentityDbContext + { + public ApplicationDbContext() + : base("DefaultConnection", throwIfV1Schema: false) + { + } + + public static ApplicationDbContext Create() + { + return new ApplicationDbContext(); + } + } +} \ No newline at end of file diff --git a/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Project_Readme.html b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Project_Readme.html new file mode 100755 index 0000000..5cc26aa --- /dev/null +++ b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Project_Readme.html @@ -0,0 +1,149 @@ + + + + + Your ASP.NET application + + + + + + + + + diff --git a/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Properties/AssemblyInfo.cs b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Properties/AssemblyInfo.cs new file mode 100755 index 0000000..663d425 --- /dev/null +++ b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/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("ResourceTokenBroker")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("ResourceTokenBroker")] +[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("9f050a77-08d0-458d-ad9f-5150c41514b8")] + +// 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.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Providers/ApplicationOAuthProvider.cs b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Providers/ApplicationOAuthProvider.cs new file mode 100755 index 0000000..e352925 --- /dev/null +++ b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Providers/ApplicationOAuthProvider.cs @@ -0,0 +1,98 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Security.Claims; +using System.Threading.Tasks; +using Microsoft.AspNet.Identity; +using Microsoft.AspNet.Identity.EntityFramework; +using Microsoft.AspNet.Identity.Owin; +using Microsoft.Owin.Security; +using Microsoft.Owin.Security.Cookies; +using Microsoft.Owin.Security.OAuth; +using ResourceTokenBroker.Models; + +namespace ResourceTokenBroker.Providers +{ + public class ApplicationOAuthProvider : OAuthAuthorizationServerProvider + { + private readonly string _publicClientId; + + public ApplicationOAuthProvider(string publicClientId) + { + if (publicClientId == null) + { + throw new ArgumentNullException("publicClientId"); + } + + _publicClientId = publicClientId; + } + + public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context) + { + var userManager = context.OwinContext.GetUserManager(); + + ApplicationUser user = await userManager.FindAsync(context.UserName, context.Password); + + if (user == null) + { + context.SetError("invalid_grant", "The user name or password is incorrect."); + return; + } + + ClaimsIdentity oAuthIdentity = await user.GenerateUserIdentityAsync(userManager, + OAuthDefaults.AuthenticationType); + ClaimsIdentity cookiesIdentity = await user.GenerateUserIdentityAsync(userManager, + CookieAuthenticationDefaults.AuthenticationType); + + AuthenticationProperties properties = CreateProperties(user.UserName); + AuthenticationTicket ticket = new AuthenticationTicket(oAuthIdentity, properties); + context.Validated(ticket); + context.Request.Context.Authentication.SignIn(cookiesIdentity); + } + + public override Task TokenEndpoint(OAuthTokenEndpointContext context) + { + foreach (KeyValuePair property in context.Properties.Dictionary) + { + context.AdditionalResponseParameters.Add(property.Key, property.Value); + } + + return Task.FromResult(null); + } + + public override Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context) + { + // Resource owner password credentials does not provide a client ID. + if (context.ClientId == null) + { + context.Validated(); + } + + return Task.FromResult(null); + } + + public override Task ValidateClientRedirectUri(OAuthValidateClientRedirectUriContext context) + { + if (context.ClientId == _publicClientId) + { + Uri expectedRootUri = new Uri(context.Request.Uri, "/"); + + if (expectedRootUri.AbsoluteUri == context.RedirectUri) + { + context.Validated(); + } + } + + return Task.FromResult(null); + } + + public static AuthenticationProperties CreateProperties(string userName) + { + IDictionary data = new Dictionary + { + { "userName", userName } + }; + return new AuthenticationProperties(data); + } + } +} \ No newline at end of file diff --git a/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/ResourceTokenBroker.csproj b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/ResourceTokenBroker.csproj new file mode 100755 index 0000000..bb63a3b --- /dev/null +++ b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/ResourceTokenBroker.csproj @@ -0,0 +1,331 @@ + + + + + + + Debug + AnyCPU + + + 2.0 + {C4233D06-E76E-4459-8D44-B9DDBEB4369C} + {349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc} + Library + Properties + ResourceTokenBroker + ResourceTokenBroker + v4.5.2 + false + true + + + + + + + + + + true + full + false + bin\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\ + TRACE + prompt + 4 + + + + ..\packages\Microsoft.Azure.DocumentDB.1.11.0\lib\net45\Microsoft.Azure.Documents.Client.dll + True + + + ..\packages\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.1.0.0\lib\net45\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.dll + True + + + + ..\packages\Newtonsoft.Json.6.0.8\lib\net45\Newtonsoft.Json.dll + True + + + + + + + + + + + + + + + + + + True + ..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll + + + + + ..\packages\Microsoft.AspNet.WebApi.Client.5.2.3\lib\net45\System.Net.Http.Formatting.dll + + + + + True + ..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.Helpers.dll + + + ..\packages\Microsoft.AspNet.WebApi.Core.5.2.3\lib\net45\System.Web.Http.dll + + + ..\packages\Microsoft.AspNet.WebApi.WebHost.5.2.3\lib\net45\System.Web.Http.WebHost.dll + + + True + ..\packages\Microsoft.AspNet.Mvc.5.2.3\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.3\lib\net45\System.Web.Razor.dll + + + True + ..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.dll + + + True + ..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Deployment.dll + + + True + ..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Razor.dll + + + True + ..\packages\WebGrease.1.5.2\lib\WebGrease.dll + + + True + ..\packages\Antlr.3.4.1.9004\lib\Antlr3.Runtime.dll + + + + + ..\packages\EntityFramework.6.1.3\lib\net45\EntityFramework.dll + + + ..\packages\EntityFramework.6.1.3\lib\net45\EntityFramework.SqlServer.dll + + + ..\packages\Microsoft.AspNet.Identity.Core.2.2.1\lib\net45\Microsoft.AspNet.Identity.Core.dll + + + ..\packages\Microsoft.AspNet.Identity.Owin.2.2.1\lib\net45\Microsoft.AspNet.Identity.Owin.dll + + + ..\packages\Microsoft.AspNet.Identity.EntityFramework.2.2.1\lib\net45\Microsoft.AspNet.Identity.EntityFramework.dll + + + ..\packages\Owin.1.0\lib\net40\Owin.dll + + + ..\packages\Microsoft.Owin.3.0.1\lib\net45\Microsoft.Owin.dll + + + ..\packages\Microsoft.Owin.Host.SystemWeb.3.0.1\lib\net45\Microsoft.Owin.Host.SystemWeb.dll + + + ..\packages\Microsoft.Owin.Security.3.0.1\lib\net45\Microsoft.Owin.Security.dll + + + ..\packages\Microsoft.Owin.Security.Facebook.3.0.1\lib\net45\Microsoft.Owin.Security.Facebook.dll + + + ..\packages\Microsoft.Owin.Security.Cookies.3.0.1\lib\net45\Microsoft.Owin.Security.Cookies.dll + + + ..\packages\Microsoft.Owin.Security.OAuth.3.0.1\lib\net45\Microsoft.Owin.Security.OAuth.dll + + + ..\packages\Microsoft.Owin.Security.Google.3.0.1\lib\net45\Microsoft.Owin.Security.Google.dll + + + ..\packages\Microsoft.Owin.Security.Twitter.3.0.1\lib\net45\Microsoft.Owin.Security.Twitter.dll + + + ..\packages\Microsoft.Owin.Security.MicrosoftAccount.3.0.1\lib\net45\Microsoft.Owin.Security.MicrosoftAccount.dll + + + ..\packages\Microsoft.AspNet.WebApi.Owin.5.2.3\lib\net45\System.Web.Http.Owin.dll + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Global.asax + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Web.config + + + Web.config + + + + + + + + + + + + + + + + + + + 10.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + + + + + + + + + True + True + 18526 + / + http://localhost:18526/ + 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/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Results/ChallengeResult.cs b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Results/ChallengeResult.cs new file mode 100755 index 0000000..a1c7c58 --- /dev/null +++ b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Results/ChallengeResult.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Net.Http; +using System.Threading; +using System.Threading.Tasks; +using System.Web.Http; + +namespace ResourceTokenBroker.Results +{ + public class ChallengeResult : IHttpActionResult + { + public ChallengeResult(string loginProvider, ApiController controller) + { + LoginProvider = loginProvider; + Request = controller.Request; + } + + public string LoginProvider { get; set; } + public HttpRequestMessage Request { get; set; } + + public Task ExecuteAsync(CancellationToken cancellationToken) + { + Request.GetOwinContext().Authentication.Challenge(LoginProvider); + + HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.Unauthorized); + response.RequestMessage = Request; + return Task.FromResult(response); + } + } +} diff --git a/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Scripts/_references.js b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Scripts/_references.js new file mode 100755 index 0000000..cbe7a47 Binary files /dev/null and b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Scripts/_references.js differ diff --git a/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Scripts/bootstrap.js b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Scripts/bootstrap.js new file mode 100755 index 0000000..5aa9982 --- /dev/null +++ b/samples/xamarin/UserItems/ResourceTokenBroker/ResourceTokenBroker/Scripts/bootstrap.js @@ -0,0 +1,2014 @@ +/* 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. Insofar as a script file is dual licensed under GPL, + * Microsoft neither took the code under GPL nor distributes it thereunder but + * under the terms set out in this paragraph. All notices and licenses + * below are for informational purposes only. + * + * NUGET: END LICENSE TEXT */ + +/** +* bootstrap.js v3.0.0 by @fat and @mdo +* Copyright 2013 Twitter Inc. +* http://www.apache.org/licenses/LICENSE-2.0 +*/ +if (!jQuery) { throw new Error("Bootstrap requires jQuery") } + +/* ======================================================================== + * Bootstrap: transition.js v3.0.0 + * http://twbs.github.com/bootstrap/javascript.html#transitions + * ======================================================================== + * Copyright 2013 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ======================================================================== */ + + ++function ($) { "use strict"; + + // CSS TRANSITION SUPPORT (Shoutout: http://www.modernizr.com/) + // ============================================================ + + function transitionEnd() { + var el = document.createElement('bootstrap') + + var transEndEventNames = { + 'WebkitTransition' : 'webkitTransitionEnd' + , 'MozTransition' : 'transitionend' + , 'OTransition' : 'oTransitionEnd otransitionend' + , 'transition' : 'transitionend' + } + + for (var name in transEndEventNames) { + if (el.style[name] !== undefined) { + return { end: transEndEventNames[name] } + } + } + } + + // http://blog.alexmaccaw.com/css-transitions + $.fn.emulateTransitionEnd = function (duration) { + var called = false, $el = this + $(this).one($.support.transition.end, function () { called = true }) + var callback = function () { if (!called) $($el).trigger($.support.transition.end) } + setTimeout(callback, duration) + return this + } + + $(function () { + $.support.transition = transitionEnd() + }) + +}(window.jQuery); + +/* ======================================================================== + * Bootstrap: alert.js v3.0.0 + * http://twbs.github.com/bootstrap/javascript.html#alerts + * ======================================================================== + * Copyright 2013 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ======================================================================== */ + + ++function ($) { "use strict"; + + // ALERT CLASS DEFINITION + // ====================== + + var dismiss = '[data-dismiss="alert"]' + var Alert = function (el) { + $(el).on('click', dismiss, this.close) + } + + Alert.prototype.close = function (e) { + var $this = $(this) + var selector = $this.attr('data-target') + + if (!selector) { + selector = $this.attr('href') + selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7 + } + + var $parent = $(selector) + + if (e) e.preventDefault() + + if (!$parent.length) { + $parent = $this.hasClass('alert') ? $this : $this.parent() + } + + $parent.trigger(e = $.Event('close.bs.alert')) + + if (e.isDefaultPrevented()) return + + $parent.removeClass('in') + + function removeElement() { + $parent.trigger('closed.bs.alert').remove() + } + + $.support.transition && $parent.hasClass('fade') ? + $parent + .one($.support.transition.end, removeElement) + .emulateTransitionEnd(150) : + removeElement() + } + + + // ALERT PLUGIN DEFINITION + // ======================= + + var old = $.fn.alert + + $.fn.alert = function (option) { + return this.each(function () { + var $this = $(this) + var data = $this.data('bs.alert') + + if (!data) $this.data('bs.alert', (data = new Alert(this))) + if (typeof option == 'string') data[option].call($this) + }) + } + + $.fn.alert.Constructor = Alert + + + // ALERT NO CONFLICT + // ================= + + $.fn.alert.noConflict = function () { + $.fn.alert = old + return this + } + + + // ALERT DATA-API + // ============== + + $(document).on('click.bs.alert.data-api', dismiss, Alert.prototype.close) + +}(window.jQuery); + +/* ======================================================================== + * Bootstrap: button.js v3.0.0 + * http://twbs.github.com/bootstrap/javascript.html#buttons + * ======================================================================== + * Copyright 2013 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ======================================================================== */ + + ++function ($) { "use strict"; + + // BUTTON PUBLIC CLASS DEFINITION + // ============================== + + var Button = function (element, options) { + this.$element = $(element) + this.options = $.extend({}, Button.DEFAULTS, options) + } + + Button.DEFAULTS = { + loadingText: 'loading...' + } + + Button.prototype.setState = function (state) { + var d = 'disabled' + var $el = this.$element + var val = $el.is('input') ? 'val' : 'html' + var data = $el.data() + + state = state + 'Text' + + if (!data.resetText) $el.data('resetText', $el[val]()) + + $el[val](data[state] || this.options[state]) + + // push to event loop to allow forms to submit + setTimeout(function () { + state == 'loadingText' ? + $el.addClass(d).attr(d, d) : + $el.removeClass(d).removeAttr(d); + }, 0) + } + + Button.prototype.toggle = function () { + var $parent = this.$element.closest('[data-toggle="buttons"]') + + if ($parent.length) { + var $input = this.$element.find('input') + .prop('checked', !this.$element.hasClass('active')) + .trigger('change') + if ($input.prop('type') === 'radio') $parent.find('.active').removeClass('active') + } + + this.$element.toggleClass('active') + } + + + // BUTTON PLUGIN DEFINITION + // ======================== + + var old = $.fn.button + + $.fn.button = function (option) { + return this.each(function () { + var $this = $(this) + var data = $this.data('bs.button') + var options = typeof option == 'object' && option + + if (!data) $this.data('bs.button', (data = new Button(this, options))) + + if (option == 'toggle') data.toggle() + else if (option) data.setState(option) + }) + } + + $.fn.button.Constructor = Button + + + // BUTTON NO CONFLICT + // ================== + + $.fn.button.noConflict = function () { + $.fn.button = old + return this + } + + + // BUTTON DATA-API + // =============== + + $(document).on('click.bs.button.data-api', '[data-toggle^=button]', function (e) { + var $btn = $(e.target) + if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn') + $btn.button('toggle') + e.preventDefault() + }) + +}(window.jQuery); + +/* ======================================================================== + * Bootstrap: carousel.js v3.0.0 + * http://twbs.github.com/bootstrap/javascript.html#carousel + * ======================================================================== + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ======================================================================== */ + + ++function ($) { "use strict"; + + // CAROUSEL CLASS DEFINITION + // ========================= + + var Carousel = function (element, options) { + this.$element = $(element) + this.$indicators = this.$element.find('.carousel-indicators') + this.options = options + this.paused = + this.sliding = + this.interval = + this.$active = + this.$items = null + + this.options.pause == 'hover' && this.$element + .on('mouseenter', $.proxy(this.pause, this)) + .on('mouseleave', $.proxy(this.cycle, this)) + } + + Carousel.DEFAULTS = { + interval: 5000 + , pause: 'hover' + , wrap: true + } + + Carousel.prototype.cycle = function (e) { + e || (this.paused = false) + + this.interval && clearInterval(this.interval) + + this.options.interval + && !this.paused + && (this.interval = setInterval($.proxy(this.next, this), this.options.interval)) + + return this + } + + Carousel.prototype.getActiveIndex = function () { + this.$active = this.$element.find('.item.active') + this.$items = this.$active.parent().children() + + return this.$items.index(this.$active) + } + + Carousel.prototype.to = function (pos) { + var that = this + var activeIndex = this.getActiveIndex() + + if (pos > (this.$items.length - 1) || pos < 0) return + + if (this.sliding) return this.$element.one('slid', function () { that.to(pos) }) + if (activeIndex == pos) return this.pause().cycle() + + return this.slide(pos > activeIndex ? 'next' : 'prev', $(this.$items[pos])) + } + + Carousel.prototype.pause = function (e) { + e || (this.paused = true) + + if (this.$element.find('.next, .prev').length && $.support.transition.end) { + this.$element.trigger($.support.transition.end) + this.cycle(true) + } + + this.interval = clearInterval(this.interval) + + return this + } + + Carousel.prototype.next = function () { + if (this.sliding) return + return this.slide('next') + } + + Carousel.prototype.prev = function () { + if (this.sliding) return + return this.slide('prev') + } + + Carousel.prototype.slide = function (type, next) { + var $active = this.$element.find('.item.active') + var $next = next || $active[type]() + var isCycling = this.interval + var direction = type == 'next' ? 'left' : 'right' + var fallback = type == 'next' ? 'first' : 'last' + var that = this + + if (!$next.length) { + if (!this.options.wrap) return + $next = this.$element.find('.item')[fallback]() + } + + this.sliding = true + + isCycling && this.pause() + + var e = $.Event('slide.bs.carousel', { relatedTarget: $next[0], direction: direction }) + + if ($next.hasClass('active')) return + + if (this.$indicators.length) { + this.$indicators.find('.active').removeClass('active') + this.$element.one('slid', function () { + var $nextIndicator = $(that.$indicators.children()[that.getActiveIndex()]) + $nextIndicator && $nextIndicator.addClass('active') + }) + } + + if ($.support.transition && this.$element.hasClass('slide')) { + this.$element.trigger(e) + if (e.isDefaultPrevented()) return + $next.addClass(type) + $next[0].offsetWidth // force reflow + $active.addClass(direction) + $next.addClass(direction) + $active + .one($.support.transition.end, function () { + $next.removeClass([type, direction].join(' ')).addClass('active') + $active.removeClass(['active', direction].join(' ')) + that.sliding = false + setTimeout(function () { that.$element.trigger('slid') }, 0) + }) + .emulateTransitionEnd(600) + } else { + this.$element.trigger(e) + if (e.isDefaultPrevented()) return + $active.removeClass('active') + $next.addClass('active') + this.sliding = false + this.$element.trigger('slid') + } + + isCycling && this.cycle() + + return this + } + + + // CAROUSEL PLUGIN DEFINITION + // ========================== + + var old = $.fn.carousel + + $.fn.carousel = function (option) { + return this.each(function () { + var $this = $(this) + var data = $this.data('bs.carousel') + var options = $.extend({}, Carousel.DEFAULTS, $this.data(), typeof option == 'object' && option) + var action = typeof option == 'string' ? option : options.slide + + if (!data) $this.data('bs.carousel', (data = new Carousel(this, options))) + if (typeof option == 'number') data.to(option) + else if (action) data[action]() + else if (options.interval) data.pause().cycle() + }) + } + + $.fn.carousel.Constructor = Carousel + + + // CAROUSEL NO CONFLICT + // ==================== + + $.fn.carousel.noConflict = function () { + $.fn.carousel = old + return this + } + + + // CAROUSEL DATA-API + // ================= + + $(document).on('click.bs.carousel.data-api', '[data-slide], [data-slide-to]', function (e) { + var $this = $(this), href + var $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7 + var options = $.extend({}, $target.data(), $this.data()) + var slideIndex = $this.attr('data-slide-to') + if (slideIndex) options.interval = false + + $target.carousel(options) + + if (slideIndex = $this.attr('data-slide-to')) { + $target.data('bs.carousel').to(slideIndex) + } + + e.preventDefault() + }) + + $(window).on('load', function () { + $('[data-ride="carousel"]').each(function () { + var $carousel = $(this) + $carousel.carousel($carousel.data()) + }) + }) + +}(window.jQuery); + +/* ======================================================================== + * Bootstrap: collapse.js v3.0.0 + * http://twbs.github.com/bootstrap/javascript.html#collapse + * ======================================================================== + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ======================================================================== */ + + ++function ($) { "use strict"; + + // COLLAPSE PUBLIC CLASS DEFINITION + // ================================ + + var Collapse = function (element, options) { + this.$element = $(element) + this.options = $.extend({}, Collapse.DEFAULTS, options) + this.transitioning = null + + if (this.options.parent) this.$parent = $(this.options.parent) + if (this.options.toggle) this.toggle() + } + + Collapse.DEFAULTS = { + toggle: true + } + + Collapse.prototype.dimension = function () { + var hasWidth = this.$element.hasClass('width') + return hasWidth ? 'width' : 'height' + } + + Collapse.prototype.show = function () { + if (this.transitioning || this.$element.hasClass('in')) return + + var startEvent = $.Event('show.bs.collapse') + this.$element.trigger(startEvent) + if (startEvent.isDefaultPrevented()) return + + var actives = this.$parent && this.$parent.find('> .panel > .in') + + if (actives && actives.length) { + var hasData = actives.data('bs.collapse') + if (hasData && hasData.transitioning) return + actives.collapse('hide') + hasData || actives.data('bs.collapse', null) + } + + var dimension = this.dimension() + + this.$element + .removeClass('collapse') + .addClass('collapsing') + [dimension](0) + + this.transitioning = 1 + + var complete = function () { + this.$element + .removeClass('collapsing') + .addClass('in') + [dimension]('auto') + this.transitioning = 0 + this.$element.trigger('shown.bs.collapse') + } + + if (!$.support.transition) return complete.call(this) + + var scrollSize = $.camelCase(['scroll', dimension].join('-')) + + this.$element + .one($.support.transition.end, $.proxy(complete, this)) + .emulateTransitionEnd(350) + [dimension](this.$element[0][scrollSize]) + } + + Collapse.prototype.hide = function () { + if (this.transitioning || !this.$element.hasClass('in')) return + + var startEvent = $.Event('hide.bs.collapse') + this.$element.trigger(startEvent) + if (startEvent.isDefaultPrevented()) return + + var dimension = this.dimension() + + this.$element + [dimension](this.$element[dimension]()) + [0].offsetHeight + + this.$element + .addClass('collapsing') + .removeClass('collapse') + .removeClass('in') + + this.transitioning = 1 + + var complete = function () { + this.transitioning = 0 + this.$element + .trigger('hidden.bs.collapse') + .removeClass('collapsing') + .addClass('collapse') + } + + if (!$.support.transition) return complete.call(this) + + this.$element + [dimension](0) + .one($.support.transition.end, $.proxy(complete, this)) + .emulateTransitionEnd(350) + } + + Collapse.prototype.toggle = function () { + this[this.$element.hasClass('in') ? 'hide' : 'show']() + } + + + // COLLAPSE PLUGIN DEFINITION + // ========================== + + var old = $.fn.collapse + + $.fn.collapse = function (option) { + return this.each(function () { + var $this = $(this) + var data = $this.data('bs.collapse') + var options = $.extend({}, Collapse.DEFAULTS, $this.data(), typeof option == 'object' && option) + + if (!data) $this.data('bs.collapse', (data = new Collapse(this, options))) + if (typeof option == 'string') data[option]() + }) + } + + $.fn.collapse.Constructor = Collapse + + + // COLLAPSE NO CONFLICT + // ==================== + + $.fn.collapse.noConflict = function () { + $.fn.collapse = old + return this + } + + + // COLLAPSE DATA-API + // ================= + + $(document).on('click.bs.collapse.data-api', '[data-toggle=collapse]', function (e) { + var $this = $(this), href + var target = $this.attr('data-target') + || e.preventDefault() + || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') //strip for ie7 + var $target = $(target) + var data = $target.data('bs.collapse') + var option = data ? 'toggle' : $this.data() + var parent = $this.attr('data-parent') + var $parent = parent && $(parent) + + if (!data || !data.transitioning) { + if ($parent) $parent.find('[data-toggle=collapse][data-parent="' + parent + '"]').not($this).addClass('collapsed') + $this[$target.hasClass('in') ? 'addClass' : 'removeClass']('collapsed') + } + + $target.collapse(option) + }) + +}(window.jQuery); + +/* ======================================================================== + * Bootstrap: dropdown.js v3.0.0 + * http://twbs.github.com/bootstrap/javascript.html#dropdowns + * ======================================================================== + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ======================================================================== */ + + ++function ($) { "use strict"; + + // DROPDOWN CLASS DEFINITION + // ========================= + + var backdrop = '.dropdown-backdrop' + var toggle = '[data-toggle=dropdown]' + var Dropdown = function (element) { + var $el = $(element).on('click.bs.dropdown', this.toggle) + } + + Dropdown.prototype.toggle = function (e) { + var $this = $(this) + + if ($this.is('.disabled, :disabled')) return + + var $parent = getParent($this) + var isActive = $parent.hasClass('open') + + clearMenus() + + if (!isActive) { + if ('ontouchstart' in document.documentElement && !$parent.closest('.navbar-nav').length) { + // if mobile we we use a backdrop because click events don't delegate + $('