├── .gitignore ├── README.md ├── TwilioChat.Tests ├── Controllers │ └── TokenControllerTest.cs ├── Properties │ └── AssemblyInfo.cs ├── TwilioChat.Tests.csproj ├── app.config └── packages.config ├── TwilioChat.Web ├── App_Start │ ├── BundleConfig.cs │ ├── FilterConfig.cs │ └── RouteConfig.cs ├── Content │ ├── Images │ │ ├── add-channel-image.png │ │ ├── connect-image.png │ │ └── twilio-logo.png │ ├── Site.css │ ├── bootstrap-theme.css │ ├── bootstrap-theme.css.map │ ├── bootstrap-theme.min.css │ ├── bootstrap-theme.min.css.map │ ├── bootstrap.css │ ├── bootstrap.css.map │ ├── bootstrap.min.css │ ├── bootstrap.min.css.map │ ├── font-awesome.css │ ├── font-awesome.min.css │ └── twilio-chat.css ├── Controllers │ ├── HomeController.cs │ └── TokenController.cs ├── Domain │ ├── Configuration.cs │ └── TokenGenerator.cs ├── Global.asax ├── Global.asax.cs ├── Properties │ └── AssemblyInfo.cs ├── Scripts │ ├── karma.conf.js │ ├── lib │ │ ├── _references.js │ │ ├── bootstrap.js │ │ ├── bootstrap.min.js │ │ ├── dateformatter.js │ │ ├── jquery-2.2.0.intellisense.js │ │ ├── jquery-2.2.0.js │ │ ├── jquery-2.2.0.min.js │ │ ├── jquery-2.2.0.min.map │ │ ├── jquery-throttle.min.js │ │ ├── jquery.loadTemplate-1.4.4.min.js │ │ ├── jquery.validate-vsdoc.js │ │ ├── jquery.validate.js │ │ ├── jquery.validate.min.js │ │ ├── jquery.validate.unobtrusive.js │ │ ├── jquery.validate.unobtrusive.min.js │ │ ├── modernizr-2.8.3.js │ │ ├── respond.js │ │ ├── respond.matchmedia.addListener.js │ │ ├── respond.matchmedia.addListener.min.js │ │ ├── respond.min.js │ │ └── twiliochat.js │ ├── package-lock.json │ ├── package.json │ └── tests │ │ ├── tests.html │ │ └── tests.js ├── TwilioChat.Web.csproj ├── Views │ ├── Home │ │ └── Index.cshtml │ ├── Shared │ │ ├── Error.cshtml │ │ └── _Layout.cshtml │ ├── Web.config │ └── _ViewStart.cshtml ├── Web.Debug.config ├── Web.Release.config ├── Web.config ├── favicon.ico ├── fonts │ ├── FontAwesome.otf │ ├── fontawesome-webfont.eot │ ├── fontawesome-webfont.svg │ ├── fontawesome-webfont.ttf │ ├── fontawesome-webfont.woff │ ├── fontawesome-webfont.woff2 │ ├── glyphicons-halflings-regular.eot │ ├── glyphicons-halflings-regular.svg │ ├── glyphicons-halflings-regular.ttf │ ├── glyphicons-halflings-regular.woff │ └── glyphicons-halflings-regular.woff2 └── packages.config ├── TwilioChat.sln └── appveyor.yml /.gitignore: -------------------------------------------------------------------------------- 1 | Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | x64/ 19 | x86/ 20 | build/ 21 | bld/ 22 | [Bb]in/ 23 | [Oo]bj/ 24 | 25 | # Visual Studo 2015 cache/options directory 26 | .vs/ 27 | 28 | # MSTest test Results 29 | [Tt]est[Rr]esult*/ 30 | [Bb]uild[Ll]og.* 31 | 32 | # NUNIT 33 | *.VisualState.xml 34 | TestResult.xml 35 | 36 | # Build Results of an ATL Project 37 | [Dd]ebugPS/ 38 | [Rr]eleasePS/ 39 | dlldata.c 40 | 41 | *_i.c 42 | *_p.c 43 | *_i.h 44 | *.ilk 45 | *.meta 46 | *.obj 47 | *.pch 48 | *.pdb 49 | *.pgc 50 | *.pgd 51 | *.rsp 52 | *.sbr 53 | *.tlb 54 | *.tli 55 | *.tlh 56 | *.tmp 57 | *.tmp_proj 58 | *.log 59 | *.vspscc 60 | *.vssscc 61 | .builds 62 | *.pidb 63 | *.svclog 64 | *.scc 65 | 66 | # Chutzpah Test files 67 | _Chutzpah* 68 | 69 | # Visual C++ cache files 70 | ipch/ 71 | *.aps 72 | *.ncb 73 | *.opensdf 74 | *.sdf 75 | *.cachefile 76 | 77 | # Visual Studio profiler 78 | *.psess 79 | *.vsp 80 | *.vspx 81 | 82 | # TFS 2012 Local Workspace 83 | $tf/ 84 | 85 | # Guidance Automation Toolkit 86 | *.gpState 87 | 88 | # ReSharper is a .NET coding add-in 89 | _ReSharper*/ 90 | *.[Rr]e[Ss]harper 91 | *.DotSettings.user 92 | 93 | # JustCode is a .NET coding addin-in 94 | .JustCode 95 | 96 | # TeamCity is a build add-in 97 | _TeamCity* 98 | 99 | # DotCover is a Code Coverage Tool 100 | *.dotCover 101 | 102 | # NCrunch 103 | _NCrunch_* 104 | .*crunch*.local.xml 105 | 106 | # MightyMoose 107 | *.mm.* 108 | AutoTest.Net/ 109 | 110 | # Web workbench (sass) 111 | .sass-cache/ 112 | 113 | # Installshield output folder 114 | [Ee]xpress/ 115 | 116 | # DocProject is a documentation generator add-in 117 | DocProject/buildhelp/ 118 | DocProject/Help/*.HxT 119 | DocProject/Help/*.HxC 120 | DocProject/Help/*.hhc 121 | DocProject/Help/*.hhk 122 | DocProject/Help/*.hhp 123 | DocProject/Help/Html2 124 | DocProject/Help/html 125 | 126 | # Click-Once directory 127 | publish/ 128 | 129 | # Publish Web Output 130 | *.[Pp]ublish.xml 131 | *.azurePubxml 132 | # TODO: Comment the next line if you want to checkin your web deploy settings 133 | # but database connection strings (with potential passwords) will be unencrypted 134 | *.pubxml 135 | *.publishproj 136 | 137 | # NuGet Packages 138 | *.nupkg 139 | # The packages folder can be ignored because of Package Restore 140 | **/packages/* 141 | # except build/, which is used as an MSBuild target. 142 | !**/packages/build/ 143 | # Uncomment if necessary however generally it will be regenerated when needed 144 | #!**/packages/repositories.config 145 | 146 | # Windows Azure Build Output 147 | csx/ 148 | *.build.csdef 149 | 150 | # Windows Store app package directory 151 | AppPackages/ 152 | 153 | # Others 154 | *.[Cc]ache 155 | ClientBin/ 156 | [Ss]tyle[Cc]op.* 157 | ~$* 158 | *~ 159 | *.dbmdl 160 | *.dbproj.schemaview 161 | *.pfx 162 | *.publishsettings 163 | node_modules/ 164 | bower_components/ 165 | 166 | # RIA/Silverlight projects 167 | Generated_Code/ 168 | 169 | # Backup & report files from converting an old project file 170 | # to a newer Visual Studio version. Backup files are not needed, 171 | # because we have git ;-) 172 | _UpgradeReport_Files/ 173 | Backup*/ 174 | UpgradeLog*.XML 175 | UpgradeLog*.htm 176 | 177 | # SQL Server files 178 | *.mdf 179 | *.ldf 180 | 181 | # Business Intelligence projects 182 | *.rdl.data 183 | *.bim.layout 184 | *.bim_*.settings 185 | 186 | # Microsoft Fakes 187 | FakesAssemblies/ 188 | 189 | # Node.js Tools for Visual Studio 190 | .ntvs_analysis.dat 191 | 192 | # Visual Studio 6 build log 193 | *.plg 194 | 195 | # Visual Studio 6 workspace options file 196 | *.opt 197 | 198 | # Project 199 | TwilioChat.Web/Local.config 200 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | Twilio 3 | 4 | 5 | # Important Notice 6 | 7 | We intend to sunset the Programmable Chat API on July 25, 2022 to focus on the next generation of chat: the [Twilio Conversations API](https://www.twilio.com/docs/conversations). Find out about the [EOL process](https://www.twilio.com/changelog/programmable-chat-end-of-life). We have also prepared [this Migration Guide](https://www.twilio.com/docs/conversations/migrating-chat-conversations) to assist in the transition from Chat to Conversations. 8 | 9 | # Twilio Chat - ASP.NET MVC 10 | 11 | C# implementation of Twilio Chat using ASP.NET MVC 12 | 13 | [![Build status](https://ci.appveyor.com/api/projects/status/e0h30vnonbjwyyhd/branch/master?svg=true)](https://ci.appveyor.com/project/TwilioDevEd/twiliochat-csharp/branch/master) 14 | 15 | ## Local Development 16 | 17 | **NOTE**: You need a Windows environment with Visual Studio to run this project. Since this project was made using .NET Framework 4.5, it's not compatible with .NET Core, so it's mandatory to run on Windows. 18 | 19 | 1. Clone this repository and `cd` into its directory: 20 | ``` 21 | git clone git@github.com:TwilioDevEd/twiliochat-csharp.git 22 | cd twiliochat-csharp 23 | ``` 24 | 25 | 1. Create a new file `TwilioChat.Web/Local.config` and update the content with: 26 | ``` 27 | 28 | 29 | 30 | 31 | 32 | 33 | ``` 34 | 35 | As usual your `TwilioAccountSid` can be found at https://www.twilio.com/user/account 36 | 37 | Your `TwilioApiKey` and `TwilioApiSecret` can be found at https://www.twilio.com/console/dev-tools/api-keys 38 | 39 | And finally, your `TwilioChatServiceSid` can be found at https://www.twilio.com/console/chat/dashboard 40 | 41 | 1. Open the project using Visual Studio 42 | 43 | 1. Using Visual Studio's UI, choose Build Solution from the Build menu. 44 | 45 | 1. To run the code, click the green play button in the toolbar. 46 | 47 | 1. Check it out at [http://localhost:1398](http://localhost:1398) 48 | 49 | That's it! 50 | 51 | ## Tests 52 | 53 | 1. If Test Explorer is not open, open it by choosing Test > Windows > Test Explorer from the top menu bar. 54 | 1. Choose Run All to run the tests. 55 | 56 | ## Meta 57 | 58 | * No warranty expressed or implied. Software is as is. Diggity. 59 | * [MIT License](http://www.opensource.org/licenses/mit-license.html) 60 | * Lovingly crafted by Twilio Developer Education. 61 | -------------------------------------------------------------------------------- /TwilioChat.Tests/Controllers/TokenControllerTest.cs: -------------------------------------------------------------------------------- 1 | using Moq; 2 | using NUnit.Framework; 3 | using TestStack.FluentMVCTesting; 4 | using TwilioChat.Web.Controllers; 5 | using TwilioChat.Web.Domain; 6 | 7 | namespace TwilioChat.Tests.Controllers 8 | { 9 | public class TokenControllerTest 10 | { 11 | [Test] 12 | public void WhenAGenerateActionIsCalled_ThenATokenIsGenerated() 13 | { 14 | var mockTokenGenerator = new Mock(); 15 | var controller = new TokenController(mockTokenGenerator.Object); 16 | 17 | controller.WithCallTo(c => c.Index("identity")) 18 | .ShouldReturnJson(); 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /TwilioChat.Tests/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("TwilioChat.Tests")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("TwilioChat.Tests")] 13 | [assembly: AssemblyCopyright("Copyright © 2016")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("ca3ac557-32e3-4fd6-9b1d-ef2709b8f7c1")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /TwilioChat.Tests/TwilioChat.Tests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | Debug 7 | AnyCPU 8 | {53EEC683-EB81-4466-B9A3-FEB99EF671C9} 9 | Library 10 | Properties 11 | TwilioChat.Tests 12 | TwilioChat.Tests 13 | v4.5 14 | 512 15 | {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 16 | 10.0 17 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) 18 | $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages 19 | False 20 | UnitTest 21 | 22 | 23 | 24 | 25 | true 26 | full 27 | false 28 | bin\Debug\ 29 | DEBUG;TRACE 30 | prompt 31 | 4 32 | x64 33 | 34 | 35 | pdbonly 36 | true 37 | bin\Release\ 38 | TRACE 39 | prompt 40 | 4 41 | 42 | 43 | 44 | ..\packages\Portable.BouncyCastle.1.8.0\lib\net45\crypto.dll 45 | True 46 | 47 | 48 | ..\packages\JWT.1.3.4\lib\3.5\JWT.dll 49 | True 50 | 51 | 52 | 53 | True 54 | ..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll 55 | 56 | 57 | ..\packages\Moq.4.2.1510.2205\lib\net40\Moq.dll 58 | 59 | 60 | ..\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll 61 | True 62 | 63 | 64 | ..\packages\NUnit.3.12.0\lib\net45\nunit.framework.dll 65 | 66 | 67 | 68 | 69 | False 70 | ..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.Helpers.dll 71 | 72 | 73 | False 74 | ..\packages\Microsoft.AspNet.Mvc.5.2.3\lib\net45\System.Web.Mvc.dll 75 | 76 | 77 | False 78 | ..\packages\Microsoft.AspNet.Razor.3.2.3\lib\net45\System.Web.Razor.dll 79 | 80 | 81 | False 82 | ..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.dll 83 | 84 | 85 | False 86 | ..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Deployment.dll 87 | 88 | 89 | False 90 | ..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Razor.dll 91 | 92 | 93 | 94 | ..\packages\TestStack.FluentMVCTesting.Mvc4.3.0.0\lib\NET40\TestStack.FluentMVCTesting.Mvc4.dll 95 | 96 | 97 | ..\packages\Twilio.5.36.0\lib\net35\Twilio.dll 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | {942E20FA-B7F7-4B1E-99D7-CA5DE688EE91} 123 | TwilioChat.Web 124 | 125 | 126 | 127 | 128 | 129 | 130 | False 131 | 132 | 133 | False 134 | 135 | 136 | False 137 | 138 | 139 | False 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 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}. 149 | 150 | 151 | 152 | 153 | 160 | -------------------------------------------------------------------------------- /TwilioChat.Tests/app.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /TwilioChat.Tests/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /TwilioChat.Web/App_Start/BundleConfig.cs: -------------------------------------------------------------------------------- 1 | using System.Web.Optimization; 2 | 3 | namespace TwilioChat.Web 4 | { 5 | public class BundleConfig 6 | { 7 | // For more information on bundling, visit http://go.microsoft.com/fwlink/?LinkId=301862 8 | public static void RegisterBundles(BundleCollection bundles) 9 | { 10 | bundles.Add(new ScriptBundle("~/bundles/jquery").Include( 11 | "~/Scripts/lib/jquery-{version}.js")); 12 | 13 | bundles.Add(new ScriptBundle("~/bundles/jqueryval").Include( 14 | "~/Scripts/lib/jquery.validate*")); 15 | 16 | // Use the development version of Modernizr to develop with and learn from. Then, when you're 17 | // ready for production, use the build tool at http://modernizr.com to pick only the tests you need. 18 | bundles.Add(new ScriptBundle("~/bundles/modernizr").Include( 19 | "~/Scripts/lib/modernizr-*")); 20 | 21 | bundles.Add(new ScriptBundle("~/bundles/bootstrap").Include( 22 | "~/Scripts/lib/bootstrap.js", 23 | "~/Scripts/lib/respond.js")); 24 | 25 | bundles.Add(new ScriptBundle("~/bundles/twiliochat").Include( 26 | "~/Scripts/lib/jquery-throttle.min.js", 27 | "~/Scripts/lib/jquery.loadTemplate-1.4.4.min.js", 28 | "~/Scripts/lib/twiliochat.js", 29 | "~/Scripts/lib/dateformatter.js")); 30 | 31 | bundles.Add(new StyleBundle("~/Content/css").Include( 32 | "~/Content/bootstrap.css", 33 | "~/Content/font-awesome.css", 34 | "~/Content/twilio-chat.css", 35 | "~/Content/site.css")); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /TwilioChat.Web/App_Start/FilterConfig.cs: -------------------------------------------------------------------------------- 1 | using System.Web.Mvc; 2 | 3 | namespace TwilioChat.Web 4 | { 5 | public class FilterConfig 6 | { 7 | public static void RegisterGlobalFilters(GlobalFilterCollection filters) 8 | { 9 | filters.Add(new HandleErrorAttribute()); 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /TwilioChat.Web/App_Start/RouteConfig.cs: -------------------------------------------------------------------------------- 1 | using System.Web.Mvc; 2 | using System.Web.Routing; 3 | 4 | namespace TwilioChat.Web 5 | { 6 | public class RouteConfig 7 | { 8 | public static void RegisterRoutes(RouteCollection routes) 9 | { 10 | routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); 11 | 12 | routes.MapRoute( 13 | name: "Default", 14 | url: "{controller}/{action}/{id}", 15 | defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional } 16 | ); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /TwilioChat.Web/Content/Images/add-channel-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TwilioDevEd/twiliochat-csharp/a1c252a088b11de29442339c86014bdb44489617/TwilioChat.Web/Content/Images/add-channel-image.png -------------------------------------------------------------------------------- /TwilioChat.Web/Content/Images/connect-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TwilioDevEd/twiliochat-csharp/a1c252a088b11de29442339c86014bdb44489617/TwilioChat.Web/Content/Images/connect-image.png -------------------------------------------------------------------------------- /TwilioChat.Web/Content/Images/twilio-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TwilioDevEd/twiliochat-csharp/a1c252a088b11de29442339c86014bdb44489617/TwilioChat.Web/Content/Images/twilio-logo.png -------------------------------------------------------------------------------- /TwilioChat.Web/Content/Site.css: -------------------------------------------------------------------------------- 1 | body { 2 | padding-top: 50px; 3 | padding-bottom: 20px; 4 | } 5 | 6 | /* Set padding to keep content from hitting the edges */ 7 | .body-content { 8 | padding-left: 15px; 9 | padding-right: 15px; 10 | } 11 | 12 | /* Override the default bootstrap behavior where horizontal description lists 13 | will truncate terms that are too long to fit in the left column 14 | */ 15 | .dl-horizontal dt { 16 | white-space: normal; 17 | } 18 | 19 | /* Set width on the form input elements since they're 100% wide by default */ 20 | input, 21 | select, 22 | textarea { 23 | max-width: 280px; 24 | } 25 | -------------------------------------------------------------------------------- /TwilioChat.Web/Content/bootstrap-theme.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap v3.3.6 (http://getbootstrap.com) 3 | * Copyright 2011-2015 Twitter, Inc. 4 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 5 | */.btn-danger,.btn-default,.btn-info,.btn-primary,.btn-success,.btn-warning{text-shadow:0 -1px 0 rgba(0,0,0,.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075)}.btn-danger.active,.btn-danger:active,.btn-default.active,.btn-default:active,.btn-info.active,.btn-info:active,.btn-primary.active,.btn-primary:active,.btn-success.active,.btn-success:active,.btn-warning.active,.btn-warning:active{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn-danger.disabled,.btn-danger[disabled],.btn-default.disabled,.btn-default[disabled],.btn-info.disabled,.btn-info[disabled],.btn-primary.disabled,.btn-primary[disabled],.btn-success.disabled,.btn-success[disabled],.btn-warning.disabled,.btn-warning[disabled],fieldset[disabled] .btn-danger,fieldset[disabled] .btn-default,fieldset[disabled] .btn-info,fieldset[disabled] .btn-primary,fieldset[disabled] .btn-success,fieldset[disabled] .btn-warning{-webkit-box-shadow:none;box-shadow:none}.btn-danger .badge,.btn-default .badge,.btn-info .badge,.btn-primary .badge,.btn-success .badge,.btn-warning .badge{text-shadow:none}.btn.active,.btn:active{background-image:none}.btn-default{text-shadow:0 1px 0 #fff;background-image:-webkit-linear-gradient(top,#fff 0,#e0e0e0 100%);background-image:-o-linear-gradient(top,#fff 0,#e0e0e0 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fff),to(#e0e0e0));background-image:linear-gradient(to bottom,#fff 0,#e0e0e0 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#dbdbdb;border-color:#ccc}.btn-default:focus,.btn-default:hover{background-color:#e0e0e0;background-position:0 -15px}.btn-default.active,.btn-default:active{background-color:#e0e0e0;border-color:#dbdbdb}.btn-default.disabled,.btn-default.disabled.active,.btn-default.disabled.focus,.btn-default.disabled:active,.btn-default.disabled:focus,.btn-default.disabled:hover,.btn-default[disabled],.btn-default[disabled].active,.btn-default[disabled].focus,.btn-default[disabled]:active,.btn-default[disabled]:focus,.btn-default[disabled]:hover,fieldset[disabled] .btn-default,fieldset[disabled] .btn-default.active,fieldset[disabled] .btn-default.focus,fieldset[disabled] .btn-default:active,fieldset[disabled] .btn-default:focus,fieldset[disabled] .btn-default:hover{background-color:#e0e0e0;background-image:none}.btn-primary{background-image:-webkit-linear-gradient(top,#337ab7 0,#265a88 100%);background-image:-o-linear-gradient(top,#337ab7 0,#265a88 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#265a88));background-image:linear-gradient(to bottom,#337ab7 0,#265a88 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff265a88', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#245580}.btn-primary:focus,.btn-primary:hover{background-color:#265a88;background-position:0 -15px}.btn-primary.active,.btn-primary:active{background-color:#265a88;border-color:#245580}.btn-primary.disabled,.btn-primary.disabled.active,.btn-primary.disabled.focus,.btn-primary.disabled:active,.btn-primary.disabled:focus,.btn-primary.disabled:hover,.btn-primary[disabled],.btn-primary[disabled].active,.btn-primary[disabled].focus,.btn-primary[disabled]:active,.btn-primary[disabled]:focus,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary,fieldset[disabled] .btn-primary.active,fieldset[disabled] .btn-primary.focus,fieldset[disabled] .btn-primary:active,fieldset[disabled] .btn-primary:focus,fieldset[disabled] .btn-primary:hover{background-color:#265a88;background-image:none}.btn-success{background-image:-webkit-linear-gradient(top,#5cb85c 0,#419641 100%);background-image:-o-linear-gradient(top,#5cb85c 0,#419641 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5cb85c),to(#419641));background-image:linear-gradient(to bottom,#5cb85c 0,#419641 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff419641', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#3e8f3e}.btn-success:focus,.btn-success:hover{background-color:#419641;background-position:0 -15px}.btn-success.active,.btn-success:active{background-color:#419641;border-color:#3e8f3e}.btn-success.disabled,.btn-success.disabled.active,.btn-success.disabled.focus,.btn-success.disabled:active,.btn-success.disabled:focus,.btn-success.disabled:hover,.btn-success[disabled],.btn-success[disabled].active,.btn-success[disabled].focus,.btn-success[disabled]:active,.btn-success[disabled]:focus,.btn-success[disabled]:hover,fieldset[disabled] .btn-success,fieldset[disabled] .btn-success.active,fieldset[disabled] .btn-success.focus,fieldset[disabled] .btn-success:active,fieldset[disabled] .btn-success:focus,fieldset[disabled] .btn-success:hover{background-color:#419641;background-image:none}.btn-info{background-image:-webkit-linear-gradient(top,#5bc0de 0,#2aabd2 100%);background-image:-o-linear-gradient(top,#5bc0de 0,#2aabd2 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5bc0de),to(#2aabd2));background-image:linear-gradient(to bottom,#5bc0de 0,#2aabd2 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2aabd2', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#28a4c9}.btn-info:focus,.btn-info:hover{background-color:#2aabd2;background-position:0 -15px}.btn-info.active,.btn-info:active{background-color:#2aabd2;border-color:#28a4c9}.btn-info.disabled,.btn-info.disabled.active,.btn-info.disabled.focus,.btn-info.disabled:active,.btn-info.disabled:focus,.btn-info.disabled:hover,.btn-info[disabled],.btn-info[disabled].active,.btn-info[disabled].focus,.btn-info[disabled]:active,.btn-info[disabled]:focus,.btn-info[disabled]:hover,fieldset[disabled] .btn-info,fieldset[disabled] .btn-info.active,fieldset[disabled] .btn-info.focus,fieldset[disabled] .btn-info:active,fieldset[disabled] .btn-info:focus,fieldset[disabled] .btn-info:hover{background-color:#2aabd2;background-image:none}.btn-warning{background-image:-webkit-linear-gradient(top,#f0ad4e 0,#eb9316 100%);background-image:-o-linear-gradient(top,#f0ad4e 0,#eb9316 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f0ad4e),to(#eb9316));background-image:linear-gradient(to bottom,#f0ad4e 0,#eb9316 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffeb9316', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#e38d13}.btn-warning:focus,.btn-warning:hover{background-color:#eb9316;background-position:0 -15px}.btn-warning.active,.btn-warning:active{background-color:#eb9316;border-color:#e38d13}.btn-warning.disabled,.btn-warning.disabled.active,.btn-warning.disabled.focus,.btn-warning.disabled:active,.btn-warning.disabled:focus,.btn-warning.disabled:hover,.btn-warning[disabled],.btn-warning[disabled].active,.btn-warning[disabled].focus,.btn-warning[disabled]:active,.btn-warning[disabled]:focus,.btn-warning[disabled]:hover,fieldset[disabled] .btn-warning,fieldset[disabled] .btn-warning.active,fieldset[disabled] .btn-warning.focus,fieldset[disabled] .btn-warning:active,fieldset[disabled] .btn-warning:focus,fieldset[disabled] .btn-warning:hover{background-color:#eb9316;background-image:none}.btn-danger{background-image:-webkit-linear-gradient(top,#d9534f 0,#c12e2a 100%);background-image:-o-linear-gradient(top,#d9534f 0,#c12e2a 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9534f),to(#c12e2a));background-image:linear-gradient(to bottom,#d9534f 0,#c12e2a 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc12e2a', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#b92c28}.btn-danger:focus,.btn-danger:hover{background-color:#c12e2a;background-position:0 -15px}.btn-danger.active,.btn-danger:active{background-color:#c12e2a;border-color:#b92c28}.btn-danger.disabled,.btn-danger.disabled.active,.btn-danger.disabled.focus,.btn-danger.disabled:active,.btn-danger.disabled:focus,.btn-danger.disabled:hover,.btn-danger[disabled],.btn-danger[disabled].active,.btn-danger[disabled].focus,.btn-danger[disabled]:active,.btn-danger[disabled]:focus,.btn-danger[disabled]:hover,fieldset[disabled] .btn-danger,fieldset[disabled] .btn-danger.active,fieldset[disabled] .btn-danger.focus,fieldset[disabled] .btn-danger:active,fieldset[disabled] .btn-danger:focus,fieldset[disabled] .btn-danger:hover{background-color:#c12e2a;background-image:none}.img-thumbnail,.thumbnail{-webkit-box-shadow:0 1px 2px rgba(0,0,0,.075);box-shadow:0 1px 2px rgba(0,0,0,.075)}.dropdown-menu>li>a:focus,.dropdown-menu>li>a:hover{background-color:#e8e8e8;background-image:-webkit-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-o-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f5f5f5),to(#e8e8e8));background-image:linear-gradient(to bottom,#f5f5f5 0,#e8e8e8 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);background-repeat:repeat-x}.dropdown-menu>.active>a,.dropdown-menu>.active>a:focus,.dropdown-menu>.active>a:hover{background-color:#2e6da4;background-image:-webkit-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-o-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#2e6da4));background-image:linear-gradient(to bottom,#337ab7 0,#2e6da4 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);background-repeat:repeat-x}.navbar-default{background-image:-webkit-linear-gradient(top,#fff 0,#f8f8f8 100%);background-image:-o-linear-gradient(top,#fff 0,#f8f8f8 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fff),to(#f8f8f8));background-image:linear-gradient(to bottom,#fff 0,#f8f8f8 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-radius:4px;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 5px rgba(0,0,0,.075);box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 5px rgba(0,0,0,.075)}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.open>a{background-image:-webkit-linear-gradient(top,#dbdbdb 0,#e2e2e2 100%);background-image:-o-linear-gradient(top,#dbdbdb 0,#e2e2e2 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#dbdbdb),to(#e2e2e2));background-image:linear-gradient(to bottom,#dbdbdb 0,#e2e2e2 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdbdbdb', endColorstr='#ffe2e2e2', GradientType=0);background-repeat:repeat-x;-webkit-box-shadow:inset 0 3px 9px rgba(0,0,0,.075);box-shadow:inset 0 3px 9px rgba(0,0,0,.075)}.navbar-brand,.navbar-nav>li>a{text-shadow:0 1px 0 rgba(255,255,255,.25)}.navbar-inverse{background-image:-webkit-linear-gradient(top,#3c3c3c 0,#222 100%);background-image:-o-linear-gradient(top,#3c3c3c 0,#222 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#3c3c3c),to(#222));background-image:linear-gradient(to bottom,#3c3c3c 0,#222 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c', endColorstr='#ff222222', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-radius:4px}.navbar-inverse .navbar-nav>.active>a,.navbar-inverse .navbar-nav>.open>a{background-image:-webkit-linear-gradient(top,#080808 0,#0f0f0f 100%);background-image:-o-linear-gradient(top,#080808 0,#0f0f0f 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#080808),to(#0f0f0f));background-image:linear-gradient(to bottom,#080808 0,#0f0f0f 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff080808', endColorstr='#ff0f0f0f', GradientType=0);background-repeat:repeat-x;-webkit-box-shadow:inset 0 3px 9px rgba(0,0,0,.25);box-shadow:inset 0 3px 9px rgba(0,0,0,.25)}.navbar-inverse .navbar-brand,.navbar-inverse .navbar-nav>li>a{text-shadow:0 -1px 0 rgba(0,0,0,.25)}.navbar-fixed-bottom,.navbar-fixed-top,.navbar-static-top{border-radius:0}@media (max-width:767px){.navbar .navbar-nav .open .dropdown-menu>.active>a,.navbar .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar .navbar-nav .open .dropdown-menu>.active>a:hover{color:#fff;background-image:-webkit-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-o-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#2e6da4));background-image:linear-gradient(to bottom,#337ab7 0,#2e6da4 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);background-repeat:repeat-x}}.alert{text-shadow:0 1px 0 rgba(255,255,255,.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.25),0 1px 2px rgba(0,0,0,.05);box-shadow:inset 0 1px 0 rgba(255,255,255,.25),0 1px 2px rgba(0,0,0,.05)}.alert-success{background-image:-webkit-linear-gradient(top,#dff0d8 0,#c8e5bc 100%);background-image:-o-linear-gradient(top,#dff0d8 0,#c8e5bc 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#dff0d8),to(#c8e5bc));background-image:linear-gradient(to bottom,#dff0d8 0,#c8e5bc 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffc8e5bc', GradientType=0);background-repeat:repeat-x;border-color:#b2dba1}.alert-info{background-image:-webkit-linear-gradient(top,#d9edf7 0,#b9def0 100%);background-image:-o-linear-gradient(top,#d9edf7 0,#b9def0 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9edf7),to(#b9def0));background-image:linear-gradient(to bottom,#d9edf7 0,#b9def0 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0);background-repeat:repeat-x;border-color:#9acfea}.alert-warning{background-image:-webkit-linear-gradient(top,#fcf8e3 0,#f8efc0 100%);background-image:-o-linear-gradient(top,#fcf8e3 0,#f8efc0 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fcf8e3),to(#f8efc0));background-image:linear-gradient(to bottom,#fcf8e3 0,#f8efc0 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fff8efc0', GradientType=0);background-repeat:repeat-x;border-color:#f5e79e}.alert-danger{background-image:-webkit-linear-gradient(top,#f2dede 0,#e7c3c3 100%);background-image:-o-linear-gradient(top,#f2dede 0,#e7c3c3 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f2dede),to(#e7c3c3));background-image:linear-gradient(to bottom,#f2dede 0,#e7c3c3 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffe7c3c3', GradientType=0);background-repeat:repeat-x;border-color:#dca7a7}.progress{background-image:-webkit-linear-gradient(top,#ebebeb 0,#f5f5f5 100%);background-image:-o-linear-gradient(top,#ebebeb 0,#f5f5f5 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#ebebeb),to(#f5f5f5));background-image:linear-gradient(to bottom,#ebebeb 0,#f5f5f5 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0);background-repeat:repeat-x}.progress-bar{background-image:-webkit-linear-gradient(top,#337ab7 0,#286090 100%);background-image:-o-linear-gradient(top,#337ab7 0,#286090 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#286090));background-image:linear-gradient(to bottom,#337ab7 0,#286090 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff286090', GradientType=0);background-repeat:repeat-x}.progress-bar-success{background-image:-webkit-linear-gradient(top,#5cb85c 0,#449d44 100%);background-image:-o-linear-gradient(top,#5cb85c 0,#449d44 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5cb85c),to(#449d44));background-image:linear-gradient(to bottom,#5cb85c 0,#449d44 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0);background-repeat:repeat-x}.progress-bar-info{background-image:-webkit-linear-gradient(top,#5bc0de 0,#31b0d5 100%);background-image:-o-linear-gradient(top,#5bc0de 0,#31b0d5 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5bc0de),to(#31b0d5));background-image:linear-gradient(to bottom,#5bc0de 0,#31b0d5 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0);background-repeat:repeat-x}.progress-bar-warning{background-image:-webkit-linear-gradient(top,#f0ad4e 0,#ec971f 100%);background-image:-o-linear-gradient(top,#f0ad4e 0,#ec971f 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f0ad4e),to(#ec971f));background-image:linear-gradient(to bottom,#f0ad4e 0,#ec971f 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0);background-repeat:repeat-x}.progress-bar-danger{background-image:-webkit-linear-gradient(top,#d9534f 0,#c9302c 100%);background-image:-o-linear-gradient(top,#d9534f 0,#c9302c 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9534f),to(#c9302c));background-image:linear-gradient(to bottom,#d9534f 0,#c9302c 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0);background-repeat:repeat-x}.progress-bar-striped{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.list-group{border-radius:4px;-webkit-box-shadow:0 1px 2px rgba(0,0,0,.075);box-shadow:0 1px 2px rgba(0,0,0,.075)}.list-group-item.active,.list-group-item.active:focus,.list-group-item.active:hover{text-shadow:0 -1px 0 #286090;background-image:-webkit-linear-gradient(top,#337ab7 0,#2b669a 100%);background-image:-o-linear-gradient(top,#337ab7 0,#2b669a 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#2b669a));background-image:linear-gradient(to bottom,#337ab7 0,#2b669a 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2b669a', GradientType=0);background-repeat:repeat-x;border-color:#2b669a}.list-group-item.active .badge,.list-group-item.active:focus .badge,.list-group-item.active:hover .badge{text-shadow:none}.panel{-webkit-box-shadow:0 1px 2px rgba(0,0,0,.05);box-shadow:0 1px 2px rgba(0,0,0,.05)}.panel-default>.panel-heading{background-image:-webkit-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-o-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f5f5f5),to(#e8e8e8));background-image:linear-gradient(to bottom,#f5f5f5 0,#e8e8e8 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);background-repeat:repeat-x}.panel-primary>.panel-heading{background-image:-webkit-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-o-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#2e6da4));background-image:linear-gradient(to bottom,#337ab7 0,#2e6da4 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);background-repeat:repeat-x}.panel-success>.panel-heading{background-image:-webkit-linear-gradient(top,#dff0d8 0,#d0e9c6 100%);background-image:-o-linear-gradient(top,#dff0d8 0,#d0e9c6 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#dff0d8),to(#d0e9c6));background-image:linear-gradient(to bottom,#dff0d8 0,#d0e9c6 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffd0e9c6', GradientType=0);background-repeat:repeat-x}.panel-info>.panel-heading{background-image:-webkit-linear-gradient(top,#d9edf7 0,#c4e3f3 100%);background-image:-o-linear-gradient(top,#d9edf7 0,#c4e3f3 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9edf7),to(#c4e3f3));background-image:linear-gradient(to bottom,#d9edf7 0,#c4e3f3 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffc4e3f3', GradientType=0);background-repeat:repeat-x}.panel-warning>.panel-heading{background-image:-webkit-linear-gradient(top,#fcf8e3 0,#faf2cc 100%);background-image:-o-linear-gradient(top,#fcf8e3 0,#faf2cc 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fcf8e3),to(#faf2cc));background-image:linear-gradient(to bottom,#fcf8e3 0,#faf2cc 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fffaf2cc', GradientType=0);background-repeat:repeat-x}.panel-danger>.panel-heading{background-image:-webkit-linear-gradient(top,#f2dede 0,#ebcccc 100%);background-image:-o-linear-gradient(top,#f2dede 0,#ebcccc 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f2dede),to(#ebcccc));background-image:linear-gradient(to bottom,#f2dede 0,#ebcccc 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffebcccc', GradientType=0);background-repeat:repeat-x}.well{background-image:-webkit-linear-gradient(top,#e8e8e8 0,#f5f5f5 100%);background-image:-o-linear-gradient(top,#e8e8e8 0,#f5f5f5 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#e8e8e8),to(#f5f5f5));background-image:linear-gradient(to bottom,#e8e8e8 0,#f5f5f5 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0);background-repeat:repeat-x;border-color:#dcdcdc;-webkit-box-shadow:inset 0 1px 3px rgba(0,0,0,.05),0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 3px rgba(0,0,0,.05),0 1px 0 rgba(255,255,255,.1)} 6 | /*# sourceMappingURL=bootstrap-theme.min.css.map */ -------------------------------------------------------------------------------- /TwilioChat.Web/Content/bootstrap-theme.min.css.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["less/theme.less","less/mixins/vendor-prefixes.less","less/mixins/gradients.less","less/mixins/reset-filter.less"],"names":[],"mappings":"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"} -------------------------------------------------------------------------------- /TwilioChat.Web/Content/twilio-chat.css: -------------------------------------------------------------------------------- 1 | html { 2 | height: 100%; 3 | padding:0; 4 | margin:0; 5 | background-color: #71271c; 6 | } 7 | body { 8 | position: absolute; 9 | top: 0; 10 | left: 0; 11 | padding:0; 12 | margin:0; 13 | height: 100%; 14 | width:100%; 15 | background: #71271c; /* Old browsers */ 16 | background: -moz-linear-gradient(-45deg, #71271c 0%, #7c362e 47%, #a53829 100%); /* FF3.6-15 */ 17 | background: -webkit-linear-gradient(-45deg, #71271c 0%,#7c362e 47%,#a53829 100%); /* Chrome10-25,Safari5.1-6 */ 18 | background: linear-gradient(135deg, #71271c 0%,#7c362e 47%,#a53829 100%); /* W3C, IE10+, FF16+, Chrome26+, Opera12+, Safari7+ */ 19 | filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#71271c', endColorstr='#a53829',GradientType=1 ); /* IE6-9 fallback on horizontal gradient */ 20 | font-family: 'Oswald', 'Source Sans Pro', sans-serif;; 21 | } 22 | 23 | #chat-window { 24 | background-color: rgba(255,255,255,0.7); 25 | height: 100%; 26 | } 27 | #container { 28 | height: 85vh; 29 | } 30 | #header { 31 | margin: auto; 32 | } 33 | #input-div { 34 | background-color: #DED4D3; 35 | height: 5%; 36 | } 37 | #typing-row { 38 | height: 3%; 39 | font-weight: lighter; 40 | font-size: small; 41 | color: #BBA0A1; 42 | vertical-align: bottom; 43 | } 44 | #typing-placeholder { 45 | height: 100%; 46 | padding-left: 10px; 47 | } 48 | #message-list { 49 | overflow-y: scroll; 50 | } 51 | #message-list.connected { 52 | height: 92%; 53 | } 54 | #message-list.disconnected { 55 | height: 80%; 56 | } 57 | #connect-panel { 58 | height: 15%; 59 | background-color: #5B1913; 60 | text-align: center; 61 | color: #DEC4C3; 62 | } 63 | #connect-panel.connected, #typing-row.disconnected { 64 | display: none; 65 | } 66 | #connect-panel.disconnected, #typing-row.disconnected { 67 | display: block; 68 | } 69 | #username-input { 70 | width: 70%; 71 | padding-left: 10px; 72 | height: 5vh; 73 | margin-left: 10px; 74 | margin-top: 10px; 75 | color: black; 76 | } 77 | #input-text { 78 | padding-left: 10px; 79 | padding-right: 10px; 80 | padding-top: 1%; 81 | height: 100%; 82 | width: 100%; 83 | background-color: #DED4D3; 84 | color: #644F52; 85 | font-weight: 300; 86 | border: 0; 87 | resize: none; 88 | } 89 | .with-shadow { 90 | -webkit-box-shadow: -5px 5px 0px 0px rgba(0,0,0,0.53); 91 | -moz-box-shadow: -5px 5px 0px 0px rgba(0,0,0,0.53); 92 | box-shadow: -5px 5px 0px 0px rgba(0,0,0,0.53); 93 | } 94 | #channel-panel { 95 | border-left: 1px solid #864035; 96 | box-shadow: -1px 0px 0px 0px #5D1E18; 97 | } 98 | #channel-list { 99 | overflow-y: scroll; 100 | overflow-x: hidden; 101 | } 102 | #channel-list.showing { 103 | max-height: 75vh; 104 | } 105 | #channel-list.not-showing { 106 | max-height: 80vh; 107 | } 108 | #new-channel-input { 109 | background-color: #F8E6E4; 110 | color: #B0ADAE; 111 | border: 0; 112 | resize: none; 113 | height: 5vh; 114 | } 115 | #new-channel-input-row.not-showing { 116 | display: none; 117 | } 118 | #new-channel-input-row.showing { 119 | display: block; 120 | } 121 | .own-message { 122 | background-color: #DDD3D2; 123 | } 124 | .message-info-row { 125 | padding-top: 0.7vh; 126 | padding-bottom: 0.5vh; 127 | } 128 | .message-body { 129 | word-break: break-all; 130 | text-align: justify; 131 | text-justify: inter-word; 132 | font-size: small; 133 | font-weight: 300; 134 | color: #644F52; 135 | } 136 | .message-username { 137 | margin-left: 15px; 138 | margin-bottom: 5px; 139 | font-size: normal; 140 | font-weight: 400; 141 | color: #5C5153; 142 | } 143 | .message-date { 144 | margin-right: 15px; 145 | margin-bottom: 5px; 146 | font-weight: lighter; 147 | font-size: normal; 148 | color: #BA9F9F; 149 | } 150 | .no-margin { 151 | margin: 0; 152 | } 153 | #add-channel-image { 154 | padding-left: 20px; 155 | padding-top: 1.5vh; 156 | padding-bottom: 1.5vh; 157 | height: 5vh; 158 | cursor: pointer; 159 | } 160 | .channel-element { 161 | width: 100%; 162 | height: 6vh; 163 | margin: 0; 164 | padding-left: 20px; 165 | line-height: 6vh; 166 | overflow: hidden; 167 | font-size: large; 168 | } 169 | .unselected-channel { 170 | color: #D47567; 171 | } 172 | .unselected-channel:hover { 173 | background-color: #F8E6E4; 174 | color: #753A35; 175 | cursor: pointer; 176 | } 177 | .selected-channel { 178 | background-color: #F8E6E4; 179 | color: #753A35; 180 | } 181 | #logo-image { 182 | height: 3vh; 183 | margin-top: 1vh; 184 | margin-bottom: 1vh; 185 | } 186 | #logo-column { 187 | text-align: center; 188 | } 189 | .right-align { 190 | text-align: right; 191 | padding: 0; 192 | } 193 | .left-align { 194 | text-align: left; 195 | padding: 0; 196 | } 197 | #status-span { 198 | color: #EE887C; 199 | } 200 | #leave-span { 201 | cursor: pointer; 202 | color: #370606; 203 | margin-left: 1vh; 204 | } 205 | #delete-channel-span { 206 | cursor: pointer; 207 | color: #370606; 208 | } 209 | #status-row { 210 | margin-bottom: 1vh; 211 | } 212 | #status-row.connected { 213 | visibility: visible; 214 | } 215 | #status-row.disconnected { 216 | visibility: hidden; 217 | } 218 | #connect-image { 219 | height: 5vh; 220 | margin-top: 1vh; 221 | cursor: pointer; 222 | } 223 | .member-status { 224 | padding: 5px; 225 | font-weight: 300; 226 | color: #C0A5A7; 227 | text-align: center; 228 | border-top: 1px solid #BCA1A3; 229 | border-bottom: 1px solid #BCA1A3; 230 | } -------------------------------------------------------------------------------- /TwilioChat.Web/Controllers/HomeController.cs: -------------------------------------------------------------------------------- 1 | using System.Web.Mvc; 2 | 3 | namespace TwilioChat.Web.Controllers 4 | { 5 | public class HomeController : Controller 6 | { 7 | public ActionResult Index() 8 | { 9 | return View(); 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /TwilioChat.Web/Controllers/TokenController.cs: -------------------------------------------------------------------------------- 1 | using System.Web.Mvc; 2 | using TwilioChat.Web.Domain; 3 | 4 | namespace TwilioChat.Web.Controllers 5 | { 6 | public class TokenController : Controller 7 | { 8 | private readonly ITokenGenerator _tokenGenerator; 9 | 10 | public TokenController() : this(new TokenGenerator()) { } 11 | 12 | public TokenController(ITokenGenerator tokenGenerator) 13 | { 14 | _tokenGenerator = tokenGenerator; 15 | } 16 | 17 | // POST: Token 18 | [HttpPost] 19 | public ActionResult Index(string identity) 20 | { 21 | if (identity == null) return null; 22 | 23 | var token = _tokenGenerator.Generate(identity); 24 | return Json(new {identity, token}); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /TwilioChat.Web/Domain/Configuration.cs: -------------------------------------------------------------------------------- 1 | using System.Web.Configuration; 2 | 3 | namespace TwilioChat.Web.Domain 4 | { 5 | public class Configuration 6 | { 7 | public static string AccountSID 8 | { 9 | get { return WebConfigurationManager.AppSettings["TwilioAccountSid"]; } 10 | } 11 | 12 | public static string ApiKey 13 | { 14 | get { return WebConfigurationManager.AppSettings["TwilioApiKey"]; } 15 | } 16 | 17 | public static string ApiSecret 18 | { 19 | get { return WebConfigurationManager.AppSettings["TwilioApiSecret"]; } 20 | } 21 | 22 | public static string ChatServiceSID 23 | { 24 | get { return WebConfigurationManager.AppSettings["TwilioChatServiceSid"]; } 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /TwilioChat.Web/Domain/TokenGenerator.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Twilio.Jwt.AccessToken; 3 | 4 | namespace TwilioChat.Web.Domain 5 | { 6 | public interface ITokenGenerator 7 | { 8 | string Generate(string identity); 9 | } 10 | 11 | public class TokenGenerator : ITokenGenerator 12 | { 13 | public string Generate(string identity) 14 | { 15 | var grants = new HashSet 16 | { 17 | new ChatGrant {ServiceSid = Configuration.ChatServiceSID} 18 | }; 19 | 20 | var token = new Token( 21 | Configuration.AccountSID, 22 | Configuration.ApiKey, 23 | Configuration.ApiSecret, 24 | identity, 25 | grants: grants); 26 | 27 | return token.ToJwt(); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /TwilioChat.Web/Global.asax: -------------------------------------------------------------------------------- 1 | <%@ Application Codebehind="Global.asax.cs" Inherits="TwilioChat.Web.MvcApplication" Language="C#" %> 2 | -------------------------------------------------------------------------------- /TwilioChat.Web/Global.asax.cs: -------------------------------------------------------------------------------- 1 | using System.Web; 2 | using System.Web.Mvc; 3 | using System.Web.Optimization; 4 | using System.Web.Routing; 5 | 6 | namespace TwilioChat.Web 7 | { 8 | public class MvcApplication : HttpApplication 9 | { 10 | protected void Application_Start() 11 | { 12 | AreaRegistration.RegisterAllAreas(); 13 | FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); 14 | RouteConfig.RegisterRoutes(RouteTable.Routes); 15 | BundleConfig.RegisterBundles(BundleTable.Bundles); 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /TwilioChat.Web/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | 4 | // General Information about an assembly is controlled through the following 5 | // set of attributes. Change these attribute values to modify the information 6 | // associated with an assembly. 7 | [assembly: AssemblyTitle("TwilioChat.Web")] 8 | [assembly: AssemblyDescription("")] 9 | [assembly: AssemblyConfiguration("")] 10 | [assembly: AssemblyCompany("")] 11 | [assembly: AssemblyProduct("TwilioChat.Web")] 12 | [assembly: AssemblyCopyright("Copyright © 2016")] 13 | [assembly: AssemblyTrademark("")] 14 | [assembly: AssemblyCulture("")] 15 | 16 | // Setting ComVisible to false makes the types in this assembly not visible 17 | // to COM components. If you need to access a type in this assembly from 18 | // COM, set the ComVisible attribute to true on that type. 19 | [assembly: ComVisible(false)] 20 | 21 | // The following GUID is for the ID of the typelib if this project is exposed to COM 22 | [assembly: Guid("e8068dfb-89c7-4e20-bca2-0335e40a9459")] 23 | 24 | // Version information for an assembly consists of the following four values: 25 | // 26 | // Major Version 27 | // Minor Version 28 | // Build Number 29 | // Revision 30 | // 31 | // You can specify all the values or you can default the Revision and Build Numbers 32 | // by using the '*' as shown below: 33 | [assembly: AssemblyVersion("1.0.0.0")] 34 | [assembly: AssemblyFileVersion("1.0.0.0")] 35 | -------------------------------------------------------------------------------- /TwilioChat.Web/Scripts/karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration 2 | // Generated on Tue Dec 13 2016 16:39:58 GMT-0300 (ART) 3 | 4 | process.env.CHROME_BIN = require('puppeteer').executablePath() 5 | 6 | module.exports = function(config) { 7 | config.set({ 8 | 9 | // base path that will be used to resolve all patterns (eg. files, exclude) 10 | basePath: '', 11 | 12 | 13 | // frameworks to use 14 | // available frameworks: https://npmjs.org/browse/keyword/karma-adapter 15 | frameworks: ['chai', 'mocha', 'sinon'], 16 | 17 | 18 | preprocessors: {'**/*.html': ['html2js']}, 19 | 20 | 21 | // list of files / patterns to load in the browser 22 | files: [ 23 | 'node_modules/babel-polyfill/dist/polyfill.js', 24 | 'node_modules/jquery/dist/jquery.js', 25 | 'node_modules/jquery-migrate/dist/jquery-migrate.js', 26 | 'node_modules/moment/moment.js', 27 | 'lib/dateformatter.js', 28 | 'lib/jquery-throttle.min.js', 29 | 'lib/jquery.loadTemplate-1.4.4.min.js', 30 | 'lib/twiliochat.js', 31 | 'tests/tests.html', 32 | 'tests/tests.js', 33 | ], 34 | 35 | 36 | // test results reporter to use 37 | // possible values: 'dots', 'progress' 38 | // available reporters: https://npmjs.org/browse/keyword/karma-reporter 39 | reporters: ['mocha'], 40 | 41 | 42 | // web server port 43 | port: 9876, 44 | 45 | 46 | // enable / disable colors in the output (reporters and logs) 47 | colors: true, 48 | 49 | 50 | // level of logging 51 | // possible values: config.LOG_DISABLE || config.LOG_ERROR || 52 | // config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG 53 | logLevel: config.LOG_INFO, 54 | 55 | 56 | // enable/disable watching file and executing tests whenever any file change 57 | autoWatch: false, 58 | 59 | 60 | // start these browsers 61 | // available browser launchers: npmjs.org/browse/keyword/karma-launcher 62 | browsers: ['ChromeHeadless'], 63 | 64 | 65 | // Continuous Integration mode 66 | // if true, Karma captures browsers, runs the tests and exits 67 | singleRun: true, 68 | 69 | // Concurrency level 70 | // how many browser should be started simultaneous 71 | concurrency: Infinity, 72 | }); 73 | }; 74 | -------------------------------------------------------------------------------- /TwilioChat.Web/Scripts/lib/_references.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TwilioDevEd/twiliochat-csharp/a1c252a088b11de29442339c86014bdb44489617/TwilioChat.Web/Scripts/lib/_references.js -------------------------------------------------------------------------------- /TwilioChat.Web/Scripts/lib/dateformatter.js: -------------------------------------------------------------------------------- 1 | var dateFormatter = (function () { 2 | var df = {}; 3 | 4 | df.getTodayDate = function (date) { 5 | var today = moment(); 6 | var inputDate = moment(date); 7 | var outputDate; 8 | 9 | if (today.format('YYYYMMDD') == inputDate.format('YYYYMMDD')) { 10 | outputDate = 'Today - '; 11 | } 12 | else { 13 | outputDate = inputDate.format('MMM. D - '); 14 | } 15 | outputDate = outputDate + inputDate.format('hh:mma'); 16 | 17 | return outputDate; 18 | } 19 | 20 | return df; 21 | })(); -------------------------------------------------------------------------------- /TwilioChat.Web/Scripts/lib/jquery-throttle.min.js: -------------------------------------------------------------------------------- 1 | (function (a) { var b = a.jQuery || a.me || (a.me = {}), i = function (e, f, g, h, c, a) { f || (f = 100); var d = !1, j = !1, i = typeof g === "function", l = function (a, b) { d = setTimeout(function () { d = !1; if (h || c) e.apply(a, b), c && (j = +new Date); i && g.apply(a, b) }, f) }, k = function () { if (!d || a) { if (!d && !h && (!c || +new Date - j > f)) e.apply(this, arguments), c && (j = +new Date); (a || !c) && clearTimeout(d); l(this, arguments) } }; if (b.guid) k.guid = e.guid = e.guid || b.guid++; return k }; b.throttle = i; b.debounce = function (a, b, g, h, c) { return i(a, b, g, h, c, !0) } })(this); -------------------------------------------------------------------------------- /TwilioChat.Web/Scripts/lib/jquery.loadTemplate-1.4.4.min.js: -------------------------------------------------------------------------------- 1 | (function (a) { var v = {}, u = {}, h = {}; function n(F, B, D) { var A = this, z, C, E; B = B || {}; E = a.extend(true, { async: true, overwriteCache: false, complete: null, success: null, error: function () { a(this).each(function () { a(this).html(E.errorMessage) }) }, errorMessage: "There was an error loading the template.", paged: false, pageNo: 1, elemPerPage: 10, append: false, prepend: false, beforeInsert: null, afterInsert: null, bindingOptions: { ignoreUndefined: false, ignoreNull: false, ignoreEmptyString: false } }, D); if (a.type(B) === "array") { return s.call(this, F, B, E) } if (!g(F)) { z = a(F); if (typeof F === "string" && F.indexOf("#") === 0) { E.isFile = false } } C = E.isFile || (typeof E.isFile === "undefined" && (typeof z === "undefined" || z.length === 0)); if (C && !E.overwriteCache && v[F]) { q(F, A, B, E) } else { if (C && !E.overwriteCache && v.hasOwnProperty(F)) { c(F, A, B, E) } else { if (C) { m(F, A, B, E) } else { o(z, A, B, E) } } } return this } function b(A, z) { if (z) { h[A] = z } else { h = a.extend(h, A) } } function g(z) { return typeof z === "string" && z.indexOf("/") > -1 } function s(I, A, F) { F = F || {}; var z = this, J = A.length, C = F.prepend && !F.append, B = 0, H = 0, D = false, E; if (F.paged) { var G = (F.pageNo - 1) * F.elemPerPage; A = A.slice(G, G + F.elemPerPage); J = A.length } E = a.extend({}, F, { complete: function () { if (this.html) { if (C) { z.prepend(this.html()) } else { z.append(this.html()) } } B++; if (B === J || D) { if (D && F && typeof F.error === "function") { F.error.call(z) } if (F && typeof F.complete === "function") { F.complete() } } }, success: function () { H++; if (H === J) { if (F && typeof F.success === "function") { F.success() } } }, error: function () { D = true } }); if (!F.append && !F.prepend) { z.html("") } if (C) { A.reverse() } a(A).each(function () { var K = a("
"); n.call(K, I, this, E); if (D) { return false } }); return this } function c(C, A, z, B) { if (u[C]) { u[C].push({ data: z, selection: A, settings: B }) } else { u[C] = [{ data: z, selection: A, settings: B }] } } function q(D, B, A, C) { var z = v[D].clone(); p.call(B, z, A, C); if (typeof C.success === "function") { C.success() } } function w() { return new Date().getTime() } function x(z) { if (z.indexOf("?") !== -1) { return z + "&_=" + w() } else { return z + "?_=" + w() } } function m(D, B, A, C) { var z = a("
"); v[D] = null; var E = D; if (C.overwriteCache) { E = x(E) } a.ajax({ url: E, async: C.async, success: function (F) { z.html(F); l(z, D, B, A, C) }, error: function () { k(D, B, A, C) } }) } function o(z, C, B, D) { var A = a("
"); if (z.is("script") || z.is("template")) { z = a.parseHTML(a.trim(z.html())) } A.html(z); p.call(C, A, B, D); if (typeof D.success === "function") { D.success() } } function p(B, z, A) { f(B, z, A); a(this).each(function () { var C = a(B.html()); if (A.beforeInsert) { A.beforeInsert(C) } if (A.append) { a(this).append(C) } else { if (A.prepend) { a(this).prepend(C) } else { a(this).html(C) } } if (A.afterInsert) { A.afterInsert(C) } }); if (typeof A.complete === "function") { A.complete.call(a(this)) } } function k(C, A, z, B) { var D; if (typeof B.error === "function") { B.error.call(A) } a(u[C]).each(function (E, F) { if (typeof F.settings.error === "function") { F.settings.error.call(F.selection) } }); if (typeof B.complete === "function") { B.complete.call(A) } while (u[C] && (D = u[C].shift())) { if (typeof D.settings.complete === "function") { D.settings.complete.call(D.selection) } } if (typeof u[C] !== "undefined" && u[C].length > 0) { u[C] = [] } } function l(z, D, B, A, C) { var E; v[D] = z.clone(); p.call(B, z, A, C); if (typeof C.success === "function") { C.success.call(B) } while (u[D] && (E = u[D].shift())) { p.call(E.selection, v[D].clone(), E.data, E.settings); if (typeof E.settings.success === "function") { E.settings.success.call(E.selection) } } } function f(B, z, A) { z = z || {}; t("data-content", B, z, A, function (C, D) { C.html(e(C, D, "content", A)) }); t("data-content-append", B, z, A, function (C, D) { C.append(e(C, D, "content", A)) }); t("data-content-prepend", B, z, A, function (C, D) { C.prepend(e(C, D, "content", A)) }); t("data-content-text", B, z, A, function (C, D) { C.text(e(C, D, "content", A)) }); t("data-src", B, z, A, function (C, D) { C.attr("src", e(C, D, "src", A)) }, function (C) { C.remove() }); t("data-href", B, z, A, function (C, D) { C.attr("href", e(C, D, "href", A)) }, function (C) { C.remove() }); t("data-alt", B, z, A, function (C, D) { C.attr("alt", e(C, D, "alt", A)) }); t("data-id", B, z, A, function (C, D) { C.attr("id", e(C, D, "id", A)) }); t("data-value", B, z, A, function (C, D) { C.attr("value", e(C, D, "value", A)) }); t("data-link", B, z, A, function (C, E) { var D = a(""); D.attr("href", e(C, E, "link", A)); D.html(C.html()); C.html(D) }); t("data-link-wrap", B, z, A, function (C, E) { var D = a(""); D.attr("href", e(C, E, "link-wrap", A)); C.wrap(D) }); t("data-options", B, z, A, function (C, D) { a(D).each(function () { var E = a("