├── .gitignore ├── src └── TwilioSdkStarterDotnetCore.Web │ ├── wwwroot │ ├── js │ │ ├── site.min.js │ │ ├── site.js │ │ ├── notify.js │ │ ├── sync.js │ │ ├── chat.js │ │ └── video.js │ ├── css │ │ ├── home.css │ │ ├── site.min.css │ │ ├── notify.css │ │ ├── site.css │ │ ├── sync.css │ │ ├── chat.css │ │ └── video.css │ ├── favicon.ico │ ├── lib │ │ ├── bootstrap │ │ │ ├── dist │ │ │ │ ├── fonts │ │ │ │ │ ├── glyphicons-halflings-regular.eot │ │ │ │ │ ├── glyphicons-halflings-regular.ttf │ │ │ │ │ ├── glyphicons-halflings-regular.woff │ │ │ │ │ └── glyphicons-halflings-regular.woff2 │ │ │ │ ├── js │ │ │ │ │ └── npm.js │ │ │ │ └── css │ │ │ │ │ ├── bootstrap-theme.min.css │ │ │ │ │ └── bootstrap-theme.min.css.map │ │ │ ├── .bower.json │ │ │ └── LICENSE │ │ ├── jquery-validation-unobtrusive │ │ │ ├── .bower.json │ │ │ ├── LICENSE.txt │ │ │ ├── jquery.validate.unobtrusive.min.js │ │ │ └── jquery.validate.unobtrusive.js │ │ ├── jquery │ │ │ ├── .bower.json │ │ │ └── LICENSE.txt │ │ └── jquery-validation │ │ │ ├── .bower.json │ │ │ ├── LICENSE.md │ │ │ └── dist │ │ │ ├── additional-methods.min.js │ │ │ └── jquery.validate.min.js │ ├── html │ │ └── facebook_messenger.html │ └── images │ │ ├── banner2.svg │ │ ├── banner1.svg │ │ └── banner3.svg │ ├── Views │ ├── _ViewStart.cshtml │ ├── _ViewImports.cshtml │ ├── Chat │ │ └── Index.cshtml │ ├── Shared │ │ ├── _ValidationScriptsPartial.cshtml │ │ └── _Layout.cshtml │ ├── Video │ │ └── Index.cshtml │ ├── Notify │ │ └── Index.cshtml │ ├── Sync │ │ └── Index.cshtml │ └── Home │ │ └── Index.cshtml │ ├── appsettings.Development.json │ ├── appsettings.json │ ├── Models │ ├── RegisterRequest.cs │ └── TwilioAccount.cs │ ├── Controllers │ ├── ChatController.cs │ ├── VideoController.cs │ ├── SyncController.cs │ ├── NotifyController.cs │ ├── HomeController.cs │ └── UtilitiesController.cs │ ├── Program.cs │ ├── TwilioSdkStarterDotnetCore.Web.csproj │ ├── Properties │ └── launchSettings.json │ └── Startup.cs ├── .travis.yml ├── Dockerfile ├── tests └── TwilioSdkStarterDotnetCore.Tests │ ├── TwilioSdkStarterDotnetCore.Tests.csproj │ └── UtilitiesControllerTests.cs ├── TwilioSdkStarterDotnetCore.sln └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | bin 2 | obj 3 | *.csproj.user 4 | .vs 5 | -------------------------------------------------------------------------------- /src/TwilioSdkStarterDotnetCore.Web/wwwroot/js/site.min.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/TwilioSdkStarterDotnetCore.Web/Views/_ViewStart.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | Layout = "_Layout"; 3 | } 4 | -------------------------------------------------------------------------------- /src/TwilioSdkStarterDotnetCore.Web/Views/_ViewImports.cshtml: -------------------------------------------------------------------------------- 1 | @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers 2 | -------------------------------------------------------------------------------- /src/TwilioSdkStarterDotnetCore.Web/wwwroot/css/home.css: -------------------------------------------------------------------------------- 1 | .config-value.set { 2 | color:seagreen; 3 | } 4 | 5 | .config-value.unset { 6 | color:darkred; 7 | } -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: required 2 | dist: trusty 3 | 4 | cache: 5 | apt: true 6 | 7 | services: 8 | - docker 9 | 10 | script: 11 | - docker build . --no-cache 12 | -------------------------------------------------------------------------------- /src/TwilioSdkStarterDotnetCore.Web/wwwroot/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TwilioDevEd/sdk-starter-csharp/HEAD/src/TwilioSdkStarterDotnetCore.Web/wwwroot/favicon.ico -------------------------------------------------------------------------------- /src/TwilioSdkStarterDotnetCore.Web/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Debug", 5 | "System": "Information", 6 | "Microsoft": "Information" 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM mcr.microsoft.com/dotnet/core/sdk:3.1 2 | WORKDIR /project 3 | COPY TwilioSdkStarterDotnetCore.sln /project/ 4 | COPY src /project/src 5 | COPY tests /project/tests 6 | RUN dotnet restore && dotnet test ./tests/TwilioSdkStarterDotnetCore.Tests 7 | -------------------------------------------------------------------------------- /src/TwilioSdkStarterDotnetCore.Web/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TwilioDevEd/sdk-starter-csharp/HEAD/src/TwilioSdkStarterDotnetCore.Web/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /src/TwilioSdkStarterDotnetCore.Web/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TwilioDevEd/sdk-starter-csharp/HEAD/src/TwilioSdkStarterDotnetCore.Web/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /src/TwilioSdkStarterDotnetCore.Web/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TwilioDevEd/sdk-starter-csharp/HEAD/src/TwilioSdkStarterDotnetCore.Web/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /src/TwilioSdkStarterDotnetCore.Web/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TwilioDevEd/sdk-starter-csharp/HEAD/src/TwilioSdkStarterDotnetCore.Web/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.woff2 -------------------------------------------------------------------------------- /src/TwilioSdkStarterDotnetCore.Web/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "TwilioAccount": { 3 | "AccountSid": "", 4 | "ApiKey": "", 5 | "ApiSecret": "", 6 | "NotificationServiceSid": "", 7 | "ChatServiceSid": "", 8 | "SyncServiceSid": "" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/TwilioSdkStarterDotnetCore.Web/wwwroot/js/site.js: -------------------------------------------------------------------------------- 1 | // Please see documentation at https://docs.microsoft.com/aspnet/core/client-side/bundling-and-minification 2 | // for details on configuring this project to bundle and minify static web assets. 3 | 4 | // Write your JavaScript code. 5 | -------------------------------------------------------------------------------- /src/TwilioSdkStarterDotnetCore.Web/Models/RegisterRequest.cs: -------------------------------------------------------------------------------- 1 | namespace TwilioSdkStarterDotnetCore.Web.Models 2 | { 3 | public class RegisterRequest 4 | { 5 | public string Identity { get; set; } 6 | public string BindingType { get; set; } 7 | public string Address { get; set; } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/TwilioSdkStarterDotnetCore.Web/wwwroot/css/site.min.css: -------------------------------------------------------------------------------- 1 | body{padding-top:50px;padding-bottom:20px}.body-content{padding-left:15px;padding-right:15px}.carousel-caption p{font-size:20px;line-height:1.4}.carousel-inner .item img[src$=".svg"]{width:100%}#qrCode{margin:15px}@media screen and (max-width:767px){.carousel-caption{display:none}} -------------------------------------------------------------------------------- /src/TwilioSdkStarterDotnetCore.Web/Controllers/ChatController.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Mvc; 2 | 3 | namespace TwilioSdkStarterDotnetCore.Web.Controllers 4 | { 5 | public class ChatController : Controller 6 | { 7 | public IActionResult Index() 8 | { 9 | return View(); 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /src/TwilioSdkStarterDotnetCore.Web/Controllers/VideoController.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Mvc; 2 | 3 | namespace TwilioSdkStarterDotnetCore.Web.Controllers 4 | { 5 | public class VideoController : Controller 6 | { 7 | public IActionResult Index() 8 | { 9 | return View(); 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /src/TwilioSdkStarterDotnetCore.Web/Controllers/SyncController.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Mvc; 2 | 3 | namespace TwilioSdkStarterDotnetCore.Web.Controllers 4 | { 5 | public class SyncController : Controller 6 | { 7 | public IActionResult Index() 8 | { 9 | return View(); 10 | } 11 | 12 | 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/TwilioSdkStarterDotnetCore.Web/Controllers/NotifyController.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Mvc; 2 | 3 | namespace TwilioSdkStarterDotnetCore.Web.Controllers 4 | { 5 | public class NotifyController : Controller 6 | { 7 | public IActionResult Index() 8 | { 9 | return View(); 10 | } 11 | 12 | 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/TwilioSdkStarterDotnetCore.Web/wwwroot/js/notify.js: -------------------------------------------------------------------------------- 1 | $(function() { 2 | $('#sendNotificationButton').on('click', function() { 3 | $.post('/send-notification', { 4 | identity: $('#identityInput').val(), 5 | body: "Hello, world!" 6 | }, function(response) { 7 | $('#identityInput').val(''); 8 | $('#message').html(response.message); 9 | console.log(response); 10 | }); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /src/TwilioSdkStarterDotnetCore.Web/Models/TwilioAccount.cs: -------------------------------------------------------------------------------- 1 | namespace TwilioSdkStarterDotnetCore.Web.Models 2 | { 3 | public class TwilioAccount 4 | { 5 | public string AccountSid { get; set; } 6 | public string AuthToken { get; set; } 7 | public string ApiKey { get; set; } 8 | public string ApiSecret { get; set; } 9 | public string ChatServiceSid { get; set; } 10 | public string SyncServiceSid { get; set; } 11 | public string NotificationServiceSid { get; set; } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/TwilioSdkStarterDotnetCore.Web/Program.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore; 2 | using Microsoft.AspNetCore.Hosting; 3 | 4 | namespace TwilioSdkStarterDotnetCore.Web 5 | { 6 | public class Program 7 | { 8 | public static void Main(string[] args) 9 | { 10 | CreateWebHostBuilder(args).Build().Run(); 11 | } 12 | 13 | public static IWebHostBuilder CreateWebHostBuilder(string[] args) => 14 | WebHost.CreateDefaultBuilder(args) 15 | .UseStartup(); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/TwilioSdkStarterDotnetCore.Web/wwwroot/lib/bootstrap/dist/js/npm.js: -------------------------------------------------------------------------------- 1 | // This file is autogenerated via the `commonjs` Grunt task. You can require() this file in a CommonJS environment. 2 | require('../../js/transition.js') 3 | require('../../js/alert.js') 4 | require('../../js/button.js') 5 | require('../../js/carousel.js') 6 | require('../../js/collapse.js') 7 | require('../../js/dropdown.js') 8 | require('../../js/modal.js') 9 | require('../../js/tooltip.js') 10 | require('../../js/popover.js') 11 | require('../../js/scrollspy.js') 12 | require('../../js/tab.js') 13 | require('../../js/affix.js') -------------------------------------------------------------------------------- /src/TwilioSdkStarterDotnetCore.Web/wwwroot/lib/jquery-validation-unobtrusive/.bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jquery-validation-unobtrusive", 3 | "homepage": "https://github.com/aspnet/jquery-validation-unobtrusive", 4 | "version": "3.2.9", 5 | "_release": "3.2.9", 6 | "_resolution": { 7 | "type": "version", 8 | "tag": "v3.2.9", 9 | "commit": "a91f5401898e125f10771c5f5f0909d8c4c82396" 10 | }, 11 | "_source": "https://github.com/aspnet/jquery-validation-unobtrusive.git", 12 | "_target": "^3.2.9", 13 | "_originalSource": "jquery-validation-unobtrusive", 14 | "_direct": true 15 | } -------------------------------------------------------------------------------- /src/TwilioSdkStarterDotnetCore.Web/wwwroot/lib/jquery-validation-unobtrusive/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) .NET Foundation. All rights reserved. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use 4 | these files except in compliance with the License. You may obtain a copy of the 5 | License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software distributed 10 | under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 11 | CONDITIONS OF ANY KIND, either express or implied. See the License for the 12 | specific language governing permissions and limitations under the License. 13 | -------------------------------------------------------------------------------- /src/TwilioSdkStarterDotnetCore.Web/wwwroot/lib/jquery/.bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jquery", 3 | "main": "dist/jquery.js", 4 | "license": "MIT", 5 | "ignore": [ 6 | "package.json" 7 | ], 8 | "keywords": [ 9 | "jquery", 10 | "javascript", 11 | "browser", 12 | "library" 13 | ], 14 | "homepage": "https://github.com/jquery/jquery-dist", 15 | "version": "3.3.1", 16 | "_release": "3.3.1", 17 | "_resolution": { 18 | "type": "version", 19 | "tag": "3.3.1", 20 | "commit": "9e8ec3d10fad04748176144f108d7355662ae75e" 21 | }, 22 | "_source": "https://github.com/jquery/jquery-dist.git", 23 | "_target": "^3.3.1", 24 | "_originalSource": "jquery", 25 | "_direct": true 26 | } -------------------------------------------------------------------------------- /src/TwilioSdkStarterDotnetCore.Web/TwilioSdkStarterDotnetCore.Web.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netcoreapp3.1 5 | 903559ff-cb6c-4fe8-b066-eadc25f3a202 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /tests/TwilioSdkStarterDotnetCore.Tests/TwilioSdkStarterDotnetCore.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netcoreapp3.1 5 | 6 | false 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /src/TwilioSdkStarterDotnetCore.Web/wwwroot/css/notify.css: -------------------------------------------------------------------------------- 1 | * { 2 | box-sizing:border-box; 3 | } 4 | 5 | html, body { 6 | padding:0; 7 | margin:0; 8 | height:100%; 9 | width:100%; 10 | color:#dedede; 11 | background-color: #849091; 12 | font-family: 'Helvetica Neue', Helvetica, sans-serif; 13 | } 14 | 15 | header { 16 | width:100%; 17 | position:absolute; 18 | text-align:center; 19 | bottom:20px; 20 | } 21 | 22 | header a, header a:visited { 23 | font-size:18px; 24 | color:#dedede; 25 | text-decoration:none; 26 | } 27 | 28 | header a:hover { 29 | text-decoration:underline; 30 | } 31 | 32 | section { 33 | background-color:#2B2B2A; 34 | text-align:center; 35 | padding:16px; 36 | } 37 | 38 | #message { 39 | padding:6px; 40 | } 41 | -------------------------------------------------------------------------------- /src/TwilioSdkStarterDotnetCore.Web/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "iisSettings": { 3 | "windowsAuthentication": false, 4 | "anonymousAuthentication": true, 5 | "iisExpress": { 6 | "applicationUrl": "http://localhost:50768", 7 | "sslPort": 44387 8 | } 9 | }, 10 | "profiles": { 11 | "IIS Express": { 12 | "commandName": "IISExpress", 13 | "launchBrowser": true, 14 | "environmentVariables": { 15 | "ASPNETCORE_ENVIRONMENT": "Development" 16 | } 17 | }, 18 | "TwilioSdkStarter.Web": { 19 | "commandName": "Project", 20 | "launchBrowser": true, 21 | "applicationUrl": "http://localhost:50768", 22 | "environmentVariables": { 23 | "ASPNETCORE_ENVIRONMENT": "Development" 24 | } 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /src/TwilioSdkStarterDotnetCore.Web/Controllers/HomeController.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.AspNetCore.Mvc; 3 | using Microsoft.Extensions.Options; 4 | using TwilioSdkStarterDotnetCore.Web.Models; 5 | 6 | namespace TwilioSdkStarterDotnetCore.Web.Controllers 7 | { 8 | public class HomeController : Controller 9 | { 10 | private readonly TwilioAccount _twilioAccount; 11 | public HomeController(IOptions twilioAccount) 12 | { 13 | _twilioAccount = twilioAccount.Value ?? throw new ArgumentException(nameof(twilioAccount)); 14 | } 15 | public IActionResult Index() 16 | { 17 | // never publicly show your credentials. This is purely to confirm correct setup 18 | return View(_twilioAccount); 19 | } 20 | 21 | 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/TwilioSdkStarterDotnetCore.Web/wwwroot/css/site.css: -------------------------------------------------------------------------------- 1 | /* Please see documentation at https://docs.microsoft.com/aspnet/core/client-side/bundling-and-minification\ 2 | for details on configuring this project to bundle and minify static web assets. */ 3 | body { 4 | padding-top: 50px; 5 | padding-bottom: 20px; 6 | } 7 | 8 | /* Wrapping element */ 9 | /* Set some basic padding to keep content from hitting the edges */ 10 | .body-content { 11 | padding-left: 15px; 12 | padding-right: 15px; 13 | } 14 | 15 | /* Carousel */ 16 | .carousel-caption p { 17 | font-size: 20px; 18 | line-height: 1.4; 19 | } 20 | 21 | /* Make .svg files in the carousel display properly in older browsers */ 22 | .carousel-inner .item img[src$=".svg"] { 23 | width: 100%; 24 | } 25 | 26 | /* QR code generator */ 27 | #qrCode { 28 | margin: 15px; 29 | } 30 | 31 | /* Hide/rearrange for smaller screens */ 32 | @media screen and (max-width: 767px) { 33 | /* Hide captions */ 34 | .carousel-caption { 35 | display: none; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/TwilioSdkStarterDotnetCore.Web/wwwroot/html/facebook_messenger.html: -------------------------------------------------------------------------------- 1 | 2 | 27 |
32 |
33 | 34 | -------------------------------------------------------------------------------- /src/TwilioSdkStarterDotnetCore.Web/wwwroot/lib/jquery-validation/.bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jquery-validation", 3 | "homepage": "https://jqueryvalidation.org/", 4 | "repository": { 5 | "type": "git", 6 | "url": "git://github.com/jquery-validation/jquery-validation.git" 7 | }, 8 | "authors": [ 9 | "Jörn Zaefferer " 10 | ], 11 | "description": "Form validation made easy", 12 | "main": "dist/jquery.validate.js", 13 | "keywords": [ 14 | "forms", 15 | "validation", 16 | "validate" 17 | ], 18 | "license": "MIT", 19 | "ignore": [ 20 | "**/.*", 21 | "node_modules", 22 | "bower_components", 23 | "test", 24 | "demo", 25 | "lib" 26 | ], 27 | "dependencies": { 28 | "jquery": ">= 1.7.2" 29 | }, 30 | "version": "1.17.0", 31 | "_release": "1.17.0", 32 | "_resolution": { 33 | "type": "version", 34 | "tag": "1.17.0", 35 | "commit": "fc9b12d3bfaa2d0c04605855b896edb2934c0772" 36 | }, 37 | "_source": "https://github.com/jzaefferer/jquery-validation.git", 38 | "_target": "^1.17.0", 39 | "_originalSource": "jquery-validation", 40 | "_direct": true 41 | } -------------------------------------------------------------------------------- /src/TwilioSdkStarterDotnetCore.Web/Views/Chat/Index.cshtml: -------------------------------------------------------------------------------- 1 | 2 | @{ 3 | ViewData["Title"] = "Twilio Chat Quickstart"; 4 | } 5 | 6 | @section Styles{ 7 | 8 | 9 | 10 | } 11 |
12 | 14 | Read the getting started guide 15 | 16 | 17 | Back 18 |
19 | 20 |
21 |
22 | 23 |
24 | 25 | @section Scripts 26 | { 27 | 28 | 29 | 30 | } 31 | 32 | -------------------------------------------------------------------------------- /src/TwilioSdkStarterDotnetCore.Web/wwwroot/lib/bootstrap/.bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bootstrap", 3 | "description": "The most popular front-end framework for developing responsive, mobile first projects on the web.", 4 | "keywords": [ 5 | "css", 6 | "js", 7 | "less", 8 | "mobile-first", 9 | "responsive", 10 | "front-end", 11 | "framework", 12 | "web" 13 | ], 14 | "homepage": "http://getbootstrap.com", 15 | "license": "MIT", 16 | "moduleType": "globals", 17 | "main": [ 18 | "less/bootstrap.less", 19 | "dist/js/bootstrap.js" 20 | ], 21 | "ignore": [ 22 | "/.*", 23 | "_config.yml", 24 | "CNAME", 25 | "composer.json", 26 | "CONTRIBUTING.md", 27 | "docs", 28 | "js/tests", 29 | "test-infra" 30 | ], 31 | "dependencies": { 32 | "jquery": "1.9.1 - 3" 33 | }, 34 | "version": "3.3.7", 35 | "_release": "3.3.7", 36 | "_resolution": { 37 | "type": "version", 38 | "tag": "v3.3.7", 39 | "commit": "0b9c4a4007c44201dce9a6cc1a38407005c26c86" 40 | }, 41 | "_source": "https://github.com/twbs/bootstrap.git", 42 | "_target": "v3.3.7", 43 | "_originalSource": "bootstrap", 44 | "_direct": true 45 | } -------------------------------------------------------------------------------- /src/TwilioSdkStarterDotnetCore.Web/wwwroot/lib/bootstrap/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2011-2016 Twitter, Inc. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/TwilioSdkStarterDotnetCore.Web/wwwroot/css/sync.css: -------------------------------------------------------------------------------- 1 | body { 2 | } 3 | * { 4 | box-sizing: border-box; 5 | } 6 | 7 | html, 8 | body { 9 | padding: 0; 10 | margin: 0; 11 | height: 100%; 12 | width: 100%; 13 | color: #dedede; 14 | background-color: #849091; 15 | font-family: 'Helvetica Neue', Helvetica, sans-serif; 16 | } 17 | 18 | header { 19 | width: 100%; 20 | position: absolute; 21 | text-align: center; 22 | bottom: 20px; 23 | } 24 | 25 | header a, 26 | header a:visited { 27 | font-size: 18px; 28 | color: #dedede; 29 | text-decoration: none; 30 | } 31 | 32 | header a:hover { 33 | text-decoration: underline; 34 | } 35 | 36 | section { 37 | background-color: #2b2b2a; 38 | text-align: center; 39 | padding: 16px; 40 | } 41 | 42 | #message { 43 | padding: 6px; 44 | } 45 | 46 | #board { 47 | width: 33%; 48 | margin-left: auto; 49 | margin-right: auto; 50 | } 51 | 52 | #board .board-row { 53 | width: 100%; 54 | padding-bottom: 3px; 55 | } 56 | 57 | #board .board-row button { 58 | width: 30%; 59 | height: 100px; 60 | font-size: 50px; 61 | color: #000; 62 | } 63 | 64 | #board .board-row button:hover { 65 | cursor: pointer; 66 | background-color: #000; 67 | color: #fff; 68 | } 69 | -------------------------------------------------------------------------------- /src/TwilioSdkStarterDotnetCore.Web/wwwroot/lib/jquery-validation/LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | ===================== 3 | 4 | Copyright Jörn Zaefferer 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /src/TwilioSdkStarterDotnetCore.Web/Views/Shared/_ValidationScriptsPartial.cshtml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 12 | 18 | 19 | -------------------------------------------------------------------------------- /src/TwilioSdkStarterDotnetCore.Web/Views/Video/Index.cshtml: -------------------------------------------------------------------------------- 1 | 2 | @{ 3 | ViewData["Title"] = "Twilio Video - Video Quickstart"; 4 | } 5 | @section Styles{ 6 | 7 | } 8 | Back 9 |
10 |
11 |
12 |

Hello Beautiful

13 |
14 | 15 |
16 | 17 |
18 |

Room Name:

19 | 20 | 21 | 22 |
23 | 24 |
25 |
26 | 27 | @section Scripts 28 | { 29 | 30 | 31 | 32 | 33 | } 34 | 35 | -------------------------------------------------------------------------------- /src/TwilioSdkStarterDotnetCore.Web/Views/Notify/Index.cshtml: -------------------------------------------------------------------------------- 1 | 2 | @{ 3 | ViewData["Title"] = "Notify Quickstart"; 4 | } 5 | @section Styles 6 | { 7 | 8 | 9 | 10 | } 11 | 12 |
13 | 14 | Read the Twilio Notify guide 15 | 16 | Back 17 |
18 | 19 |
20 |

Send Notification to Identity

21 | 22 | 23 |

24 | 25 | 26 |

Welcome to Notify!
27 | 28 |

After you set up a notification binding, go ahead and send a notification to that identity!

29 |
30 | @section Scripts { 31 | 32 | 33 | } -------------------------------------------------------------------------------- /src/TwilioSdkStarterDotnetCore.Web/wwwroot/css/chat.css: -------------------------------------------------------------------------------- 1 | * { 2 | box-sizing:border-box; 3 | } 4 | 5 | html, body { 6 | padding:0; 7 | margin:0; 8 | height:100%; 9 | width:100%; 10 | color:#dedede; 11 | background-color: #849091; 12 | font-family: 'Helvetica Neue', Helvetica, sans-serif; 13 | } 14 | 15 | header { 16 | width:100%; 17 | position:absolute; 18 | text-align:center; 19 | bottom:20px; 20 | } 21 | 22 | header a, header a:visited { 23 | font-size:18px; 24 | color:#dedede; 25 | text-decoration:none; 26 | } 27 | 28 | header a:hover { 29 | text-decoration:underline; 30 | } 31 | 32 | section { 33 | height:70%; 34 | background-color:#2B2B2A; 35 | } 36 | 37 | section input { 38 | display:block; 39 | height:52px; 40 | width:800px; 41 | margin:10px auto; 42 | outline:none; 43 | background-color:transparent; 44 | border:none; 45 | border-bottom:1px solid #2B2B2A; 46 | padding:0; 47 | font-size:42px; 48 | color:#eee; 49 | } 50 | 51 | #messages { 52 | background-color:#232323; 53 | padding:10px; 54 | height:100%; 55 | width:800px; 56 | margin:0 auto; 57 | overflow-y:auto; 58 | } 59 | 60 | #messages p { 61 | margin:5px 0; 62 | padding:0; 63 | } 64 | 65 | .info { 66 | margin:5px 0; 67 | font-style:italic; 68 | } 69 | 70 | .message-container { 71 | margin:5px 0; 72 | color:#fff; 73 | } 74 | 75 | .message-container .username { 76 | display:inline-block; 77 | margin-right:5px; 78 | font-weight:bold; 79 | color:#849091; 80 | } 81 | 82 | .me, .username.me { 83 | font-weight:bold; 84 | color:cyan; 85 | } 86 | 87 | .message-container .username.me { 88 | display:inline-block; 89 | margin-right:5px; 90 | } -------------------------------------------------------------------------------- /src/TwilioSdkStarterDotnetCore.Web/wwwroot/lib/jquery/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright JS Foundation and other contributors, https://js.foundation/ 2 | 3 | This software consists of voluntary contributions made by many 4 | individuals. For exact contribution history, see the revision history 5 | available at https://github.com/jquery/jquery 6 | 7 | The following license applies to all parts of this software except as 8 | documented below: 9 | 10 | ==== 11 | 12 | Permission is hereby granted, free of charge, to any person obtaining 13 | a copy of this software and associated documentation files (the 14 | "Software"), to deal in the Software without restriction, including 15 | without limitation the rights to use, copy, modify, merge, publish, 16 | distribute, sublicense, and/or sell copies of the Software, and to 17 | permit persons to whom the Software is furnished to do so, subject to 18 | the following conditions: 19 | 20 | The above copyright notice and this permission notice shall be 21 | included in all copies or substantial portions of the Software. 22 | 23 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 24 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 25 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 27 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 28 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 29 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 30 | 31 | ==== 32 | 33 | All files located in the node_modules and external directories are 34 | externally maintained libraries used by this software which have their 35 | own licenses; we recommend you read them, as their terms may differ from 36 | the terms above. 37 | -------------------------------------------------------------------------------- /tests/TwilioSdkStarterDotnetCore.Tests/UtilitiesControllerTests.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Microsoft.AspNetCore.Mvc; 3 | using Microsoft.Extensions.Options; 4 | using Moq; 5 | using NUnit.Framework; 6 | using TwilioSdkStarterDotnetCore.Web.Controllers; 7 | using TwilioSdkStarterDotnetCore.Web.Models; 8 | 9 | 10 | namespace TwilioSdkStarterDotnetCore.Tests 11 | { 12 | [TestFixture] 13 | public class UtilitiesControllerTests 14 | { 15 | private TwilioAccount _twilioAccount; 16 | 17 | private UtilitiesController _sut; 18 | 19 | [SetUp] 20 | public void Setup() 21 | { 22 | _twilioAccount = new TwilioAccount 23 | { 24 | AuthToken = "ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", 25 | AccountSid = "ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", 26 | ApiKey = "SKXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", 27 | ApiSecret = "aXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", 28 | ChatServiceSid = "ISXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", 29 | NotificationServiceSid = "ISXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", 30 | SyncServiceSid = "ISXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" 31 | }; 32 | 33 | var options = Options.Create(_twilioAccount); 34 | 35 | _sut = new UtilitiesController(options); 36 | } 37 | 38 | [Test] 39 | public void GivenNullOptions_Should_ThrowException() 40 | { 41 | Assert.That( 42 | () => new UtilitiesController(null), 43 | Throws.ArgumentNullException.With.Message.Contains("Parameter 'twilioAccount'")); 44 | } 45 | 46 | [Test] 47 | public void Token_Returns_ExpectedJsonResult() 48 | { 49 | var result = _sut.Token(); 50 | var tokenResult = (Dictionary)result.Value; 51 | 52 | Assert.True(tokenResult.ContainsKey("token")); 53 | Assert.True(tokenResult.ContainsKey("identity")); 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/TwilioSdkStarterDotnetCore.Web/Startup.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Builder; 2 | using Microsoft.AspNetCore.Hosting; 3 | using Microsoft.AspNetCore.Mvc; 4 | using Microsoft.Extensions.Configuration; 5 | using Microsoft.Extensions.DependencyInjection; 6 | using TwilioSdkStarterDotnetCore.Web.Models; 7 | 8 | namespace TwilioSdkStarterDotnetCore.Web 9 | { 10 | public class Startup 11 | { 12 | public Startup(IConfiguration configuration) 13 | { 14 | Configuration = configuration; 15 | } 16 | 17 | public IConfiguration Configuration { get; } 18 | 19 | // This method gets called by the runtime. Use this method to add services to the container. 20 | public void ConfigureServices(IServiceCollection services) 21 | { 22 | // this will extract our Twilio account details from the appsettings.json and map them to an object 23 | services.Configure(Configuration.GetSection("TwilioAccount")); 24 | 25 | services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_3_0); 26 | } 27 | 28 | // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. 29 | public void Configure(IApplicationBuilder app, IHostingEnvironment env) 30 | { 31 | if (env.IsDevelopment()) 32 | { 33 | app.UseDeveloperExceptionPage(); 34 | } 35 | else 36 | { 37 | app.UseExceptionHandler("/Home/Error"); 38 | app.UseHsts(); 39 | } 40 | 41 | app.UseHttpsRedirection(); 42 | app.UseStaticFiles(); 43 | app.UseCookiePolicy(); 44 | 45 | app.UseRouting(); 46 | 47 | app.UseEndpoints(endpoints => 48 | { 49 | endpoints.MapDefaultControllerRoute(); 50 | }); 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/TwilioSdkStarterDotnetCore.Web/Views/Sync/Index.cshtml: -------------------------------------------------------------------------------- 1 | 2 | @{ 3 | ViewData["Title"] = "Tic-Tac-Twilio - Sync Quickstart"; 4 | } 5 | 6 | @section Styles 7 | { 8 | 9 | 10 | 11 | } 12 |
13 | 15 | Read the getting started guide 16 | 17 | 18 | Back 19 |
20 | 21 |
22 |

Tic-Tac-Twilio

23 | 24 |
25 |
26 | 27 | 28 | 29 |
30 |
31 | 32 | 33 | 34 |
35 |
36 | 37 | 38 | 39 |
40 |
41 | 42 |
43 | Welcome! Initializing Sync... 44 |
45 | 46 |

Open this page in a few tabs to test!

47 |
48 | 49 | @section Scripts 50 | { 51 | 52 | 53 | 54 | } 55 | -------------------------------------------------------------------------------- /TwilioSdkStarterDotnetCore.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.28010.2036 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{927F0DE5-9163-468A-AC36-9D4D11035776}" 7 | EndProject 8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{335EDF36-138D-4FA0-A0A7-2BCF946DC438}" 9 | EndProject 10 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TwilioSdkStarterDotnetCore.Web", "src\TwilioSdkStarterDotnetCore.Web\TwilioSdkStarterDotnetCore.Web.csproj", "{79A347A8-313A-4D83-8C0C-7FE1CBA0AA67}" 11 | EndProject 12 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{9317EA5E-8603-4F08-A7ED-3EE87A94534D}" 13 | ProjectSection(SolutionItems) = preProject 14 | README.md = README.md 15 | EndProjectSection 16 | EndProject 17 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TwilioSdkStarterDotnetCore.Tests", "tests\TwilioSdkStarterDotnetCore.Tests\TwilioSdkStarterDotnetCore.Tests.csproj", "{EA1B08D7-0EE1-44F6-A1C6-745FADFF9AA3}" 18 | EndProject 19 | Global 20 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 21 | Debug|Any CPU = Debug|Any CPU 22 | Release|Any CPU = Release|Any CPU 23 | EndGlobalSection 24 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 25 | {79A347A8-313A-4D83-8C0C-7FE1CBA0AA67}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 26 | {79A347A8-313A-4D83-8C0C-7FE1CBA0AA67}.Debug|Any CPU.Build.0 = Debug|Any CPU 27 | {79A347A8-313A-4D83-8C0C-7FE1CBA0AA67}.Release|Any CPU.ActiveCfg = Release|Any CPU 28 | {79A347A8-313A-4D83-8C0C-7FE1CBA0AA67}.Release|Any CPU.Build.0 = Release|Any CPU 29 | {EA1B08D7-0EE1-44F6-A1C6-745FADFF9AA3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 30 | {EA1B08D7-0EE1-44F6-A1C6-745FADFF9AA3}.Debug|Any CPU.Build.0 = Debug|Any CPU 31 | {EA1B08D7-0EE1-44F6-A1C6-745FADFF9AA3}.Release|Any CPU.ActiveCfg = Release|Any CPU 32 | {EA1B08D7-0EE1-44F6-A1C6-745FADFF9AA3}.Release|Any CPU.Build.0 = Release|Any CPU 33 | EndGlobalSection 34 | GlobalSection(SolutionProperties) = preSolution 35 | HideSolutionNode = FALSE 36 | EndGlobalSection 37 | GlobalSection(NestedProjects) = preSolution 38 | {79A347A8-313A-4D83-8C0C-7FE1CBA0AA67} = {927F0DE5-9163-468A-AC36-9D4D11035776} 39 | {EA1B08D7-0EE1-44F6-A1C6-745FADFF9AA3} = {335EDF36-138D-4FA0-A0A7-2BCF946DC438} 40 | EndGlobalSection 41 | GlobalSection(ExtensibilityGlobals) = postSolution 42 | SolutionGuid = {02136022-3040-4D82-A5EA-EEC2D5A71D1A} 43 | EndGlobalSection 44 | EndGlobal 45 | -------------------------------------------------------------------------------- /src/TwilioSdkStarterDotnetCore.Web/Views/Shared/_Layout.cshtml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | @ViewData["Title"] - TwilioSdkStarter.Web 7 | 8 | 9 | 10 | 11 | @RenderSection("Styles", required: false) 12 | 13 | 14 | 17 | 18 | 19 | 20 | 21 | @* 41 | 42 | *@ 43 | 44 |
45 | @RenderBody() 46 | @*
47 |
48 |

© 2018 - TwilioSdkStarter.Web

49 |
*@ 50 |
51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 64 | 70 | 71 | 72 | 73 | @RenderSection("Scripts", required: false) 74 | 75 | 76 | -------------------------------------------------------------------------------- /src/TwilioSdkStarterDotnetCore.Web/Views/Home/Index.cshtml: -------------------------------------------------------------------------------- 1 | @using TwilioSdkStarterDotnetCore.Web.Models 2 | @model TwilioSdkStarterDotnetCore.Web.Models.TwilioAccount 3 | @{ 4 | ViewData["Title"] = "Twilio Sdk Starter Kit"; 5 | ViewData["NotConfiguredMessage"] = "Not configured in appsettings.json or secrets.json"; 6 | } 7 | 8 | @section Styles{ 9 | 12 | 13 | } 14 |

Twilio Server Starter Kit Environment Setup

15 |

Never publicly show your credentials. This is purely to confirm correct setup.

16 |

Account Information

17 | 18 | 19 | 20 | 23 | 24 | 25 | 26 | 29 | 30 | 31 | 32 | 35 | 36 |
AccountSid 21 | @(string.IsNullOrEmpty(Model.AccountSid) ? ViewData["NotConfiguredMessage"] : Model.AccountSid) 22 |
ApiKey 27 | @(string.IsNullOrEmpty(Model.ApiKey) ? ViewData["NotConfiguredMessage"] : Model.ApiKey) 28 |
ApiSecret 33 | @(string.IsNullOrEmpty(Model.ApiSecret) ? ViewData["NotConfiguredMessage"] : "Configured properly") 34 |
37 |

Products

38 | 39 | 40 | 41 | 42 | 45 | 46 | 47 | 48 | 49 | 52 | 53 | 54 | 55 | 56 | 59 | 60 |
NotifyNotificationServiceSid 43 | @(string.IsNullOrEmpty(Model.NotificationServiceSid) ? ViewData["NotConfiguredMessage"] : Model.NotificationServiceSid) 44 |
ChatChatServiceSid 50 | @(string.IsNullOrEmpty(Model.ChatServiceSid) ? ViewData["NotConfiguredMessage"] : Model.ChatServiceSid) 51 |
SyncSyncServiceSid 57 | @(string.IsNullOrEmpty(Model.SyncServiceSid) ? "default" : Model.SyncServiceSid) 58 |
61 |

Demos

62 | 63 | Video 64 | Sync 65 | Notify 66 | Chat 67 | 68 | 69 | 70 | @section Scripts{ 71 | 72 | 75 | // 76 | } 77 | 78 | -------------------------------------------------------------------------------- /src/TwilioSdkStarterDotnetCore.Web/wwwroot/js/sync.js: -------------------------------------------------------------------------------- 1 | $(function () { 2 | //We'll use message to tell the user what's happening 3 | var $message = $('#message'); 4 | 5 | //Get handle to the game board buttons 6 | var $buttons = $('#board .board-row button'); 7 | 8 | //Our interface to the Sync service 9 | var syncClient; 10 | 11 | // Every browser Sync client relies on FPA tokens to authenticate and authorize it 12 | // for access to your Sync data. 13 | // 14 | // In this quickstart, we're using our own token generator. You can generate a token 15 | // in any backend language that Twilio supports, or generate a Twilio Function so 16 | // Twilio can host it for you. See the docs for more details. 17 | // 18 | $.getJSON('/token', function (tokenResponse) { 19 | 20 | // Once we have the token, we can initialize the Sync client and start subscribing 21 | // to data. The client will initialize asynchronously while we load the rest of 22 | // the user interface. 23 | // 24 | syncClient = new Twilio.Sync.Client(tokenResponse.token, { logLevel: 'info' }); 25 | syncClient.on('connectionStateChanged', function(state) { 26 | if (state != 'connected') { 27 | $message.html('Sync is not live (websocket connection ' + state + ')…'); 28 | } else { 29 | // Now that we're connected, lets light up our board and play! 30 | $buttons.attr('disabled', false); 31 | $message.html('Sync is live!'); 32 | } 33 | }); 34 | 35 | // Let's pop a message on the screen to show that Sync is working 36 | $message.html('Loading board data…'); 37 | 38 | // Our game state is stored in a Sync document. Here, we'll attach to that document 39 | // (or create it, if it doesn't exist) and connect the necessary event handlers. 40 | // 41 | syncClient.document('SyncGame').then(function(syncDoc) { 42 | var data = syncDoc.value; 43 | if (data.board) { 44 | updateUserInterface(data); 45 | } 46 | 47 | // Any time the board changes, we want to show the new state. The 'updated' 48 | // event is for this. 49 | syncDoc.on('updated', function(event) { 50 | console.debug("Board was updated", event.isLocal? "locally." : "by the other guy."); 51 | updateUserInterface(event.value); 52 | }); 53 | 54 | // Let's make our buttons control the game state in Sync… 55 | $buttons.on('click', function (e) { 56 | // Toggle the value: X, O, or empty 57 | toggleCellValue($(e.target)); 58 | 59 | // Send updated document to Sync. This will trigger "updated" events for all players. 60 | var data = readGameBoardFromUserInterface(); 61 | syncDoc.set(data); 62 | }); 63 | }); 64 | 65 | }); 66 | 67 | //Toggle the value: X, O, or empty (  for UI) 68 | function toggleCellValue($cell) { 69 | var cellValue = $cell.html(); 70 | 71 | if (cellValue === 'X') { 72 | $cell.html('O'); 73 | } else if (cellValue === 'O') { 74 | $cell.html(' '); 75 | } else { 76 | $cell.html('X'); 77 | } 78 | } 79 | 80 | //Read the state of the UI and create a new document 81 | function readGameBoardFromUserInterface() { 82 | var board = [ 83 | ['', '', ''], 84 | ['', '', ''], 85 | ['', '', ''] 86 | ]; 87 | 88 | for (var row = 0; row < 3; row++) { 89 | for (var col = 0; col < 3; col++) { 90 | var selector = '[data-row="' + row + '"]' + 91 | '[data-col="' + col + '"]'; 92 | board[row][col] = $(selector).html().replace(' ', ''); 93 | } 94 | } 95 | 96 | return {board: board}; 97 | } 98 | 99 | //Update the buttons on the board to match our document 100 | function updateUserInterface(data) { 101 | for (var row = 0; row < 3; row++) { 102 | for (var col = 0; col < 3; col++) { 103 | var this_cell = '[data-row="' + row + '"]' + '[data-col="' + col + '"]'; 104 | var cellValue = data.board[row][col]; 105 | $(this_cell).html(cellValue === '' ? ' ' : cellValue); 106 | } 107 | } 108 | } 109 | }); 110 | -------------------------------------------------------------------------------- /src/TwilioSdkStarterDotnetCore.Web/wwwroot/js/chat.js: -------------------------------------------------------------------------------- 1 | $(function() { 2 | // Get handle to the chat div 3 | var $chatWindow = $('#messages'); 4 | 5 | // Our interface to the Chat service 6 | var chatClient; 7 | 8 | // A handle to the "general" chat channel - the one and only channel we 9 | // will have in this sample app 10 | var generalChannel; 11 | 12 | // The server will assign the client a random username - store that value 13 | // here 14 | var username; 15 | 16 | // Helper function to print info messages to the chat window 17 | function print(infoMessage, asHtml) { 18 | var $msg = $('
'); 19 | if (asHtml) { 20 | $msg.html(infoMessage); 21 | } else { 22 | $msg.text(infoMessage); 23 | } 24 | $chatWindow.append($msg); 25 | } 26 | 27 | // Helper function to print chat message to the chat window 28 | function printMessage(fromUser, message) { 29 | var $user = $('').text(fromUser + ':'); 30 | if (fromUser === username) { 31 | $user.addClass('me'); 32 | } 33 | var $message = $('').text(message); 34 | var $container = $('
'); 35 | $container.append($user).append($message); 36 | $chatWindow.append($container); 37 | $chatWindow.scrollTop($chatWindow[0].scrollHeight); 38 | } 39 | 40 | // Alert the user they have been assigned a random username 41 | print('Logging in...'); 42 | 43 | // Get an access token for the current user, passing a username (identity) 44 | $.getJSON('/token', function(data) { 45 | 46 | 47 | // Initialize the Chat client 48 | Twilio.Chat.Client.create(data.token).then(client => { 49 | console.log('Created chat client'); 50 | chatClient = client; 51 | chatClient.getSubscribedChannels().then(createOrJoinGeneralChannel); 52 | 53 | // when the access token is about to expire, refresh it 54 | chatClient.on('tokenAboutToExpire', function() { 55 | refreshToken(username); 56 | }); 57 | 58 | // if the access token already expired, refresh it 59 | chatClient.on('tokenExpired', function() { 60 | refreshToken(username); 61 | }); 62 | 63 | // Alert the user they have been assigned a random username 64 | username = data.identity; 65 | print('You have been assigned a random username of: ' 66 | + '' + username + '', true); 67 | 68 | }).catch(error => { 69 | console.error(error); 70 | print('There was an error creating the chat client:
' + error, true); 71 | print('Please check your .env file.', false); 72 | }); 73 | }); 74 | 75 | function refreshToken(identity) { 76 | console.log('Token about to expire'); 77 | // Make a secure request to your backend to retrieve a refreshed access token. 78 | // Use an authentication mechanism to prevent token exposure to 3rd parties. 79 | $.getJSON('/token/' + identity, function(data) { 80 | console.log('updated token for chat client'); 81 | chatClient.updateToken(data.token); 82 | }); 83 | } 84 | 85 | function createOrJoinGeneralChannel() { 86 | // Get the general chat channel, which is where all the messages are 87 | // sent in this simple application 88 | print('Attempting to join "general" chat channel...'); 89 | chatClient.getChannelByUniqueName('general') 90 | .then(function(channel) { 91 | generalChannel = channel; 92 | console.log('Found general channel:'); 93 | console.log(generalChannel); 94 | setupChannel(); 95 | }).catch(function() { 96 | // If it doesn't exist, let's create it 97 | console.log('Creating general channel'); 98 | chatClient.createChannel({ 99 | uniqueName: 'general', 100 | friendlyName: 'General Chat Channel' 101 | }).then(function(channel) { 102 | console.log('Created general channel:'); 103 | console.log(channel); 104 | generalChannel = channel; 105 | setupChannel(); 106 | }).catch(function(channel) { 107 | console.log('Channel could not be created:'); 108 | console.log(channel); 109 | }); 110 | }); 111 | } 112 | 113 | // Set up channel after it has been found 114 | function setupChannel() { 115 | // Join the general channel 116 | generalChannel.join().then(function(channel) { 117 | print('Joined channel as ' 118 | + '' + username + '.', true); 119 | }); 120 | 121 | // Listen for new messages sent to the channel 122 | generalChannel.on('messageAdded', function(message) { 123 | printMessage(message.author, message.body); 124 | }); 125 | } 126 | 127 | // Send a new message to the general channel 128 | var $input = $('#chat-input'); 129 | $input.on('keydown', function(e) { 130 | 131 | if (e.keyCode == 13) { 132 | if (generalChannel === undefined) { 133 | print('The Chat Service is not configured. Please check your .env file.', false); 134 | return; 135 | } 136 | generalChannel.sendMessage($input.val()) 137 | $input.val(''); 138 | } 139 | }); 140 | }); 141 | -------------------------------------------------------------------------------- /src/TwilioSdkStarterDotnetCore.Web/wwwroot/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js: -------------------------------------------------------------------------------- 1 | // Unobtrusive validation support library for jQuery and jQuery Validate 2 | // Copyright (C) Microsoft Corporation. All rights reserved. 3 | // @version v3.2.9 4 | !function(a){"function"==typeof define&&define.amd?define("jquery.validate.unobtrusive",["jquery.validation"],a):"object"==typeof module&&module.exports?module.exports=a(require("jquery-validation")):jQuery.validator.unobtrusive=a(jQuery)}(function(a){function e(a,e,n){a.rules[e]=n,a.message&&(a.messages[e]=a.message)}function n(a){return a.replace(/^\s+|\s+$/g,"").split(/\s*,\s*/g)}function t(a){return a.replace(/([!"#$%&'()*+,.\/:;<=>?@\[\\\]^`{|}~])/g,"\\$1")}function r(a){return a.substr(0,a.lastIndexOf(".")+1)}function i(a,e){return 0===a.indexOf("*.")&&(a=a.replace("*.",e)),a}function o(e,n){var r=a(this).find("[data-valmsg-for='"+t(n[0].name)+"']"),i=r.attr("data-valmsg-replace"),o=i?a.parseJSON(i)!==!1:null;r.removeClass("field-validation-valid").addClass("field-validation-error"),e.data("unobtrusiveContainer",r),o?(r.empty(),e.removeClass("input-validation-error").appendTo(r)):e.hide()}function d(e,n){var t=a(this).find("[data-valmsg-summary=true]"),r=t.find("ul");r&&r.length&&n.errorList.length&&(r.empty(),t.addClass("validation-summary-errors").removeClass("validation-summary-valid"),a.each(n.errorList,function(){a("
  • ").html(this.message).appendTo(r)}))}function s(e){var n=e.data("unobtrusiveContainer");if(n){var t=n.attr("data-valmsg-replace"),r=t?a.parseJSON(t):null;n.addClass("field-validation-valid").removeClass("field-validation-error"),e.removeData("unobtrusiveContainer"),r&&n.empty()}}function l(e){var n=a(this),t="__jquery_unobtrusive_validation_form_reset";if(!n.data(t)){n.data(t,!0);try{n.data("validator").resetForm()}finally{n.removeData(t)}n.find(".validation-summary-errors").addClass("validation-summary-valid").removeClass("validation-summary-errors"),n.find(".field-validation-error").addClass("field-validation-valid").removeClass("field-validation-error").removeData("unobtrusiveContainer").find(">*").removeData("unobtrusiveContainer")}}function u(e){var n=a(e),t=n.data(v),r=a.proxy(l,e),i=f.unobtrusive.options||{},u=function(n,t){var r=i[n];r&&a.isFunction(r)&&r.apply(e,t)};return t||(t={options:{errorClass:i.errorClass||"input-validation-error",errorElement:i.errorElement||"span",errorPlacement:function(){o.apply(e,arguments),u("errorPlacement",arguments)},invalidHandler:function(){d.apply(e,arguments),u("invalidHandler",arguments)},messages:{},rules:{},success:function(){s.apply(e,arguments),u("success",arguments)}},attachValidation:function(){n.off("reset."+v,r).on("reset."+v,r).validate(this.options)},validate:function(){return n.validate(),n.valid()}},n.data(v,t)),t}var m,f=a.validator,v="unobtrusiveValidation";return f.unobtrusive={adapters:[],parseElement:function(e,n){var t,r,i,o=a(e),d=o.parents("form")[0];d&&(t=u(d),t.options.rules[e.name]=r={},t.options.messages[e.name]=i={},a.each(this.adapters,function(){var n="data-val-"+this.name,t=o.attr(n),s={};void 0!==t&&(n+="-",a.each(this.params,function(){s[this]=o.attr(n+this)}),this.adapt({element:e,form:d,message:t,params:s,rules:r,messages:i}))}),a.extend(r,{__dummy__:!0}),n||t.attachValidation())},parse:function(e){var n=a(e),t=n.parents().addBack().filter("form").add(n.find("form")).has("[data-val=true]");n.find("[data-val=true]").each(function(){f.unobtrusive.parseElement(this,!0)}),t.each(function(){var a=u(this);a&&a.attachValidation()})}},m=f.unobtrusive.adapters,m.add=function(a,e,n){return n||(n=e,e=[]),this.push({name:a,params:e,adapt:n}),this},m.addBool=function(a,n){return this.add(a,function(t){e(t,n||a,!0)})},m.addMinMax=function(a,n,t,r,i,o){return this.add(a,[i||"min",o||"max"],function(a){var i=a.params.min,o=a.params.max;i&&o?e(a,r,[i,o]):i?e(a,n,i):o&&e(a,t,o)})},m.addSingleVal=function(a,n,t){return this.add(a,[n||"val"],function(r){e(r,t||a,r.params[n])})},f.addMethod("__dummy__",function(a,e,n){return!0}),f.addMethod("regex",function(a,e,n){var t;return!!this.optional(e)||(t=new RegExp(n).exec(a),t&&0===t.index&&t[0].length===a.length)}),f.addMethod("nonalphamin",function(a,e,n){var t;return n&&(t=a.match(/\W/g),t=t&&t.length>=n),t}),f.methods.extension?(m.addSingleVal("accept","mimtype"),m.addSingleVal("extension","extension")):m.addSingleVal("extension","extension","accept"),m.addSingleVal("regex","pattern"),m.addBool("creditcard").addBool("date").addBool("digits").addBool("email").addBool("number").addBool("url"),m.addMinMax("length","minlength","maxlength","rangelength").addMinMax("range","min","max","range"),m.addMinMax("minlength","minlength").addMinMax("maxlength","minlength","maxlength"),m.add("equalto",["other"],function(n){var o=r(n.element.name),d=n.params.other,s=i(d,o),l=a(n.form).find(":input").filter("[name='"+t(s)+"']")[0];e(n,"equalTo",l)}),m.add("required",function(a){"INPUT"===a.element.tagName.toUpperCase()&&"CHECKBOX"===a.element.type.toUpperCase()||e(a,"required",!0)}),m.add("remote",["url","type","additionalfields"],function(o){var d={url:o.params.url,type:o.params.type||"GET",data:{}},s=r(o.element.name);a.each(n(o.params.additionalfields||o.element.name),function(e,n){var r=i(n,s);d.data[r]=function(){var e=a(o.form).find(":input").filter("[name='"+t(r)+"']");return e.is(":checkbox")?e.filter(":checked").val()||e.filter(":hidden").val()||"":e.is(":radio")?e.filter(":checked").val()||"":e.val()}}),e(o,"remote",d)}),m.add("password",["min","nonalphamin","regex"],function(a){a.params.min&&e(a,"minlength",a.params.min),a.params.nonalphamin&&e(a,"nonalphamin",a.params.nonalphamin),a.params.regex&&e(a,"regex",a.params.regex)}),m.add("fileextensions",["extensions"],function(a){e(a,"extension",a.params.extensions)}),a(function(){f.unobtrusive.parse(document)}),f.unobtrusive}); -------------------------------------------------------------------------------- /src/TwilioSdkStarterDotnetCore.Web/wwwroot/js/video.js: -------------------------------------------------------------------------------- 1 | var activeRoom; 2 | var previewTracks; 3 | var identity; 4 | var roomName; 5 | 6 | function attachTracks(tracks, container) { 7 | tracks.forEach(function (track) { 8 | container.appendChild(track.attach()); 9 | }); 10 | } 11 | 12 | function attachParticipantTracks(participant, container) { 13 | var tracks = Array.from(participant.tracks.values()); 14 | attachTracks(tracks, container); 15 | } 16 | 17 | function detachTracks(tracks) { 18 | tracks.forEach(function (track) { 19 | track.detach().forEach(function (detachedElement) { 20 | detachedElement.remove(); 21 | }); 22 | }); 23 | } 24 | 25 | function detachParticipantTracks(participant) { 26 | var tracks = Array.from(participant.tracks.values()); 27 | detachTracks(tracks); 28 | } 29 | 30 | // Check for WebRTC 31 | if (!navigator.webkitGetUserMedia && !navigator.mozGetUserMedia) { 32 | alert('WebRTC is not available in your browser.'); 33 | } 34 | 35 | // When we are about to transition away from this page, disconnect 36 | // from the room, if joined. 37 | window.addEventListener('beforeunload', leaveRoomIfJoined); 38 | 39 | $.getJSON('/token', function (data) { 40 | identity = data.identity; 41 | 42 | document.getElementById('room-controls').style.display = 'block'; 43 | 44 | // Bind button to join room 45 | document.getElementById('button-join').onclick = function () { 46 | roomName = document.getElementById('room-name').value; 47 | if (roomName) { 48 | log("Joining room '" + roomName + "'..."); 49 | 50 | var connectOptions = { name: roomName, logLevel: 'debug' }; 51 | if (previewTracks) { 52 | connectOptions.tracks = previewTracks; 53 | } 54 | 55 | Twilio.Video.connect(data.token, connectOptions).then(roomJoined, function (error) { 56 | log('Could not connect to Twilio: ' + error.message); 57 | }); 58 | } else { 59 | alert('Please enter a room name.'); 60 | } 61 | }; 62 | 63 | // Bind button to leave room 64 | document.getElementById('button-leave').onclick = function () { 65 | log('Leaving room...'); 66 | activeRoom.disconnect(); 67 | }; 68 | }); 69 | 70 | // Successfully connected! 71 | function roomJoined(room) { 72 | activeRoom = room; 73 | 74 | log("Joined as '" + identity + "'"); 75 | document.getElementById('button-join').style.display = 'none'; 76 | document.getElementById('button-leave').style.display = 'inline'; 77 | 78 | // Draw local video, if not already previewing 79 | var previewContainer = document.getElementById('local-media'); 80 | if (!previewContainer.querySelector('video')) { 81 | attachParticipantTracks(room.localParticipant, previewContainer); 82 | } 83 | 84 | room.participants.forEach(function (participant) { 85 | log("Already in Room: '" + participant.identity + "'"); 86 | var previewContainer = document.getElementById('remote-media'); 87 | attachParticipantTracks(participant, previewContainer); 88 | }); 89 | 90 | // When a participant joins, draw their video on screen 91 | room.on('participantConnected', function (participant) { 92 | log("Joining: '" + participant.identity + "'"); 93 | }); 94 | 95 | room.on('trackAdded', function (track, participant) { 96 | log(participant.identity + " added track: " + track.kind); 97 | var previewContainer = document.getElementById('remote-media'); 98 | attachTracks([track], previewContainer); 99 | }); 100 | 101 | room.on('trackRemoved', function (track, participant) { 102 | log(participant.identity + " removed track: " + track.kind); 103 | detachTracks([track]); 104 | }); 105 | 106 | // When a participant disconnects, note in log 107 | room.on('participantDisconnected', function (participant) { 108 | log("Participant '" + participant.identity + "' left the room"); 109 | detachParticipantTracks(participant); 110 | }); 111 | 112 | // When we are disconnected, stop capturing local video 113 | // Also remove media for all remote participants 114 | room.on('disconnected', function () { 115 | log('Left'); 116 | detachParticipantTracks(room.localParticipant); 117 | room.participants.forEach(detachParticipantTracks); 118 | activeRoom = null; 119 | document.getElementById('button-join').style.display = 'inline'; 120 | document.getElementById('button-leave').style.display = 'none'; 121 | }); 122 | } 123 | 124 | // Local video preview 125 | document.getElementById('button-preview').onclick = function () { 126 | var localTracksPromise = previewTracks 127 | ? Promise.resolve(previewTracks) 128 | : Twilio.Video.createLocalTracks(); 129 | 130 | localTracksPromise.then(function (tracks) { 131 | previewTracks = tracks; 132 | var previewContainer = document.getElementById('local-media'); 133 | if (!previewContainer.querySelector('video')) { 134 | attachTracks(tracks, previewContainer); 135 | } 136 | }, function (error) { 137 | console.error('Unable to access local media', error); 138 | log('Unable to access Camera and Microphone'); 139 | }); 140 | }; 141 | 142 | // Activity log 143 | function log(message) { 144 | var logDiv = document.getElementById('log'); 145 | logDiv.innerHTML += '

    > ' + message + '

    '; 146 | logDiv.scrollTop = logDiv.scrollHeight; 147 | } 148 | 149 | function leaveRoomIfJoined() { 150 | if (activeRoom) { 151 | activeRoom.disconnect(); 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /src/TwilioSdkStarterDotnetCore.Web/Controllers/UtilitiesController.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Microsoft.AspNetCore.Mvc; 4 | using Microsoft.Extensions.Options; 5 | using Twilio; 6 | using Twilio.Jwt.AccessToken; 7 | using Twilio.Rest.Notify.V1.Service; 8 | using Twilio.Rest.Sync.V1; 9 | using TwilioSdkStarterDotnetCore.Web.Models; 10 | 11 | namespace TwilioSdkStarterDotnetCore.Web.Controllers 12 | { 13 | [Route("api/[controller]")] 14 | [ApiController] 15 | public class UtilitiesController : ControllerBase 16 | { 17 | private readonly TwilioAccount _twilioAccount; 18 | 19 | public UtilitiesController(IOptions twilioAccount) 20 | { 21 | if (twilioAccount == null) 22 | { 23 | throw new ArgumentNullException(nameof(twilioAccount)); 24 | } 25 | _twilioAccount = twilioAccount.Value; 26 | 27 | // if the Sync Service SID is blank, use the default Sync Service instead 28 | if (_twilioAccount.SyncServiceSid == string.Empty) 29 | { 30 | _twilioAccount.SyncServiceSid = "default"; 31 | } 32 | TwilioClient.Init( 33 | _twilioAccount.ApiKey, 34 | _twilioAccount.ApiSecret, 35 | _twilioAccount.AccountSid 36 | ); 37 | 38 | // Ensure that the Sync Default Service is provisioned 39 | ProvisionSyncDefaultService(_twilioAccount.SyncServiceSid); 40 | 41 | } 42 | 43 | [HttpGet("/token")] 44 | public JsonResult Token() 45 | { 46 | // This can be tracked internally by your web app. 47 | var identity = randomUserId(); 48 | 49 | return CreateTokenResult(identity); 50 | } 51 | 52 | [HttpGet("/token/{identity:alpha}")] 53 | public JsonResult TokenForIdentity(string identity) 54 | { 55 | return CreateTokenResult(identity); 56 | } 57 | 58 | private JsonResult CreateTokenResult(string identity) 59 | { 60 | 61 | var grants = new HashSet(); 62 | 63 | var videoGrant = new VideoGrant(); 64 | 65 | grants.Add(videoGrant); 66 | 67 | if (_twilioAccount.ChatServiceSid != String.Empty) 68 | { 69 | // Create a "grant" which enables a client to use IPM as a given user, 70 | // on a given device. 71 | var chatGrant = new ChatGrant() 72 | { 73 | ServiceSid = _twilioAccount.ChatServiceSid 74 | }; 75 | 76 | grants.Add(chatGrant); 77 | } 78 | 79 | if (_twilioAccount.SyncServiceSid != String.Empty) 80 | { 81 | var syncGrant = new SyncGrant() 82 | { 83 | ServiceSid = _twilioAccount.SyncServiceSid 84 | }; 85 | 86 | grants.Add(syncGrant); 87 | } 88 | 89 | var token = new Token( 90 | 91 | _twilioAccount.AccountSid, 92 | _twilioAccount.ApiKey, 93 | _twilioAccount.ApiSecret, 94 | identity, 95 | grants: grants 96 | ).ToJwt(); 97 | 98 | return new JsonResult(new Dictionary() 99 | { 100 | {"identity", identity}, 101 | {"token", token} 102 | }); 103 | } 104 | 105 | [HttpPost("/register")] 106 | public JsonResult Register([FromBody] RegisterRequest request) 107 | { 108 | var _ = CreateNotificationServiceBinding(request); 109 | 110 | return new JsonResult(new Dictionary() 111 | { 112 | {"message", "Binding Created!"} 113 | } 114 | ); 115 | } 116 | private void ProvisionSyncDefaultService(string serviceSid) 117 | { 118 | if (serviceSid.Equals("default")) 119 | { 120 | ServiceResource.Fetch("default"); 121 | } 122 | } 123 | private string randomUserId() 124 | { 125 | return Guid.NewGuid().ToString(); 126 | } 127 | 128 | private BindingResource CreateNotificationServiceBinding(RegisterRequest request) 129 | { 130 | // This dumpster fire of a switch statement should be temporary 131 | // until we introduce a way to parse the enum 132 | BindingResource.BindingTypeEnum bindingType; 133 | switch (request.BindingType.ToLower()) 134 | { 135 | case "apn": 136 | bindingType = BindingResource.BindingTypeEnum.Apn; 137 | break; 138 | case "fcm": 139 | bindingType = BindingResource.BindingTypeEnum.Fcm; 140 | break; 141 | case "gcm": 142 | bindingType = BindingResource.BindingTypeEnum.Gcm; 143 | break; 144 | case "sms": 145 | bindingType = BindingResource.BindingTypeEnum.Sms; 146 | break; 147 | case "facebookmessenger": 148 | bindingType = BindingResource.BindingTypeEnum.FacebookMessenger; 149 | break; 150 | case "alexa": 151 | bindingType = BindingResource.BindingTypeEnum.Alexa; 152 | break; 153 | default: 154 | throw new Exception("Unknown binding type."); 155 | } 156 | 157 | 158 | return BindingResource.Create( 159 | pathServiceSid: _twilioAccount.NotificationServiceSid, 160 | identity: request.Identity, 161 | bindingType: bindingType, 162 | address: request.Address 163 | ); 164 | } 165 | } 166 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | Twilio 3 | 4 | 5 | # Twilio SDK Starter Application for C# 6 | 7 | [![Build Status](https://travis-ci.org/TwilioDevEd/sdk-starter-csharp.svg?branch=master)](https://travis-ci.org/TwilioDevEd/sdk-starter-csharp) 8 | 9 | ## .NET Core 3.1 Project 10 | 11 | This sample project demonstrates how to use Twilio APIs in a C# web 12 | application. Once the app is up and running, check out [the home page](http://localhost:3000) 13 | to see which demos you can run. You'll find examples for [Chat](https://www.twilio.com/chat), 14 | [Video](https://www.twilio.com/video), [Sync](https://www.twilio.com/sync), and more. 15 | 16 | Let's get started! 17 | 18 | NOTE: This project requires Visual Studio 2019, or .NET Core 3.1 installed on your computer. 19 | 20 | ## Setup 21 | 22 | 1. Install [.NET Core](https://www.microsoft.com/net/core). 23 | 2. Clone this repository: 24 | ```bash 25 | git clone https://github.com/TwilioDevEd/sdk-starter-csharp.git 26 | ``` 27 | 28 | ## Configure the sample application 29 | 30 | To run the application, you'll need to gather your Twilio account credentials and configure them 31 | in User Secrets via the `secrets.json` file. If you are unsure how to do this, check out this blog post on [User Secrets](https://www.twilio.com/blog/2018/05/user-secrets-in-a-net-core-web-app.html). 32 | These credentials should mirror those in the `appsettings.json` file found in the root of the `TwilioSdkStarterDotnetCore.Web` project. 33 | 34 | ### Configure account information 35 | 36 | Every sample in the demo requires some basic credentials from your Twilio account. Configure these first. 37 | 38 | | Config Value | Description | 39 | | :----------------- | :-------------------------------------------------------------------------------------------------------------------- | 40 | | `TwilioAccount:AccountSid` | Your primary Twilio account identifier - find this [in the console here](https://www.twilio.com/console). | 41 | | `TwilioAccount:ApiKey` | Used to authenticate - [generate one here](https://www.twilio.com/console/dev-tools/api-keys). | 42 | | `TwilioAccount:ApiSecret` | Used to authenticate - [just like the above, you'll get one here](https://www.twilio.com/console/dev-tools/api-keys). | 43 | 44 | To set a configuration value, use the `dotnet` command line: 45 | 46 | ```bash 47 | cd sdk-starter-dotnet-core/src/TwilioSdkStarterDotnetCore.Web 48 | dotnet user-secrets set "TwilioAccount:AccountSid" "ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" 49 | dotnet user-secrets set "TwilioAccount:ApiKey" "SKXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" 50 | dotnet user-secrets set "TwilioAccount:ApiSecret" "xxxxxxxxxxxxxxxxxxxxxxxx" 51 | ``` 52 | 53 | #### A Note on API Keys 54 | 55 | When you generate an API key pair at the URLs above, your API Secret will only be shown once - 56 | make sure to save this information in a secure location. 57 | 58 | ## Configure product-specific settings 59 | 60 | Depending on which demos you'd like to run, you may need to configure a few more values. 61 | 62 | ### Configuring Twilio Sync 63 | 64 | Twilio Sync works out of the box, using default settings per account. 65 | 66 | ### Configuring Twilio Chat 67 | 68 | In addition to the above, you'll need to [generate a Chat Service](https://www.twilio.com/console/chat/services) in the Twilio Console. Put the result in your secrets. 69 | 70 | | Config Value | Where to get one. | 71 | | :--------------------- | :-------------------------------------------------------------------------------------- | 72 | | `TwilioAccount:ChatServiceSid` | [Generate one in the Twilio Chat console](https://www.twilio.com/console/chat/services) | 73 | 74 | ```bash 75 | cd sdk-starter-csharp/src/TwilioSdkStarterDotnetCore.Web 76 | dotnet user-secrets set "TwilioAccount:ChatServiceSid" "ISXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" 77 | ``` 78 | 79 | ### Configuring Twilio Notify 80 | 81 | You will need to create a Notify Service and add at least one credential on the [Mobile Push Credential screen](https://www.twilio.com/console/notify/credentials) (such as Apple Push Notification Service or Firebase Cloud Messaging for Android) to send notifications using Notify. 82 | 83 | | Config Value | Where to get one. | 84 | | :----------------------------- | :--------------------------------------------------------------------------------------------------------------------------------- | 85 | | `TwilioAccount:NotificationServiceSid` | Generate one in the [Notify Console](https://www.twilio.com/console/notify/services). | 86 | | A Push Credential | Generate one with Apple or Google and [configure it as a Notify credential](https://www.twilio.com/console/notify/credentials). | 87 | 88 | ```bash 89 | cd sdk-starter-csharp/src/TwilioSdkStarterDotnetCore.Web 90 | dotnet user-secrets set "TwilioAccount:NotificationServiceSid" "ISXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" 91 | ``` 92 | 93 | ## Run The Application 94 | 95 | ### Visual Studio 96 | 97 | Open `TwilioSdkStarterDotnetCore.sln` and press _F5_ or click the Run button 98 | 99 | ### Windows CLI, OS X or Linux 100 | 101 | ```bash 102 | cd sdk-starter-csharp/src/TwilioSdkStarterDotnetCore.Web 103 | dotnet restore 104 | dotnet run 105 | ``` 106 | 107 | Your application should now be running at [http://localhost:50768/](http://localhost:50768/). 108 | 109 | ![Home Screen](https://cloud.githubusercontent.com/assets/809856/23171215/8107bd9e-f817-11e6-94c5-2b132d798fae.png) 110 | 111 | Check your config values, and follow the links to the demo applications! 112 | 113 | ## Running the SDK Starter Kit with ngrok 114 | 115 | If you are going to connect to this SDK Starter Kit with a mobile app (and you should try it out!), your phone won't be able to access localhost directly. You'll need to create a publicly accessible URL using a tool like [ngrok](https://ngrok.com/) to send HTTP/HTTPS traffic to a server running on your localhost. Use HTTPS to make web connections that retrieve a Twilio access token. 116 | 117 | ```bash 118 | ngrok http 50768 119 | ``` 120 | 121 | ## Run Tests 122 | 123 | ```bash 124 | dotnet test tests/TwilioSdkStarterDotnetCore.Tests 125 | ``` 126 | 127 | ## License 128 | 129 | MIT 130 | -------------------------------------------------------------------------------- /src/TwilioSdkStarterDotnetCore.Web/wwwroot/css/video.css: -------------------------------------------------------------------------------- 1 | @import url(https://fonts.googleapis.com/css?family=Share+Tech+Mono); 2 | 3 | body, 4 | p { 5 | padding: 0; 6 | margin: 0; 7 | } 8 | 9 | body { 10 | background: #272726; 11 | } 12 | 13 | div#remote-media { 14 | height: 43%; 15 | width: 100%; 16 | background-color: #fff; 17 | text-align: center; 18 | margin: auto; 19 | } 20 | 21 | div#remote-media video { 22 | border: 1px solid #272726; 23 | margin: 3em 2em; 24 | height: 70%; 25 | max-width: 27% !important; 26 | background-color: #272726; 27 | background-repeat: no-repeat; 28 | } 29 | 30 | div#controls { 31 | padding: 3em; 32 | max-width: 1200px; 33 | margin: 0 auto; 34 | } 35 | 36 | div#controls div { 37 | float: left; 38 | } 39 | 40 | div#controls div#room-controls, 41 | div#controls div#preview { 42 | width: 16em; 43 | margin: 0 1.5em; 44 | text-align: center; 45 | } 46 | 47 | div#controls p.instructions { 48 | text-align: left; 49 | margin-bottom: 1em; 50 | font-family: Helvetica-LightOblique, Helvetica, sans-serif; 51 | font-style: oblique; 52 | font-size: 1.25em; 53 | color: #777776; 54 | } 55 | 56 | div#controls button { 57 | width: 15em; 58 | height: 2.5em; 59 | margin-top: 1.75em; 60 | border-radius: 1em; 61 | font-family: "Helvetica Light", Helvetica, sans-serif; 62 | font-size: .8em; 63 | font-weight: lighter; 64 | outline: 0; 65 | } 66 | 67 | div#controls div#room-controls input { 68 | font-family: Helvetica-LightOblique, Helvetica, sans-serif; 69 | font-style: oblique; 70 | font-size: 1em; 71 | } 72 | 73 | div#controls button:active { 74 | position: relative; 75 | top: 1px; 76 | } 77 | 78 | div#controls div#preview div#local-media { 79 | width: 270px; 80 | height: 202px; 81 | border: 1px solid #cececc; 82 | box-sizing: border-box; 83 | background-image: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+Cjxzdmcgd2lkdGg9IjgwcHgiIGhlaWdodD0iODBweCIgdmlld0JveD0iMCAwIDgwIDgwIiB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHhtbG5zOnNrZXRjaD0iaHR0cDovL3d3dy5ib2hlbWlhbmNvZGluZy5jb20vc2tldGNoL25zIj4KICAgIDwhLS0gR2VuZXJhdG9yOiBTa2V0Y2ggMy4zLjEgKDEyMDAyKSAtIGh0dHA6Ly93d3cuYm9oZW1pYW5jb2RpbmcuY29tL3NrZXRjaCAtLT4KICAgIDx0aXRsZT5GaWxsIDUxICsgRmlsbCA1MjwvdGl0bGU+CiAgICA8ZGVzYz5DcmVhdGVkIHdpdGggU2tldGNoLjwvZGVzYz4KICAgIDxkZWZzPjwvZGVmcz4KICAgIDxnIGlkPSJQYWdlLTEiIHN0cm9rZT0ibm9uZSIgc3Ryb2tlLXdpZHRoPSIxIiBmaWxsPSJub25lIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiIHNrZXRjaDp0eXBlPSJNU1BhZ2UiPgogICAgICAgIDxnIGlkPSJjdW1tYWNrIiBza2V0Y2g6dHlwZT0iTVNMYXllckdyb3VwIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMTU5LjAwMDAwMCwgLTE3NDYuMDAwMDAwKSIgZmlsbD0iI0ZGRkZGRiI+CiAgICAgICAgICAgIDxnIGlkPSJGaWxsLTUxLSstRmlsbC01MiIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMTU5LjAwMDAwMCwgMTc0Ni4wMDAwMDApIiBza2V0Y2g6dHlwZT0iTVNTaGFwZUdyb3VwIj4KICAgICAgICAgICAgICAgIDxwYXRoIGQ9Ik0zOS42ODYsMC43MyBDMTcuODUsMC43MyAwLjA4NSwxOC41IDAuMDg1LDQwLjMzIEMwLjA4NSw2Mi4xNyAxNy44NSw3OS45MyAzOS42ODYsNzkuOTMgQzYxLjUyMiw3OS45MyA3OS4yODcsNjIuMTcgNzkuMjg3LDQwLjMzIEM3OS4yODcsMTguNSA2MS41MjIsMC43MyAzOS42ODYsMC43MyBMMzkuNjg2LDAuNzMgWiBNMzkuNjg2LDEuNzMgQzYxLjAwNSwxLjczIDc4LjI4NywxOS4wMiA3OC4yODcsNDAuMzMgQzc4LjI4Nyw2MS42NSA2MS4wMDUsNzguOTMgMzkuNjg2LDc4LjkzIEMxOC4zNjcsNzguOTMgMS4wODUsNjEuNjUgMS4wODUsNDAuMzMgQzEuMDg1LDE5LjAyIDE4LjM2NywxLjczIDM5LjY4NiwxLjczIEwzOS42ODYsMS43MyBaIiBpZD0iRmlsbC01MSI+PC9wYXRoPgogICAgICAgICAgICAgICAgPHBhdGggZD0iTTQ3Ljk2LDUzLjMzNSBMNDcuOTYsNTIuODM1IEwyMC4wOTMsNTIuODM1IEwyMC4wOTMsMjcuODI1IEw0Ny40NiwyNy44MjUgTDQ3LjQ2LDM4LjI1NSBMNTkuMjc5LDMwLjgwNSBMNTkuMjc5LDQ5Ljg1NSBMNDcuNDYsNDIuNDA1IEw0Ny40Niw1My4zMzUgTDQ3Ljk2LDUzLjMzNSBMNDcuOTYsNTIuODM1IEw0Ny45Niw1My4zMzUgTDQ4LjQ2LDUzLjMzNSBMNDguNDYsNDQuMjE1IEw2MC4yNzksNTEuNjY1IEw2MC4yNzksMjguOTk1IEw0OC40NiwzNi40NDUgTDQ4LjQ2LDI2LjgyNSBMMTkuMDkzLDI2LjgyNSBMMTkuMDkzLDUzLjgzNSBMNDguNDYsNTMuODM1IEw0OC40Niw1My4zMzUgTDQ3Ljk2LDUzLjMzNSIgaWQ9IkZpbGwtNTIiPjwvcGF0aD4KICAgICAgICAgICAgPC9nPgogICAgICAgIDwvZz4KICAgIDwvZz4KPC9zdmc+); 84 | background-position: center; 85 | background-repeat: no-repeat; 86 | margin: 0 auto; 87 | } 88 | 89 | div#controls div#preview div#local-media video { 90 | max-width: 100%; 91 | max-height: 100%; 92 | border: none; 93 | } 94 | 95 | div#controls div#preview button#button-preview { 96 | background: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+Cjxzdmcgd2lkdGg9IjE3cHgiIGhlaWdodD0iMTJweCIgdmlld0JveD0iMCAwIDE3IDEyIiB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHhtbG5zOnNrZXRjaD0iaHR0cDovL3d3dy5ib2hlbWlhbmNvZGluZy5jb20vc2tldGNoL25zIj4KICAgIDwhLS0gR2VuZXJhdG9yOiBTa2V0Y2ggMy4zLjEgKDEyMDAyKSAtIGh0dHA6Ly93d3cuYm9oZW1pYW5jb2RpbmcuY29tL3NrZXRjaCAtLT4KICAgIDx0aXRsZT5GaWxsIDM0PC90aXRsZT4KICAgIDxkZXNjPkNyZWF0ZWQgd2l0aCBTa2V0Y2guPC9kZXNjPgogICAgPGRlZnM+PC9kZWZzPgogICAgPGcgaWQ9IlBhZ2UtMSIgc3Ryb2tlPSJub25lIiBzdHJva2Utd2lkdGg9IjEiIGZpbGw9Im5vbmUiIGZpbGwtcnVsZT0iZXZlbm9kZCIgc2tldGNoOnR5cGU9Ik1TUGFnZSI+CiAgICAgICAgPGcgaWQ9ImN1bW1hY2siIHNrZXRjaDp0eXBlPSJNU0xheWVyR3JvdXAiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0xMjUuMDAwMDAwLCAtMTkwOS4wMDAwMDApIiBmaWxsPSIjMEEwQjA5Ij4KICAgICAgICAgICAgPHBhdGggZD0iTTEzNi40NzEsMTkxOS44NyBMMTM2LjQ3MSwxOTE5LjYyIEwxMjUuNzY3LDE5MTkuNjIgTDEyNS43NjcsMTkxMC4wOCBMMTM2LjIyMSwxOTEwLjA4IEwxMzYuMjIxLDE5MTQuMTUgTDE0MC43ODUsMTkxMS4yNyBMMTQwLjc4NSwxOTE4LjQyIEwxMzYuMjIxLDE5MTUuNTUgTDEzNi4yMjEsMTkxOS44NyBMMTM2LjQ3MSwxOTE5Ljg3IEwxMzYuNDcxLDE5MTkuNjIgTDEzNi40NzEsMTkxOS44NyBMMTM2LjcyMSwxOTE5Ljg3IEwxMzYuNzIxLDE5MTYuNDUgTDE0MS4yODUsMTkxOS4zMyBMMTQxLjI4NSwxOTEwLjM3IEwxMzYuNzIxLDE5MTMuMjQgTDEzNi43MjEsMTkwOS41OCBMMTI1LjI2NywxOTA5LjU4IEwxMjUuMjY3LDE5MjAuMTIgTDEzNi43MjEsMTkyMC4xMiBMMTM2LjcyMSwxOTE5Ljg3IEwxMzYuNDcxLDE5MTkuODciIGlkPSJGaWxsLTM0IiBza2V0Y2g6dHlwZT0iTVNTaGFwZUdyb3VwIj48L3BhdGg+CiAgICAgICAgPC9nPgogICAgPC9nPgo8L3N2Zz4=)1em center no-repeat #fff; 97 | border: none; 98 | padding-left: 1.5em; 99 | } 100 | 101 | div#controls div#log { 102 | border: 1px solid #686865; 103 | } 104 | 105 | div#controls div#room-controls { 106 | display: none; 107 | } 108 | 109 | div#controls div#room-controls input { 110 | width: 100%; 111 | height: 2.5em; 112 | padding: .5em; 113 | display: block; 114 | } 115 | 116 | div#controls div#room-controls button { 117 | color: #fff; 118 | background: 0 0; 119 | border: 1px solid #686865; 120 | } 121 | 122 | div#controls div#room-controls button#button-leave { 123 | display: none; 124 | } 125 | 126 | div#controls div#log { 127 | width: 35%; 128 | height: 9.5em; 129 | margin-top: 2.75em; 130 | text-align: left; 131 | padding: 1.5em; 132 | float: right; 133 | overflow-y: scroll; 134 | } 135 | 136 | div#controls div#log p { 137 | color: #686865; 138 | font-family: 'Share Tech Mono', 'Courier New', Courier, fixed-width; 139 | font-size: 1.25em; 140 | line-height: 1.25em; 141 | margin-left: 1em; 142 | text-indent: -1.25em; 143 | width: 90%; 144 | } 145 | -------------------------------------------------------------------------------- /src/TwilioSdkStarterDotnetCore.Web/wwwroot/images/banner2.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/TwilioSdkStarterDotnetCore.Web/wwwroot/images/banner1.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/TwilioSdkStarterDotnetCore.Web/wwwroot/images/banner3.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/TwilioSdkStarterDotnetCore.Web/wwwroot/lib/jquery-validation/dist/additional-methods.min.js: -------------------------------------------------------------------------------- 1 | /*! jQuery Validation Plugin - v1.17.0 - 7/29/2017 2 | * https://jqueryvalidation.org/ 3 | * Copyright (c) 2017 Jörn Zaefferer; Licensed MIT */ 4 | !function(a){"function"==typeof define&&define.amd?define(["jquery","./jquery.validate.min"],a):"object"==typeof module&&module.exports?module.exports=a(require("jquery")):a(jQuery)}(function(a){return function(){function b(a){return a.replace(/<.[^<>]*?>/g," ").replace(/ | /gi," ").replace(/[.(),;:!?%#$'\"_+=\/\-“”’]*/g,"")}a.validator.addMethod("maxWords",function(a,c,d){return this.optional(c)||b(a).match(/\b\w+\b/g).length<=d},a.validator.format("Please enter {0} words or less.")),a.validator.addMethod("minWords",function(a,c,d){return this.optional(c)||b(a).match(/\b\w+\b/g).length>=d},a.validator.format("Please enter at least {0} words.")),a.validator.addMethod("rangeWords",function(a,c,d){var e=b(a),f=/\b\w+\b/g;return this.optional(c)||e.match(f).length>=d[0]&&e.match(f).length<=d[1]},a.validator.format("Please enter between {0} and {1} words."))}(),a.validator.addMethod("accept",function(b,c,d){var e,f,g,h="string"==typeof d?d.replace(/\s/g,""):"image/*",i=this.optional(c);if(i)return i;if("file"===a(c).attr("type")&&(h=h.replace(/[\-\[\]\/\{\}\(\)\+\?\.\\\^\$\|]/g,"\\$&").replace(/,/g,"|").replace(/\/\*/g,"/.*"),c.files&&c.files.length))for(g=new RegExp(".?("+h+")$","i"),e=0;e9?"0":f,g="JABCDEFGHI".substr(f,1).toString(),i.match(/[ABEH]/)?k===f:i.match(/[KPQS]/)?k===g:k===f||k===g},"Please specify a valid CIF number."),a.validator.addMethod("cpfBR",function(a){if(a=a.replace(/([~!@#$%^&*()_+=`{}\[\]\-|\\:;'<>,.\/? ])+/g,""),11!==a.length)return!1;var b,c,d,e,f=0;if(b=parseInt(a.substring(9,10),10),c=parseInt(a.substring(10,11),10),d=function(a,b){var c=10*a%11;return 10!==c&&11!==c||(c=0),c===b},""===a||"00000000000"===a||"11111111111"===a||"22222222222"===a||"33333333333"===a||"44444444444"===a||"55555555555"===a||"66666666666"===a||"77777777777"===a||"88888888888"===a||"99999999999"===a)return!1;for(e=1;e<=9;e++)f+=parseInt(a.substring(e-1,e),10)*(11-e);if(d(f,b)){for(f=0,e=1;e<=10;e++)f+=parseInt(a.substring(e-1,e),10)*(12-e);return d(f,c)}return!1},"Please specify a valid CPF number"),a.validator.addMethod("creditcard",function(a,b){if(this.optional(b))return"dependency-mismatch";if(/[^0-9 \-]+/.test(a))return!1;var c,d,e=0,f=0,g=!1;if(a=a.replace(/\D/g,""),a.length<13||a.length>19)return!1;for(c=a.length-1;c>=0;c--)d=a.charAt(c),f=parseInt(d,10),g&&(f*=2)>9&&(f-=9),e+=f,g=!g;return e%10===0},"Please enter a valid credit card number."),a.validator.addMethod("creditcardtypes",function(a,b,c){if(/[^0-9\-]+/.test(a))return!1;a=a.replace(/\D/g,"");var d=0;return c.mastercard&&(d|=1),c.visa&&(d|=2),c.amex&&(d|=4),c.dinersclub&&(d|=8),c.enroute&&(d|=16),c.discover&&(d|=32),c.jcb&&(d|=64),c.unknown&&(d|=128),c.all&&(d=255),1&d&&/^(5[12345])/.test(a)?16===a.length:2&d&&/^(4)/.test(a)?16===a.length:4&d&&/^(3[47])/.test(a)?15===a.length:8&d&&/^(3(0[012345]|[68]))/.test(a)?14===a.length:16&d&&/^(2(014|149))/.test(a)?15===a.length:32&d&&/^(6011)/.test(a)?16===a.length:64&d&&/^(3)/.test(a)?16===a.length:64&d&&/^(2131|1800)/.test(a)?15===a.length:!!(128&d)},"Please enter a valid credit card number."),a.validator.addMethod("currency",function(a,b,c){var d,e="string"==typeof c,f=e?c:c[0],g=!!e||c[1];return f=f.replace(/,/g,""),f=g?f+"]":f+"]?",d="^["+f+"([1-9]{1}[0-9]{0,2}(\\,[0-9]{3})*(\\.[0-9]{0,2})?|[1-9]{1}[0-9]{0,}(\\.[0-9]{0,2})?|0(\\.[0-9]{0,2})?|(\\.[0-9]{1,2})?)$",d=new RegExp(d),this.optional(b)||d.test(a)},"Please specify a valid currency"),a.validator.addMethod("dateFA",function(a,b){return this.optional(b)||/^[1-4]\d{3}\/((0?[1-6]\/((3[0-1])|([1-2][0-9])|(0?[1-9])))|((1[0-2]|(0?[7-9]))\/(30|([1-2][0-9])|(0?[1-9]))))$/.test(a)},a.validator.messages.date),a.validator.addMethod("dateITA",function(a,b){var c,d,e,f,g,h=!1,i=/^\d{1,2}\/\d{1,2}\/\d{4}$/;return i.test(a)?(c=a.split("/"),d=parseInt(c[0],10),e=parseInt(c[1],10),f=parseInt(c[2],10),g=new Date(Date.UTC(f,e-1,d,12,0,0,0)),h=g.getUTCFullYear()===f&&g.getUTCMonth()===e-1&&g.getUTCDate()===d):h=!1,this.optional(b)||h},a.validator.messages.date),a.validator.addMethod("dateNL",function(a,b){return this.optional(b)||/^(0?[1-9]|[12]\d|3[01])[\.\/\-](0?[1-9]|1[012])[\.\/\-]([12]\d)?(\d\d)$/.test(a)},a.validator.messages.date),a.validator.addMethod("extension",function(a,b,c){return c="string"==typeof c?c.replace(/,/g,"|"):"png|jpe?g|gif",this.optional(b)||a.match(new RegExp("\\.("+c+")$","i"))},a.validator.format("Please enter a value with a valid extension.")),a.validator.addMethod("giroaccountNL",function(a,b){return this.optional(b)||/^[0-9]{1,7}$/.test(a)},"Please specify a valid giro account number"),a.validator.addMethod("iban",function(a,b){if(this.optional(b))return!0;var c,d,e,f,g,h,i,j,k,l=a.replace(/ /g,"").toUpperCase(),m="",n=!0,o="",p="",q=5;if(l.length9&&a.match(/^(?:(?:(?:00\s?|\+)44\s?|0)7(?:[1345789]\d{2}|624)\s?\d{3}\s?\d{3})$/)},"Please specify a valid mobile number"),a.validator.addMethod("netmask",function(a,b){return this.optional(b)||/^(254|252|248|240|224|192|128)\.0\.0\.0|255\.(254|252|248|240|224|192|128|0)\.0\.0|255\.255\.(254|252|248|240|224|192|128|0)\.0|255\.255\.255\.(254|252|248|240|224|192|128|0)/i.test(a)},"Please enter a valid netmask."),a.validator.addMethod("nieES",function(a,b){"use strict";if(this.optional(b))return!0;var c,d=new RegExp(/^[MXYZ]{1}[0-9]{7,8}[TRWAGMYFPDXBNJZSQVHLCKET]{1}$/gi),e="TRWAGMYFPDXBNJZSQVHLCKET",f=a.substr(a.length-1).toUpperCase();return a=a.toString().toUpperCase(),!(a.length>10||a.length<9||!d.test(a))&&(a=a.replace(/^[X]/,"0").replace(/^[Y]/,"1").replace(/^[Z]/,"2"),c=9===a.length?a.substr(0,8):a.substr(0,9),e.charAt(parseInt(c,10)%23)===f)},"Please specify a valid NIE number."),a.validator.addMethod("nifES",function(a,b){"use strict";return!!this.optional(b)||(a=a.toUpperCase(),!!a.match("((^[A-Z]{1}[0-9]{7}[A-Z0-9]{1}$|^[T]{1}[A-Z0-9]{8}$)|^[0-9]{8}[A-Z]{1}$)")&&(/^[0-9]{8}[A-Z]{1}$/.test(a)?"TRWAGMYFPDXBNJZSQVHLCKE".charAt(a.substring(8,0)%23)===a.charAt(8):!!/^[KLM]{1}/.test(a)&&a[8]==="TRWAGMYFPDXBNJZSQVHLCKE".charAt(a.substring(8,1)%23)))},"Please specify a valid NIF number."),a.validator.addMethod("nipPL",function(a){"use strict";if(a=a.replace(/[^0-9]/g,""),10!==a.length)return!1;for(var b=[6,5,7,2,3,4,5,6,7],c=0,d=0;d<9;d++)c+=b[d]*a[d];var e=c%11,f=10===e?0:e;return f===parseInt(a[9],10)},"Please specify a valid NIP number."),a.validator.addMethod("notEqualTo",function(b,c,d){return this.optional(c)||!a.validator.methods.equalTo.call(this,b,c,d)},"Please enter a different value, values must not be the same."),a.validator.addMethod("nowhitespace",function(a,b){return this.optional(b)||/^\S+$/i.test(a)},"No white space please"),a.validator.addMethod("pattern",function(a,b,c){return!!this.optional(b)||("string"==typeof c&&(c=new RegExp("^(?:"+c+")$")),c.test(a))},"Invalid format."),a.validator.addMethod("phoneNL",function(a,b){return this.optional(b)||/^((\+|00(\s|\s?\-\s?)?)31(\s|\s?\-\s?)?(\(0\)[\-\s]?)?|0)[1-9]((\s|\s?\-\s?)?[0-9]){8}$/.test(a)},"Please specify a valid phone number."),a.validator.addMethod("phonesUK",function(a,b){return a=a.replace(/\(|\)|\s+|-/g,""),this.optional(b)||a.length>9&&a.match(/^(?:(?:(?:00\s?|\+)44\s?|0)(?:1\d{8,9}|[23]\d{9}|7(?:[1345789]\d{8}|624\d{6})))$/)},"Please specify a valid uk phone number"),a.validator.addMethod("phoneUK",function(a,b){return a=a.replace(/\(|\)|\s+|-/g,""),this.optional(b)||a.length>9&&a.match(/^(?:(?:(?:00\s?|\+)44\s?)|(?:\(?0))(?:\d{2}\)?\s?\d{4}\s?\d{4}|\d{3}\)?\s?\d{3}\s?\d{3,4}|\d{4}\)?\s?(?:\d{5}|\d{3}\s?\d{3})|\d{5}\)?\s?\d{4,5})$/)},"Please specify a valid phone number"),a.validator.addMethod("phoneUS",function(a,b){return a=a.replace(/\s+/g,""),this.optional(b)||a.length>9&&a.match(/^(\+?1-?)?(\([2-9]([02-9]\d|1[02-9])\)|[2-9]([02-9]\d|1[02-9]))-?[2-9]([02-9]\d|1[02-9])-?\d{4}$/)},"Please specify a valid phone number"),a.validator.addMethod("postalcodeBR",function(a,b){return this.optional(b)||/^\d{2}.\d{3}-\d{3}?$|^\d{5}-?\d{3}?$/.test(a)},"Informe um CEP válido."),a.validator.addMethod("postalCodeCA",function(a,b){return this.optional(b)||/^[ABCEGHJKLMNPRSTVXY]\d[ABCEGHJKLMNPRSTVWXYZ] *\d[ABCEGHJKLMNPRSTVWXYZ]\d$/i.test(a)},"Please specify a valid postal code"),a.validator.addMethod("postalcodeIT",function(a,b){return this.optional(b)||/^\d{5}$/.test(a)},"Please specify a valid postal code"),a.validator.addMethod("postalcodeNL",function(a,b){return this.optional(b)||/^[1-9][0-9]{3}\s?[a-zA-Z]{2}$/.test(a)},"Please specify a valid postal code"),a.validator.addMethod("postcodeUK",function(a,b){return this.optional(b)||/^((([A-PR-UWYZ][0-9])|([A-PR-UWYZ][0-9][0-9])|([A-PR-UWYZ][A-HK-Y][0-9])|([A-PR-UWYZ][A-HK-Y][0-9][0-9])|([A-PR-UWYZ][0-9][A-HJKSTUW])|([A-PR-UWYZ][A-HK-Y][0-9][ABEHMNPRVWXY]))\s?([0-9][ABD-HJLNP-UW-Z]{2})|(GIR)\s?(0AA))$/i.test(a)},"Please specify a valid UK postcode"),a.validator.addMethod("require_from_group",function(b,c,d){var e=a(d[1],c.form),f=e.eq(0),g=f.data("valid_req_grp")?f.data("valid_req_grp"):a.extend({},this),h=e.filter(function(){return g.elementValue(this)}).length>=d[0];return f.data("valid_req_grp",g),a(c).data("being_validated")||(e.data("being_validated",!0),e.each(function(){g.element(this)}),e.data("being_validated",!1)),h},a.validator.format("Please fill at least {0} of these fields.")),a.validator.addMethod("skip_or_fill_minimum",function(b,c,d){var e=a(d[1],c.form),f=e.eq(0),g=f.data("valid_skip")?f.data("valid_skip"):a.extend({},this),h=e.filter(function(){return g.elementValue(this)}).length,i=0===h||h>=d[0];return f.data("valid_skip",g),a(c).data("being_validated")||(e.data("being_validated",!0),e.each(function(){g.element(this)}),e.data("being_validated",!1)),i},a.validator.format("Please either skip these fields or fill at least {0} of them.")),a.validator.addMethod("stateUS",function(a,b,c){var d,e="undefined"==typeof c,f=!e&&"undefined"!=typeof c.caseSensitive&&c.caseSensitive,g=!e&&"undefined"!=typeof c.includeTerritories&&c.includeTerritories,h=!e&&"undefined"!=typeof c.includeMilitary&&c.includeMilitary;return d=g||h?g&&h?"^(A[AEKLPRSZ]|C[AOT]|D[CE]|FL|G[AU]|HI|I[ADLN]|K[SY]|LA|M[ADEINOPST]|N[CDEHJMVY]|O[HKR]|P[AR]|RI|S[CD]|T[NX]|UT|V[AIT]|W[AIVY])$":g?"^(A[KLRSZ]|C[AOT]|D[CE]|FL|G[AU]|HI|I[ADLN]|K[SY]|LA|M[ADEINOPST]|N[CDEHJMVY]|O[HKR]|P[AR]|RI|S[CD]|T[NX]|UT|V[AIT]|W[AIVY])$":"^(A[AEKLPRZ]|C[AOT]|D[CE]|FL|GA|HI|I[ADLN]|K[SY]|LA|M[ADEINOST]|N[CDEHJMVY]|O[HKR]|PA|RI|S[CD]|T[NX]|UT|V[AT]|W[AIVY])$":"^(A[KLRZ]|C[AOT]|D[CE]|FL|GA|HI|I[ADLN]|K[SY]|LA|M[ADEINOST]|N[CDEHJMVY]|O[HKR]|PA|RI|S[CD]|T[NX]|UT|V[AT]|W[AIVY])$",d=f?new RegExp(d):new RegExp(d,"i"),this.optional(b)||d.test(a)},"Please specify a valid state"),a.validator.addMethod("strippedminlength",function(b,c,d){return a(b).text().length>=d},a.validator.format("Please enter at least {0} characters")),a.validator.addMethod("time",function(a,b){return this.optional(b)||/^([01]\d|2[0-3]|[0-9])(:[0-5]\d){1,2}$/.test(a)},"Please enter a valid time, between 00:00 and 23:59"),a.validator.addMethod("time12h",function(a,b){return this.optional(b)||/^((0?[1-9]|1[012])(:[0-5]\d){1,2}(\ ?[AP]M))$/i.test(a)},"Please enter a valid time in 12-hour am/pm format"),a.validator.addMethod("url2",function(a,b){return this.optional(b)||/^(https?|ftp):\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)*(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/i.test(a)},a.validator.messages.url),a.validator.addMethod("vinUS",function(a){if(17!==a.length)return!1;var b,c,d,e,f,g,h=["A","B","C","D","E","F","G","H","J","K","L","M","N","P","R","S","T","U","V","W","X","Y","Z"],i=[1,2,3,4,5,6,7,8,1,2,3,4,5,7,9,2,3,4,5,6,7,8,9],j=[8,7,6,5,4,3,2,10,0,9,8,7,6,5,4,3,2],k=0;for(b=0;b<17;b++){if(e=j[b],d=a.slice(b,b+1),8===b&&(g=d),isNaN(d)){for(c=0;c?@\[\\\]^`{|}~])/g, "\\$1"); 38 | } 39 | 40 | function getModelPrefix(fieldName) { 41 | return fieldName.substr(0, fieldName.lastIndexOf(".") + 1); 42 | } 43 | 44 | function appendModelPrefix(value, prefix) { 45 | if (value.indexOf("*.") === 0) { 46 | value = value.replace("*.", prefix); 47 | } 48 | return value; 49 | } 50 | 51 | function onError(error, inputElement) { // 'this' is the form element 52 | var container = $(this).find("[data-valmsg-for='" + escapeAttributeValue(inputElement[0].name) + "']"), 53 | replaceAttrValue = container.attr("data-valmsg-replace"), 54 | replace = replaceAttrValue ? $.parseJSON(replaceAttrValue) !== false : null; 55 | 56 | container.removeClass("field-validation-valid").addClass("field-validation-error"); 57 | error.data("unobtrusiveContainer", container); 58 | 59 | if (replace) { 60 | container.empty(); 61 | error.removeClass("input-validation-error").appendTo(container); 62 | } 63 | else { 64 | error.hide(); 65 | } 66 | } 67 | 68 | function onErrors(event, validator) { // 'this' is the form element 69 | var container = $(this).find("[data-valmsg-summary=true]"), 70 | list = container.find("ul"); 71 | 72 | if (list && list.length && validator.errorList.length) { 73 | list.empty(); 74 | container.addClass("validation-summary-errors").removeClass("validation-summary-valid"); 75 | 76 | $.each(validator.errorList, function () { 77 | $("
  • ").html(this.message).appendTo(list); 78 | }); 79 | } 80 | } 81 | 82 | function onSuccess(error) { // 'this' is the form element 83 | var container = error.data("unobtrusiveContainer"); 84 | 85 | if (container) { 86 | var replaceAttrValue = container.attr("data-valmsg-replace"), 87 | replace = replaceAttrValue ? $.parseJSON(replaceAttrValue) : null; 88 | 89 | container.addClass("field-validation-valid").removeClass("field-validation-error"); 90 | error.removeData("unobtrusiveContainer"); 91 | 92 | if (replace) { 93 | container.empty(); 94 | } 95 | } 96 | } 97 | 98 | function onReset(event) { // 'this' is the form element 99 | var $form = $(this), 100 | key = '__jquery_unobtrusive_validation_form_reset'; 101 | if ($form.data(key)) { 102 | return; 103 | } 104 | // Set a flag that indicates we're currently resetting the form. 105 | $form.data(key, true); 106 | try { 107 | $form.data("validator").resetForm(); 108 | } finally { 109 | $form.removeData(key); 110 | } 111 | 112 | $form.find(".validation-summary-errors") 113 | .addClass("validation-summary-valid") 114 | .removeClass("validation-summary-errors"); 115 | $form.find(".field-validation-error") 116 | .addClass("field-validation-valid") 117 | .removeClass("field-validation-error") 118 | .removeData("unobtrusiveContainer") 119 | .find(">*") // If we were using valmsg-replace, get the underlying error 120 | .removeData("unobtrusiveContainer"); 121 | } 122 | 123 | function validationInfo(form) { 124 | var $form = $(form), 125 | result = $form.data(data_validation), 126 | onResetProxy = $.proxy(onReset, form), 127 | defaultOptions = $jQval.unobtrusive.options || {}, 128 | execInContext = function (name, args) { 129 | var func = defaultOptions[name]; 130 | func && $.isFunction(func) && func.apply(form, args); 131 | }; 132 | 133 | if (!result) { 134 | result = { 135 | options: { // options structure passed to jQuery Validate's validate() method 136 | errorClass: defaultOptions.errorClass || "input-validation-error", 137 | errorElement: defaultOptions.errorElement || "span", 138 | errorPlacement: function () { 139 | onError.apply(form, arguments); 140 | execInContext("errorPlacement", arguments); 141 | }, 142 | invalidHandler: function () { 143 | onErrors.apply(form, arguments); 144 | execInContext("invalidHandler", arguments); 145 | }, 146 | messages: {}, 147 | rules: {}, 148 | success: function () { 149 | onSuccess.apply(form, arguments); 150 | execInContext("success", arguments); 151 | } 152 | }, 153 | attachValidation: function () { 154 | $form 155 | .off("reset." + data_validation, onResetProxy) 156 | .on("reset." + data_validation, onResetProxy) 157 | .validate(this.options); 158 | }, 159 | validate: function () { // a validation function that is called by unobtrusive Ajax 160 | $form.validate(); 161 | return $form.valid(); 162 | } 163 | }; 164 | $form.data(data_validation, result); 165 | } 166 | 167 | return result; 168 | } 169 | 170 | $jQval.unobtrusive = { 171 | adapters: [], 172 | 173 | parseElement: function (element, skipAttach) { 174 | /// 175 | /// Parses a single HTML element for unobtrusive validation attributes. 176 | /// 177 | /// The HTML element to be parsed. 178 | /// [Optional] true to skip attaching the 179 | /// validation to the form. If parsing just this single element, you should specify true. 180 | /// If parsing several elements, you should specify false, and manually attach the validation 181 | /// to the form when you are finished. The default is false. 182 | var $element = $(element), 183 | form = $element.parents("form")[0], 184 | valInfo, rules, messages; 185 | 186 | if (!form) { // Cannot do client-side validation without a form 187 | return; 188 | } 189 | 190 | valInfo = validationInfo(form); 191 | valInfo.options.rules[element.name] = rules = {}; 192 | valInfo.options.messages[element.name] = messages = {}; 193 | 194 | $.each(this.adapters, function () { 195 | var prefix = "data-val-" + this.name, 196 | message = $element.attr(prefix), 197 | paramValues = {}; 198 | 199 | if (message !== undefined) { // Compare against undefined, because an empty message is legal (and falsy) 200 | prefix += "-"; 201 | 202 | $.each(this.params, function () { 203 | paramValues[this] = $element.attr(prefix + this); 204 | }); 205 | 206 | this.adapt({ 207 | element: element, 208 | form: form, 209 | message: message, 210 | params: paramValues, 211 | rules: rules, 212 | messages: messages 213 | }); 214 | } 215 | }); 216 | 217 | $.extend(rules, { "__dummy__": true }); 218 | 219 | if (!skipAttach) { 220 | valInfo.attachValidation(); 221 | } 222 | }, 223 | 224 | parse: function (selector) { 225 | /// 226 | /// Parses all the HTML elements in the specified selector. It looks for input elements decorated 227 | /// with the [data-val=true] attribute value and enables validation according to the data-val-* 228 | /// attribute values. 229 | /// 230 | /// Any valid jQuery selector. 231 | 232 | // $forms includes all forms in selector's DOM hierarchy (parent, children and self) that have at least one 233 | // element with data-val=true 234 | var $selector = $(selector), 235 | $forms = $selector.parents() 236 | .addBack() 237 | .filter("form") 238 | .add($selector.find("form")) 239 | .has("[data-val=true]"); 240 | 241 | $selector.find("[data-val=true]").each(function () { 242 | $jQval.unobtrusive.parseElement(this, true); 243 | }); 244 | 245 | $forms.each(function () { 246 | var info = validationInfo(this); 247 | if (info) { 248 | info.attachValidation(); 249 | } 250 | }); 251 | } 252 | }; 253 | 254 | adapters = $jQval.unobtrusive.adapters; 255 | 256 | adapters.add = function (adapterName, params, fn) { 257 | /// Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation. 258 | /// The name of the adapter to be added. This matches the name used 259 | /// in the data-val-nnnn HTML attribute (where nnnn is the adapter name). 260 | /// [Optional] An array of parameter names (strings) that will 261 | /// be extracted from the data-val-nnnn-mmmm HTML attributes (where nnnn is the adapter name, and 262 | /// mmmm is the parameter name). 263 | /// The function to call, which adapts the values from the HTML 264 | /// attributes into jQuery Validate rules and/or messages. 265 | /// 266 | if (!fn) { // Called with no params, just a function 267 | fn = params; 268 | params = []; 269 | } 270 | this.push({ name: adapterName, params: params, adapt: fn }); 271 | return this; 272 | }; 273 | 274 | adapters.addBool = function (adapterName, ruleName) { 275 | /// Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation, where 276 | /// the jQuery Validate validation rule has no parameter values. 277 | /// The name of the adapter to be added. This matches the name used 278 | /// in the data-val-nnnn HTML attribute (where nnnn is the adapter name). 279 | /// [Optional] The name of the jQuery Validate rule. If not provided, the value 280 | /// of adapterName will be used instead. 281 | /// 282 | return this.add(adapterName, function (options) { 283 | setValidationValues(options, ruleName || adapterName, true); 284 | }); 285 | }; 286 | 287 | adapters.addMinMax = function (adapterName, minRuleName, maxRuleName, minMaxRuleName, minAttribute, maxAttribute) { 288 | /// Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation, where 289 | /// the jQuery Validate validation has three potential rules (one for min-only, one for max-only, and 290 | /// one for min-and-max). The HTML parameters are expected to be named -min and -max. 291 | /// The name of the adapter to be added. This matches the name used 292 | /// in the data-val-nnnn HTML attribute (where nnnn is the adapter name). 293 | /// The name of the jQuery Validate rule to be used when you only 294 | /// have a minimum value. 295 | /// The name of the jQuery Validate rule to be used when you only 296 | /// have a maximum value. 297 | /// The name of the jQuery Validate rule to be used when you 298 | /// have both a minimum and maximum value. 299 | /// [Optional] The name of the HTML attribute that 300 | /// contains the minimum value. The default is "min". 301 | /// [Optional] The name of the HTML attribute that 302 | /// contains the maximum value. The default is "max". 303 | /// 304 | return this.add(adapterName, [minAttribute || "min", maxAttribute || "max"], function (options) { 305 | var min = options.params.min, 306 | max = options.params.max; 307 | 308 | if (min && max) { 309 | setValidationValues(options, minMaxRuleName, [min, max]); 310 | } 311 | else if (min) { 312 | setValidationValues(options, minRuleName, min); 313 | } 314 | else if (max) { 315 | setValidationValues(options, maxRuleName, max); 316 | } 317 | }); 318 | }; 319 | 320 | adapters.addSingleVal = function (adapterName, attribute, ruleName) { 321 | /// Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation, where 322 | /// the jQuery Validate validation rule has a single value. 323 | /// The name of the adapter to be added. This matches the name used 324 | /// in the data-val-nnnn HTML attribute(where nnnn is the adapter name). 325 | /// [Optional] The name of the HTML attribute that contains the value. 326 | /// The default is "val". 327 | /// [Optional] The name of the jQuery Validate rule. If not provided, the value 328 | /// of adapterName will be used instead. 329 | /// 330 | return this.add(adapterName, [attribute || "val"], function (options) { 331 | setValidationValues(options, ruleName || adapterName, options.params[attribute]); 332 | }); 333 | }; 334 | 335 | $jQval.addMethod("__dummy__", function (value, element, params) { 336 | return true; 337 | }); 338 | 339 | $jQval.addMethod("regex", function (value, element, params) { 340 | var match; 341 | if (this.optional(element)) { 342 | return true; 343 | } 344 | 345 | match = new RegExp(params).exec(value); 346 | return (match && (match.index === 0) && (match[0].length === value.length)); 347 | }); 348 | 349 | $jQval.addMethod("nonalphamin", function (value, element, nonalphamin) { 350 | var match; 351 | if (nonalphamin) { 352 | match = value.match(/\W/g); 353 | match = match && match.length >= nonalphamin; 354 | } 355 | return match; 356 | }); 357 | 358 | if ($jQval.methods.extension) { 359 | adapters.addSingleVal("accept", "mimtype"); 360 | adapters.addSingleVal("extension", "extension"); 361 | } else { 362 | // for backward compatibility, when the 'extension' validation method does not exist, such as with versions 363 | // of JQuery Validation plugin prior to 1.10, we should use the 'accept' method for 364 | // validating the extension, and ignore mime-type validations as they are not supported. 365 | adapters.addSingleVal("extension", "extension", "accept"); 366 | } 367 | 368 | adapters.addSingleVal("regex", "pattern"); 369 | adapters.addBool("creditcard").addBool("date").addBool("digits").addBool("email").addBool("number").addBool("url"); 370 | adapters.addMinMax("length", "minlength", "maxlength", "rangelength").addMinMax("range", "min", "max", "range"); 371 | adapters.addMinMax("minlength", "minlength").addMinMax("maxlength", "minlength", "maxlength"); 372 | adapters.add("equalto", ["other"], function (options) { 373 | var prefix = getModelPrefix(options.element.name), 374 | other = options.params.other, 375 | fullOtherName = appendModelPrefix(other, prefix), 376 | element = $(options.form).find(":input").filter("[name='" + escapeAttributeValue(fullOtherName) + "']")[0]; 377 | 378 | setValidationValues(options, "equalTo", element); 379 | }); 380 | adapters.add("required", function (options) { 381 | // jQuery Validate equates "required" with "mandatory" for checkbox elements 382 | if (options.element.tagName.toUpperCase() !== "INPUT" || options.element.type.toUpperCase() !== "CHECKBOX") { 383 | setValidationValues(options, "required", true); 384 | } 385 | }); 386 | adapters.add("remote", ["url", "type", "additionalfields"], function (options) { 387 | var value = { 388 | url: options.params.url, 389 | type: options.params.type || "GET", 390 | data: {} 391 | }, 392 | prefix = getModelPrefix(options.element.name); 393 | 394 | $.each(splitAndTrim(options.params.additionalfields || options.element.name), function (i, fieldName) { 395 | var paramName = appendModelPrefix(fieldName, prefix); 396 | value.data[paramName] = function () { 397 | var field = $(options.form).find(":input").filter("[name='" + escapeAttributeValue(paramName) + "']"); 398 | // For checkboxes and radio buttons, only pick up values from checked fields. 399 | if (field.is(":checkbox")) { 400 | return field.filter(":checked").val() || field.filter(":hidden").val() || ''; 401 | } 402 | else if (field.is(":radio")) { 403 | return field.filter(":checked").val() || ''; 404 | } 405 | return field.val(); 406 | }; 407 | }); 408 | 409 | setValidationValues(options, "remote", value); 410 | }); 411 | adapters.add("password", ["min", "nonalphamin", "regex"], function (options) { 412 | if (options.params.min) { 413 | setValidationValues(options, "minlength", options.params.min); 414 | } 415 | if (options.params.nonalphamin) { 416 | setValidationValues(options, "nonalphamin", options.params.nonalphamin); 417 | } 418 | if (options.params.regex) { 419 | setValidationValues(options, "regex", options.params.regex); 420 | } 421 | }); 422 | adapters.add("fileextensions", ["extensions"], function (options) { 423 | setValidationValues(options, "extension", options.params.extensions); 424 | }); 425 | 426 | $(function () { 427 | $jQval.unobtrusive.parse(document); 428 | }); 429 | 430 | return $jQval.unobtrusive; 431 | })); -------------------------------------------------------------------------------- /src/TwilioSdkStarterDotnetCore.Web/wwwroot/lib/jquery-validation/dist/jquery.validate.min.js: -------------------------------------------------------------------------------- 1 | /*! jQuery Validation Plugin - v1.17.0 - 7/29/2017 2 | * https://jqueryvalidation.org/ 3 | * Copyright (c) 2017 Jörn Zaefferer; Licensed MIT */ 4 | !function(a){"function"==typeof define&&define.amd?define(["jquery"],a):"object"==typeof module&&module.exports?module.exports=a(require("jquery")):a(jQuery)}(function(a){a.extend(a.fn,{validate:function(b){if(!this.length)return void(b&&b.debug&&window.console&&console.warn("Nothing selected, can't validate, returning nothing."));var c=a.data(this[0],"validator");return c?c:(this.attr("novalidate","novalidate"),c=new a.validator(b,this[0]),a.data(this[0],"validator",c),c.settings.onsubmit&&(this.on("click.validate",":submit",function(b){c.submitButton=b.currentTarget,a(this).hasClass("cancel")&&(c.cancelSubmit=!0),void 0!==a(this).attr("formnovalidate")&&(c.cancelSubmit=!0)}),this.on("submit.validate",function(b){function d(){var d,e;return c.submitButton&&(c.settings.submitHandler||c.formSubmitted)&&(d=a("").attr("name",c.submitButton.name).val(a(c.submitButton).val()).appendTo(c.currentForm)),!c.settings.submitHandler||(e=c.settings.submitHandler.call(c,c.currentForm,b),d&&d.remove(),void 0!==e&&e)}return c.settings.debug&&b.preventDefault(),c.cancelSubmit?(c.cancelSubmit=!1,d()):c.form()?c.pendingRequest?(c.formSubmitted=!0,!1):d():(c.focusInvalid(),!1)})),c)},valid:function(){var b,c,d;return a(this[0]).is("form")?b=this.validate().form():(d=[],b=!0,c=a(this[0].form).validate(),this.each(function(){b=c.element(this)&&b,b||(d=d.concat(c.errorList))}),c.errorList=d),b},rules:function(b,c){var d,e,f,g,h,i,j=this[0];if(null!=j&&(!j.form&&j.hasAttribute("contenteditable")&&(j.form=this.closest("form")[0],j.name=this.attr("name")),null!=j.form)){if(b)switch(d=a.data(j.form,"validator").settings,e=d.rules,f=a.validator.staticRules(j),b){case"add":a.extend(f,a.validator.normalizeRule(c)),delete f.messages,e[j.name]=f,c.messages&&(d.messages[j.name]=a.extend(d.messages[j.name],c.messages));break;case"remove":return c?(i={},a.each(c.split(/\s/),function(a,b){i[b]=f[b],delete f[b]}),i):(delete e[j.name],f)}return g=a.validator.normalizeRules(a.extend({},a.validator.classRules(j),a.validator.attributeRules(j),a.validator.dataRules(j),a.validator.staticRules(j)),j),g.required&&(h=g.required,delete g.required,g=a.extend({required:h},g)),g.remote&&(h=g.remote,delete g.remote,g=a.extend(g,{remote:h})),g}}}),a.extend(a.expr.pseudos||a.expr[":"],{blank:function(b){return!a.trim(""+a(b).val())},filled:function(b){var c=a(b).val();return null!==c&&!!a.trim(""+c)},unchecked:function(b){return!a(b).prop("checked")}}),a.validator=function(b,c){this.settings=a.extend(!0,{},a.validator.defaults,b),this.currentForm=c,this.init()},a.validator.format=function(b,c){return 1===arguments.length?function(){var c=a.makeArray(arguments);return c.unshift(b),a.validator.format.apply(this,c)}:void 0===c?b:(arguments.length>2&&c.constructor!==Array&&(c=a.makeArray(arguments).slice(1)),c.constructor!==Array&&(c=[c]),a.each(c,function(a,c){b=b.replace(new RegExp("\\{"+a+"\\}","g"),function(){return c})}),b)},a.extend(a.validator,{defaults:{messages:{},groups:{},rules:{},errorClass:"error",pendingClass:"pending",validClass:"valid",errorElement:"label",focusCleanup:!1,focusInvalid:!0,errorContainer:a([]),errorLabelContainer:a([]),onsubmit:!0,ignore:":hidden",ignoreTitle:!1,onfocusin:function(a){this.lastActive=a,this.settings.focusCleanup&&(this.settings.unhighlight&&this.settings.unhighlight.call(this,a,this.settings.errorClass,this.settings.validClass),this.hideThese(this.errorsFor(a)))},onfocusout:function(a){this.checkable(a)||!(a.name in this.submitted)&&this.optional(a)||this.element(a)},onkeyup:function(b,c){var d=[16,17,18,20,35,36,37,38,39,40,45,144,225];9===c.which&&""===this.elementValue(b)||a.inArray(c.keyCode,d)!==-1||(b.name in this.submitted||b.name in this.invalid)&&this.element(b)},onclick:function(a){a.name in this.submitted?this.element(a):a.parentNode.name in this.submitted&&this.element(a.parentNode)},highlight:function(b,c,d){"radio"===b.type?this.findByName(b.name).addClass(c).removeClass(d):a(b).addClass(c).removeClass(d)},unhighlight:function(b,c,d){"radio"===b.type?this.findByName(b.name).removeClass(c).addClass(d):a(b).removeClass(c).addClass(d)}},setDefaults:function(b){a.extend(a.validator.defaults,b)},messages:{required:"This field is required.",remote:"Please fix this field.",email:"Please enter a valid email address.",url:"Please enter a valid URL.",date:"Please enter a valid date.",dateISO:"Please enter a valid date (ISO).",number:"Please enter a valid number.",digits:"Please enter only digits.",equalTo:"Please enter the same value again.",maxlength:a.validator.format("Please enter no more than {0} characters."),minlength:a.validator.format("Please enter at least {0} characters."),rangelength:a.validator.format("Please enter a value between {0} and {1} characters long."),range:a.validator.format("Please enter a value between {0} and {1}."),max:a.validator.format("Please enter a value less than or equal to {0}."),min:a.validator.format("Please enter a value greater than or equal to {0}."),step:a.validator.format("Please enter a multiple of {0}.")},autoCreateRanges:!1,prototype:{init:function(){function b(b){!this.form&&this.hasAttribute("contenteditable")&&(this.form=a(this).closest("form")[0],this.name=a(this).attr("name"));var c=a.data(this.form,"validator"),d="on"+b.type.replace(/^validate/,""),e=c.settings;e[d]&&!a(this).is(e.ignore)&&e[d].call(c,this,b)}this.labelContainer=a(this.settings.errorLabelContainer),this.errorContext=this.labelContainer.length&&this.labelContainer||a(this.currentForm),this.containers=a(this.settings.errorContainer).add(this.settings.errorLabelContainer),this.submitted={},this.valueCache={},this.pendingRequest=0,this.pending={},this.invalid={},this.reset();var c,d=this.groups={};a.each(this.settings.groups,function(b,c){"string"==typeof c&&(c=c.split(/\s/)),a.each(c,function(a,c){d[c]=b})}),c=this.settings.rules,a.each(c,function(b,d){c[b]=a.validator.normalizeRule(d)}),a(this.currentForm).on("focusin.validate focusout.validate keyup.validate",":text, [type='password'], [type='file'], select, textarea, [type='number'], [type='search'], [type='tel'], [type='url'], [type='email'], [type='datetime'], [type='date'], [type='month'], [type='week'], [type='time'], [type='datetime-local'], [type='range'], [type='color'], [type='radio'], [type='checkbox'], [contenteditable], [type='button']",b).on("click.validate","select, option, [type='radio'], [type='checkbox']",b),this.settings.invalidHandler&&a(this.currentForm).on("invalid-form.validate",this.settings.invalidHandler)},form:function(){return this.checkForm(),a.extend(this.submitted,this.errorMap),this.invalid=a.extend({},this.errorMap),this.valid()||a(this.currentForm).triggerHandler("invalid-form",[this]),this.showErrors(),this.valid()},checkForm:function(){this.prepareForm();for(var a=0,b=this.currentElements=this.elements();b[a];a++)this.check(b[a]);return this.valid()},element:function(b){var c,d,e=this.clean(b),f=this.validationTargetFor(e),g=this,h=!0;return void 0===f?delete this.invalid[e.name]:(this.prepareElement(f),this.currentElements=a(f),d=this.groups[f.name],d&&a.each(this.groups,function(a,b){b===d&&a!==f.name&&(e=g.validationTargetFor(g.clean(g.findByName(a))),e&&e.name in g.invalid&&(g.currentElements.push(e),h=g.check(e)&&h))}),c=this.check(f)!==!1,h=h&&c,c?this.invalid[f.name]=!1:this.invalid[f.name]=!0,this.numberOfInvalids()||(this.toHide=this.toHide.add(this.containers)),this.showErrors(),a(b).attr("aria-invalid",!c)),h},showErrors:function(b){if(b){var c=this;a.extend(this.errorMap,b),this.errorList=a.map(this.errorMap,function(a,b){return{message:a,element:c.findByName(b)[0]}}),this.successList=a.grep(this.successList,function(a){return!(a.name in b)})}this.settings.showErrors?this.settings.showErrors.call(this,this.errorMap,this.errorList):this.defaultShowErrors()},resetForm:function(){a.fn.resetForm&&a(this.currentForm).resetForm(),this.invalid={},this.submitted={},this.prepareForm(),this.hideErrors();var b=this.elements().removeData("previousValue").removeAttr("aria-invalid");this.resetElements(b)},resetElements:function(a){var b;if(this.settings.unhighlight)for(b=0;a[b];b++)this.settings.unhighlight.call(this,a[b],this.settings.errorClass,""),this.findByName(a[b].name).removeClass(this.settings.validClass);else a.removeClass(this.settings.errorClass).removeClass(this.settings.validClass)},numberOfInvalids:function(){return this.objectLength(this.invalid)},objectLength:function(a){var b,c=0;for(b in a)void 0!==a[b]&&null!==a[b]&&a[b]!==!1&&c++;return c},hideErrors:function(){this.hideThese(this.toHide)},hideThese:function(a){a.not(this.containers).text(""),this.addWrapper(a).hide()},valid:function(){return 0===this.size()},size:function(){return this.errorList.length},focusInvalid:function(){if(this.settings.focusInvalid)try{a(this.findLastActive()||this.errorList.length&&this.errorList[0].element||[]).filter(":visible").focus().trigger("focusin")}catch(b){}},findLastActive:function(){var b=this.lastActive;return b&&1===a.grep(this.errorList,function(a){return a.element.name===b.name}).length&&b},elements:function(){var b=this,c={};return a(this.currentForm).find("input, select, textarea, [contenteditable]").not(":submit, :reset, :image, :disabled").not(this.settings.ignore).filter(function(){var d=this.name||a(this).attr("name");return!d&&b.settings.debug&&window.console&&console.error("%o has no name assigned",this),this.hasAttribute("contenteditable")&&(this.form=a(this).closest("form")[0],this.name=d),!(d in c||!b.objectLength(a(this).rules()))&&(c[d]=!0,!0)})},clean:function(b){return a(b)[0]},errors:function(){var b=this.settings.errorClass.split(" ").join(".");return a(this.settings.errorElement+"."+b,this.errorContext)},resetInternals:function(){this.successList=[],this.errorList=[],this.errorMap={},this.toShow=a([]),this.toHide=a([])},reset:function(){this.resetInternals(),this.currentElements=a([])},prepareForm:function(){this.reset(),this.toHide=this.errors().add(this.containers)},prepareElement:function(a){this.reset(),this.toHide=this.errorsFor(a)},elementValue:function(b){var c,d,e=a(b),f=b.type;return"radio"===f||"checkbox"===f?this.findByName(b.name).filter(":checked").val():"number"===f&&"undefined"!=typeof b.validity?b.validity.badInput?"NaN":e.val():(c=b.hasAttribute("contenteditable")?e.text():e.val(),"file"===f?"C:\\fakepath\\"===c.substr(0,12)?c.substr(12):(d=c.lastIndexOf("/"),d>=0?c.substr(d+1):(d=c.lastIndexOf("\\"),d>=0?c.substr(d+1):c)):"string"==typeof c?c.replace(/\r/g,""):c)},check:function(b){b=this.validationTargetFor(this.clean(b));var c,d,e,f,g=a(b).rules(),h=a.map(g,function(a,b){return b}).length,i=!1,j=this.elementValue(b);if("function"==typeof g.normalizer?f=g.normalizer:"function"==typeof this.settings.normalizer&&(f=this.settings.normalizer),f){if(j=f.call(b,j),"string"!=typeof j)throw new TypeError("The normalizer should return a string value.");delete g.normalizer}for(d in g){e={method:d,parameters:g[d]};try{if(c=a.validator.methods[d].call(this,j,b,e.parameters),"dependency-mismatch"===c&&1===h){i=!0;continue}if(i=!1,"pending"===c)return void(this.toHide=this.toHide.not(this.errorsFor(b)));if(!c)return this.formatAndAdd(b,e),!1}catch(k){throw this.settings.debug&&window.console&&console.log("Exception occurred when checking element "+b.id+", check the '"+e.method+"' method.",k),k instanceof TypeError&&(k.message+=". Exception occurred when checking element "+b.id+", check the '"+e.method+"' method."),k}}if(!i)return this.objectLength(g)&&this.successList.push(b),!0},customDataMessage:function(b,c){return a(b).data("msg"+c.charAt(0).toUpperCase()+c.substring(1).toLowerCase())||a(b).data("msg")},customMessage:function(a,b){var c=this.settings.messages[a];return c&&(c.constructor===String?c:c[b])},findDefined:function(){for(var a=0;aWarning: No message defined for "+b.name+""),e=/\$?\{(\d+)\}/g;return"function"==typeof d?d=d.call(this,c.parameters,b):e.test(d)&&(d=a.validator.format(d.replace(e,"{$1}"),c.parameters)),d},formatAndAdd:function(a,b){var c=this.defaultMessage(a,b);this.errorList.push({message:c,element:a,method:b.method}),this.errorMap[a.name]=c,this.submitted[a.name]=c},addWrapper:function(a){return this.settings.wrapper&&(a=a.add(a.parent(this.settings.wrapper))),a},defaultShowErrors:function(){var a,b,c;for(a=0;this.errorList[a];a++)c=this.errorList[a],this.settings.highlight&&this.settings.highlight.call(this,c.element,this.settings.errorClass,this.settings.validClass),this.showLabel(c.element,c.message);if(this.errorList.length&&(this.toShow=this.toShow.add(this.containers)),this.settings.success)for(a=0;this.successList[a];a++)this.showLabel(this.successList[a]);if(this.settings.unhighlight)for(a=0,b=this.validElements();b[a];a++)this.settings.unhighlight.call(this,b[a],this.settings.errorClass,this.settings.validClass);this.toHide=this.toHide.not(this.toShow),this.hideErrors(),this.addWrapper(this.toShow).show()},validElements:function(){return this.currentElements.not(this.invalidElements())},invalidElements:function(){return a(this.errorList).map(function(){return this.element})},showLabel:function(b,c){var d,e,f,g,h=this.errorsFor(b),i=this.idOrName(b),j=a(b).attr("aria-describedby");h.length?(h.removeClass(this.settings.validClass).addClass(this.settings.errorClass),h.html(c)):(h=a("<"+this.settings.errorElement+">").attr("id",i+"-error").addClass(this.settings.errorClass).html(c||""),d=h,this.settings.wrapper&&(d=h.hide().show().wrap("<"+this.settings.wrapper+"/>").parent()),this.labelContainer.length?this.labelContainer.append(d):this.settings.errorPlacement?this.settings.errorPlacement.call(this,d,a(b)):d.insertAfter(b),h.is("label")?h.attr("for",i):0===h.parents("label[for='"+this.escapeCssMeta(i)+"']").length&&(f=h.attr("id"),j?j.match(new RegExp("\\b"+this.escapeCssMeta(f)+"\\b"))||(j+=" "+f):j=f,a(b).attr("aria-describedby",j),e=this.groups[b.name],e&&(g=this,a.each(g.groups,function(b,c){c===e&&a("[name='"+g.escapeCssMeta(b)+"']",g.currentForm).attr("aria-describedby",h.attr("id"))})))),!c&&this.settings.success&&(h.text(""),"string"==typeof this.settings.success?h.addClass(this.settings.success):this.settings.success(h,b)),this.toShow=this.toShow.add(h)},errorsFor:function(b){var c=this.escapeCssMeta(this.idOrName(b)),d=a(b).attr("aria-describedby"),e="label[for='"+c+"'], label[for='"+c+"'] *";return d&&(e=e+", #"+this.escapeCssMeta(d).replace(/\s+/g,", #")),this.errors().filter(e)},escapeCssMeta:function(a){return a.replace(/([\\!"#$%&'()*+,.\/:;<=>?@\[\]^`{|}~])/g,"\\$1")},idOrName:function(a){return this.groups[a.name]||(this.checkable(a)?a.name:a.id||a.name)},validationTargetFor:function(b){return this.checkable(b)&&(b=this.findByName(b.name)),a(b).not(this.settings.ignore)[0]},checkable:function(a){return/radio|checkbox/i.test(a.type)},findByName:function(b){return a(this.currentForm).find("[name='"+this.escapeCssMeta(b)+"']")},getLength:function(b,c){switch(c.nodeName.toLowerCase()){case"select":return a("option:selected",c).length;case"input":if(this.checkable(c))return this.findByName(c.name).filter(":checked").length}return b.length},depend:function(a,b){return!this.dependTypes[typeof a]||this.dependTypes[typeof a](a,b)},dependTypes:{"boolean":function(a){return a},string:function(b,c){return!!a(b,c.form).length},"function":function(a,b){return a(b)}},optional:function(b){var c=this.elementValue(b);return!a.validator.methods.required.call(this,c,b)&&"dependency-mismatch"},startRequest:function(b){this.pending[b.name]||(this.pendingRequest++,a(b).addClass(this.settings.pendingClass),this.pending[b.name]=!0)},stopRequest:function(b,c){this.pendingRequest--,this.pendingRequest<0&&(this.pendingRequest=0),delete this.pending[b.name],a(b).removeClass(this.settings.pendingClass),c&&0===this.pendingRequest&&this.formSubmitted&&this.form()?(a(this.currentForm).submit(),this.submitButton&&a("input:hidden[name='"+this.submitButton.name+"']",this.currentForm).remove(),this.formSubmitted=!1):!c&&0===this.pendingRequest&&this.formSubmitted&&(a(this.currentForm).triggerHandler("invalid-form",[this]),this.formSubmitted=!1)},previousValue:function(b,c){return c="string"==typeof c&&c||"remote",a.data(b,"previousValue")||a.data(b,"previousValue",{old:null,valid:!0,message:this.defaultMessage(b,{method:c})})},destroy:function(){this.resetForm(),a(this.currentForm).off(".validate").removeData("validator").find(".validate-equalTo-blur").off(".validate-equalTo").removeClass("validate-equalTo-blur")}},classRuleSettings:{required:{required:!0},email:{email:!0},url:{url:!0},date:{date:!0},dateISO:{dateISO:!0},number:{number:!0},digits:{digits:!0},creditcard:{creditcard:!0}},addClassRules:function(b,c){b.constructor===String?this.classRuleSettings[b]=c:a.extend(this.classRuleSettings,b)},classRules:function(b){var c={},d=a(b).attr("class");return d&&a.each(d.split(" "),function(){this in a.validator.classRuleSettings&&a.extend(c,a.validator.classRuleSettings[this])}),c},normalizeAttributeRule:function(a,b,c,d){/min|max|step/.test(c)&&(null===b||/number|range|text/.test(b))&&(d=Number(d),isNaN(d)&&(d=void 0)),d||0===d?a[c]=d:b===c&&"range"!==b&&(a[c]=!0)},attributeRules:function(b){var c,d,e={},f=a(b),g=b.getAttribute("type");for(c in a.validator.methods)"required"===c?(d=b.getAttribute(c),""===d&&(d=!0),d=!!d):d=f.attr(c),this.normalizeAttributeRule(e,g,c,d);return e.maxlength&&/-1|2147483647|524288/.test(e.maxlength)&&delete e.maxlength,e},dataRules:function(b){var c,d,e={},f=a(b),g=b.getAttribute("type");for(c in a.validator.methods)d=f.data("rule"+c.charAt(0).toUpperCase()+c.substring(1).toLowerCase()),this.normalizeAttributeRule(e,g,c,d);return e},staticRules:function(b){var c={},d=a.data(b.form,"validator");return d.settings.rules&&(c=a.validator.normalizeRule(d.settings.rules[b.name])||{}),c},normalizeRules:function(b,c){return a.each(b,function(d,e){if(e===!1)return void delete b[d];if(e.param||e.depends){var f=!0;switch(typeof e.depends){case"string":f=!!a(e.depends,c.form).length;break;case"function":f=e.depends.call(c,c)}f?b[d]=void 0===e.param||e.param:(a.data(c.form,"validator").resetElements(a(c)),delete b[d])}}),a.each(b,function(d,e){b[d]=a.isFunction(e)&&"normalizer"!==d?e(c):e}),a.each(["minlength","maxlength"],function(){b[this]&&(b[this]=Number(b[this]))}),a.each(["rangelength","range"],function(){var c;b[this]&&(a.isArray(b[this])?b[this]=[Number(b[this][0]),Number(b[this][1])]:"string"==typeof b[this]&&(c=b[this].replace(/[\[\]]/g,"").split(/[\s,]+/),b[this]=[Number(c[0]),Number(c[1])]))}),a.validator.autoCreateRanges&&(null!=b.min&&null!=b.max&&(b.range=[b.min,b.max],delete b.min,delete b.max),null!=b.minlength&&null!=b.maxlength&&(b.rangelength=[b.minlength,b.maxlength],delete b.minlength,delete b.maxlength)),b},normalizeRule:function(b){if("string"==typeof b){var c={};a.each(b.split(/\s/),function(){c[this]=!0}),b=c}return b},addMethod:function(b,c,d){a.validator.methods[b]=c,a.validator.messages[b]=void 0!==d?d:a.validator.messages[b],c.length<3&&a.validator.addClassRules(b,a.validator.normalizeRule(b))},methods:{required:function(b,c,d){if(!this.depend(d,c))return"dependency-mismatch";if("select"===c.nodeName.toLowerCase()){var e=a(c).val();return e&&e.length>0}return this.checkable(c)?this.getLength(b,c)>0:b.length>0},email:function(a,b){return this.optional(b)||/^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/.test(a)},url:function(a,b){return this.optional(b)||/^(?:(?:(?:https?|ftp):)?\/\/)(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})).?)(?::\d{2,5})?(?:[\/?#]\S*)?$/i.test(a)},date:function(a,b){return this.optional(b)||!/Invalid|NaN/.test(new Date(a).toString())},dateISO:function(a,b){return this.optional(b)||/^\d{4}[\/\-](0?[1-9]|1[012])[\/\-](0?[1-9]|[12][0-9]|3[01])$/.test(a)},number:function(a,b){return this.optional(b)||/^(?:-?\d+|-?\d{1,3}(?:,\d{3})+)?(?:\.\d+)?$/.test(a)},digits:function(a,b){return this.optional(b)||/^\d+$/.test(a)},minlength:function(b,c,d){var e=a.isArray(b)?b.length:this.getLength(b,c);return this.optional(c)||e>=d},maxlength:function(b,c,d){var e=a.isArray(b)?b.length:this.getLength(b,c);return this.optional(c)||e<=d},rangelength:function(b,c,d){var e=a.isArray(b)?b.length:this.getLength(b,c);return this.optional(c)||e>=d[0]&&e<=d[1]},min:function(a,b,c){return this.optional(b)||a>=c},max:function(a,b,c){return this.optional(b)||a<=c},range:function(a,b,c){return this.optional(b)||a>=c[0]&&a<=c[1]},step:function(b,c,d){var e,f=a(c).attr("type"),g="Step attribute on input type "+f+" is not supported.",h=["text","number","range"],i=new RegExp("\\b"+f+"\\b"),j=f&&!i.test(h.join()),k=function(a){var b=(""+a).match(/(?:\.(\d+))?$/);return b&&b[1]?b[1].length:0},l=function(a){return Math.round(a*Math.pow(10,e))},m=!0;if(j)throw new Error(g);return e=k(d),(k(b)>e||l(b)%l(d)!==0)&&(m=!1),this.optional(c)||m},equalTo:function(b,c,d){var e=a(d);return this.settings.onfocusout&&e.not(".validate-equalTo-blur").length&&e.addClass("validate-equalTo-blur").on("blur.validate-equalTo",function(){a(c).valid()}),b===e.val()},remote:function(b,c,d,e){if(this.optional(c))return"dependency-mismatch";e="string"==typeof e&&e||"remote";var f,g,h,i=this.previousValue(c,e);return this.settings.messages[c.name]||(this.settings.messages[c.name]={}),i.originalMessage=i.originalMessage||this.settings.messages[c.name][e],this.settings.messages[c.name][e]=i.message,d="string"==typeof d&&{url:d}||d,h=a.param(a.extend({data:b},d.data)),i.old===h?i.valid:(i.old=h,f=this,this.startRequest(c),g={},g[c.name]=b,a.ajax(a.extend(!0,{mode:"abort",port:"validate"+c.name,dataType:"json",data:g,context:f.currentForm,success:function(a){var d,g,h,j=a===!0||"true"===a;f.settings.messages[c.name][e]=i.originalMessage,j?(h=f.formSubmitted,f.resetInternals(),f.toHide=f.errorsFor(c),f.formSubmitted=h,f.successList.push(c),f.invalid[c.name]=!1,f.showErrors()):(d={},g=a||f.defaultMessage(c,{method:e,parameters:b}),d[c.name]=i.message=g,f.invalid[c.name]=!0,f.showErrors(d)),i.valid=j,f.stopRequest(c,j)}},d)),"pending")}}});var b,c={};return a.ajaxPrefilter?a.ajaxPrefilter(function(a,b,d){var e=a.port;"abort"===a.mode&&(c[e]&&c[e].abort(),c[e]=d)}):(b=a.ajax,a.ajax=function(d){var e=("mode"in d?d:a.ajaxSettings).mode,f=("port"in d?d:a.ajaxSettings).port;return"abort"===e?(c[f]&&c[f].abort(),c[f]=b.apply(this,arguments),c[f]):b.apply(this,arguments)}),a}); -------------------------------------------------------------------------------- /src/TwilioSdkStarterDotnetCore.Web/wwwroot/lib/bootstrap/dist/css/bootstrap-theme.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap v3.3.7 (http://getbootstrap.com) 3 | * Copyright 2011-2016 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 */ -------------------------------------------------------------------------------- /src/TwilioSdkStarterDotnetCore.Web/wwwroot/lib/bootstrap/dist/css/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":";;;;AAmBA,YAAA,aAAA,UAAA,aAAA,aAAA,aAME,YAAA,EAAA,KAAA,EAAA,eC2CA,mBAAA,MAAA,EAAA,IAAA,EAAA,sBAAA,EAAA,IAAA,IAAA,iBACQ,WAAA,MAAA,EAAA,IAAA,EAAA,sBAAA,EAAA,IAAA,IAAA,iBDvCR,mBAAA,mBAAA,oBAAA,oBAAA,iBAAA,iBAAA,oBAAA,oBAAA,oBAAA,oBAAA,oBAAA,oBCsCA,mBAAA,MAAA,EAAA,IAAA,IAAA,iBACQ,WAAA,MAAA,EAAA,IAAA,IAAA,iBDlCR,qBAAA,sBAAA,sBAAA,uBAAA,mBAAA,oBAAA,sBAAA,uBAAA,sBAAA,uBAAA,sBAAA,uBAAA,+BAAA,gCAAA,6BAAA,gCAAA,gCAAA,gCCiCA,mBAAA,KACQ,WAAA,KDlDV,mBAAA,oBAAA,iBAAA,oBAAA,oBAAA,oBAuBI,YAAA,KAyCF,YAAA,YAEE,iBAAA,KAKJ,aErEI,YAAA,EAAA,IAAA,EAAA,KACA,iBAAA,iDACA,iBAAA,4CAAA,iBAAA,qEAEA,iBAAA,+CCnBF,OAAA,+GH4CA,OAAA,0DACA,kBAAA,SAuC2C,aAAA,QAA2B,aAAA,KArCtE,mBAAA,mBAEE,iBAAA,QACA,oBAAA,EAAA,MAGF,oBAAA,oBAEE,iBAAA,QACA,aAAA,QAMA,sBAAA,6BAAA,4BAAA,6BAAA,4BAAA,4BAAA,uBAAA,8BAAA,6BAAA,8BAAA,6BAAA,6BAAA,gCAAA,uCAAA,sCAAA,uCAAA,sCAAA,sCAME,iBAAA,QACA,iBAAA,KAgBN,aEtEI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDAEA,OAAA,+GCnBF,OAAA,0DH4CA,kBAAA,SACA,aAAA,QAEA,mBAAA,mBAEE,iBAAA,QACA,oBAAA,EAAA,MAGF,oBAAA,oBAEE,iBAAA,QACA,aAAA,QAMA,sBAAA,6BAAA,4BAAA,6BAAA,4BAAA,4BAAA,uBAAA,8BAAA,6BAAA,8BAAA,6BAAA,6BAAA,gCAAA,uCAAA,sCAAA,uCAAA,sCAAA,sCAME,iBAAA,QACA,iBAAA,KAiBN,aEvEI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDAEA,OAAA,+GCnBF,OAAA,0DH4CA,kBAAA,SACA,aAAA,QAEA,mBAAA,mBAEE,iBAAA,QACA,oBAAA,EAAA,MAGF,oBAAA,oBAEE,iBAAA,QACA,aAAA,QAMA,sBAAA,6BAAA,4BAAA,6BAAA,4BAAA,4BAAA,uBAAA,8BAAA,6BAAA,8BAAA,6BAAA,6BAAA,gCAAA,uCAAA,sCAAA,uCAAA,sCAAA,sCAME,iBAAA,QACA,iBAAA,KAkBN,UExEI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDAEA,OAAA,+GCnBF,OAAA,0DH4CA,kBAAA,SACA,aAAA,QAEA,gBAAA,gBAEE,iBAAA,QACA,oBAAA,EAAA,MAGF,iBAAA,iBAEE,iBAAA,QACA,aAAA,QAMA,mBAAA,0BAAA,yBAAA,0BAAA,yBAAA,yBAAA,oBAAA,2BAAA,0BAAA,2BAAA,0BAAA,0BAAA,6BAAA,oCAAA,mCAAA,oCAAA,mCAAA,mCAME,iBAAA,QACA,iBAAA,KAmBN,aEzEI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDAEA,OAAA,+GCnBF,OAAA,0DH4CA,kBAAA,SACA,aAAA,QAEA,mBAAA,mBAEE,iBAAA,QACA,oBAAA,EAAA,MAGF,oBAAA,oBAEE,iBAAA,QACA,aAAA,QAMA,sBAAA,6BAAA,4BAAA,6BAAA,4BAAA,4BAAA,uBAAA,8BAAA,6BAAA,8BAAA,6BAAA,6BAAA,gCAAA,uCAAA,sCAAA,uCAAA,sCAAA,sCAME,iBAAA,QACA,iBAAA,KAoBN,YE1EI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDAEA,OAAA,+GCnBF,OAAA,0DH4CA,kBAAA,SACA,aAAA,QAEA,kBAAA,kBAEE,iBAAA,QACA,oBAAA,EAAA,MAGF,mBAAA,mBAEE,iBAAA,QACA,aAAA,QAMA,qBAAA,4BAAA,2BAAA,4BAAA,2BAAA,2BAAA,sBAAA,6BAAA,4BAAA,6BAAA,4BAAA,4BAAA,+BAAA,sCAAA,qCAAA,sCAAA,qCAAA,qCAME,iBAAA,QACA,iBAAA,KA2BN,eAAA,WClCE,mBAAA,EAAA,IAAA,IAAA,iBACQ,WAAA,EAAA,IAAA,IAAA,iBD2CV,0BAAA,0BE3FI,iBAAA,QACA,iBAAA,oDACA,iBAAA,+CAAA,iBAAA,wEACA,iBAAA,kDACA,OAAA,+GF0FF,kBAAA,SAEF,yBAAA,+BAAA,+BEhGI,iBAAA,QACA,iBAAA,oDACA,iBAAA,+CAAA,iBAAA,wEACA,iBAAA,kDACA,OAAA,+GFgGF,kBAAA,SASF,gBE7GI,iBAAA,iDACA,iBAAA,4CACA,iBAAA,qEAAA,iBAAA,+CACA,OAAA,+GACA,OAAA,0DCnBF,kBAAA,SH+HA,cAAA,ICjEA,mBAAA,MAAA,EAAA,IAAA,EAAA,sBAAA,EAAA,IAAA,IAAA,iBACQ,WAAA,MAAA,EAAA,IAAA,EAAA,sBAAA,EAAA,IAAA,IAAA,iBD6DV,sCAAA,oCE7GI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SD2CF,mBAAA,MAAA,EAAA,IAAA,IAAA,iBACQ,WAAA,MAAA,EAAA,IAAA,IAAA,iBD0EV,cAAA,iBAEE,YAAA,EAAA,IAAA,EAAA,sBAIF,gBEhII,iBAAA,iDACA,iBAAA,4CACA,iBAAA,qEAAA,iBAAA,+CACA,OAAA,+GACA,OAAA,0DCnBF,kBAAA,SHkJA,cAAA,IAHF,sCAAA,oCEhII,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SD2CF,mBAAA,MAAA,EAAA,IAAA,IAAA,gBACQ,WAAA,MAAA,EAAA,IAAA,IAAA,gBDgFV,8BAAA,iCAYI,YAAA,EAAA,KAAA,EAAA,gBAKJ,qBAAA,kBAAA,mBAGE,cAAA,EAqBF,yBAfI,mDAAA,yDAAA,yDAGE,MAAA,KE7JF,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,UFqKJ,OACE,YAAA,EAAA,IAAA,EAAA,qBC3HA,mBAAA,MAAA,EAAA,IAAA,EAAA,sBAAA,EAAA,IAAA,IAAA,gBACQ,WAAA,MAAA,EAAA,IAAA,EAAA,sBAAA,EAAA,IAAA,IAAA,gBDsIV,eEtLI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SF8KF,aAAA,QAKF,YEvLI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SF8KF,aAAA,QAMF,eExLI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SF8KF,aAAA,QAOF,cEzLI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SF8KF,aAAA,QAeF,UEjMI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SFuMJ,cE3MI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SFwMJ,sBE5MI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SFyMJ,mBE7MI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SF0MJ,sBE9MI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SF2MJ,qBE/MI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SF+MJ,sBElLI,iBAAA,yKACA,iBAAA,oKACA,iBAAA,iKFyLJ,YACE,cAAA,IC9KA,mBAAA,EAAA,IAAA,IAAA,iBACQ,WAAA,EAAA,IAAA,IAAA,iBDgLV,wBAAA,8BAAA,8BAGE,YAAA,EAAA,KAAA,EAAA,QEnOE,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SFiOF,aAAA,QALF,+BAAA,qCAAA,qCAQI,YAAA,KAUJ,OCnME,mBAAA,EAAA,IAAA,IAAA,gBACQ,WAAA,EAAA,IAAA,IAAA,gBD4MV,8BE5PI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SFyPJ,8BE7PI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SF0PJ,8BE9PI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SF2PJ,2BE/PI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SF4PJ,8BEhQI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SF6PJ,6BEjQI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SFoQJ,MExQI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SFsQF,aAAA,QC3NA,mBAAA,MAAA,EAAA,IAAA,IAAA,gBAAA,EAAA,IAAA,EAAA,qBACQ,WAAA,MAAA,EAAA,IAAA,IAAA,gBAAA,EAAA,IAAA,EAAA","sourcesContent":["/*!\n * Bootstrap v3.3.7 (http://getbootstrap.com)\n * Copyright 2011-2016 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n */\n\n//\n// Load core variables and mixins\n// --------------------------------------------------\n\n@import \"variables.less\";\n@import \"mixins.less\";\n\n\n//\n// Buttons\n// --------------------------------------------------\n\n// Common styles\n.btn-default,\n.btn-primary,\n.btn-success,\n.btn-info,\n.btn-warning,\n.btn-danger {\n text-shadow: 0 -1px 0 rgba(0,0,0,.2);\n @shadow: inset 0 1px 0 rgba(255,255,255,.15), 0 1px 1px rgba(0,0,0,.075);\n .box-shadow(@shadow);\n\n // Reset the shadow\n &:active,\n &.active {\n .box-shadow(inset 0 3px 5px rgba(0,0,0,.125));\n }\n\n &.disabled,\n &[disabled],\n fieldset[disabled] & {\n .box-shadow(none);\n }\n\n .badge {\n text-shadow: none;\n }\n}\n\n// Mixin for generating new styles\n.btn-styles(@btn-color: #555) {\n #gradient > .vertical(@start-color: @btn-color; @end-color: darken(@btn-color, 12%));\n .reset-filter(); // Disable gradients for IE9 because filter bleeds through rounded corners; see https://github.com/twbs/bootstrap/issues/10620\n background-repeat: repeat-x;\n border-color: darken(@btn-color, 14%);\n\n &:hover,\n &:focus {\n background-color: darken(@btn-color, 12%);\n background-position: 0 -15px;\n }\n\n &:active,\n &.active {\n background-color: darken(@btn-color, 12%);\n border-color: darken(@btn-color, 14%);\n }\n\n &.disabled,\n &[disabled],\n fieldset[disabled] & {\n &,\n &:hover,\n &:focus,\n &.focus,\n &:active,\n &.active {\n background-color: darken(@btn-color, 12%);\n background-image: none;\n }\n }\n}\n\n// Common styles\n.btn {\n // Remove the gradient for the pressed/active state\n &:active,\n &.active {\n background-image: none;\n }\n}\n\n// Apply the mixin to the buttons\n.btn-default { .btn-styles(@btn-default-bg); text-shadow: 0 1px 0 #fff; border-color: #ccc; }\n.btn-primary { .btn-styles(@btn-primary-bg); }\n.btn-success { .btn-styles(@btn-success-bg); }\n.btn-info { .btn-styles(@btn-info-bg); }\n.btn-warning { .btn-styles(@btn-warning-bg); }\n.btn-danger { .btn-styles(@btn-danger-bg); }\n\n\n//\n// Images\n// --------------------------------------------------\n\n.thumbnail,\n.img-thumbnail {\n .box-shadow(0 1px 2px rgba(0,0,0,.075));\n}\n\n\n//\n// Dropdowns\n// --------------------------------------------------\n\n.dropdown-menu > li > a:hover,\n.dropdown-menu > li > a:focus {\n #gradient > .vertical(@start-color: @dropdown-link-hover-bg; @end-color: darken(@dropdown-link-hover-bg, 5%));\n background-color: darken(@dropdown-link-hover-bg, 5%);\n}\n.dropdown-menu > .active > a,\n.dropdown-menu > .active > a:hover,\n.dropdown-menu > .active > a:focus {\n #gradient > .vertical(@start-color: @dropdown-link-active-bg; @end-color: darken(@dropdown-link-active-bg, 5%));\n background-color: darken(@dropdown-link-active-bg, 5%);\n}\n\n\n//\n// Navbar\n// --------------------------------------------------\n\n// Default navbar\n.navbar-default {\n #gradient > .vertical(@start-color: lighten(@navbar-default-bg, 10%); @end-color: @navbar-default-bg);\n .reset-filter(); // Remove gradient in IE<10 to fix bug where dropdowns don't get triggered\n border-radius: @navbar-border-radius;\n @shadow: inset 0 1px 0 rgba(255,255,255,.15), 0 1px 5px rgba(0,0,0,.075);\n .box-shadow(@shadow);\n\n .navbar-nav > .open > a,\n .navbar-nav > .active > a {\n #gradient > .vertical(@start-color: darken(@navbar-default-link-active-bg, 5%); @end-color: darken(@navbar-default-link-active-bg, 2%));\n .box-shadow(inset 0 3px 9px rgba(0,0,0,.075));\n }\n}\n.navbar-brand,\n.navbar-nav > li > a {\n text-shadow: 0 1px 0 rgba(255,255,255,.25);\n}\n\n// Inverted navbar\n.navbar-inverse {\n #gradient > .vertical(@start-color: lighten(@navbar-inverse-bg, 10%); @end-color: @navbar-inverse-bg);\n .reset-filter(); // Remove gradient in IE<10 to fix bug where dropdowns don't get triggered; see https://github.com/twbs/bootstrap/issues/10257\n border-radius: @navbar-border-radius;\n .navbar-nav > .open > a,\n .navbar-nav > .active > a {\n #gradient > .vertical(@start-color: @navbar-inverse-link-active-bg; @end-color: lighten(@navbar-inverse-link-active-bg, 2.5%));\n .box-shadow(inset 0 3px 9px rgba(0,0,0,.25));\n }\n\n .navbar-brand,\n .navbar-nav > li > a {\n text-shadow: 0 -1px 0 rgba(0,0,0,.25);\n }\n}\n\n// Undo rounded corners in static and fixed navbars\n.navbar-static-top,\n.navbar-fixed-top,\n.navbar-fixed-bottom {\n border-radius: 0;\n}\n\n// Fix active state of dropdown items in collapsed mode\n@media (max-width: @grid-float-breakpoint-max) {\n .navbar .navbar-nav .open .dropdown-menu > .active > a {\n &,\n &:hover,\n &:focus {\n color: #fff;\n #gradient > .vertical(@start-color: @dropdown-link-active-bg; @end-color: darken(@dropdown-link-active-bg, 5%));\n }\n }\n}\n\n\n//\n// Alerts\n// --------------------------------------------------\n\n// Common styles\n.alert {\n text-shadow: 0 1px 0 rgba(255,255,255,.2);\n @shadow: inset 0 1px 0 rgba(255,255,255,.25), 0 1px 2px rgba(0,0,0,.05);\n .box-shadow(@shadow);\n}\n\n// Mixin for generating new styles\n.alert-styles(@color) {\n #gradient > .vertical(@start-color: @color; @end-color: darken(@color, 7.5%));\n border-color: darken(@color, 15%);\n}\n\n// Apply the mixin to the alerts\n.alert-success { .alert-styles(@alert-success-bg); }\n.alert-info { .alert-styles(@alert-info-bg); }\n.alert-warning { .alert-styles(@alert-warning-bg); }\n.alert-danger { .alert-styles(@alert-danger-bg); }\n\n\n//\n// Progress bars\n// --------------------------------------------------\n\n// Give the progress background some depth\n.progress {\n #gradient > .vertical(@start-color: darken(@progress-bg, 4%); @end-color: @progress-bg)\n}\n\n// Mixin for generating new styles\n.progress-bar-styles(@color) {\n #gradient > .vertical(@start-color: @color; @end-color: darken(@color, 10%));\n}\n\n// Apply the mixin to the progress bars\n.progress-bar { .progress-bar-styles(@progress-bar-bg); }\n.progress-bar-success { .progress-bar-styles(@progress-bar-success-bg); }\n.progress-bar-info { .progress-bar-styles(@progress-bar-info-bg); }\n.progress-bar-warning { .progress-bar-styles(@progress-bar-warning-bg); }\n.progress-bar-danger { .progress-bar-styles(@progress-bar-danger-bg); }\n\n// Reset the striped class because our mixins don't do multiple gradients and\n// the above custom styles override the new `.progress-bar-striped` in v3.2.0.\n.progress-bar-striped {\n #gradient > .striped();\n}\n\n\n//\n// List groups\n// --------------------------------------------------\n\n.list-group {\n border-radius: @border-radius-base;\n .box-shadow(0 1px 2px rgba(0,0,0,.075));\n}\n.list-group-item.active,\n.list-group-item.active:hover,\n.list-group-item.active:focus {\n text-shadow: 0 -1px 0 darken(@list-group-active-bg, 10%);\n #gradient > .vertical(@start-color: @list-group-active-bg; @end-color: darken(@list-group-active-bg, 7.5%));\n border-color: darken(@list-group-active-border, 7.5%);\n\n .badge {\n text-shadow: none;\n }\n}\n\n\n//\n// Panels\n// --------------------------------------------------\n\n// Common styles\n.panel {\n .box-shadow(0 1px 2px rgba(0,0,0,.05));\n}\n\n// Mixin for generating new styles\n.panel-heading-styles(@color) {\n #gradient > .vertical(@start-color: @color; @end-color: darken(@color, 5%));\n}\n\n// Apply the mixin to the panel headings only\n.panel-default > .panel-heading { .panel-heading-styles(@panel-default-heading-bg); }\n.panel-primary > .panel-heading { .panel-heading-styles(@panel-primary-heading-bg); }\n.panel-success > .panel-heading { .panel-heading-styles(@panel-success-heading-bg); }\n.panel-info > .panel-heading { .panel-heading-styles(@panel-info-heading-bg); }\n.panel-warning > .panel-heading { .panel-heading-styles(@panel-warning-heading-bg); }\n.panel-danger > .panel-heading { .panel-heading-styles(@panel-danger-heading-bg); }\n\n\n//\n// Wells\n// --------------------------------------------------\n\n.well {\n #gradient > .vertical(@start-color: darken(@well-bg, 5%); @end-color: @well-bg);\n border-color: darken(@well-bg, 10%);\n @shadow: inset 0 1px 3px rgba(0,0,0,.05), 0 1px 0 rgba(255,255,255,.1);\n .box-shadow(@shadow);\n}\n","// Vendor Prefixes\n//\n// All vendor mixins are deprecated as of v3.2.0 due to the introduction of\n// Autoprefixer in our Gruntfile. They have been removed in v4.\n\n// - Animations\n// - Backface visibility\n// - Box shadow\n// - Box sizing\n// - Content columns\n// - Hyphens\n// - Placeholder text\n// - Transformations\n// - Transitions\n// - User Select\n\n\n// Animations\n.animation(@animation) {\n -webkit-animation: @animation;\n -o-animation: @animation;\n animation: @animation;\n}\n.animation-name(@name) {\n -webkit-animation-name: @name;\n animation-name: @name;\n}\n.animation-duration(@duration) {\n -webkit-animation-duration: @duration;\n animation-duration: @duration;\n}\n.animation-timing-function(@timing-function) {\n -webkit-animation-timing-function: @timing-function;\n animation-timing-function: @timing-function;\n}\n.animation-delay(@delay) {\n -webkit-animation-delay: @delay;\n animation-delay: @delay;\n}\n.animation-iteration-count(@iteration-count) {\n -webkit-animation-iteration-count: @iteration-count;\n animation-iteration-count: @iteration-count;\n}\n.animation-direction(@direction) {\n -webkit-animation-direction: @direction;\n animation-direction: @direction;\n}\n.animation-fill-mode(@fill-mode) {\n -webkit-animation-fill-mode: @fill-mode;\n animation-fill-mode: @fill-mode;\n}\n\n// Backface visibility\n// Prevent browsers from flickering when using CSS 3D transforms.\n// Default value is `visible`, but can be changed to `hidden`\n\n.backface-visibility(@visibility) {\n -webkit-backface-visibility: @visibility;\n -moz-backface-visibility: @visibility;\n backface-visibility: @visibility;\n}\n\n// Drop shadows\n//\n// Note: Deprecated `.box-shadow()` as of v3.1.0 since all of Bootstrap's\n// supported browsers that have box shadow capabilities now support it.\n\n.box-shadow(@shadow) {\n -webkit-box-shadow: @shadow; // iOS <4.3 & Android <4.1\n box-shadow: @shadow;\n}\n\n// Box sizing\n.box-sizing(@boxmodel) {\n -webkit-box-sizing: @boxmodel;\n -moz-box-sizing: @boxmodel;\n box-sizing: @boxmodel;\n}\n\n// CSS3 Content Columns\n.content-columns(@column-count; @column-gap: @grid-gutter-width) {\n -webkit-column-count: @column-count;\n -moz-column-count: @column-count;\n column-count: @column-count;\n -webkit-column-gap: @column-gap;\n -moz-column-gap: @column-gap;\n column-gap: @column-gap;\n}\n\n// Optional hyphenation\n.hyphens(@mode: auto) {\n word-wrap: break-word;\n -webkit-hyphens: @mode;\n -moz-hyphens: @mode;\n -ms-hyphens: @mode; // IE10+\n -o-hyphens: @mode;\n hyphens: @mode;\n}\n\n// Placeholder text\n.placeholder(@color: @input-color-placeholder) {\n // Firefox\n &::-moz-placeholder {\n color: @color;\n opacity: 1; // Override Firefox's unusual default opacity; see https://github.com/twbs/bootstrap/pull/11526\n }\n &:-ms-input-placeholder { color: @color; } // Internet Explorer 10+\n &::-webkit-input-placeholder { color: @color; } // Safari and Chrome\n}\n\n// Transformations\n.scale(@ratio) {\n -webkit-transform: scale(@ratio);\n -ms-transform: scale(@ratio); // IE9 only\n -o-transform: scale(@ratio);\n transform: scale(@ratio);\n}\n.scale(@ratioX; @ratioY) {\n -webkit-transform: scale(@ratioX, @ratioY);\n -ms-transform: scale(@ratioX, @ratioY); // IE9 only\n -o-transform: scale(@ratioX, @ratioY);\n transform: scale(@ratioX, @ratioY);\n}\n.scaleX(@ratio) {\n -webkit-transform: scaleX(@ratio);\n -ms-transform: scaleX(@ratio); // IE9 only\n -o-transform: scaleX(@ratio);\n transform: scaleX(@ratio);\n}\n.scaleY(@ratio) {\n -webkit-transform: scaleY(@ratio);\n -ms-transform: scaleY(@ratio); // IE9 only\n -o-transform: scaleY(@ratio);\n transform: scaleY(@ratio);\n}\n.skew(@x; @y) {\n -webkit-transform: skewX(@x) skewY(@y);\n -ms-transform: skewX(@x) skewY(@y); // See https://github.com/twbs/bootstrap/issues/4885; IE9+\n -o-transform: skewX(@x) skewY(@y);\n transform: skewX(@x) skewY(@y);\n}\n.translate(@x; @y) {\n -webkit-transform: translate(@x, @y);\n -ms-transform: translate(@x, @y); // IE9 only\n -o-transform: translate(@x, @y);\n transform: translate(@x, @y);\n}\n.translate3d(@x; @y; @z) {\n -webkit-transform: translate3d(@x, @y, @z);\n transform: translate3d(@x, @y, @z);\n}\n.rotate(@degrees) {\n -webkit-transform: rotate(@degrees);\n -ms-transform: rotate(@degrees); // IE9 only\n -o-transform: rotate(@degrees);\n transform: rotate(@degrees);\n}\n.rotateX(@degrees) {\n -webkit-transform: rotateX(@degrees);\n -ms-transform: rotateX(@degrees); // IE9 only\n -o-transform: rotateX(@degrees);\n transform: rotateX(@degrees);\n}\n.rotateY(@degrees) {\n -webkit-transform: rotateY(@degrees);\n -ms-transform: rotateY(@degrees); // IE9 only\n -o-transform: rotateY(@degrees);\n transform: rotateY(@degrees);\n}\n.perspective(@perspective) {\n -webkit-perspective: @perspective;\n -moz-perspective: @perspective;\n perspective: @perspective;\n}\n.perspective-origin(@perspective) {\n -webkit-perspective-origin: @perspective;\n -moz-perspective-origin: @perspective;\n perspective-origin: @perspective;\n}\n.transform-origin(@origin) {\n -webkit-transform-origin: @origin;\n -moz-transform-origin: @origin;\n -ms-transform-origin: @origin; // IE9 only\n transform-origin: @origin;\n}\n\n\n// Transitions\n\n.transition(@transition) {\n -webkit-transition: @transition;\n -o-transition: @transition;\n transition: @transition;\n}\n.transition-property(@transition-property) {\n -webkit-transition-property: @transition-property;\n transition-property: @transition-property;\n}\n.transition-delay(@transition-delay) {\n -webkit-transition-delay: @transition-delay;\n transition-delay: @transition-delay;\n}\n.transition-duration(@transition-duration) {\n -webkit-transition-duration: @transition-duration;\n transition-duration: @transition-duration;\n}\n.transition-timing-function(@timing-function) {\n -webkit-transition-timing-function: @timing-function;\n transition-timing-function: @timing-function;\n}\n.transition-transform(@transition) {\n -webkit-transition: -webkit-transform @transition;\n -moz-transition: -moz-transform @transition;\n -o-transition: -o-transform @transition;\n transition: transform @transition;\n}\n\n\n// User select\n// For selecting text on the page\n\n.user-select(@select) {\n -webkit-user-select: @select;\n -moz-user-select: @select;\n -ms-user-select: @select; // IE10+\n user-select: @select;\n}\n","// Gradients\n\n#gradient {\n\n // Horizontal gradient, from left to right\n //\n // Creates two color stops, start and end, by specifying a color and position for each color stop.\n // Color stops are not available in IE9 and below.\n .horizontal(@start-color: #555; @end-color: #333; @start-percent: 0%; @end-percent: 100%) {\n background-image: -webkit-linear-gradient(left, @start-color @start-percent, @end-color @end-percent); // Safari 5.1-6, Chrome 10+\n background-image: -o-linear-gradient(left, @start-color @start-percent, @end-color @end-percent); // Opera 12\n background-image: linear-gradient(to right, @start-color @start-percent, @end-color @end-percent); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+\n background-repeat: repeat-x;\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=1)\",argb(@start-color),argb(@end-color))); // IE9 and down\n }\n\n // Vertical gradient, from top to bottom\n //\n // Creates two color stops, start and end, by specifying a color and position for each color stop.\n // Color stops are not available in IE9 and below.\n .vertical(@start-color: #555; @end-color: #333; @start-percent: 0%; @end-percent: 100%) {\n background-image: -webkit-linear-gradient(top, @start-color @start-percent, @end-color @end-percent); // Safari 5.1-6, Chrome 10+\n background-image: -o-linear-gradient(top, @start-color @start-percent, @end-color @end-percent); // Opera 12\n background-image: linear-gradient(to bottom, @start-color @start-percent, @end-color @end-percent); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+\n background-repeat: repeat-x;\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)\",argb(@start-color),argb(@end-color))); // IE9 and down\n }\n\n .directional(@start-color: #555; @end-color: #333; @deg: 45deg) {\n background-repeat: repeat-x;\n background-image: -webkit-linear-gradient(@deg, @start-color, @end-color); // Safari 5.1-6, Chrome 10+\n background-image: -o-linear-gradient(@deg, @start-color, @end-color); // Opera 12\n background-image: linear-gradient(@deg, @start-color, @end-color); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+\n }\n .horizontal-three-colors(@start-color: #00b3ee; @mid-color: #7a43b6; @color-stop: 50%; @end-color: #c3325f) {\n background-image: -webkit-linear-gradient(left, @start-color, @mid-color @color-stop, @end-color);\n background-image: -o-linear-gradient(left, @start-color, @mid-color @color-stop, @end-color);\n background-image: linear-gradient(to right, @start-color, @mid-color @color-stop, @end-color);\n background-repeat: no-repeat;\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=1)\",argb(@start-color),argb(@end-color))); // IE9 and down, gets no color-stop at all for proper fallback\n }\n .vertical-three-colors(@start-color: #00b3ee; @mid-color: #7a43b6; @color-stop: 50%; @end-color: #c3325f) {\n background-image: -webkit-linear-gradient(@start-color, @mid-color @color-stop, @end-color);\n background-image: -o-linear-gradient(@start-color, @mid-color @color-stop, @end-color);\n background-image: linear-gradient(@start-color, @mid-color @color-stop, @end-color);\n background-repeat: no-repeat;\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)\",argb(@start-color),argb(@end-color))); // IE9 and down, gets no color-stop at all for proper fallback\n }\n .radial(@inner-color: #555; @outer-color: #333) {\n background-image: -webkit-radial-gradient(circle, @inner-color, @outer-color);\n background-image: radial-gradient(circle, @inner-color, @outer-color);\n background-repeat: no-repeat;\n }\n .striped(@color: rgba(255,255,255,.15); @angle: 45deg) {\n background-image: -webkit-linear-gradient(@angle, @color 25%, transparent 25%, transparent 50%, @color 50%, @color 75%, transparent 75%, transparent);\n background-image: -o-linear-gradient(@angle, @color 25%, transparent 25%, transparent 50%, @color 50%, @color 75%, transparent 75%, transparent);\n background-image: linear-gradient(@angle, @color 25%, transparent 25%, transparent 50%, @color 50%, @color 75%, transparent 75%, transparent);\n }\n}\n","// Reset filters for IE\n//\n// When you need to remove a gradient background, do not forget to use this to reset\n// the IE filter for IE9 and below.\n\n.reset-filter() {\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(enabled = false)\"));\n}\n"]} --------------------------------------------------------------------------------