squares);
12 | bool TryGetPlayerClaims(out int[] ids);
13 | void SetPlayerClaims(int[] claims);
14 | }
15 | }
--------------------------------------------------------------------------------
/test/NdcBingo.Data.Tests/Base36Tests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Xunit;
3 |
4 | namespace NdcBingo.Data.Tests
5 | {
6 | public class Base36Tests
7 | {
8 | [Theory]
9 | [InlineData(123456L)]
10 | [InlineData(long.MaxValue)]
11 | public void EncodesAndDecodes(long expected)
12 | {
13 | var code = Base36.Encode(expected);
14 | var actual = Base36.Decode(code);
15 | Assert.Equal(expected, actual);
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/NdcBingo.Data/StringExtensions.cs:
--------------------------------------------------------------------------------
1 | using System.Text.RegularExpressions;
2 |
3 | namespace NdcBingo.Data
4 | {
5 | internal static class StringExtensions
6 | {
7 | public static string ToSnakeCase(this string input)
8 | {
9 | if (string.IsNullOrEmpty(input)) { return input; }
10 |
11 | var startUnderscores = Regex.Match(input, @"^_+");
12 | return startUnderscores + Regex.Replace(input, @"([a-z0-9])([A-Z])", "$1_$2").ToLower();
13 | }
14 | }
15 | }
--------------------------------------------------------------------------------
/src/NdcBingo/Views/Home/Privacy.cshtml:
--------------------------------------------------------------------------------
1 | @{
2 | ViewData["Title"] = "Privacy Policy";
3 | }
4 |
5 | @ViewData["Title"]
6 |
7 | NDC Bingo uses cookies to store your progress. Your player name and code is saved
8 | in a PostgreSQL database so you can switch between devices. Some metrics are generated
9 | including your player code for demonstration purposes in a talk. Your chosen player name
10 | is not included in that data.
11 |
12 | NDC Bingo is a non-evil application. I hope you have fun with it.
13 |
14 | Thanks,
15 | Mark
--------------------------------------------------------------------------------
/src/NdcBingo.Data/NdcBingo.Data.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.0
5 | latest
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/src/NdcBingo.ClrMetrics/ThreadPoolMetrics.cs:
--------------------------------------------------------------------------------
1 | using App.Metrics;
2 | using App.Metrics.Gauge;
3 |
4 | namespace NdcBingo.ClrMetrics
5 | {
6 | internal static class ThreadPoolMetrics
7 | {
8 | private static readonly GaugeOptions ThreadCount = new GaugeOptions
9 | {
10 | Name = "clr_threadpool_thread_count",
11 | MeasurementUnit = Unit.Threads
12 | };
13 |
14 | public static void SetThreadCount(this IMetrics metrics, uint threadCount)
15 | {
16 | metrics.Measure.Gauge.SetValue(ThreadCount, threadCount);
17 | }
18 | }
19 | }
--------------------------------------------------------------------------------
/src/NdcBingo.Data/PlayerMetrics.cs:
--------------------------------------------------------------------------------
1 | using App.Metrics;
2 | using App.Metrics.Counter;
3 |
4 | namespace NdcBingo.Data
5 | {
6 | public static class PlayerMetrics
7 | {
8 | private static readonly CounterOptions Players = new CounterOptions
9 | {
10 | Name = "players",
11 | MeasurementUnit = Unit.Items
12 | };
13 |
14 | public static void SetPlayerCount(this IMetrics metrics, int count)
15 | {
16 | metrics.Provider.Counter.Instance(Players).Reset();
17 | metrics.Measure.Counter.Increment(Players, count);
18 | }
19 | }
20 | }
--------------------------------------------------------------------------------
/test/NdcBingo.Data.Tests/NdcBingo.Data.Tests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp2.2
5 |
6 | false
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/test/NdcBingo.Game.Tests/NdcBingo.Game.Tests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp2.2
5 |
6 | false
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/src/NdcBingo.Data/PlayerIdGenerator.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Security.Cryptography;
3 |
4 | namespace NdcBingo.Data
5 | {
6 | public class PlayerIdGenerator : IPlayerIdGenerator
7 | {
8 | private readonly RandomNumberGenerator _generator = new RNGCryptoServiceProvider();
9 | private readonly object _sync = new object();
10 |
11 | public long Get()
12 | {
13 | var bytes = new byte[8];
14 | lock (_sync)
15 | {
16 | _generator.GetBytes(bytes);
17 | }
18 |
19 | return Math.Abs(BitConverter.ToInt64(bytes, 0));
20 | }
21 | }
22 | }
--------------------------------------------------------------------------------
/src/NdcBingo/Models/Game/SquareViewModel.cs:
--------------------------------------------------------------------------------
1 | namespace NdcBingo.Models.Game
2 | {
3 | public class SquareViewModel
4 | {
5 | public SquareViewModel(int id, string text, string type, string description)
6 | {
7 | Id = id;
8 | Text = text;
9 | Type = type;
10 | Description = description;
11 | }
12 |
13 | public int Id { get; set; }
14 | public string Text { get; set; }
15 | public string Type { get; set; }
16 | public string Description { get; set; }
17 | public string ClaimLink { get; set; }
18 | public bool Claimed { get; set; }
19 | }
20 | }
--------------------------------------------------------------------------------
/src/NdcBingo/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/NdcBingo.Data.Migrate/NdcBingo.Data.Migrate.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | netcoreapp2.2
6 | latest
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: '3'
2 |
3 | services:
4 |
5 | db:
6 | image: postgres:10.7-alpine
7 | environment:
8 | POSTGRES_USER: bingo
9 | POSTGRES_PASSWORD: SecretSquirrel
10 | ports:
11 | - 5432:5432
12 |
13 | influxdb:
14 | image: influxdb:1.7.3
15 | ports:
16 | - 8086:8086
17 | environment:
18 | INFLUXDB_DB: bingo
19 |
20 | chronograf:
21 | image: chronograf:1.7.5
22 | ports:
23 | - 8888:8888
24 | depends_on:
25 | - influxdb
26 | links:
27 | - influxdb
28 |
29 | grafana:
30 | image: grafana/grafana:5.3.2
31 | ports:
32 | - 3000:3000
33 | depends_on:
34 | - influxdb
35 | links:
36 | - influxdb
37 |
--------------------------------------------------------------------------------
/src/NdcBingo/Views/Me/Index.cshtml:
--------------------------------------------------------------------------------
1 | @model NdcBingo.Models.Me.MeViewModel
2 |
3 | @{
4 | ViewBag.Title = "Me";
5 | Layout = "_Layout";
6 | }
7 |
8 |
13 |
14 |
28 |
--------------------------------------------------------------------------------
/src/NdcBingo/Views/Shared/Error.cshtml:
--------------------------------------------------------------------------------
1 | @model ErrorViewModel
2 | @{
3 | ViewData["Title"] = "Error";
4 | }
5 |
6 | Error.
7 | An error occurred while processing your request.
8 |
9 | @if (Model.ShowRequestId)
10 | {
11 |
12 | Request ID: @Model.RequestId
13 |
14 | }
15 |
16 | Development Mode
17 |
18 | Swapping to Development environment will display more detailed information about the error that occurred.
19 |
20 |
21 | The Development environment shouldn't be enabled for deployed applications.
22 | It can result in displaying sensitive information from exceptions to end users.
23 | For local debugging, enable the Development environment by setting the ASPNETCORE_ENVIRONMENT environment variable to Development
24 | and restarting the app.
25 |
26 |
--------------------------------------------------------------------------------
/src/NdcBingo.ClrMetrics/ExceptionMetrics.cs:
--------------------------------------------------------------------------------
1 | using App.Metrics;
2 | using App.Metrics.Gauge;
3 | using App.Metrics.Meter;
4 |
5 | namespace NdcBingo.ClrMetrics
6 | {
7 | internal static class ExceptionMetrics
8 | {
9 | private static readonly MeterOptions Exceptions = new MeterOptions
10 | {
11 | Name = "clr_exceptions_thrown",
12 | MeasurementUnit = Unit.Errors,
13 | };
14 |
15 | public static void ExceptionThrown(this IMetrics metrics, string type)
16 | {
17 | metrics.Measure.Meter.Mark(Exceptions, new MetricTags("exception_type", type ?? "Unknown"));
18 | }
19 | }
20 |
21 | internal static class ProcessMetrics
22 | {
23 | private static readonly GaugeOptions PhysicalMemory = new GaugeOptions
24 | {
25 | Name = "physical_memory",
26 | MeasurementUnit = Unit.Bytes
27 | };
28 |
29 | public static void SetPhysicalMemory(this IMetrics metrics, long memory)
30 | {
31 | metrics.Measure.Gauge.SetValue(PhysicalMemory, memory);
32 | }
33 | }
34 | }
--------------------------------------------------------------------------------
/src/NdcBingo/Views/Shared/_CookieConsentPartial.cshtml:
--------------------------------------------------------------------------------
1 | @using Microsoft.AspNetCore.Http.Features
2 |
3 | @{
4 | var consentFeature = Context.Features.Get();
5 | var showBanner = !consentFeature?.CanTrack ?? false;
6 | var cookieString = consentFeature?.CreateConsentCookie();
7 | }
8 |
9 | @if (showBanner)
10 | {
11 |
12 | Use this space to summarize your privacy and cookie use policy.
Learn More .
13 |
14 | Accept
15 |
16 |
17 |
25 | }
26 |
--------------------------------------------------------------------------------
/src/NdcBingo/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/NdcBingo/NdcBingo.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp2.2
5 | InProcess
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/src/NdcBingo/Views/Shared/_ValidationScriptsPartial.cshtml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
12 |
18 |
19 |
--------------------------------------------------------------------------------
/src/NdcBingo/wwwroot/lib/bootstrap/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2011-2018 Twitter, Inc.
4 | Copyright (c) 2011-2018 The Bootstrap Authors
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/NdcBingo/Views/Players/New.cshtml:
--------------------------------------------------------------------------------
1 | @model NdcBingo.Models.Players.NewViewModel
2 |
3 | @{
4 | ViewBag.Title = "New Player";
5 | Layout = "_Layout";
6 | }
7 |
8 |
9 |
10 |
Player setup
11 |
If this is your first sign-in, just enter your name.
12 |
If you already have a code from another device, enter it in the code field to link this device.
13 |
14 |
15 |
30 |
--------------------------------------------------------------------------------
/src/NdcBingo/wwwroot/js/game.js:
--------------------------------------------------------------------------------
1 | $(function () {
2 | const selectedTextElement = $('#selected-text');
3 | const selectedDescriptionElement = $('#selected-description');
4 | const claimButton = $('#claim-button');
5 | claimButton.hide();
6 | var selectedCard;
7 |
8 | $('.bingo-square').click(function (e) {
9 | const $this = $(this);
10 | if (selectedCard) {
11 | selectedCard.toggleClass('active');
12 | if (selectedCard.attr('data-square-id') === $this.attr('data-square-id')) {
13 | selectedTextElement.text('');
14 | selectedDescriptionElement.text('');
15 | claimButton.hide();
16 | selectedCard = null;
17 | return;
18 | }
19 | }
20 | selectedCard = $this;
21 | selectedCard.toggleClass('active');
22 | selectedTextElement.text($this.attr('data-square-text'));
23 | selectedDescriptionElement.text($this.attr('data-square-description'));
24 | const link = $this.attr('data-claim-link');
25 | if (!!link) {
26 | claimButton.attr('href', link);
27 | claimButton.show();
28 | } else {
29 | claimButton.attr('href', '');
30 | claimButton.hide();
31 | }
32 | });
33 | });
--------------------------------------------------------------------------------
/src/NdcBingo/Views/Home/Index.cshtml:
--------------------------------------------------------------------------------
1 | @model IndexViewModel
2 | @{
3 | ViewData["Title"] = "Home";
4 | }
5 |
6 |
7 |
8 |
NDC Bingo
9 |
at NDC Porto 2019
10 |
11 |
12 |
13 |
14 |
15 |
Welcome to NDC Porto! I've made this little game you can play to help you enjoy the conference even more.
16 | When you click Play , you'll get your own personal Bingo card with 25 things to tick off.
17 | Some are things you might hear in talks. Others are little challenges for you to complete.
18 | Collect rows, columns, or the whole square. It's up to you!
19 |
You will also be generating (anonymous) metrics data for Mark Rendle's "Measure All The Things" talk,
20 | which will make him super happy.
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/src/NdcBingo/Controllers/HomeController.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Diagnostics;
3 | using System.Threading.Tasks;
4 | using Microsoft.AspNetCore.Mvc;
5 | using Microsoft.Extensions.Logging;
6 | using NdcBingo.Data;
7 | using NdcBingo.Models;
8 |
9 | namespace NdcBingo.Controllers
10 | {
11 | [Route("")]
12 | public class HomeController : Controller
13 | {
14 | private readonly IPlayerData _playerData;
15 | private readonly ILogger _logger;
16 |
17 | public HomeController(IPlayerData playerData, ILogger logger)
18 | {
19 | _playerData = playerData;
20 | _logger = logger;
21 | }
22 |
23 | [HttpGet("")]
24 | public IActionResult Index()
25 | {
26 | var vm = new IndexViewModel();
27 |
28 | return View(vm);
29 | }
30 |
31 | [HttpGet("privacy")]
32 | public IActionResult Privacy()
33 | {
34 | return View();
35 | }
36 |
37 | [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
38 | public IActionResult Error()
39 | {
40 | return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
41 | }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/NdcBingo.Data.Migrate/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 | using System.Threading.Tasks;
4 | using Microsoft.EntityFrameworkCore;
5 | using Microsoft.EntityFrameworkCore.Design;
6 | using Microsoft.Extensions.Logging;
7 | using RendleLabs.EntityFrameworkCore.MigrateHelper;
8 |
9 | namespace NdcBingo.Data.Migrate
10 | {
11 | class Program
12 | {
13 | static async Task Main(string[] args)
14 | {
15 | var loggerFactory = new LoggerFactory().AddConsole((_, level) => true);
16 | await new MigrationHelper(loggerFactory).TryMigrate(args);
17 | Console.WriteLine("Migration complete.");
18 | }
19 | }
20 |
21 | public class DesignTimeNoteContextFactory : IDesignTimeDbContextFactory
22 | {
23 | public const string LocalPostgres = "Host=localhost;Database=bingo;Username=bingo;Password=SecretSquirrel";
24 |
25 | public static readonly string MigrationAssemblyName =
26 | typeof(DesignTimeNoteContextFactory).Assembly.GetName().Name;
27 |
28 | public BingoContext CreateDbContext(string[] args)
29 | {
30 | var builder = new DbContextOptionsBuilder()
31 | .UseNpgsql(args.FirstOrDefault() ?? LocalPostgres, b => b.MigrationsAssembly(MigrationAssemblyName));
32 | return new BingoContext(builder.Options);
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/NdcBingo.ClrMetrics/ClrMetricsService.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Diagnostics;
3 | using System.Threading;
4 | using System.Threading.Tasks;
5 | using App.Metrics;
6 | using Microsoft.Extensions.Hosting;
7 |
8 | namespace NdcBingo.ClrMetrics
9 | {
10 | public class ClrMetricsService : IHostedService
11 | {
12 | private static readonly TimeSpan TimerInterval = TimeSpan.FromSeconds(5);
13 | private readonly IMetrics _metrics;
14 | private GcEventListener _gcEventListener;
15 | private readonly Process _process;
16 | private readonly Timer _timer;
17 |
18 | public ClrMetricsService(IMetrics metrics)
19 | {
20 | _metrics = metrics;
21 | _process = Process.GetCurrentProcess();
22 | _timer = new Timer(OnTimer);
23 | }
24 |
25 | private void OnTimer(object state)
26 | {
27 | _metrics.SetPhysicalMemory(_process.WorkingSet64);
28 | }
29 |
30 | public Task StartAsync(CancellationToken cancellationToken)
31 | {
32 | _timer.Change(TimerInterval, TimerInterval);
33 | _gcEventListener = new GcEventListener(_metrics);
34 | return Task.CompletedTask;
35 | }
36 |
37 | public Task StopAsync(CancellationToken cancellationToken)
38 | {
39 | _gcEventListener.Dispose();
40 | return Task.CompletedTask;
41 | }
42 | }
43 | }
--------------------------------------------------------------------------------
/src/NdcBingo.ClrMetrics/GcEventListener.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Diagnostics.Tracing;
4 | using App.Metrics;
5 |
6 | namespace NdcBingo.ClrMetrics
7 | {
8 | public class GcEventListener : EventListener
9 | {
10 | private readonly IMetrics _metrics;
11 | private readonly HashSet _seen = new HashSet();
12 |
13 | public GcEventListener(IMetrics metrics)
14 | {
15 | _metrics = metrics;
16 | }
17 |
18 | protected override void OnEventSourceCreated(EventSource eventSource)
19 | {
20 | if (eventSource.Name.Equals("Microsoft-Windows-DotNETRuntime"))
21 | {
22 | EnableEvents(eventSource, EventLevel.Verbose, (EventKeywords)(-1));
23 | }
24 | }
25 |
26 | protected override void OnEventWritten(EventWrittenEventArgs eventData)
27 | {
28 | switch ((EventIds)eventData.EventId)
29 | {
30 | case EventIds.ThreadPoolWorkerThreadAdjustmentAdjustment:
31 | var newWorkerThreadCount = (uint) eventData.Payload[1];
32 | _metrics.SetThreadCount(newWorkerThreadCount);
33 | break;
34 | case EventIds.ExceptionThrownV1:
35 | _metrics.ExceptionThrown(eventData.Payload[0] as string);
36 | break;
37 | }
38 | }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/NdcBingo/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 |
4 | a.navbar-brand {
5 | white-space: normal;
6 | text-align: center;
7 | word-break: break-all;
8 | }
9 |
10 | /* Sticky footer styles
11 | -------------------------------------------------- */
12 | html {
13 | font-size: 14px;
14 | }
15 | @media (min-width: 768px) {
16 | html {
17 | font-size: 16px;
18 | }
19 | }
20 |
21 | .border-top {
22 | border-top: 1px solid #e5e5e5;
23 | }
24 | .border-bottom {
25 | border-bottom: 1px solid #e5e5e5;
26 | }
27 |
28 | .box-shadow {
29 | box-shadow: 0 .25rem .75rem rgba(0, 0, 0, .05);
30 | }
31 |
32 | button.accept-policy {
33 | font-size: 1rem;
34 | line-height: inherit;
35 | }
36 |
37 | /* Sticky footer styles
38 | -------------------------------------------------- */
39 | html {
40 | position: relative;
41 | min-height: 100%;
42 | }
43 |
44 | body {
45 | /* Margin bottom by footer height */
46 | margin-bottom: 60px;
47 | }
48 | .footer {
49 | position: absolute;
50 | bottom: 0;
51 | width: 100%;
52 | white-space: nowrap;
53 | /* Set the fixed height of the footer here */
54 | height: 60px;
55 | line-height: 60px; /* Vertically center the text there */
56 | }
57 |
58 | .bingo-square {
59 | cursor: pointer;
60 | }
61 |
62 | .card.bg-success.active {
63 | background-color: #3d8b40 !important;
64 | }
--------------------------------------------------------------------------------
/src/NdcBingo/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Linq;
5 | using System.Threading.Tasks;
6 | using App.Metrics;
7 | using App.Metrics.AspNetCore;
8 | using App.Metrics.Extensions.Configuration;
9 | using App.Metrics.Formatters.InfluxDB;
10 | using App.Metrics.Reporting.InfluxDB;
11 | using Microsoft.AspNetCore;
12 | using Microsoft.AspNetCore.Hosting;
13 | using Microsoft.Extensions.Configuration;
14 | using Microsoft.Extensions.Logging;
15 |
16 | namespace NdcBingo
17 | {
18 | public class Program
19 | {
20 | public static void Main(string[] args)
21 | {
22 | CreateWebHostBuilder(args).Build().Run();
23 | }
24 |
25 | public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
26 | WebHost.CreateDefaultBuilder(args)
27 | // .ConfigureMetricsWithDefaults(
28 | // (context, builder) =>
29 | // {
30 | // builder.Configuration.ReadFrom(context.Configuration);
31 | // builder.Report.ToInfluxDb(options =>
32 | // {
33 | // context.Configuration.GetSection("MetricsOptions").Bind(options);
34 | // options.MetricsOutputFormatter = new MetricsInfluxDbLineProtocolOutputFormatter();
35 | // });
36 | // })
37 | .UseMetrics()
38 | .UseStartup();
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/NdcBingo.Data/Base36.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Buffers;
3 | using System.Net;
4 |
5 | namespace NdcBingo.Data
6 | {
7 | public static class Base36
8 | {
9 | private static readonly char[] CharacterSet = "abcdefghijklmnopqrstuvwxyz1234567890".ToCharArray();
10 |
11 | public static string Encode(long number)
12 | {
13 | if (number < 0) throw new ArgumentOutOfRangeException();
14 |
15 | var chars = ArrayPool.Shared.Rent(16);
16 | try
17 | {
18 | int index = 0;
19 | while (number > 0)
20 | {
21 | int digit = (int) (number % 36);
22 | chars[index++] = CharacterSet[digit];
23 | number = number / 36;
24 | }
25 |
26 | return new string(chars, 0, index);
27 | }
28 | finally
29 | {
30 | ArrayPool.Shared.Return(chars);
31 | }
32 | }
33 |
34 | public static long Decode(string code)
35 | {
36 | long number = 0;
37 | long multiplier = 1;
38 | for (int i = 0, l = code.Length; i < l; i++)
39 | {
40 | int index = Array.IndexOf(CharacterSet, code[i]);
41 | if (index >= 0)
42 | {
43 | number += index * multiplier;
44 | multiplier *= 36;
45 | }
46 | }
47 |
48 | return number;
49 | }
50 | }
51 | }
--------------------------------------------------------------------------------
/src/NdcBingo.Data/BingoContext.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.EntityFrameworkCore;
2 |
3 | namespace NdcBingo.Data
4 | {
5 | public class BingoContext : DbContext
6 | {
7 | public BingoContext(DbContextOptions options) : base(options)
8 | {
9 | }
10 |
11 | public DbSet Squares { get; set; }
12 | public DbSet Players { get; set; }
13 |
14 | protected override void OnModelCreating(ModelBuilder builder)
15 | {
16 | base.OnModelCreating(builder);
17 |
18 | foreach (var entity in builder.Model.GetEntityTypes())
19 | {
20 | // Replace table names
21 | entity.Relational().TableName = entity.Relational().TableName.ToSnakeCase();
22 |
23 | // Replace column names
24 | foreach (var property in entity.GetProperties())
25 | {
26 | property.Relational().ColumnName = property.Name.ToSnakeCase();
27 | }
28 |
29 | foreach (var key in entity.GetKeys())
30 | {
31 | key.Relational().Name = key.Relational().Name.ToSnakeCase();
32 | }
33 |
34 | foreach (var key in entity.GetForeignKeys())
35 | {
36 | key.Relational().Name = key.Relational().Name.ToSnakeCase();
37 | }
38 |
39 | foreach (var index in entity.GetIndexes())
40 | {
41 | index.Relational().Name = index.Relational().Name.ToSnakeCase();
42 | }
43 | }
44 | }
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/src/NdcBingo.Data/SquareData.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 | using System.Threading.Tasks;
4 | using App.Metrics;
5 | using Dapper;
6 | using Microsoft.EntityFrameworkCore;
7 |
8 | namespace NdcBingo.Data
9 | {
10 | public class SquareData : ISquareData
11 | {
12 | private readonly BingoContext _context;
13 | private readonly IMetrics _metrics;
14 |
15 | public SquareData(BingoContext context, IMetrics metrics)
16 | {
17 | _context = context;
18 | _metrics = metrics;
19 | }
20 |
21 | public async Task GetRandomSquaresAsync(int limit)
22 | {
23 | using (_metrics.RandomSquaresQueryTimer())
24 | {
25 | var cn = _context.Database.GetDbConnection();
26 | var squares = await cn.QueryAsync(
27 | "select id, text, type, description from squares order by random() limit @limit", new {limit});
28 | return squares.ToArray();
29 | }
30 | }
31 |
32 | public async Task GetSquaresAsync(int[] ids)
33 | {
34 | using (_metrics.SquaresQueryTimer())
35 | {
36 | var squares = new Square[ids.Length];
37 | foreach (var s in await _context.Squares.Where(s => ids.Contains(s.Id)).ToListAsync())
38 | {
39 | int index = Array.IndexOf(ids, s.Id);
40 | if (index > -1)
41 | {
42 | squares[index] = s;
43 | }
44 | }
45 |
46 | return squares;
47 | }
48 | }
49 | }
50 | }
--------------------------------------------------------------------------------
/src/NdcBingo/Controllers/MeController.cs:
--------------------------------------------------------------------------------
1 | using System.Runtime.CompilerServices;
2 | using System.Threading.Tasks;
3 | using Microsoft.AspNetCore.Mvc;
4 | using Microsoft.Extensions.Logging;
5 | using NdcBingo.Data;
6 | using NdcBingo.Models.Me;
7 | using NdcBingo.Services;
8 |
9 | namespace NdcBingo.Controllers
10 | {
11 | [Route("me")]
12 | public class MeController : Controller
13 | {
14 | private readonly IDataCookies _dataCookies;
15 | private readonly IPlayerData _playerData;
16 | private readonly ILogger _logger;
17 |
18 | public MeController(IDataCookies dataCookies, IPlayerData playerData, ILogger logger)
19 | {
20 | _dataCookies = dataCookies;
21 | _playerData = playerData;
22 | _logger = logger;
23 | }
24 |
25 | [HttpGet]
26 | [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
27 | public async Task Index()
28 | {
29 | if (_dataCookies.TryGetPlayerCode(out var code))
30 | {
31 | var player = await _playerData.Get(code);
32 | if (player != null)
33 | {
34 | var vm = new MeViewModel
35 | {
36 | Code = player.Code,
37 | Name = player.Name
38 | };
39 | return View(vm);
40 | }
41 | }
42 |
43 | _logger.LogInformation("New player");
44 |
45 | return RedirectToAction("New", "Players", new { returnUrl = Url.Action("Index")});
46 | }
47 | }
48 | }
--------------------------------------------------------------------------------
/src/NdcBingo/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 |
--------------------------------------------------------------------------------
/src/NdcBingo.Data.Migrate/Migrations/20190225180443_InitialCreate.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.EntityFrameworkCore.Migrations;
2 | using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
3 |
4 | namespace NdcBingo.Data.Migrate.Migrations
5 | {
6 | public partial class InitialCreate : Migration
7 | {
8 | protected override void Up(MigrationBuilder migrationBuilder)
9 | {
10 | migrationBuilder.CreateTable(
11 | name: "players",
12 | columns: table => new
13 | {
14 | id = table.Column(nullable: false)
15 | .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.SerialColumn),
16 | name = table.Column(nullable: true)
17 | },
18 | constraints: table =>
19 | {
20 | table.PrimaryKey("pk_players", x => x.id);
21 | });
22 |
23 | migrationBuilder.CreateTable(
24 | name: "squares",
25 | columns: table => new
26 | {
27 | id = table.Column(nullable: false)
28 | .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.SerialColumn),
29 | text = table.Column(nullable: true),
30 | type = table.Column(nullable: true),
31 | description = table.Column(nullable: true)
32 | },
33 | constraints: table =>
34 | {
35 | table.PrimaryKey("pk_squares", x => x.id);
36 | });
37 | }
38 |
39 | protected override void Down(MigrationBuilder migrationBuilder)
40 | {
41 | migrationBuilder.DropTable(
42 | name: "players");
43 |
44 | migrationBuilder.DropTable(
45 | name: "squares");
46 | }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/src/NdcBingo.Data.Migrate/Migrations/BingoContextModelSnapshot.cs:
--------------------------------------------------------------------------------
1 | //
2 | using Microsoft.EntityFrameworkCore;
3 | using Microsoft.EntityFrameworkCore.Infrastructure;
4 | using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
5 | using NdcBingo.Data;
6 | using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
7 |
8 | namespace NdcBingo.Data.Migrate.Migrations
9 | {
10 | [DbContext(typeof(BingoContext))]
11 | partial class BingoContextModelSnapshot : ModelSnapshot
12 | {
13 | protected override void BuildModel(ModelBuilder modelBuilder)
14 | {
15 | #pragma warning disable 612, 618
16 | modelBuilder
17 | .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.SerialColumn)
18 | .HasAnnotation("ProductVersion", "2.2.2-servicing-10034")
19 | .HasAnnotation("Relational:MaxIdentifierLength", 63);
20 |
21 | modelBuilder.Entity("NdcBingo.Data.Player", b =>
22 | {
23 | b.Property("Id")
24 | .ValueGeneratedOnAdd()
25 | .HasColumnName("id");
26 |
27 | b.Property("Name")
28 | .HasColumnName("name");
29 |
30 | b.HasKey("Id")
31 | .HasName("pk_players");
32 |
33 | b.ToTable("players");
34 | });
35 |
36 | modelBuilder.Entity("NdcBingo.Data.Square", b =>
37 | {
38 | b.Property("Id")
39 | .ValueGeneratedOnAdd()
40 | .HasColumnName("id");
41 |
42 | b.Property("Description")
43 | .HasColumnName("description");
44 |
45 | b.Property("Text")
46 | .HasColumnName("text");
47 |
48 | b.Property("Type")
49 | .HasColumnName("type");
50 |
51 | b.HasKey("Id")
52 | .HasName("pk_squares");
53 |
54 | b.ToTable("squares");
55 | });
56 | #pragma warning restore 612, 618
57 | }
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/src/NdcBingo.Data.Migrate/Migrations/20190225180443_InitialCreate.Designer.cs:
--------------------------------------------------------------------------------
1 | //
2 | using Microsoft.EntityFrameworkCore;
3 | using Microsoft.EntityFrameworkCore.Infrastructure;
4 | using Microsoft.EntityFrameworkCore.Migrations;
5 | using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
6 | using NdcBingo.Data;
7 | using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
8 |
9 | namespace NdcBingo.Data.Migrate.Migrations
10 | {
11 | [DbContext(typeof(BingoContext))]
12 | [Migration("20190225180443_InitialCreate")]
13 | partial class InitialCreate
14 | {
15 | protected override void BuildTargetModel(ModelBuilder modelBuilder)
16 | {
17 | #pragma warning disable 612, 618
18 | modelBuilder
19 | .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.SerialColumn)
20 | .HasAnnotation("ProductVersion", "2.2.2-servicing-10034")
21 | .HasAnnotation("Relational:MaxIdentifierLength", 63);
22 |
23 | modelBuilder.Entity("NdcBingo.Data.Player", b =>
24 | {
25 | b.Property("Id")
26 | .ValueGeneratedOnAdd()
27 | .HasColumnName("id");
28 |
29 | b.Property("Name")
30 | .HasColumnName("name");
31 |
32 | b.HasKey("Id")
33 | .HasName("pk_players");
34 |
35 | b.ToTable("players");
36 | });
37 |
38 | modelBuilder.Entity("NdcBingo.Data.Square", b =>
39 | {
40 | b.Property("Id")
41 | .ValueGeneratedOnAdd()
42 | .HasColumnName("id");
43 |
44 | b.Property("Description")
45 | .HasColumnName("description");
46 |
47 | b.Property("Text")
48 | .HasColumnName("text");
49 |
50 | b.Property("Type")
51 | .HasColumnName("type");
52 |
53 | b.HasKey("Id")
54 | .HasName("pk_squares");
55 |
56 | b.ToTable("squares");
57 | });
58 | #pragma warning restore 612, 618
59 | }
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/src/NdcBingo/Startup.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 | using Microsoft.AspNetCore.Builder;
6 | using Microsoft.AspNetCore.Hosting;
7 | using Microsoft.AspNetCore.Http;
8 | using Microsoft.AspNetCore.HttpsPolicy;
9 | using Microsoft.AspNetCore.Mvc;
10 | using Microsoft.EntityFrameworkCore;
11 | using Microsoft.Extensions.Configuration;
12 | using Microsoft.Extensions.DependencyInjection;
13 | using NdcBingo.ClrMetrics;
14 | using NdcBingo.Data;
15 | using NdcBingo.Services;
16 |
17 | namespace NdcBingo
18 | {
19 | public class Startup
20 | {
21 | public Startup(IConfiguration configuration)
22 | {
23 | Configuration = configuration;
24 | }
25 |
26 | public IConfiguration Configuration { get; }
27 |
28 | // This method gets called by the runtime. Use this method to add services to the container.
29 | public void ConfigureServices(IServiceCollection services)
30 | {
31 | services.AddDbContextPool(options =>
32 | {
33 | options.UseNpgsql(Configuration.GetConnectionString("Bingo"));
34 | options.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking);
35 | });
36 |
37 | services.AddHttpContextAccessor();
38 | services.AddSingleton();
39 | services.AddSingleton();
40 | services.AddScoped();
41 | services.AddScoped();
42 | services.AddHostedService();
43 |
44 | services.AddMvc()
45 | .SetCompatibilityVersion(CompatibilityVersion.Version_2_2)
46 | .AddMetrics();
47 | }
48 |
49 | // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
50 | public void Configure(IApplicationBuilder app, IHostingEnvironment env)
51 | {
52 | if (env.IsDevelopment())
53 | {
54 | app.UseDeveloperExceptionPage();
55 | }
56 | else
57 | {
58 | app.UseExceptionHandler("/Home/Error");
59 | }
60 |
61 | app.UseStaticFiles();
62 |
63 | app.UseMvc();
64 | }
65 | }
66 |
67 | public static class Constants
68 | {
69 | public const int SquareCount = 16;
70 | public const int SquaresPerLine = 4;
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/src/NdcBingo.Data/DatabaseMetrics.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using App.Metrics;
3 | using App.Metrics.Timer;
4 |
5 | namespace NdcBingo.Data
6 | {
7 | public static class DatabaseMetrics
8 | {
9 | private static readonly TimerOptions PlayerQuery = new TimerOptions
10 | {
11 | Name = "db_player_query",
12 | DurationUnit = TimeUnit.Milliseconds,
13 | RateUnit = TimeUnit.Minutes
14 | };
15 |
16 | public static IDisposable PlayerQueryTimer(this IMetrics metrics, string by) =>
17 | metrics.Measure.Timer.Time(PlayerQuery, new MetricTags("by", by));
18 |
19 | private static readonly TimerOptions PlayerCreate = new TimerOptions
20 | {
21 | Name = "db_player_create",
22 | DurationUnit = TimeUnit.Milliseconds,
23 | RateUnit = TimeUnit.Minutes
24 | };
25 |
26 | public static IDisposable PlayerCreateTimer(this IMetrics metrics) =>
27 | metrics.Measure.Timer.Time(PlayerCreate);
28 |
29 | private static readonly TimerOptions PlayerCountQuery = new TimerOptions
30 | {
31 | Name = "db_player_count_query",
32 | DurationUnit = TimeUnit.Milliseconds,
33 | RateUnit = TimeUnit.Minutes
34 | };
35 |
36 | public static IDisposable PlayerCountQueryTimer(this IMetrics metrics) =>
37 | metrics.Measure.Timer.Time(PlayerCountQuery);
38 |
39 | private static readonly TimerOptions PlayerIdDuplicateCheck = new TimerOptions
40 | {
41 | Name = "db_player_query",
42 | DurationUnit = TimeUnit.Milliseconds,
43 | RateUnit = TimeUnit.Minutes
44 | };
45 |
46 | public static IDisposable PlayerIdDuplicateCheckTimer(this IMetrics metrics) =>
47 | metrics.Measure.Timer.Time(PlayerIdDuplicateCheck);
48 |
49 | private static readonly TimerOptions RandomSquaresQuery = new TimerOptions
50 | {
51 | Name = "db_random_squares_query",
52 | DurationUnit = TimeUnit.Milliseconds,
53 | RateUnit = TimeUnit.Minutes
54 | };
55 |
56 | public static IDisposable RandomSquaresQueryTimer(this IMetrics metrics) =>
57 | metrics.Measure.Timer.Time(PlayerIdDuplicateCheck);
58 |
59 | private static readonly TimerOptions SquaresQuery = new TimerOptions
60 | {
61 | Name = "db_squares_query",
62 | DurationUnit = TimeUnit.Milliseconds,
63 | RateUnit = TimeUnit.Minutes
64 | };
65 |
66 | public static IDisposable SquaresQueryTimer(this IMetrics metrics) =>
67 | metrics.Measure.Timer.Time(PlayerIdDuplicateCheck);
68 | }
69 | }
--------------------------------------------------------------------------------
/src/NdcBingo/Controllers/PlayersController.cs:
--------------------------------------------------------------------------------
1 | using System.Threading.Tasks;
2 | using App.Metrics;
3 | using App.Metrics.Counter;
4 | using Microsoft.AspNetCore.Mvc;
5 | using Microsoft.Extensions.Logging;
6 | using NdcBingo.Data;
7 | using NdcBingo.Models.Players;
8 | using NdcBingo.Services;
9 |
10 | namespace NdcBingo.Controllers
11 | {
12 | [Route("players")]
13 | public class PlayersController : Controller
14 | {
15 | private readonly IPlayerData _playerData;
16 | private readonly IDataCookies _dataCookies;
17 | private readonly ILogger _logger;
18 | private readonly IMetrics _metrics;
19 |
20 | public PlayersController(ILogger logger, IDataCookies dataCookies, IPlayerData playerData, IMetrics metrics)
21 | {
22 | _logger = logger;
23 | _dataCookies = dataCookies;
24 | _playerData = playerData;
25 | _metrics = metrics;
26 | }
27 |
28 | [HttpGet("new")]
29 | public IActionResult New([FromQuery] string message, [FromQuery] string returnUrl)
30 | {
31 | var model = new NewViewModel
32 | {
33 | Message = message,
34 | Player = new NewPlayerViewModel(),
35 | ReturnUrl = returnUrl
36 | };
37 | return View(model);
38 | }
39 |
40 | [HttpPost]
41 | public async Task CreatePlayer([FromForm] NewPlayerViewModel model, [FromQuery]string returnUrl)
42 | {
43 | if (!string.IsNullOrWhiteSpace(model.Code))
44 | {
45 | var player = await _playerData.Get(model.Code);
46 | if (player == null)
47 | {
48 | return RedirectToAction("New", new {message = "No matching code found."});
49 | }
50 |
51 | _dataCookies.SetPlayerCode(player.Code);
52 | }
53 | else if (!string.IsNullOrWhiteSpace(model.Name))
54 | {
55 | var (created, player) = await _playerData.TryCreate(model.Name);
56 | if (!created)
57 | {
58 | return RedirectToAction("New", new {message = "Sorry, that name is taken."});
59 | }
60 |
61 | _dataCookies.SetPlayerCode(player.Code);
62 | }
63 | else
64 | {
65 | return RedirectToAction("New", new {message = "Enter a Name or Code."});
66 | }
67 |
68 | if (!string.IsNullOrWhiteSpace(model.ReturnUrl))
69 | {
70 | return Redirect(model.ReturnUrl);
71 | }
72 |
73 | return RedirectToAction("Play", "Game");
74 | }
75 | }
76 |
77 | }
--------------------------------------------------------------------------------
/src/NdcBingo/Views/Game/Play.cshtml:
--------------------------------------------------------------------------------
1 | @model NdcBingo.Models.Game.GameViewModel
2 |
3 | @{
4 | ViewBag.Title = "Game";
5 | Layout = "_Layout";
6 | }
7 |
8 |
9 |
10 |
@Model.PlayerName
11 |
Lines: @(Model.WinningLines) / 10
12 |
13 |
14 | @for (int r = 0; r < Model.Squares.Length; r += Model.ColumnCount)
15 | {
16 |
17 |
18 |
19 | @for (int s = 0; s < Model.ColumnCount; s++)
20 | {
21 | var square = Model.Squares[r + s];
22 | var color = square.Claimed ? "bg-info" : "bg-success";
23 |
24 |
29 | @if (square.Type.Equals("tech", StringComparison.OrdinalIgnoreCase))
30 | {
31 |
32 | }
33 | else if (square.Type.Equals("expo", StringComparison.OrdinalIgnoreCase))
34 | {
35 |
36 | }
37 | else
38 | {
39 |
40 | }
41 |
@square.Text
42 |
43 | }
44 |
45 |
46 |
47 | }
48 |
63 |
64 | @section Scripts
65 | {
66 |
67 | }
--------------------------------------------------------------------------------
/src/NdcBingo/Services/DataCookies.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using Microsoft.AspNetCore.Http;
5 | using NdcBingo.Data;
6 |
7 | namespace NdcBingo.Services
8 | {
9 | public class DataCookies : IDataCookies
10 | {
11 | private const string PlayerNameKey = "player_name";
12 | private const string PlayerSquaresKey = "player_squares";
13 | private const string PlayerClaimsKey = "player_claims";
14 | private readonly IHttpContextAccessor _contextAccessor;
15 |
16 | public DataCookies(IHttpContextAccessor contextAccessor)
17 | {
18 | _contextAccessor = contextAccessor;
19 | }
20 |
21 | public bool TryGetPlayerCode(out string code)
22 | {
23 | return _contextAccessor.HttpContext.Request.Cookies.TryGetValue(PlayerNameKey, out code);
24 | }
25 |
26 | public void SetPlayerCode(string code)
27 | {
28 | _contextAccessor.HttpContext.Response.Cookies.Append(PlayerNameKey, code, new CookieOptions
29 | {
30 | MaxAge = TimeSpan.FromDays(7)
31 | });
32 | }
33 |
34 | public bool TryGetPlayerSquares(out int[] ids)
35 | {
36 | if (!_contextAccessor.HttpContext.Request.Cookies.TryGetValue(PlayerSquaresKey, out var value))
37 | {
38 | ids = null;
39 | return false;
40 | }
41 |
42 | ids = value.Split(',', StringSplitOptions.RemoveEmptyEntries)
43 | .Select(s => int.TryParse(s, out int i) ? i : -1)
44 | .Where(i => i > -1)
45 | .ToArray();
46 | return true;
47 | }
48 |
49 | public void SetPlayerSquares(IEnumerable squares)
50 | {
51 | var value = string.Join(',', squares.Select(square => square.Id.ToString()));
52 | _contextAccessor.HttpContext.Response.Cookies.Append(PlayerSquaresKey, value, new CookieOptions
53 | {
54 | MaxAge = TimeSpan.FromDays(7)
55 | });
56 | }
57 |
58 | public bool TryGetPlayerClaims(out int[] ids)
59 | {
60 | if (!_contextAccessor.HttpContext.Request.Cookies.TryGetValue(PlayerClaimsKey, out var value))
61 | {
62 | ids = null;
63 | return false;
64 | }
65 |
66 | ids = value.Split(',', StringSplitOptions.RemoveEmptyEntries)
67 | .Select(s => int.TryParse(s, out int i) ? i : -1)
68 | .Where(i => i > -1)
69 | .ToArray();
70 |
71 | return true;
72 | }
73 |
74 | public void SetPlayerClaims(int[] claims)
75 | {
76 | var value = string.Join(',', claims.Select(c => c.ToString()));
77 |
78 | _contextAccessor.HttpContext.Response.Cookies.Append(PlayerClaimsKey, value, new CookieOptions
79 | {
80 | MaxAge = TimeSpan.FromDays(7),
81 | IsEssential = true
82 | });
83 | }
84 | }
85 | }
--------------------------------------------------------------------------------
/src/NdcBingo.Game/WinCondition.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace NdcBingo.Game
4 | {
5 | public class WinningLines
6 | {
7 | public int Horizontal { get; set; }
8 | public int Vertical { get; set; }
9 | public int Diagonal { get; set; }
10 | }
11 | public static class WinCondition
12 | {
13 | public static WinningLines Check(int[] claims)
14 | {
15 | double columnCountD = Math.Sqrt((double) claims.Length);
16 | if (Math.Abs(columnCountD % 1d) > double.Epsilon)
17 | {
18 | throw new ArgumentException("Array is not a square.");
19 | }
20 |
21 | int columnCount = (int) columnCountD;
22 |
23 | return new WinningLines
24 | {
25 | Horizontal = CheckHorizontalLines(claims, columnCount),
26 | Vertical = CheckVerticalLines(claims, columnCount),
27 | Diagonal = CheckDiagonalFromTopLeft(claims, columnCount) +
28 | CheckDiagonalFromTopRight(claims, columnCount)
29 | };
30 | }
31 |
32 | private static int CheckDiagonalFromTopRight(int[] claims, int columnCount)
33 | {
34 | int claimed = 0;
35 |
36 | for (int i = columnCount - 1, c = 0; c < columnCount; i += columnCount - 1, c++)
37 | {
38 | claimed += OneOrZero(claims[i]);
39 | }
40 |
41 | return claimed == columnCount ? 1 : 0;
42 | }
43 |
44 | private static int CheckDiagonalFromTopLeft(int[] claims, int columnCount)
45 | {
46 | int claimed = 0;
47 |
48 | for (int i = 0, l = claims.Length; i < l; i += columnCount + 1)
49 | {
50 | claimed += OneOrZero(claims[i]);
51 | }
52 |
53 | return claimed == columnCount ? 1 : 0;
54 | }
55 |
56 | private static int CheckVerticalLines(int[] claims, int columnCount)
57 | {
58 | int count = 0;
59 | for (int i = 0; i < columnCount; i++)
60 | {
61 | int claimed = 0;
62 | for (int j = 0, l = claims.Length; j < l; j += columnCount)
63 | {
64 | claimed += OneOrZero(claims[i + j]);
65 | }
66 |
67 | if (claimed == columnCount)
68 | {
69 | count++;
70 | }
71 | }
72 |
73 | return count;
74 | }
75 |
76 | private static int CheckHorizontalLines(int[] claims, int columnCount)
77 | {
78 | int count = 0;
79 | for (int i = 0, l = claims.Length; i < l; i += columnCount)
80 | {
81 | int claimed = 0;
82 | for (int j = 0; j < columnCount; j++)
83 | {
84 | claimed += OneOrZero(claims[i + j]);
85 | }
86 |
87 | if (claimed == columnCount)
88 | {
89 | count++;
90 | }
91 | }
92 |
93 | return count;
94 | }
95 |
96 | private static int OneOrZero(int n) => n == 0 ? 0 : 1;
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/src/NdcBingo.Data/PlayerData.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Threading.Tasks;
3 | using App.Metrics;
4 | using Microsoft.EntityFrameworkCore;
5 |
6 | namespace NdcBingo.Data
7 | {
8 | public class PlayerData : IPlayerData
9 | {
10 | private readonly BingoContext _context;
11 | private readonly IPlayerIdGenerator _playerIdGenerator;
12 | private readonly IMetrics _metrics;
13 |
14 | public PlayerData(BingoContext context, IPlayerIdGenerator playerIdGenerator, IMetrics metrics)
15 | {
16 | _context = context;
17 | _playerIdGenerator = playerIdGenerator;
18 | _metrics = metrics;
19 | }
20 |
21 | public async Task<(bool, Player)> TryCreate(string name)
22 | {
23 | using (_metrics.PlayerQueryTimer(nameof(name)))
24 | {
25 | if (await _context.Players.AnyAsync(p => p.Name == name))
26 | {
27 | return (false, default);
28 | }
29 | }
30 |
31 | var id = await GeneratePlayerIdAsync();
32 |
33 | var player = new Player
34 | {
35 | Id = id,
36 | Name = name
37 | };
38 |
39 | return await SavePlayerAsync(player);
40 | }
41 |
42 | private async Task<(bool, Player)> SavePlayerAsync(Player player)
43 | {
44 | _context.Players.Add(player);
45 | try
46 | {
47 | using (_metrics.PlayerCreateTimer())
48 | {
49 | await _context.SaveChangesAsync();
50 | }
51 |
52 | int playerCount;
53 | using (_metrics.PlayerCountQueryTimer())
54 | {
55 | playerCount = await _context.Players.CountAsync();
56 | }
57 |
58 | _metrics.SetPlayerCount(playerCount);
59 |
60 | return (true, player);
61 | }
62 | catch (Exception e)
63 | {
64 | return (false, default);
65 | }
66 | }
67 |
68 | private async Task GeneratePlayerIdAsync()
69 | {
70 | long id;
71 | using (_metrics.PlayerIdDuplicateCheckTimer())
72 | {
73 | do
74 | {
75 | id = _playerIdGenerator.Get();
76 | } while (await _context.Players.AnyAsync(p => p.Id == id));
77 | }
78 |
79 | return id;
80 | }
81 |
82 | public async Task Get(long id)
83 | {
84 | using (_metrics.PlayerQueryTimer(nameof(id)))
85 | {
86 | var player = await _context.Players.FirstOrDefaultAsync(p => p.Id == id);
87 | return player;
88 | }
89 | }
90 |
91 | public async Task Get(string code)
92 | {
93 | var id = Base36.Decode(code);
94 | using (_metrics.PlayerQueryTimer(nameof(code)))
95 | {
96 | var player = await _context.Players.FirstOrDefaultAsync(p => p.Id == id);
97 | return player;
98 | }
99 | }
100 | }
101 | }
--------------------------------------------------------------------------------
/test/NdcBingo.Game.Tests/WinConditionTests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using Xunit;
4 |
5 | namespace NdcBingo.Game.Tests
6 | {
7 | public class WinConditionTests
8 | {
9 | [Theory]
10 | [MemberData(nameof(WinningHorizontalLines))]
11 | public void HorizontalLinesWin(int[] claims)
12 | {
13 | Assert.Equal(1, WinCondition.Check(claims).Horizontal);
14 | }
15 |
16 | [Theory]
17 | [MemberData(nameof(WinningVerticalLines))]
18 | public void VerticalLinesWin(int[] claims)
19 | {
20 | Assert.Equal(1, WinCondition.Check(claims).Vertical);
21 | }
22 |
23 | [Theory]
24 | [MemberData(nameof(WinningDiagonalLines))]
25 | public void DiagonalLinesWin(int[] claims)
26 | {
27 | Assert.Equal(1, WinCondition.Check(claims).Diagonal);
28 | }
29 |
30 | public static IEnumerable WinningHorizontalLines()
31 | {
32 | yield return Claims(
33 | 1, 1, 1, 1,
34 | 0, 0, 0, 0,
35 | 0, 0, 0, 0,
36 | 0, 0, 0, 0
37 | );
38 | yield return Claims(
39 | 0, 0, 0, 0,
40 | 1, 1, 1, 1,
41 | 0, 0, 0, 0,
42 | 0, 0, 0, 0
43 | );
44 | yield return Claims(
45 | 0, 0, 0, 0,
46 | 0, 0, 0, 0,
47 | 1, 1, 1, 1,
48 | 0, 0, 0, 0
49 | );
50 | yield return Claims(
51 | 0, 0, 0, 0,
52 | 0, 0, 0, 0,
53 | 0, 0, 0, 0,
54 | 1, 1, 1, 1
55 | );
56 | }
57 |
58 | public static IEnumerable WinningVerticalLines()
59 | {
60 | yield return Claims(
61 | 1, 0, 0, 0,
62 | 1, 0, 0, 0,
63 | 1, 0, 0, 0,
64 | 1, 0, 0, 0
65 | );
66 | yield return Claims(
67 | 0, 1, 0, 0,
68 | 0, 1, 0, 0,
69 | 0, 1, 0, 0,
70 | 0, 1, 0, 0
71 | );
72 | yield return Claims(
73 | 0, 0, 1, 0,
74 | 0, 0, 1, 0,
75 | 0, 0, 1, 0,
76 | 0, 0, 1, 0
77 | );
78 | yield return Claims(
79 | 0, 0, 0, 1,
80 | 0, 0, 0, 1,
81 | 0, 0, 0, 1,
82 | 0, 0, 0, 1
83 | );
84 | }
85 |
86 | public static IEnumerable WinningDiagonalLines()
87 | {
88 | yield return Claims(
89 | 1, 0, 0, 0,
90 | 0, 1, 0, 0,
91 | 0, 0, 1, 0,
92 | 0, 0, 0, 1
93 | );
94 | yield return Claims(
95 | 0, 0, 0, 1,
96 | 0, 0, 1, 0,
97 | 0, 1, 0, 0,
98 | 1, 0, 0, 0
99 | );
100 | }
101 |
102 | private static object[] Claims(params int[] claims)
103 | {
104 | return new object[] { claims };
105 | }
106 | }
107 | }
--------------------------------------------------------------------------------
/src/NdcBingo/Views/Shared/_Layout.cshtml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | @ViewData["Title"] - NdcBingo
7 |
8 |
9 |
10 |
11 |
12 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
37 |
38 |
39 | @RenderBody()
40 |
41 |
42 |
43 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
60 |
66 |
67 |
68 |
69 | @RenderSection("Scripts", required: false)
70 |
71 |
72 |
--------------------------------------------------------------------------------
/src/NdcBingo/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.min.css:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap Reboot v4.1.3 (https://getbootstrap.com/)
3 | * Copyright 2011-2018 The Bootstrap Authors
4 | * Copyright 2011-2018 Twitter, Inc.
5 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
6 | * Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)
7 | */*,::after,::before{box-sizing:border-box}html{font-family:sans-serif;line-height:1.15;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;-ms-overflow-style:scrollbar;-webkit-tap-highlight-color:transparent}@-ms-viewport{width:device-width}article,aside,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}body{margin:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";font-size:1rem;font-weight:400;line-height:1.5;color:#212529;text-align:left;background-color:#fff}[tabindex="-1"]:focus{outline:0!important}hr{box-sizing:content-box;height:0;overflow:visible}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem}p{margin-top:0;margin-bottom:1rem}abbr[data-original-title],abbr[title]{text-decoration:underline;-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;border-bottom:0}address{margin-bottom:1rem;font-style:normal;line-height:inherit}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}dfn{font-style:italic}b,strong{font-weight:bolder}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#007bff;text-decoration:none;background-color:transparent;-webkit-text-decoration-skip:objects}a:hover{color:#0056b3;text-decoration:underline}a:not([href]):not([tabindex]){color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus,a:not([href]):not([tabindex]):hover{color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus{outline:0}code,kbd,pre,samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;font-size:1em}pre{margin-top:0;margin-bottom:1rem;overflow:auto;-ms-overflow-style:scrollbar}figure{margin:0 0 1rem}img{vertical-align:middle;border-style:none}svg{overflow:hidden;vertical-align:middle}table{border-collapse:collapse}caption{padding-top:.75rem;padding-bottom:.75rem;color:#6c757d;text-align:left;caption-side:bottom}th{text-align:inherit}label{display:inline-block;margin-bottom:.5rem}button{border-radius:0}button:focus{outline:1px dotted;outline:5px auto -webkit-focus-ring-color}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,input{overflow:visible}button,select{text-transform:none}[type=reset],[type=submit],button,html [type=button]{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{padding:0;border-style:none}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}input[type=date],input[type=datetime-local],input[type=month],input[type=time]{-webkit-appearance:listbox}textarea{overflow:auto;resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;max-width:100%;padding:0;margin-bottom:.5rem;font-size:1.5rem;line-height:inherit;color:inherit;white-space:normal}progress{vertical-align:baseline}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:none}[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}summary{display:list-item;cursor:pointer}template{display:none}[hidden]{display:none!important}
8 | /*# sourceMappingURL=bootstrap-reboot.min.css.map */
--------------------------------------------------------------------------------
/data/NDCPorto2019.csv:
--------------------------------------------------------------------------------
1 | name,start_time,end_time,time_zone
2 | The Moon: Gateway to the Solar System,2019-02-28T08:00:00,2019-02-28T09:00:00,1
3 | Insecure Transit - Microservice Security,2019-02-28T09:20:00,2019-02-28T10:20:00,1
4 | C# 8 and Beyond,2019-02-28T09:20:00,2019-02-28T10:20:00,1
5 | The secret unit testing tools no-one ever told you about,2019-02-28T09:20:00,2019-02-28T10:20:00,1
6 | Neural Networks: A Primer,2019-02-28T09:20:00,2019-02-28T10:20:00,1
7 | Securing Web Applications and APIs with ASP.NET Core 2.2 and 3.0,2019-02-28T10:40:00,2019-02-28T11:40:00,1
8 | How to build a social network entirely on serverless,2019-02-28T10:40:00,2019-02-28T11:40:00,1
9 | Using Kotlin Coroutines for Asynchronous and Concurrent Programming,2019-02-28T10:40:00,2019-02-28T11:40:00,1
10 | Six Little Lines of Fail,2019-02-28T10:40:00,2019-02-28T11:40:00,1
11 | Embracing Messaging and Eventual Consistency in your Microservices Solutions,2019-02-28T12:40:00,2019-02-28T13:40:00,1
12 | I have 99 problems but GraphQL is not one,2019-02-28T12:40:00,2019-02-28T13:40:00,1
13 | The Enterprise DevOps Challenge,2019-02-28T12:40:00,2019-02-28T13:40:00,1
14 | Adapting ASP.NET Core MVC to your needs,2019-02-28T12:40:00,2019-02-28T13:40:00,1
15 | Async Injection,2019-02-28T14:00:00,2019-02-28T15:00:00,1
16 | Building Clients for OpenID Connect/OAuth2-based Systems,2019-02-28T14:00:00,2019-02-28T15:00:00,1
17 | Finding your service boundaries - a practical guide,2019-02-28T14:00:00,2019-02-28T15:00:00,1
18 | Rock-Solid Components with TypeScript and GraphQL,2019-02-28T14:00:00,2019-02-28T15:00:00,1
19 | Using C# Expression Trees in the Real World,2019-02-28T15:20:00,2019-02-28T16:20:00,1
20 | Implement DevSecOps in Azure,2019-02-28T15:20:00,2019-02-28T16:20:00,1
21 | Natural Language Processing with Deep Learning and TensorFlow,2019-02-28T15:20:00,2019-02-28T16:20:00,1
22 | "ARMGDN - Build modern web apps using Apollo, React, MobX GraphQL, Db and Node.js",2019-02-28T15:20:00,2019-02-28T16:20:00,1
23 | Hacking your work life balance to take over the world,2019-02-28T16:40:00,2019-02-28T17:40:00,1
24 | Functional-first programming with F#,2019-02-28T16:40:00,2019-02-28T17:40:00,1
25 | Practical Security for Web Applications,2019-02-28T16:40:00,2019-02-28T17:40:00,1
26 | .NET Rocks Live,2019-02-28T16:40:00,2019-02-28T17:40:00,1
27 | How to seamlessly transition from Developer to Leader,2019-03-01T08:00:00,2019-03-01T09:00:00,1
28 | "Tabs, spaces and salaries: a data science detective story",2019-03-01T08:00:00,2019-03-01T09:00:00,1
29 | Give it a REST - Tips for designing and consuming public APIs,2019-03-01T08:00:00,2019-03-01T09:00:00,1
30 | Building Progressive Web Apps with React,2019-03-01T08:00:00,2019-03-01T09:00:00,1
31 | Kubernetes - going beyond the basics,2019-03-01T09:20:00,2019-03-01T10:20:00,1
32 | A Practical Guide to Dashboarding,2019-03-01T09:20:00,2019-03-01T10:20:00,1
33 | Need for speed 8 - performance tuning of your web application,2019-03-01T09:20:00,2019-03-01T10:20:00,1
34 | "Build software like a bag of marbles, not a castle of LEGO",2019-03-01T09:20:00,2019-03-01T10:20:00,1
35 | Containers for Real Integration Tests,2019-03-01T10:40:00,2019-03-01T11:40:00,1
36 | "Dungeons, Dragons and Functions",2019-03-01T10:40:00,2019-03-01T11:40:00,1
37 | Measure All The Things with App Metrics,2019-03-01T10:40:00,2019-03-01T11:40:00,1
38 | "Using Service Meshes and Kubernetes to Solve Service-to-Service Communications, Scaling and Security",2019-03-01T10:40:00,2019-03-01T11:40:00,1
39 | Build vs Buy: Software Systems at Jurassic Park,2019-03-01T12:40:00,2019-03-01T13:40:00,1
40 | "Drones, AI and IoT - What's all the buzz about?",2019-03-01T12:40:00,2019-03-01T13:40:00,1
41 | HTTPS in ASP.NET Core 2 in Docker Linux Containers Deep Dive,2019-03-01T12:40:00,2019-03-01T13:40:00,1
42 | Breaking Down Your Build: Architectural Patterns For A More Efficient Pipeline,2019-03-01T12:40:00,2019-03-01T13:40:00,1
43 | Reactive DDD - When Concurrent Waxes Fluent,2019-03-01T14:00:00,2019-03-01T15:00:00,1
44 | Handy Tools for Designing Great Web APIs,2019-03-01T14:00:00,2019-03-01T15:00:00,1
45 | Manual Memory management in .NET Framework,2019-03-01T14:00:00,2019-03-01T15:00:00,1
46 | Migrating to Microservice Databases: From Relational Monolith to Distributed Data,2019-03-01T14:00:00,2019-03-01T15:00:00,1
47 | The Web That Never Was,2019-03-01T15:20:00,2019-03-01T16:20:00,1
48 | Leadership Guide for the Reluctant Leader,2019-03-01T15:20:00,2019-03-01T16:20:00,1
49 | Agile Software Architecture,2019-03-01T15:20:00,2019-03-01T16:20:00,1
50 | Real Quantum Computing,2019-03-01T15:20:00,2019-03-01T16:20:00,1
51 |
--------------------------------------------------------------------------------
/src/NdcBingo/Controllers/GameController.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 | using System.Threading.Tasks;
4 | using Microsoft.AspNetCore.Mvc;
5 | using NdcBingo.Data;
6 | using NdcBingo.Game;
7 | using NdcBingo.Models.Game;
8 | using NdcBingo.Services;
9 |
10 | namespace NdcBingo.Controllers
11 | {
12 | [Route("game")]
13 | public class GameController : Controller
14 | {
15 | private readonly IPlayerData _playerData;
16 | private readonly ISquareData _squareData;
17 | private readonly IDataCookies _dataCookies;
18 |
19 | public GameController(ISquareData squareData, IDataCookies dataCookies, IPlayerData playerData)
20 | {
21 | _squareData = squareData;
22 | _dataCookies = dataCookies;
23 | _playerData = playerData;
24 | }
25 |
26 | [HttpGet]
27 | [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
28 | public async Task Play()
29 | {
30 | if (!_dataCookies.TryGetPlayerCode(out var code))
31 | {
32 | return RedirectToAction("New", "Players", new {returnUrl = Url.Action("Play")});
33 | }
34 |
35 | var player = await _playerData.Get(code);
36 | if (player == null)
37 | {
38 | return RedirectToAction("New", "Players", new {returnUrl = Url.Action("Play")});
39 | }
40 |
41 | var vm = await CreateGameViewModel();
42 | vm.ColumnCount = Constants.SquaresPerLine;
43 |
44 | vm.PlayerName = player.Name;
45 |
46 | return View(vm);
47 | }
48 |
49 | private async Task CreateGameViewModel()
50 | {
51 | GameViewModel vm;
52 | if (_dataCookies.TryGetPlayerSquares(out var squareIds))
53 | {
54 | vm = await CreateGameInProgressViewModel(squareIds);
55 | }
56 | else
57 | {
58 | vm = await CreateNewGameViewModel();
59 | }
60 |
61 | foreach (var square in vm.Squares.Where(s => !s.Claimed))
62 | {
63 | square.ClaimLink = Url.Action("Claim", new {squareId = square.Id});
64 | }
65 |
66 | return vm;
67 | }
68 |
69 | [HttpGet("claim/{squareId}")]
70 | [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
71 | public IActionResult Claim(int squareId)
72 | {
73 | if (_dataCookies.TryGetPlayerSquares(out var squareIds))
74 | {
75 | int index = Array.IndexOf(squareIds, squareId);
76 | if (index > -1)
77 | {
78 | if (!_dataCookies.TryGetPlayerClaims(out var claims))
79 | {
80 | claims = new int[Constants.SquareCount];
81 | }
82 |
83 | claims[index] = 1;
84 | _dataCookies.SetPlayerClaims(claims);
85 | }
86 | }
87 |
88 | return RedirectToAction("Play");
89 | }
90 |
91 | private async Task CreateNewGameViewModel()
92 | {
93 | GameViewModel vm;
94 | var squares = await _squareData.GetRandomSquaresAsync(Constants.SquareCount);
95 | vm = new GameViewModel
96 | {
97 | Squares = squares.Select(s => new SquareViewModel(s.Id, s.Text, s.Type, s.Description)).ToArray(),
98 | Claims = new int[Constants.SquareCount]
99 | };
100 | _dataCookies.SetPlayerSquares(squares);
101 | _dataCookies.SetPlayerClaims(new int[Constants.SquareCount]);
102 | return vm;
103 | }
104 |
105 | private async Task CreateGameInProgressViewModel(int[] squareIds)
106 | {
107 | var squares = await _squareData.GetSquaresAsync(squareIds);
108 | var vm = new GameViewModel
109 | {
110 | Squares = squares.Select(s => new SquareViewModel(s.Id, s.Text, s.Type, s.Description)).ToArray()
111 | };
112 | if (_dataCookies.TryGetPlayerClaims(out var claims))
113 | {
114 | for (int i = 0, l = Math.Min(vm.Squares.Length, claims.Length); i < l; i++)
115 | {
116 | vm.Squares[i].Claimed = claims[i] > 0;
117 | }
118 |
119 | var winningLines = WinCondition.Check(claims);
120 | vm.WinningLines = winningLines.Horizontal + winningLines.Vertical + winningLines.Diagonal;
121 | }
122 |
123 | return vm;
124 | }
125 | }
126 | }
--------------------------------------------------------------------------------
/src/NdcBingo/wwwroot/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js:
--------------------------------------------------------------------------------
1 | // Unobtrusive validation support library for jQuery and jQuery Validate
2 | // Copyright (c) .NET Foundation. All rights reserved.
3 | // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
4 | // @version v3.2.11
5 | !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/NdcBingo/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.css:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap Reboot v4.1.3 (https://getbootstrap.com/)
3 | * Copyright 2011-2018 The Bootstrap Authors
4 | * Copyright 2011-2018 Twitter, Inc.
5 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
6 | * Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)
7 | */
8 | *,
9 | *::before,
10 | *::after {
11 | box-sizing: border-box;
12 | }
13 |
14 | html {
15 | font-family: sans-serif;
16 | line-height: 1.15;
17 | -webkit-text-size-adjust: 100%;
18 | -ms-text-size-adjust: 100%;
19 | -ms-overflow-style: scrollbar;
20 | -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
21 | }
22 |
23 | @-ms-viewport {
24 | width: device-width;
25 | }
26 |
27 | article, aside, figcaption, figure, footer, header, hgroup, main, nav, section {
28 | display: block;
29 | }
30 |
31 | body {
32 | margin: 0;
33 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
34 | font-size: 1rem;
35 | font-weight: 400;
36 | line-height: 1.5;
37 | color: #212529;
38 | text-align: left;
39 | background-color: #fff;
40 | }
41 |
42 | [tabindex="-1"]:focus {
43 | outline: 0 !important;
44 | }
45 |
46 | hr {
47 | box-sizing: content-box;
48 | height: 0;
49 | overflow: visible;
50 | }
51 |
52 | h1, h2, h3, h4, h5, h6 {
53 | margin-top: 0;
54 | margin-bottom: 0.5rem;
55 | }
56 |
57 | p {
58 | margin-top: 0;
59 | margin-bottom: 1rem;
60 | }
61 |
62 | abbr[title],
63 | abbr[data-original-title] {
64 | text-decoration: underline;
65 | -webkit-text-decoration: underline dotted;
66 | text-decoration: underline dotted;
67 | cursor: help;
68 | border-bottom: 0;
69 | }
70 |
71 | address {
72 | margin-bottom: 1rem;
73 | font-style: normal;
74 | line-height: inherit;
75 | }
76 |
77 | ol,
78 | ul,
79 | dl {
80 | margin-top: 0;
81 | margin-bottom: 1rem;
82 | }
83 |
84 | ol ol,
85 | ul ul,
86 | ol ul,
87 | ul ol {
88 | margin-bottom: 0;
89 | }
90 |
91 | dt {
92 | font-weight: 700;
93 | }
94 |
95 | dd {
96 | margin-bottom: .5rem;
97 | margin-left: 0;
98 | }
99 |
100 | blockquote {
101 | margin: 0 0 1rem;
102 | }
103 |
104 | dfn {
105 | font-style: italic;
106 | }
107 |
108 | b,
109 | strong {
110 | font-weight: bolder;
111 | }
112 |
113 | small {
114 | font-size: 80%;
115 | }
116 |
117 | sub,
118 | sup {
119 | position: relative;
120 | font-size: 75%;
121 | line-height: 0;
122 | vertical-align: baseline;
123 | }
124 |
125 | sub {
126 | bottom: -.25em;
127 | }
128 |
129 | sup {
130 | top: -.5em;
131 | }
132 |
133 | a {
134 | color: #007bff;
135 | text-decoration: none;
136 | background-color: transparent;
137 | -webkit-text-decoration-skip: objects;
138 | }
139 |
140 | a:hover {
141 | color: #0056b3;
142 | text-decoration: underline;
143 | }
144 |
145 | a:not([href]):not([tabindex]) {
146 | color: inherit;
147 | text-decoration: none;
148 | }
149 |
150 | a:not([href]):not([tabindex]):hover, a:not([href]):not([tabindex]):focus {
151 | color: inherit;
152 | text-decoration: none;
153 | }
154 |
155 | a:not([href]):not([tabindex]):focus {
156 | outline: 0;
157 | }
158 |
159 | pre,
160 | code,
161 | kbd,
162 | samp {
163 | font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
164 | font-size: 1em;
165 | }
166 |
167 | pre {
168 | margin-top: 0;
169 | margin-bottom: 1rem;
170 | overflow: auto;
171 | -ms-overflow-style: scrollbar;
172 | }
173 |
174 | figure {
175 | margin: 0 0 1rem;
176 | }
177 |
178 | img {
179 | vertical-align: middle;
180 | border-style: none;
181 | }
182 |
183 | svg {
184 | overflow: hidden;
185 | vertical-align: middle;
186 | }
187 |
188 | table {
189 | border-collapse: collapse;
190 | }
191 |
192 | caption {
193 | padding-top: 0.75rem;
194 | padding-bottom: 0.75rem;
195 | color: #6c757d;
196 | text-align: left;
197 | caption-side: bottom;
198 | }
199 |
200 | th {
201 | text-align: inherit;
202 | }
203 |
204 | label {
205 | display: inline-block;
206 | margin-bottom: 0.5rem;
207 | }
208 |
209 | button {
210 | border-radius: 0;
211 | }
212 |
213 | button:focus {
214 | outline: 1px dotted;
215 | outline: 5px auto -webkit-focus-ring-color;
216 | }
217 |
218 | input,
219 | button,
220 | select,
221 | optgroup,
222 | textarea {
223 | margin: 0;
224 | font-family: inherit;
225 | font-size: inherit;
226 | line-height: inherit;
227 | }
228 |
229 | button,
230 | input {
231 | overflow: visible;
232 | }
233 |
234 | button,
235 | select {
236 | text-transform: none;
237 | }
238 |
239 | button,
240 | html [type="button"],
241 | [type="reset"],
242 | [type="submit"] {
243 | -webkit-appearance: button;
244 | }
245 |
246 | button::-moz-focus-inner,
247 | [type="button"]::-moz-focus-inner,
248 | [type="reset"]::-moz-focus-inner,
249 | [type="submit"]::-moz-focus-inner {
250 | padding: 0;
251 | border-style: none;
252 | }
253 |
254 | input[type="radio"],
255 | input[type="checkbox"] {
256 | box-sizing: border-box;
257 | padding: 0;
258 | }
259 |
260 | input[type="date"],
261 | input[type="time"],
262 | input[type="datetime-local"],
263 | input[type="month"] {
264 | -webkit-appearance: listbox;
265 | }
266 |
267 | textarea {
268 | overflow: auto;
269 | resize: vertical;
270 | }
271 |
272 | fieldset {
273 | min-width: 0;
274 | padding: 0;
275 | margin: 0;
276 | border: 0;
277 | }
278 |
279 | legend {
280 | display: block;
281 | width: 100%;
282 | max-width: 100%;
283 | padding: 0;
284 | margin-bottom: .5rem;
285 | font-size: 1.5rem;
286 | line-height: inherit;
287 | color: inherit;
288 | white-space: normal;
289 | }
290 |
291 | progress {
292 | vertical-align: baseline;
293 | }
294 |
295 | [type="number"]::-webkit-inner-spin-button,
296 | [type="number"]::-webkit-outer-spin-button {
297 | height: auto;
298 | }
299 |
300 | [type="search"] {
301 | outline-offset: -2px;
302 | -webkit-appearance: none;
303 | }
304 |
305 | [type="search"]::-webkit-search-cancel-button,
306 | [type="search"]::-webkit-search-decoration {
307 | -webkit-appearance: none;
308 | }
309 |
310 | ::-webkit-file-upload-button {
311 | font: inherit;
312 | -webkit-appearance: button;
313 | }
314 |
315 | output {
316 | display: inline-block;
317 | }
318 |
319 | summary {
320 | display: list-item;
321 | cursor: pointer;
322 | }
323 |
324 | template {
325 | display: none;
326 | }
327 |
328 | [hidden] {
329 | display: none !important;
330 | }
331 | /*# sourceMappingURL=bootstrap-reboot.css.map */
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 | ##
4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
5 |
6 | # User-specific files
7 | *.suo
8 | *.user
9 | *.userosscache
10 | *.sln.docstates
11 |
12 | # User-specific files (MonoDevelop/Xamarin Studio)
13 | *.userprefs
14 |
15 | # Build results
16 | [Dd]ebug/
17 | [Dd]ebugPublic/
18 | [Rr]elease/
19 | [Rr]eleases/
20 | x64/
21 | x86/
22 | bld/
23 | [Bb]in/
24 | [Oo]bj/
25 | [Ll]og/
26 |
27 | # Visual Studio 2015/2017 cache/options directory
28 | .vs/
29 | .vscode/
30 | # Uncomment if you have tasks that create the project's static files in wwwroot
31 | #wwwroot/
32 |
33 | # Visual Studio 2017 auto generated files
34 | Generated\ Files/
35 |
36 | # MSTest test Results
37 | [Tt]est[Rr]esult*/
38 | [Bb]uild[Ll]og.*
39 |
40 | # NUNIT
41 | *.VisualState.xml
42 | TestResult.xml
43 |
44 | # Build Results of an ATL Project
45 | [Dd]ebugPS/
46 | [Rr]eleasePS/
47 | dlldata.c
48 |
49 | # Benchmark Results
50 | BenchmarkDotNet.Artifacts/
51 |
52 | # .NET Core
53 | project.lock.json
54 | project.fragment.lock.json
55 | artifacts/
56 | **/Properties/launchSettings.json
57 |
58 | # StyleCop
59 | StyleCopReport.xml
60 |
61 | # Files built by Visual Studio
62 | *_i.c
63 | *_p.c
64 | *_i.h
65 | *.ilk
66 | *.meta
67 | *.obj
68 | *.iobj
69 | *.pch
70 | *.pdb
71 | *.ipdb
72 | *.pgc
73 | *.pgd
74 | *.rsp
75 | *.sbr
76 | *.tlb
77 | *.tli
78 | *.tlh
79 | *.tmp
80 | *.tmp_proj
81 | *.log
82 | *.vspscc
83 | *.vssscc
84 | .builds
85 | *.pidb
86 | *.svclog
87 | *.scc
88 |
89 | # Chutzpah Test files
90 | _Chutzpah*
91 |
92 | # Visual C++ cache files
93 | ipch/
94 | *.aps
95 | *.ncb
96 | *.opendb
97 | *.opensdf
98 | *.sdf
99 | *.cachefile
100 | *.VC.db
101 | *.VC.VC.opendb
102 |
103 | # Visual Studio profiler
104 | *.psess
105 | *.vsp
106 | *.vspx
107 | *.sap
108 |
109 | # Visual Studio Trace Files
110 | *.e2e
111 |
112 | # TFS 2012 Local Workspace
113 | $tf/
114 |
115 | # Guidance Automation Toolkit
116 | *.gpState
117 |
118 | # ReSharper is a .NET coding add-in
119 | _ReSharper*/
120 | *.[Rr]e[Ss]harper
121 | *.DotSettings.user
122 |
123 | # JustCode is a .NET coding add-in
124 | .JustCode
125 |
126 | # TeamCity is a build add-in
127 | _TeamCity*
128 |
129 | # DotCover is a Code Coverage Tool
130 | *.dotCover
131 |
132 | # AxoCover is a Code Coverage Tool
133 | .axoCover/*
134 | !.axoCover/settings.json
135 |
136 | # Visual Studio code coverage results
137 | *.coverage
138 | *.coveragexml
139 |
140 | # NCrunch
141 | _NCrunch_*
142 | .*crunch*.local.xml
143 | nCrunchTemp_*
144 |
145 | # MightyMoose
146 | *.mm.*
147 | AutoTest.Net/
148 |
149 | # Web workbench (sass)
150 | .sass-cache/
151 |
152 | # Installshield output folder
153 | [Ee]xpress/
154 |
155 | # DocProject is a documentation generator add-in
156 | DocProject/buildhelp/
157 | DocProject/Help/*.HxT
158 | DocProject/Help/*.HxC
159 | DocProject/Help/*.hhc
160 | DocProject/Help/*.hhk
161 | DocProject/Help/*.hhp
162 | DocProject/Help/Html2
163 | DocProject/Help/html
164 |
165 | # Click-Once directory
166 | publish/
167 |
168 | # Publish Web Output
169 | *.[Pp]ublish.xml
170 | *.azurePubxml
171 | # Note: Comment the next line if you want to checkin your web deploy settings,
172 | # but database connection strings (with potential passwords) will be unencrypted
173 | *.pubxml
174 | *.publishproj
175 |
176 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
177 | # checkin your Azure Web App publish settings, but sensitive information contained
178 | # in these scripts will be unencrypted
179 | PublishScripts/
180 |
181 | # NuGet Packages
182 | *.nupkg
183 | # The packages folder can be ignored because of Package Restore
184 | **/[Pp]ackages/*
185 | # except build/, which is used as an MSBuild target.
186 | !**/[Pp]ackages/build/
187 | # Uncomment if necessary however generally it will be regenerated when needed
188 | #!**/[Pp]ackages/repositories.config
189 | # NuGet v3's project.json files produces more ignorable files
190 | *.nuget.props
191 | *.nuget.targets
192 |
193 | # Microsoft Azure Build Output
194 | csx/
195 | *.build.csdef
196 |
197 | # Microsoft Azure Emulator
198 | ecf/
199 | rcf/
200 |
201 | # Windows Store app package directories and files
202 | AppPackages/
203 | BundleArtifacts/
204 | Package.StoreAssociation.xml
205 | _pkginfo.txt
206 | *.appx
207 |
208 | # Visual Studio cache files
209 | # files ending in .cache can be ignored
210 | *.[Cc]ache
211 | # but keep track of directories ending in .cache
212 | !*.[Cc]ache/
213 |
214 | # Others
215 | ClientBin/
216 | ~$*
217 | *~
218 | *.dbmdl
219 | *.dbproj.schemaview
220 | *.jfm
221 | *.pfx
222 | *.publishsettings
223 | orleans.codegen.cs
224 |
225 | # Including strong name files can present a security risk
226 | # (https://github.com/github/gitignore/pull/2483#issue-259490424)
227 | #*.snk
228 |
229 | # Since there are multiple workflows, uncomment next line to ignore bower_components
230 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
231 | #bower_components/
232 |
233 | # RIA/Silverlight projects
234 | Generated_Code/
235 |
236 | # Backup & report files from converting an old project file
237 | # to a newer Visual Studio version. Backup files are not needed,
238 | # because we have git ;-)
239 | _UpgradeReport_Files/
240 | Backup*/
241 | UpgradeLog*.XML
242 | UpgradeLog*.htm
243 | ServiceFabricBackup/
244 | *.rptproj.bak
245 |
246 | # SQL Server files
247 | *.mdf
248 | *.ldf
249 | *.ndf
250 |
251 | # Business Intelligence projects
252 | *.rdl.data
253 | *.bim.layout
254 | *.bim_*.settings
255 | *.rptproj.rsuser
256 |
257 | # Microsoft Fakes
258 | FakesAssemblies/
259 |
260 | # GhostDoc plugin setting file
261 | *.GhostDoc.xml
262 |
263 | # Node.js Tools for Visual Studio
264 | .ntvs_analysis.dat
265 | node_modules/
266 |
267 | # Visual Studio 6 build log
268 | *.plg
269 |
270 | # Visual Studio 6 workspace options file
271 | *.opt
272 |
273 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
274 | *.vbw
275 |
276 | # Visual Studio LightSwitch build output
277 | **/*.HTMLClient/GeneratedArtifacts
278 | **/*.DesktopClient/GeneratedArtifacts
279 | **/*.DesktopClient/ModelManifest.xml
280 | **/*.Server/GeneratedArtifacts
281 | **/*.Server/ModelManifest.xml
282 | _Pvt_Extensions
283 |
284 | # Paket dependency manager
285 | .paket/paket.exe
286 | paket-files/
287 |
288 | # FAKE - F# Make
289 | .fake/
290 |
291 | # JetBrains Rider
292 | .idea/
293 | *.sln.iml
294 |
295 | # CodeRush
296 | .cr/
297 |
298 | # Python Tools for Visual Studio (PTVS)
299 | __pycache__/
300 | *.pyc
301 |
302 | # Cake - Uncomment if you are using it
303 | # tools/**
304 | # !tools/packages.config
305 |
306 | # Tabs Studio
307 | *.tss
308 |
309 | # Telerik's JustMock configuration file
310 | *.jmconfig
311 |
312 | # BizTalk build output
313 | *.btp.cs
314 | *.btm.cs
315 | *.odx.cs
316 | *.xsd.cs
317 |
318 | # OpenCover UI analysis results
319 | OpenCover/
320 |
321 | # Azure Stream Analytics local run output
322 | ASALocalRun/
323 |
324 | # MSBuild Binary and Structured Log
325 | *.binlog
326 |
327 | # NVidia Nsight GPU debugger configuration file
328 | *.nvuser
329 |
330 | # MFractors (Xamarin productivity tool) working folder
331 | .mfractor/
332 |
--------------------------------------------------------------------------------
/NdcBingo.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 15
4 | VisualStudioVersion = 15.0.26124.0
5 | MinimumVisualStudioVersion = 15.0.26124.0
6 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{CE143445-2075-49E2-B46D-92D4EDDB600E}"
7 | EndProject
8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NdcBingo", "src\NdcBingo\NdcBingo.csproj", "{C8CFFFA3-B699-4189-922B-660FDCE4FB88}"
9 | EndProject
10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NdcBingo.Data", "src\NdcBingo.Data\NdcBingo.Data.csproj", "{6E9632A9-CA7C-4AF6-804A-67046B09023F}"
11 | EndProject
12 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NdcBingo.Data.Migrate", "src\NdcBingo.Data.Migrate\NdcBingo.Data.Migrate.csproj", "{4172F589-AA5C-4784-A0C2-9739FD4CBB39}"
13 | EndProject
14 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{E3B5ECC6-545F-4147-ABE8-5BCAD5E54FA6}"
15 | EndProject
16 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NdcBingo.Data.Tests", "test\NdcBingo.Data.Tests\NdcBingo.Data.Tests.csproj", "{96D84947-8E8B-4AAB-96C2-F147C961D824}"
17 | EndProject
18 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NdcBingo.Game", "src\NdcBingo.Game\NdcBingo.Game.csproj", "{3BD31689-54B9-4AD4-8046-0F2783BEAEE2}"
19 | EndProject
20 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NdcBingo.Game.Tests", "test\NdcBingo.Game.Tests\NdcBingo.Game.Tests.csproj", "{A982C089-8B6F-4B80-A1A6-6CC689B496DB}"
21 | EndProject
22 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NdcBingo.ClrMetrics", "src\NdcBingo.ClrMetrics\NdcBingo.ClrMetrics.csproj", "{7EC2EC82-22C9-4CE6-88F2-F80D40A12718}"
23 | EndProject
24 | Global
25 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
26 | Debug|Any CPU = Debug|Any CPU
27 | Debug|x64 = Debug|x64
28 | Debug|x86 = Debug|x86
29 | Release|Any CPU = Release|Any CPU
30 | Release|x64 = Release|x64
31 | Release|x86 = Release|x86
32 | EndGlobalSection
33 | GlobalSection(SolutionProperties) = preSolution
34 | HideSolutionNode = FALSE
35 | EndGlobalSection
36 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
37 | {C8CFFFA3-B699-4189-922B-660FDCE4FB88}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
38 | {C8CFFFA3-B699-4189-922B-660FDCE4FB88}.Debug|Any CPU.Build.0 = Debug|Any CPU
39 | {C8CFFFA3-B699-4189-922B-660FDCE4FB88}.Debug|x64.ActiveCfg = Debug|Any CPU
40 | {C8CFFFA3-B699-4189-922B-660FDCE4FB88}.Debug|x64.Build.0 = Debug|Any CPU
41 | {C8CFFFA3-B699-4189-922B-660FDCE4FB88}.Debug|x86.ActiveCfg = Debug|Any CPU
42 | {C8CFFFA3-B699-4189-922B-660FDCE4FB88}.Debug|x86.Build.0 = Debug|Any CPU
43 | {C8CFFFA3-B699-4189-922B-660FDCE4FB88}.Release|Any CPU.ActiveCfg = Release|Any CPU
44 | {C8CFFFA3-B699-4189-922B-660FDCE4FB88}.Release|Any CPU.Build.0 = Release|Any CPU
45 | {C8CFFFA3-B699-4189-922B-660FDCE4FB88}.Release|x64.ActiveCfg = Release|Any CPU
46 | {C8CFFFA3-B699-4189-922B-660FDCE4FB88}.Release|x64.Build.0 = Release|Any CPU
47 | {C8CFFFA3-B699-4189-922B-660FDCE4FB88}.Release|x86.ActiveCfg = Release|Any CPU
48 | {C8CFFFA3-B699-4189-922B-660FDCE4FB88}.Release|x86.Build.0 = Release|Any CPU
49 | {6E9632A9-CA7C-4AF6-804A-67046B09023F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
50 | {6E9632A9-CA7C-4AF6-804A-67046B09023F}.Debug|Any CPU.Build.0 = Debug|Any CPU
51 | {6E9632A9-CA7C-4AF6-804A-67046B09023F}.Debug|x64.ActiveCfg = Debug|Any CPU
52 | {6E9632A9-CA7C-4AF6-804A-67046B09023F}.Debug|x64.Build.0 = Debug|Any CPU
53 | {6E9632A9-CA7C-4AF6-804A-67046B09023F}.Debug|x86.ActiveCfg = Debug|Any CPU
54 | {6E9632A9-CA7C-4AF6-804A-67046B09023F}.Debug|x86.Build.0 = Debug|Any CPU
55 | {6E9632A9-CA7C-4AF6-804A-67046B09023F}.Release|Any CPU.ActiveCfg = Release|Any CPU
56 | {6E9632A9-CA7C-4AF6-804A-67046B09023F}.Release|Any CPU.Build.0 = Release|Any CPU
57 | {6E9632A9-CA7C-4AF6-804A-67046B09023F}.Release|x64.ActiveCfg = Release|Any CPU
58 | {6E9632A9-CA7C-4AF6-804A-67046B09023F}.Release|x64.Build.0 = Release|Any CPU
59 | {6E9632A9-CA7C-4AF6-804A-67046B09023F}.Release|x86.ActiveCfg = Release|Any CPU
60 | {6E9632A9-CA7C-4AF6-804A-67046B09023F}.Release|x86.Build.0 = Release|Any CPU
61 | {4172F589-AA5C-4784-A0C2-9739FD4CBB39}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
62 | {4172F589-AA5C-4784-A0C2-9739FD4CBB39}.Debug|Any CPU.Build.0 = Debug|Any CPU
63 | {4172F589-AA5C-4784-A0C2-9739FD4CBB39}.Debug|x64.ActiveCfg = Debug|Any CPU
64 | {4172F589-AA5C-4784-A0C2-9739FD4CBB39}.Debug|x64.Build.0 = Debug|Any CPU
65 | {4172F589-AA5C-4784-A0C2-9739FD4CBB39}.Debug|x86.ActiveCfg = Debug|Any CPU
66 | {4172F589-AA5C-4784-A0C2-9739FD4CBB39}.Debug|x86.Build.0 = Debug|Any CPU
67 | {4172F589-AA5C-4784-A0C2-9739FD4CBB39}.Release|Any CPU.ActiveCfg = Release|Any CPU
68 | {4172F589-AA5C-4784-A0C2-9739FD4CBB39}.Release|Any CPU.Build.0 = Release|Any CPU
69 | {4172F589-AA5C-4784-A0C2-9739FD4CBB39}.Release|x64.ActiveCfg = Release|Any CPU
70 | {4172F589-AA5C-4784-A0C2-9739FD4CBB39}.Release|x64.Build.0 = Release|Any CPU
71 | {4172F589-AA5C-4784-A0C2-9739FD4CBB39}.Release|x86.ActiveCfg = Release|Any CPU
72 | {4172F589-AA5C-4784-A0C2-9739FD4CBB39}.Release|x86.Build.0 = Release|Any CPU
73 | {96D84947-8E8B-4AAB-96C2-F147C961D824}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
74 | {96D84947-8E8B-4AAB-96C2-F147C961D824}.Debug|Any CPU.Build.0 = Debug|Any CPU
75 | {96D84947-8E8B-4AAB-96C2-F147C961D824}.Debug|x64.ActiveCfg = Debug|Any CPU
76 | {96D84947-8E8B-4AAB-96C2-F147C961D824}.Debug|x64.Build.0 = Debug|Any CPU
77 | {96D84947-8E8B-4AAB-96C2-F147C961D824}.Debug|x86.ActiveCfg = Debug|Any CPU
78 | {96D84947-8E8B-4AAB-96C2-F147C961D824}.Debug|x86.Build.0 = Debug|Any CPU
79 | {96D84947-8E8B-4AAB-96C2-F147C961D824}.Release|Any CPU.ActiveCfg = Release|Any CPU
80 | {96D84947-8E8B-4AAB-96C2-F147C961D824}.Release|Any CPU.Build.0 = Release|Any CPU
81 | {96D84947-8E8B-4AAB-96C2-F147C961D824}.Release|x64.ActiveCfg = Release|Any CPU
82 | {96D84947-8E8B-4AAB-96C2-F147C961D824}.Release|x64.Build.0 = Release|Any CPU
83 | {96D84947-8E8B-4AAB-96C2-F147C961D824}.Release|x86.ActiveCfg = Release|Any CPU
84 | {96D84947-8E8B-4AAB-96C2-F147C961D824}.Release|x86.Build.0 = Release|Any CPU
85 | {3BD31689-54B9-4AD4-8046-0F2783BEAEE2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
86 | {3BD31689-54B9-4AD4-8046-0F2783BEAEE2}.Debug|Any CPU.Build.0 = Debug|Any CPU
87 | {3BD31689-54B9-4AD4-8046-0F2783BEAEE2}.Debug|x64.ActiveCfg = Debug|Any CPU
88 | {3BD31689-54B9-4AD4-8046-0F2783BEAEE2}.Debug|x64.Build.0 = Debug|Any CPU
89 | {3BD31689-54B9-4AD4-8046-0F2783BEAEE2}.Debug|x86.ActiveCfg = Debug|Any CPU
90 | {3BD31689-54B9-4AD4-8046-0F2783BEAEE2}.Debug|x86.Build.0 = Debug|Any CPU
91 | {3BD31689-54B9-4AD4-8046-0F2783BEAEE2}.Release|Any CPU.ActiveCfg = Release|Any CPU
92 | {3BD31689-54B9-4AD4-8046-0F2783BEAEE2}.Release|Any CPU.Build.0 = Release|Any CPU
93 | {3BD31689-54B9-4AD4-8046-0F2783BEAEE2}.Release|x64.ActiveCfg = Release|Any CPU
94 | {3BD31689-54B9-4AD4-8046-0F2783BEAEE2}.Release|x64.Build.0 = Release|Any CPU
95 | {3BD31689-54B9-4AD4-8046-0F2783BEAEE2}.Release|x86.ActiveCfg = Release|Any CPU
96 | {3BD31689-54B9-4AD4-8046-0F2783BEAEE2}.Release|x86.Build.0 = Release|Any CPU
97 | {A982C089-8B6F-4B80-A1A6-6CC689B496DB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
98 | {A982C089-8B6F-4B80-A1A6-6CC689B496DB}.Debug|Any CPU.Build.0 = Debug|Any CPU
99 | {A982C089-8B6F-4B80-A1A6-6CC689B496DB}.Debug|x64.ActiveCfg = Debug|Any CPU
100 | {A982C089-8B6F-4B80-A1A6-6CC689B496DB}.Debug|x64.Build.0 = Debug|Any CPU
101 | {A982C089-8B6F-4B80-A1A6-6CC689B496DB}.Debug|x86.ActiveCfg = Debug|Any CPU
102 | {A982C089-8B6F-4B80-A1A6-6CC689B496DB}.Debug|x86.Build.0 = Debug|Any CPU
103 | {A982C089-8B6F-4B80-A1A6-6CC689B496DB}.Release|Any CPU.ActiveCfg = Release|Any CPU
104 | {A982C089-8B6F-4B80-A1A6-6CC689B496DB}.Release|Any CPU.Build.0 = Release|Any CPU
105 | {A982C089-8B6F-4B80-A1A6-6CC689B496DB}.Release|x64.ActiveCfg = Release|Any CPU
106 | {A982C089-8B6F-4B80-A1A6-6CC689B496DB}.Release|x64.Build.0 = Release|Any CPU
107 | {A982C089-8B6F-4B80-A1A6-6CC689B496DB}.Release|x86.ActiveCfg = Release|Any CPU
108 | {A982C089-8B6F-4B80-A1A6-6CC689B496DB}.Release|x86.Build.0 = Release|Any CPU
109 | {7EC2EC82-22C9-4CE6-88F2-F80D40A12718}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
110 | {7EC2EC82-22C9-4CE6-88F2-F80D40A12718}.Debug|Any CPU.Build.0 = Debug|Any CPU
111 | {7EC2EC82-22C9-4CE6-88F2-F80D40A12718}.Debug|x64.ActiveCfg = Debug|Any CPU
112 | {7EC2EC82-22C9-4CE6-88F2-F80D40A12718}.Debug|x64.Build.0 = Debug|Any CPU
113 | {7EC2EC82-22C9-4CE6-88F2-F80D40A12718}.Debug|x86.ActiveCfg = Debug|Any CPU
114 | {7EC2EC82-22C9-4CE6-88F2-F80D40A12718}.Debug|x86.Build.0 = Debug|Any CPU
115 | {7EC2EC82-22C9-4CE6-88F2-F80D40A12718}.Release|Any CPU.ActiveCfg = Release|Any CPU
116 | {7EC2EC82-22C9-4CE6-88F2-F80D40A12718}.Release|Any CPU.Build.0 = Release|Any CPU
117 | {7EC2EC82-22C9-4CE6-88F2-F80D40A12718}.Release|x64.ActiveCfg = Release|Any CPU
118 | {7EC2EC82-22C9-4CE6-88F2-F80D40A12718}.Release|x64.Build.0 = Release|Any CPU
119 | {7EC2EC82-22C9-4CE6-88F2-F80D40A12718}.Release|x86.ActiveCfg = Release|Any CPU
120 | {7EC2EC82-22C9-4CE6-88F2-F80D40A12718}.Release|x86.Build.0 = Release|Any CPU
121 | EndGlobalSection
122 | GlobalSection(NestedProjects) = preSolution
123 | {C8CFFFA3-B699-4189-922B-660FDCE4FB88} = {CE143445-2075-49E2-B46D-92D4EDDB600E}
124 | {6E9632A9-CA7C-4AF6-804A-67046B09023F} = {CE143445-2075-49E2-B46D-92D4EDDB600E}
125 | {4172F589-AA5C-4784-A0C2-9739FD4CBB39} = {CE143445-2075-49E2-B46D-92D4EDDB600E}
126 | {96D84947-8E8B-4AAB-96C2-F147C961D824} = {E3B5ECC6-545F-4147-ABE8-5BCAD5E54FA6}
127 | {3BD31689-54B9-4AD4-8046-0F2783BEAEE2} = {CE143445-2075-49E2-B46D-92D4EDDB600E}
128 | {A982C089-8B6F-4B80-A1A6-6CC689B496DB} = {E3B5ECC6-545F-4147-ABE8-5BCAD5E54FA6}
129 | {7EC2EC82-22C9-4CE6-88F2-F80D40A12718} = {CE143445-2075-49E2-B46D-92D4EDDB600E}
130 | EndGlobalSection
131 | EndGlobal
132 |
--------------------------------------------------------------------------------
/src/NdcBingo/wwwroot/lib/fontawesome/js/v4-shims.min.js:
--------------------------------------------------------------------------------
1 | var l,a;l=this,a=function(){"use strict";var l={},a={};try{"undefined"!=typeof window&&(l=window),"undefined"!=typeof document&&(a=document)}catch(l){}var e=(l.navigator||{}).userAgent,r=void 0===e?"":e,n=l,o=a,u=(n.document,!!o.documentElement&&!!o.head&&"function"==typeof o.addEventListener&&o.createElement,~r.indexOf("MSIE")||r.indexOf("Trident/"),"___FONT_AWESOME___"),f=function(){try{return"production"===process.env.NODE_ENV}catch(l){return!1}}();var t=n||{};t[u]||(t[u]={}),t[u].styles||(t[u].styles={}),t[u].hooks||(t[u].hooks={}),t[u].shims||(t[u].shims=[]);var i=t[u],s=[["glass",null,"glass-martini"],["meetup","fab",null],["star-o","far","star"],["remove",null,"times"],["close",null,"times"],["gear",null,"cog"],["trash-o","far","trash-alt"],["file-o","far","file"],["clock-o","far","clock"],["arrow-circle-o-down","far","arrow-alt-circle-down"],["arrow-circle-o-up","far","arrow-alt-circle-up"],["play-circle-o","far","play-circle"],["repeat",null,"redo"],["rotate-right",null,"redo"],["refresh",null,"sync"],["list-alt","far",null],["dedent",null,"outdent"],["video-camera",null,"video"],["picture-o","far","image"],["photo","far","image"],["image","far","image"],["pencil",null,"pencil-alt"],["map-marker",null,"map-marker-alt"],["pencil-square-o","far","edit"],["share-square-o","far","share-square"],["check-square-o","far","check-square"],["arrows",null,"arrows-alt"],["times-circle-o","far","times-circle"],["check-circle-o","far","check-circle"],["mail-forward",null,"share"],["eye","far",null],["eye-slash","far",null],["warning",null,"exclamation-triangle"],["calendar",null,"calendar-alt"],["arrows-v",null,"arrows-alt-v"],["arrows-h",null,"arrows-alt-h"],["bar-chart","far","chart-bar"],["bar-chart-o","far","chart-bar"],["twitter-square","fab",null],["facebook-square","fab",null],["gears",null,"cogs"],["thumbs-o-up","far","thumbs-up"],["thumbs-o-down","far","thumbs-down"],["heart-o","far","heart"],["sign-out",null,"sign-out-alt"],["linkedin-square","fab","linkedin"],["thumb-tack",null,"thumbtack"],["external-link",null,"external-link-alt"],["sign-in",null,"sign-in-alt"],["github-square","fab",null],["lemon-o","far","lemon"],["square-o","far","square"],["bookmark-o","far","bookmark"],["twitter","fab",null],["facebook","fab","facebook-f"],["facebook-f","fab","facebook-f"],["github","fab",null],["credit-card","far",null],["feed",null,"rss"],["hdd-o","far","hdd"],["hand-o-right","far","hand-point-right"],["hand-o-left","far","hand-point-left"],["hand-o-up","far","hand-point-up"],["hand-o-down","far","hand-point-down"],["arrows-alt",null,"expand-arrows-alt"],["group",null,"users"],["chain",null,"link"],["scissors",null,"cut"],["files-o","far","copy"],["floppy-o","far","save"],["navicon",null,"bars"],["reorder",null,"bars"],["pinterest","fab",null],["pinterest-square","fab",null],["google-plus-square","fab",null],["google-plus","fab","google-plus-g"],["money","far","money-bill-alt"],["unsorted",null,"sort"],["sort-desc",null,"sort-down"],["sort-asc",null,"sort-up"],["linkedin","fab","linkedin-in"],["rotate-left",null,"undo"],["legal",null,"gavel"],["tachometer",null,"tachometer-alt"],["dashboard",null,"tachometer-alt"],["comment-o","far","comment"],["comments-o","far","comments"],["flash",null,"bolt"],["clipboard","far",null],["paste","far","clipboard"],["lightbulb-o","far","lightbulb"],["exchange",null,"exchange-alt"],["cloud-download",null,"cloud-download-alt"],["cloud-upload",null,"cloud-upload-alt"],["bell-o","far","bell"],["cutlery",null,"utensils"],["file-text-o","far","file-alt"],["building-o","far","building"],["hospital-o","far","hospital"],["tablet",null,"tablet-alt"],["mobile",null,"mobile-alt"],["mobile-phone",null,"mobile-alt"],["circle-o","far","circle"],["mail-reply",null,"reply"],["github-alt","fab",null],["folder-o","far","folder"],["folder-open-o","far","folder-open"],["smile-o","far","smile"],["frown-o","far","frown"],["meh-o","far","meh"],["keyboard-o","far","keyboard"],["flag-o","far","flag"],["mail-reply-all",null,"reply-all"],["star-half-o","far","star-half"],["star-half-empty","far","star-half"],["star-half-full","far","star-half"],["code-fork",null,"code-branch"],["chain-broken",null,"unlink"],["shield",null,"shield-alt"],["calendar-o","far","calendar"],["maxcdn","fab",null],["html5","fab",null],["css3","fab",null],["ticket",null,"ticket-alt"],["minus-square-o","far","minus-square"],["level-up",null,"level-up-alt"],["level-down",null,"level-down-alt"],["pencil-square",null,"pen-square"],["external-link-square",null,"external-link-square-alt"],["compass","far",null],["caret-square-o-down","far","caret-square-down"],["toggle-down","far","caret-square-down"],["caret-square-o-up","far","caret-square-up"],["toggle-up","far","caret-square-up"],["caret-square-o-right","far","caret-square-right"],["toggle-right","far","caret-square-right"],["eur",null,"euro-sign"],["euro",null,"euro-sign"],["gbp",null,"pound-sign"],["usd",null,"dollar-sign"],["dollar",null,"dollar-sign"],["inr",null,"rupee-sign"],["rupee",null,"rupee-sign"],["jpy",null,"yen-sign"],["cny",null,"yen-sign"],["rmb",null,"yen-sign"],["yen",null,"yen-sign"],["rub",null,"ruble-sign"],["ruble",null,"ruble-sign"],["rouble",null,"ruble-sign"],["krw",null,"won-sign"],["won",null,"won-sign"],["btc","fab",null],["bitcoin","fab","btc"],["file-text",null,"file-alt"],["sort-alpha-asc",null,"sort-alpha-down"],["sort-alpha-desc",null,"sort-alpha-up"],["sort-amount-asc",null,"sort-amount-down"],["sort-amount-desc",null,"sort-amount-up"],["sort-numeric-asc",null,"sort-numeric-down"],["sort-numeric-desc",null,"sort-numeric-up"],["youtube-square","fab",null],["youtube","fab",null],["xing","fab",null],["xing-square","fab",null],["youtube-play","fab","youtube"],["dropbox","fab",null],["stack-overflow","fab",null],["instagram","fab",null],["flickr","fab",null],["adn","fab",null],["bitbucket","fab",null],["bitbucket-square","fab","bitbucket"],["tumblr","fab",null],["tumblr-square","fab",null],["long-arrow-down",null,"long-arrow-alt-down"],["long-arrow-up",null,"long-arrow-alt-up"],["long-arrow-left",null,"long-arrow-alt-left"],["long-arrow-right",null,"long-arrow-alt-right"],["apple","fab",null],["windows","fab",null],["android","fab",null],["linux","fab",null],["dribbble","fab",null],["skype","fab",null],["foursquare","fab",null],["trello","fab",null],["gratipay","fab",null],["gittip","fab","gratipay"],["sun-o","far","sun"],["moon-o","far","moon"],["vk","fab",null],["weibo","fab",null],["renren","fab",null],["pagelines","fab",null],["stack-exchange","fab",null],["arrow-circle-o-right","far","arrow-alt-circle-right"],["arrow-circle-o-left","far","arrow-alt-circle-left"],["caret-square-o-left","far","caret-square-left"],["toggle-left","far","caret-square-left"],["dot-circle-o","far","dot-circle"],["vimeo-square","fab",null],["try",null,"lira-sign"],["turkish-lira",null,"lira-sign"],["plus-square-o","far","plus-square"],["slack","fab",null],["wordpress","fab",null],["openid","fab",null],["institution",null,"university"],["bank",null,"university"],["mortar-board",null,"graduation-cap"],["yahoo","fab",null],["google","fab",null],["reddit","fab",null],["reddit-square","fab",null],["stumbleupon-circle","fab",null],["stumbleupon","fab",null],["delicious","fab",null],["digg","fab",null],["pied-piper-pp","fab",null],["pied-piper-alt","fab",null],["drupal","fab",null],["joomla","fab",null],["spoon",null,"utensil-spoon"],["behance","fab",null],["behance-square","fab",null],["steam","fab",null],["steam-square","fab",null],["automobile",null,"car"],["cab",null,"taxi"],["envelope-o","far","envelope"],["deviantart","fab",null],["soundcloud","fab",null],["file-pdf-o","far","file-pdf"],["file-word-o","far","file-word"],["file-excel-o","far","file-excel"],["file-powerpoint-o","far","file-powerpoint"],["file-image-o","far","file-image"],["file-photo-o","far","file-image"],["file-picture-o","far","file-image"],["file-archive-o","far","file-archive"],["file-zip-o","far","file-archive"],["file-audio-o","far","file-audio"],["file-sound-o","far","file-audio"],["file-video-o","far","file-video"],["file-movie-o","far","file-video"],["file-code-o","far","file-code"],["vine","fab",null],["codepen","fab",null],["jsfiddle","fab",null],["life-ring","far",null],["life-bouy","far","life-ring"],["life-buoy","far","life-ring"],["life-saver","far","life-ring"],["support","far","life-ring"],["circle-o-notch",null,"circle-notch"],["rebel","fab",null],["ra","fab","rebel"],["resistance","fab","rebel"],["empire","fab",null],["ge","fab","empire"],["git-square","fab",null],["git","fab",null],["hacker-news","fab",null],["y-combinator-square","fab","hacker-news"],["yc-square","fab","hacker-news"],["tencent-weibo","fab",null],["qq","fab",null],["weixin","fab",null],["wechat","fab","weixin"],["send",null,"paper-plane"],["paper-plane-o","far","paper-plane"],["send-o","far","paper-plane"],["circle-thin","far","circle"],["header",null,"heading"],["sliders",null,"sliders-h"],["futbol-o","far","futbol"],["soccer-ball-o","far","futbol"],["slideshare","fab",null],["twitch","fab",null],["yelp","fab",null],["newspaper-o","far","newspaper"],["paypal","fab",null],["google-wallet","fab",null],["cc-visa","fab",null],["cc-mastercard","fab",null],["cc-discover","fab",null],["cc-amex","fab",null],["cc-paypal","fab",null],["cc-stripe","fab",null],["bell-slash-o","far","bell-slash"],["trash",null,"trash-alt"],["copyright","far",null],["eyedropper",null,"eye-dropper"],["area-chart",null,"chart-area"],["pie-chart",null,"chart-pie"],["line-chart",null,"chart-line"],["lastfm","fab",null],["lastfm-square","fab",null],["ioxhost","fab",null],["angellist","fab",null],["cc","far","closed-captioning"],["ils",null,"shekel-sign"],["shekel",null,"shekel-sign"],["sheqel",null,"shekel-sign"],["meanpath","fab","font-awesome"],["buysellads","fab",null],["connectdevelop","fab",null],["dashcube","fab",null],["forumbee","fab",null],["leanpub","fab",null],["sellsy","fab",null],["shirtsinbulk","fab",null],["simplybuilt","fab",null],["skyatlas","fab",null],["diamond","far","gem"],["intersex",null,"transgender"],["facebook-official","fab","facebook"],["pinterest-p","fab",null],["whatsapp","fab",null],["hotel",null,"bed"],["viacoin","fab",null],["medium","fab",null],["y-combinator","fab",null],["yc","fab","y-combinator"],["optin-monster","fab",null],["opencart","fab",null],["expeditedssl","fab",null],["battery-4",null,"battery-full"],["battery",null,"battery-full"],["battery-3",null,"battery-three-quarters"],["battery-2",null,"battery-half"],["battery-1",null,"battery-quarter"],["battery-0",null,"battery-empty"],["object-group","far",null],["object-ungroup","far",null],["sticky-note-o","far","sticky-note"],["cc-jcb","fab",null],["cc-diners-club","fab",null],["clone","far",null],["hourglass-o","far","hourglass"],["hourglass-1",null,"hourglass-start"],["hourglass-2",null,"hourglass-half"],["hourglass-3",null,"hourglass-end"],["hand-rock-o","far","hand-rock"],["hand-grab-o","far","hand-rock"],["hand-paper-o","far","hand-paper"],["hand-stop-o","far","hand-paper"],["hand-scissors-o","far","hand-scissors"],["hand-lizard-o","far","hand-lizard"],["hand-spock-o","far","hand-spock"],["hand-pointer-o","far","hand-pointer"],["hand-peace-o","far","hand-peace"],["registered","far",null],["creative-commons","fab",null],["gg","fab",null],["gg-circle","fab",null],["tripadvisor","fab",null],["odnoklassniki","fab",null],["odnoklassniki-square","fab",null],["get-pocket","fab",null],["wikipedia-w","fab",null],["safari","fab",null],["chrome","fab",null],["firefox","fab",null],["opera","fab",null],["internet-explorer","fab",null],["television",null,"tv"],["contao","fab",null],["500px","fab",null],["amazon","fab",null],["calendar-plus-o","far","calendar-plus"],["calendar-minus-o","far","calendar-minus"],["calendar-times-o","far","calendar-times"],["calendar-check-o","far","calendar-check"],["map-o","far","map"],["commenting",null,"comment-dots"],["commenting-o","far","comment-dots"],["houzz","fab",null],["vimeo","fab","vimeo-v"],["black-tie","fab",null],["fonticons","fab",null],["reddit-alien","fab",null],["edge","fab",null],["credit-card-alt",null,"credit-card"],["codiepie","fab",null],["modx","fab",null],["fort-awesome","fab",null],["usb","fab",null],["product-hunt","fab",null],["mixcloud","fab",null],["scribd","fab",null],["pause-circle-o","far","pause-circle"],["stop-circle-o","far","stop-circle"],["bluetooth","fab",null],["bluetooth-b","fab",null],["gitlab","fab",null],["wpbeginner","fab",null],["wpforms","fab",null],["envira","fab",null],["wheelchair-alt","fab","accessible-icon"],["question-circle-o","far","question-circle"],["volume-control-phone",null,"phone-volume"],["asl-interpreting",null,"american-sign-language-interpreting"],["deafness",null,"deaf"],["hard-of-hearing",null,"deaf"],["glide","fab",null],["glide-g","fab",null],["signing",null,"sign-language"],["viadeo","fab",null],["viadeo-square","fab",null],["snapchat","fab",null],["snapchat-ghost","fab",null],["snapchat-square","fab",null],["pied-piper","fab",null],["first-order","fab",null],["yoast","fab",null],["themeisle","fab",null],["google-plus-official","fab","google-plus"],["google-plus-circle","fab","google-plus"],["font-awesome","fab",null],["fa","fab","font-awesome"],["handshake-o","far","handshake"],["envelope-open-o","far","envelope-open"],["linode","fab",null],["address-book-o","far","address-book"],["vcard",null,"address-card"],["address-card-o","far","address-card"],["vcard-o","far","address-card"],["user-circle-o","far","user-circle"],["user-o","far","user"],["id-badge","far",null],["drivers-license",null,"id-card"],["id-card-o","far","id-card"],["drivers-license-o","far","id-card"],["quora","fab",null],["free-code-camp","fab",null],["telegram","fab",null],["thermometer-4",null,"thermometer-full"],["thermometer",null,"thermometer-full"],["thermometer-3",null,"thermometer-three-quarters"],["thermometer-2",null,"thermometer-half"],["thermometer-1",null,"thermometer-quarter"],["thermometer-0",null,"thermometer-empty"],["bathtub",null,"bath"],["s15",null,"bath"],["window-maximize","far",null],["window-restore","far",null],["times-rectangle",null,"window-close"],["window-close-o","far","window-close"],["times-rectangle-o","far","window-close"],["bandcamp","fab",null],["grav","fab",null],["etsy","fab",null],["imdb","fab",null],["ravelry","fab",null],["eercast","fab","sellcast"],["snowflake-o","far","snowflake"],["superpowers","fab",null],["wpexplorer","fab",null],["spotify","fab",null]];return function(l){try{l()}catch(l){if(!f)throw l}}(function(){var l;"function"==typeof i.hooks.addShims?i.hooks.addShims(s):(l=i.shims).push.apply(l,s)}),s},"object"==typeof exports&&"undefined"!=typeof module?module.exports=a():"function"==typeof define&&define.amd?define(a):l["fontawesome-pro-shims"]=a();
--------------------------------------------------------------------------------
/src/NdcBingo/wwwroot/lib/fontawesome/js/v4-shims.js:
--------------------------------------------------------------------------------
1 | (function (global, factory) {
2 | typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
3 | typeof define === 'function' && define.amd ? define(factory) :
4 | (global['fontawesome-pro-shims'] = factory());
5 | }(this, (function () { 'use strict';
6 |
7 | var _WINDOW = {};
8 | var _DOCUMENT = {};
9 |
10 | try {
11 | if (typeof window !== 'undefined') _WINDOW = window;
12 | if (typeof document !== 'undefined') _DOCUMENT = document;
13 | } catch (e) {}
14 |
15 | var _ref = _WINDOW.navigator || {},
16 | _ref$userAgent = _ref.userAgent,
17 | userAgent = _ref$userAgent === void 0 ? '' : _ref$userAgent;
18 |
19 | var WINDOW = _WINDOW;
20 | var DOCUMENT = _DOCUMENT;
21 | var IS_BROWSER = !!WINDOW.document;
22 | var IS_DOM = !!DOCUMENT.documentElement && !!DOCUMENT.head && typeof DOCUMENT.addEventListener === 'function' && typeof DOCUMENT.createElement === 'function';
23 | var IS_IE = ~userAgent.indexOf('MSIE') || ~userAgent.indexOf('Trident/');
24 |
25 | var NAMESPACE_IDENTIFIER = '___FONT_AWESOME___';
26 | var PRODUCTION = function () {
27 | try {
28 | return process.env.NODE_ENV === 'production';
29 | } catch (e) {
30 | return false;
31 | }
32 | }();
33 |
34 | function bunker(fn) {
35 | try {
36 | fn();
37 | } catch (e) {
38 | if (!PRODUCTION) {
39 | throw e;
40 | }
41 | }
42 | }
43 |
44 | var w = WINDOW || {};
45 | if (!w[NAMESPACE_IDENTIFIER]) w[NAMESPACE_IDENTIFIER] = {};
46 | if (!w[NAMESPACE_IDENTIFIER].styles) w[NAMESPACE_IDENTIFIER].styles = {};
47 | if (!w[NAMESPACE_IDENTIFIER].hooks) w[NAMESPACE_IDENTIFIER].hooks = {};
48 | if (!w[NAMESPACE_IDENTIFIER].shims) w[NAMESPACE_IDENTIFIER].shims = [];
49 | var namespace = w[NAMESPACE_IDENTIFIER];
50 |
51 | var shims = [["glass", null, "glass-martini"], ["meetup", "fab", null], ["star-o", "far", "star"], ["remove", null, "times"], ["close", null, "times"], ["gear", null, "cog"], ["trash-o", "far", "trash-alt"], ["file-o", "far", "file"], ["clock-o", "far", "clock"], ["arrow-circle-o-down", "far", "arrow-alt-circle-down"], ["arrow-circle-o-up", "far", "arrow-alt-circle-up"], ["play-circle-o", "far", "play-circle"], ["repeat", null, "redo"], ["rotate-right", null, "redo"], ["refresh", null, "sync"], ["list-alt", "far", null], ["dedent", null, "outdent"], ["video-camera", null, "video"], ["picture-o", "far", "image"], ["photo", "far", "image"], ["image", "far", "image"], ["pencil", null, "pencil-alt"], ["map-marker", null, "map-marker-alt"], ["pencil-square-o", "far", "edit"], ["share-square-o", "far", "share-square"], ["check-square-o", "far", "check-square"], ["arrows", null, "arrows-alt"], ["times-circle-o", "far", "times-circle"], ["check-circle-o", "far", "check-circle"], ["mail-forward", null, "share"], ["eye", "far", null], ["eye-slash", "far", null], ["warning", null, "exclamation-triangle"], ["calendar", null, "calendar-alt"], ["arrows-v", null, "arrows-alt-v"], ["arrows-h", null, "arrows-alt-h"], ["bar-chart", "far", "chart-bar"], ["bar-chart-o", "far", "chart-bar"], ["twitter-square", "fab", null], ["facebook-square", "fab", null], ["gears", null, "cogs"], ["thumbs-o-up", "far", "thumbs-up"], ["thumbs-o-down", "far", "thumbs-down"], ["heart-o", "far", "heart"], ["sign-out", null, "sign-out-alt"], ["linkedin-square", "fab", "linkedin"], ["thumb-tack", null, "thumbtack"], ["external-link", null, "external-link-alt"], ["sign-in", null, "sign-in-alt"], ["github-square", "fab", null], ["lemon-o", "far", "lemon"], ["square-o", "far", "square"], ["bookmark-o", "far", "bookmark"], ["twitter", "fab", null], ["facebook", "fab", "facebook-f"], ["facebook-f", "fab", "facebook-f"], ["github", "fab", null], ["credit-card", "far", null], ["feed", null, "rss"], ["hdd-o", "far", "hdd"], ["hand-o-right", "far", "hand-point-right"], ["hand-o-left", "far", "hand-point-left"], ["hand-o-up", "far", "hand-point-up"], ["hand-o-down", "far", "hand-point-down"], ["arrows-alt", null, "expand-arrows-alt"], ["group", null, "users"], ["chain", null, "link"], ["scissors", null, "cut"], ["files-o", "far", "copy"], ["floppy-o", "far", "save"], ["navicon", null, "bars"], ["reorder", null, "bars"], ["pinterest", "fab", null], ["pinterest-square", "fab", null], ["google-plus-square", "fab", null], ["google-plus", "fab", "google-plus-g"], ["money", "far", "money-bill-alt"], ["unsorted", null, "sort"], ["sort-desc", null, "sort-down"], ["sort-asc", null, "sort-up"], ["linkedin", "fab", "linkedin-in"], ["rotate-left", null, "undo"], ["legal", null, "gavel"], ["tachometer", null, "tachometer-alt"], ["dashboard", null, "tachometer-alt"], ["comment-o", "far", "comment"], ["comments-o", "far", "comments"], ["flash", null, "bolt"], ["clipboard", "far", null], ["paste", "far", "clipboard"], ["lightbulb-o", "far", "lightbulb"], ["exchange", null, "exchange-alt"], ["cloud-download", null, "cloud-download-alt"], ["cloud-upload", null, "cloud-upload-alt"], ["bell-o", "far", "bell"], ["cutlery", null, "utensils"], ["file-text-o", "far", "file-alt"], ["building-o", "far", "building"], ["hospital-o", "far", "hospital"], ["tablet", null, "tablet-alt"], ["mobile", null, "mobile-alt"], ["mobile-phone", null, "mobile-alt"], ["circle-o", "far", "circle"], ["mail-reply", null, "reply"], ["github-alt", "fab", null], ["folder-o", "far", "folder"], ["folder-open-o", "far", "folder-open"], ["smile-o", "far", "smile"], ["frown-o", "far", "frown"], ["meh-o", "far", "meh"], ["keyboard-o", "far", "keyboard"], ["flag-o", "far", "flag"], ["mail-reply-all", null, "reply-all"], ["star-half-o", "far", "star-half"], ["star-half-empty", "far", "star-half"], ["star-half-full", "far", "star-half"], ["code-fork", null, "code-branch"], ["chain-broken", null, "unlink"], ["shield", null, "shield-alt"], ["calendar-o", "far", "calendar"], ["maxcdn", "fab", null], ["html5", "fab", null], ["css3", "fab", null], ["ticket", null, "ticket-alt"], ["minus-square-o", "far", "minus-square"], ["level-up", null, "level-up-alt"], ["level-down", null, "level-down-alt"], ["pencil-square", null, "pen-square"], ["external-link-square", null, "external-link-square-alt"], ["compass", "far", null], ["caret-square-o-down", "far", "caret-square-down"], ["toggle-down", "far", "caret-square-down"], ["caret-square-o-up", "far", "caret-square-up"], ["toggle-up", "far", "caret-square-up"], ["caret-square-o-right", "far", "caret-square-right"], ["toggle-right", "far", "caret-square-right"], ["eur", null, "euro-sign"], ["euro", null, "euro-sign"], ["gbp", null, "pound-sign"], ["usd", null, "dollar-sign"], ["dollar", null, "dollar-sign"], ["inr", null, "rupee-sign"], ["rupee", null, "rupee-sign"], ["jpy", null, "yen-sign"], ["cny", null, "yen-sign"], ["rmb", null, "yen-sign"], ["yen", null, "yen-sign"], ["rub", null, "ruble-sign"], ["ruble", null, "ruble-sign"], ["rouble", null, "ruble-sign"], ["krw", null, "won-sign"], ["won", null, "won-sign"], ["btc", "fab", null], ["bitcoin", "fab", "btc"], ["file-text", null, "file-alt"], ["sort-alpha-asc", null, "sort-alpha-down"], ["sort-alpha-desc", null, "sort-alpha-up"], ["sort-amount-asc", null, "sort-amount-down"], ["sort-amount-desc", null, "sort-amount-up"], ["sort-numeric-asc", null, "sort-numeric-down"], ["sort-numeric-desc", null, "sort-numeric-up"], ["youtube-square", "fab", null], ["youtube", "fab", null], ["xing", "fab", null], ["xing-square", "fab", null], ["youtube-play", "fab", "youtube"], ["dropbox", "fab", null], ["stack-overflow", "fab", null], ["instagram", "fab", null], ["flickr", "fab", null], ["adn", "fab", null], ["bitbucket", "fab", null], ["bitbucket-square", "fab", "bitbucket"], ["tumblr", "fab", null], ["tumblr-square", "fab", null], ["long-arrow-down", null, "long-arrow-alt-down"], ["long-arrow-up", null, "long-arrow-alt-up"], ["long-arrow-left", null, "long-arrow-alt-left"], ["long-arrow-right", null, "long-arrow-alt-right"], ["apple", "fab", null], ["windows", "fab", null], ["android", "fab", null], ["linux", "fab", null], ["dribbble", "fab", null], ["skype", "fab", null], ["foursquare", "fab", null], ["trello", "fab", null], ["gratipay", "fab", null], ["gittip", "fab", "gratipay"], ["sun-o", "far", "sun"], ["moon-o", "far", "moon"], ["vk", "fab", null], ["weibo", "fab", null], ["renren", "fab", null], ["pagelines", "fab", null], ["stack-exchange", "fab", null], ["arrow-circle-o-right", "far", "arrow-alt-circle-right"], ["arrow-circle-o-left", "far", "arrow-alt-circle-left"], ["caret-square-o-left", "far", "caret-square-left"], ["toggle-left", "far", "caret-square-left"], ["dot-circle-o", "far", "dot-circle"], ["vimeo-square", "fab", null], ["try", null, "lira-sign"], ["turkish-lira", null, "lira-sign"], ["plus-square-o", "far", "plus-square"], ["slack", "fab", null], ["wordpress", "fab", null], ["openid", "fab", null], ["institution", null, "university"], ["bank", null, "university"], ["mortar-board", null, "graduation-cap"], ["yahoo", "fab", null], ["google", "fab", null], ["reddit", "fab", null], ["reddit-square", "fab", null], ["stumbleupon-circle", "fab", null], ["stumbleupon", "fab", null], ["delicious", "fab", null], ["digg", "fab", null], ["pied-piper-pp", "fab", null], ["pied-piper-alt", "fab", null], ["drupal", "fab", null], ["joomla", "fab", null], ["spoon", null, "utensil-spoon"], ["behance", "fab", null], ["behance-square", "fab", null], ["steam", "fab", null], ["steam-square", "fab", null], ["automobile", null, "car"], ["cab", null, "taxi"], ["envelope-o", "far", "envelope"], ["deviantart", "fab", null], ["soundcloud", "fab", null], ["file-pdf-o", "far", "file-pdf"], ["file-word-o", "far", "file-word"], ["file-excel-o", "far", "file-excel"], ["file-powerpoint-o", "far", "file-powerpoint"], ["file-image-o", "far", "file-image"], ["file-photo-o", "far", "file-image"], ["file-picture-o", "far", "file-image"], ["file-archive-o", "far", "file-archive"], ["file-zip-o", "far", "file-archive"], ["file-audio-o", "far", "file-audio"], ["file-sound-o", "far", "file-audio"], ["file-video-o", "far", "file-video"], ["file-movie-o", "far", "file-video"], ["file-code-o", "far", "file-code"], ["vine", "fab", null], ["codepen", "fab", null], ["jsfiddle", "fab", null], ["life-ring", "far", null], ["life-bouy", "far", "life-ring"], ["life-buoy", "far", "life-ring"], ["life-saver", "far", "life-ring"], ["support", "far", "life-ring"], ["circle-o-notch", null, "circle-notch"], ["rebel", "fab", null], ["ra", "fab", "rebel"], ["resistance", "fab", "rebel"], ["empire", "fab", null], ["ge", "fab", "empire"], ["git-square", "fab", null], ["git", "fab", null], ["hacker-news", "fab", null], ["y-combinator-square", "fab", "hacker-news"], ["yc-square", "fab", "hacker-news"], ["tencent-weibo", "fab", null], ["qq", "fab", null], ["weixin", "fab", null], ["wechat", "fab", "weixin"], ["send", null, "paper-plane"], ["paper-plane-o", "far", "paper-plane"], ["send-o", "far", "paper-plane"], ["circle-thin", "far", "circle"], ["header", null, "heading"], ["sliders", null, "sliders-h"], ["futbol-o", "far", "futbol"], ["soccer-ball-o", "far", "futbol"], ["slideshare", "fab", null], ["twitch", "fab", null], ["yelp", "fab", null], ["newspaper-o", "far", "newspaper"], ["paypal", "fab", null], ["google-wallet", "fab", null], ["cc-visa", "fab", null], ["cc-mastercard", "fab", null], ["cc-discover", "fab", null], ["cc-amex", "fab", null], ["cc-paypal", "fab", null], ["cc-stripe", "fab", null], ["bell-slash-o", "far", "bell-slash"], ["trash", null, "trash-alt"], ["copyright", "far", null], ["eyedropper", null, "eye-dropper"], ["area-chart", null, "chart-area"], ["pie-chart", null, "chart-pie"], ["line-chart", null, "chart-line"], ["lastfm", "fab", null], ["lastfm-square", "fab", null], ["ioxhost", "fab", null], ["angellist", "fab", null], ["cc", "far", "closed-captioning"], ["ils", null, "shekel-sign"], ["shekel", null, "shekel-sign"], ["sheqel", null, "shekel-sign"], ["meanpath", "fab", "font-awesome"], ["buysellads", "fab", null], ["connectdevelop", "fab", null], ["dashcube", "fab", null], ["forumbee", "fab", null], ["leanpub", "fab", null], ["sellsy", "fab", null], ["shirtsinbulk", "fab", null], ["simplybuilt", "fab", null], ["skyatlas", "fab", null], ["diamond", "far", "gem"], ["intersex", null, "transgender"], ["facebook-official", "fab", "facebook"], ["pinterest-p", "fab", null], ["whatsapp", "fab", null], ["hotel", null, "bed"], ["viacoin", "fab", null], ["medium", "fab", null], ["y-combinator", "fab", null], ["yc", "fab", "y-combinator"], ["optin-monster", "fab", null], ["opencart", "fab", null], ["expeditedssl", "fab", null], ["battery-4", null, "battery-full"], ["battery", null, "battery-full"], ["battery-3", null, "battery-three-quarters"], ["battery-2", null, "battery-half"], ["battery-1", null, "battery-quarter"], ["battery-0", null, "battery-empty"], ["object-group", "far", null], ["object-ungroup", "far", null], ["sticky-note-o", "far", "sticky-note"], ["cc-jcb", "fab", null], ["cc-diners-club", "fab", null], ["clone", "far", null], ["hourglass-o", "far", "hourglass"], ["hourglass-1", null, "hourglass-start"], ["hourglass-2", null, "hourglass-half"], ["hourglass-3", null, "hourglass-end"], ["hand-rock-o", "far", "hand-rock"], ["hand-grab-o", "far", "hand-rock"], ["hand-paper-o", "far", "hand-paper"], ["hand-stop-o", "far", "hand-paper"], ["hand-scissors-o", "far", "hand-scissors"], ["hand-lizard-o", "far", "hand-lizard"], ["hand-spock-o", "far", "hand-spock"], ["hand-pointer-o", "far", "hand-pointer"], ["hand-peace-o", "far", "hand-peace"], ["registered", "far", null], ["creative-commons", "fab", null], ["gg", "fab", null], ["gg-circle", "fab", null], ["tripadvisor", "fab", null], ["odnoklassniki", "fab", null], ["odnoklassniki-square", "fab", null], ["get-pocket", "fab", null], ["wikipedia-w", "fab", null], ["safari", "fab", null], ["chrome", "fab", null], ["firefox", "fab", null], ["opera", "fab", null], ["internet-explorer", "fab", null], ["television", null, "tv"], ["contao", "fab", null], ["500px", "fab", null], ["amazon", "fab", null], ["calendar-plus-o", "far", "calendar-plus"], ["calendar-minus-o", "far", "calendar-minus"], ["calendar-times-o", "far", "calendar-times"], ["calendar-check-o", "far", "calendar-check"], ["map-o", "far", "map"], ["commenting", null, "comment-dots"], ["commenting-o", "far", "comment-dots"], ["houzz", "fab", null], ["vimeo", "fab", "vimeo-v"], ["black-tie", "fab", null], ["fonticons", "fab", null], ["reddit-alien", "fab", null], ["edge", "fab", null], ["credit-card-alt", null, "credit-card"], ["codiepie", "fab", null], ["modx", "fab", null], ["fort-awesome", "fab", null], ["usb", "fab", null], ["product-hunt", "fab", null], ["mixcloud", "fab", null], ["scribd", "fab", null], ["pause-circle-o", "far", "pause-circle"], ["stop-circle-o", "far", "stop-circle"], ["bluetooth", "fab", null], ["bluetooth-b", "fab", null], ["gitlab", "fab", null], ["wpbeginner", "fab", null], ["wpforms", "fab", null], ["envira", "fab", null], ["wheelchair-alt", "fab", "accessible-icon"], ["question-circle-o", "far", "question-circle"], ["volume-control-phone", null, "phone-volume"], ["asl-interpreting", null, "american-sign-language-interpreting"], ["deafness", null, "deaf"], ["hard-of-hearing", null, "deaf"], ["glide", "fab", null], ["glide-g", "fab", null], ["signing", null, "sign-language"], ["viadeo", "fab", null], ["viadeo-square", "fab", null], ["snapchat", "fab", null], ["snapchat-ghost", "fab", null], ["snapchat-square", "fab", null], ["pied-piper", "fab", null], ["first-order", "fab", null], ["yoast", "fab", null], ["themeisle", "fab", null], ["google-plus-official", "fab", "google-plus"], ["google-plus-circle", "fab", "google-plus"], ["font-awesome", "fab", null], ["fa", "fab", "font-awesome"], ["handshake-o", "far", "handshake"], ["envelope-open-o", "far", "envelope-open"], ["linode", "fab", null], ["address-book-o", "far", "address-book"], ["vcard", null, "address-card"], ["address-card-o", "far", "address-card"], ["vcard-o", "far", "address-card"], ["user-circle-o", "far", "user-circle"], ["user-o", "far", "user"], ["id-badge", "far", null], ["drivers-license", null, "id-card"], ["id-card-o", "far", "id-card"], ["drivers-license-o", "far", "id-card"], ["quora", "fab", null], ["free-code-camp", "fab", null], ["telegram", "fab", null], ["thermometer-4", null, "thermometer-full"], ["thermometer", null, "thermometer-full"], ["thermometer-3", null, "thermometer-three-quarters"], ["thermometer-2", null, "thermometer-half"], ["thermometer-1", null, "thermometer-quarter"], ["thermometer-0", null, "thermometer-empty"], ["bathtub", null, "bath"], ["s15", null, "bath"], ["window-maximize", "far", null], ["window-restore", "far", null], ["times-rectangle", null, "window-close"], ["window-close-o", "far", "window-close"], ["times-rectangle-o", "far", "window-close"], ["bandcamp", "fab", null], ["grav", "fab", null], ["etsy", "fab", null], ["imdb", "fab", null], ["ravelry", "fab", null], ["eercast", "fab", "sellcast"], ["snowflake-o", "far", "snowflake"], ["superpowers", "fab", null], ["wpexplorer", "fab", null], ["spotify", "fab", null]];
52 | bunker(function () {
53 | if (typeof namespace.hooks.addShims === 'function') {
54 | namespace.hooks.addShims(shims);
55 | } else {
56 | var _namespace$shims;
57 |
58 | (_namespace$shims = namespace.shims).push.apply(_namespace$shims, shims);
59 | }
60 | });
61 |
62 | return shims;
63 |
64 | })));
65 |
--------------------------------------------------------------------------------
/src/NdcBingo/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");
39 | }
40 |
41 | function getModelPrefix(fieldName) {
42 | return fieldName.substr(0, fieldName.lastIndexOf(".") + 1);
43 | }
44 |
45 | function appendModelPrefix(value, prefix) {
46 | if (value.indexOf("*.") === 0) {
47 | value = value.replace("*.", prefix);
48 | }
49 | return value;
50 | }
51 |
52 | function onError(error, inputElement) { // 'this' is the form element
53 | var container = $(this).find("[data-valmsg-for='" + escapeAttributeValue(inputElement[0].name) + "']"),
54 | replaceAttrValue = container.attr("data-valmsg-replace"),
55 | replace = replaceAttrValue ? $.parseJSON(replaceAttrValue) !== false : null;
56 |
57 | container.removeClass("field-validation-valid").addClass("field-validation-error");
58 | error.data("unobtrusiveContainer", container);
59 |
60 | if (replace) {
61 | container.empty();
62 | error.removeClass("input-validation-error").appendTo(container);
63 | }
64 | else {
65 | error.hide();
66 | }
67 | }
68 |
69 | function onErrors(event, validator) { // 'this' is the form element
70 | var container = $(this).find("[data-valmsg-summary=true]"),
71 | list = container.find("ul");
72 |
73 | if (list && list.length && validator.errorList.length) {
74 | list.empty();
75 | container.addClass("validation-summary-errors").removeClass("validation-summary-valid");
76 |
77 | $.each(validator.errorList, function () {
78 | $(" ").html(this.message).appendTo(list);
79 | });
80 | }
81 | }
82 |
83 | function onSuccess(error) { // 'this' is the form element
84 | var container = error.data("unobtrusiveContainer");
85 |
86 | if (container) {
87 | var replaceAttrValue = container.attr("data-valmsg-replace"),
88 | replace = replaceAttrValue ? $.parseJSON(replaceAttrValue) : null;
89 |
90 | container.addClass("field-validation-valid").removeClass("field-validation-error");
91 | error.removeData("unobtrusiveContainer");
92 |
93 | if (replace) {
94 | container.empty();
95 | }
96 | }
97 | }
98 |
99 | function onReset(event) { // 'this' is the form element
100 | var $form = $(this),
101 | key = '__jquery_unobtrusive_validation_form_reset';
102 | if ($form.data(key)) {
103 | return;
104 | }
105 | // Set a flag that indicates we're currently resetting the form.
106 | $form.data(key, true);
107 | try {
108 | $form.data("validator").resetForm();
109 | } finally {
110 | $form.removeData(key);
111 | }
112 |
113 | $form.find(".validation-summary-errors")
114 | .addClass("validation-summary-valid")
115 | .removeClass("validation-summary-errors");
116 | $form.find(".field-validation-error")
117 | .addClass("field-validation-valid")
118 | .removeClass("field-validation-error")
119 | .removeData("unobtrusiveContainer")
120 | .find(">*") // If we were using valmsg-replace, get the underlying error
121 | .removeData("unobtrusiveContainer");
122 | }
123 |
124 | function validationInfo(form) {
125 | var $form = $(form),
126 | result = $form.data(data_validation),
127 | onResetProxy = $.proxy(onReset, form),
128 | defaultOptions = $jQval.unobtrusive.options || {},
129 | execInContext = function (name, args) {
130 | var func = defaultOptions[name];
131 | func && $.isFunction(func) && func.apply(form, args);
132 | };
133 |
134 | if (!result) {
135 | result = {
136 | options: { // options structure passed to jQuery Validate's validate() method
137 | errorClass: defaultOptions.errorClass || "input-validation-error",
138 | errorElement: defaultOptions.errorElement || "span",
139 | errorPlacement: function () {
140 | onError.apply(form, arguments);
141 | execInContext("errorPlacement", arguments);
142 | },
143 | invalidHandler: function () {
144 | onErrors.apply(form, arguments);
145 | execInContext("invalidHandler", arguments);
146 | },
147 | messages: {},
148 | rules: {},
149 | success: function () {
150 | onSuccess.apply(form, arguments);
151 | execInContext("success", arguments);
152 | }
153 | },
154 | attachValidation: function () {
155 | $form
156 | .off("reset." + data_validation, onResetProxy)
157 | .on("reset." + data_validation, onResetProxy)
158 | .validate(this.options);
159 | },
160 | validate: function () { // a validation function that is called by unobtrusive Ajax
161 | $form.validate();
162 | return $form.valid();
163 | }
164 | };
165 | $form.data(data_validation, result);
166 | }
167 |
168 | return result;
169 | }
170 |
171 | $jQval.unobtrusive = {
172 | adapters: [],
173 |
174 | parseElement: function (element, skipAttach) {
175 | ///
176 | /// Parses a single HTML element for unobtrusive validation attributes.
177 | ///
178 | /// The HTML element to be parsed.
179 | /// [Optional] true to skip attaching the
180 | /// validation to the form. If parsing just this single element, you should specify true.
181 | /// If parsing several elements, you should specify false, and manually attach the validation
182 | /// to the form when you are finished. The default is false.
183 | var $element = $(element),
184 | form = $element.parents("form")[0],
185 | valInfo, rules, messages;
186 |
187 | if (!form) { // Cannot do client-side validation without a form
188 | return;
189 | }
190 |
191 | valInfo = validationInfo(form);
192 | valInfo.options.rules[element.name] = rules = {};
193 | valInfo.options.messages[element.name] = messages = {};
194 |
195 | $.each(this.adapters, function () {
196 | var prefix = "data-val-" + this.name,
197 | message = $element.attr(prefix),
198 | paramValues = {};
199 |
200 | if (message !== undefined) { // Compare against undefined, because an empty message is legal (and falsy)
201 | prefix += "-";
202 |
203 | $.each(this.params, function () {
204 | paramValues[this] = $element.attr(prefix + this);
205 | });
206 |
207 | this.adapt({
208 | element: element,
209 | form: form,
210 | message: message,
211 | params: paramValues,
212 | rules: rules,
213 | messages: messages
214 | });
215 | }
216 | });
217 |
218 | $.extend(rules, { "__dummy__": true });
219 |
220 | if (!skipAttach) {
221 | valInfo.attachValidation();
222 | }
223 | },
224 |
225 | parse: function (selector) {
226 | ///
227 | /// Parses all the HTML elements in the specified selector. It looks for input elements decorated
228 | /// with the [data-val=true] attribute value and enables validation according to the data-val-*
229 | /// attribute values.
230 | ///
231 | /// Any valid jQuery selector.
232 |
233 | // $forms includes all forms in selector's DOM hierarchy (parent, children and self) that have at least one
234 | // element with data-val=true
235 | var $selector = $(selector),
236 | $forms = $selector.parents()
237 | .addBack()
238 | .filter("form")
239 | .add($selector.find("form"))
240 | .has("[data-val=true]");
241 |
242 | $selector.find("[data-val=true]").each(function () {
243 | $jQval.unobtrusive.parseElement(this, true);
244 | });
245 |
246 | $forms.each(function () {
247 | var info = validationInfo(this);
248 | if (info) {
249 | info.attachValidation();
250 | }
251 | });
252 | }
253 | };
254 |
255 | adapters = $jQval.unobtrusive.adapters;
256 |
257 | adapters.add = function (adapterName, params, fn) {
258 | /// Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation.
259 | /// The name of the adapter to be added. This matches the name used
260 | /// in the data-val-nnnn HTML attribute (where nnnn is the adapter name).
261 | /// [Optional] An array of parameter names (strings) that will
262 | /// be extracted from the data-val-nnnn-mmmm HTML attributes (where nnnn is the adapter name, and
263 | /// mmmm is the parameter name).
264 | /// The function to call, which adapts the values from the HTML
265 | /// attributes into jQuery Validate rules and/or messages.
266 | ///
267 | if (!fn) { // Called with no params, just a function
268 | fn = params;
269 | params = [];
270 | }
271 | this.push({ name: adapterName, params: params, adapt: fn });
272 | return this;
273 | };
274 |
275 | adapters.addBool = function (adapterName, ruleName) {
276 | /// Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation, where
277 | /// the jQuery Validate validation rule has no parameter values.
278 | /// The name of the adapter to be added. This matches the name used
279 | /// in the data-val-nnnn HTML attribute (where nnnn is the adapter name).
280 | /// [Optional] The name of the jQuery Validate rule. If not provided, the value
281 | /// of adapterName will be used instead.
282 | ///
283 | return this.add(adapterName, function (options) {
284 | setValidationValues(options, ruleName || adapterName, true);
285 | });
286 | };
287 |
288 | adapters.addMinMax = function (adapterName, minRuleName, maxRuleName, minMaxRuleName, minAttribute, maxAttribute) {
289 | /// Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation, where
290 | /// the jQuery Validate validation has three potential rules (one for min-only, one for max-only, and
291 | /// one for min-and-max). The HTML parameters are expected to be named -min and -max.
292 | /// The name of the adapter to be added. This matches the name used
293 | /// in the data-val-nnnn HTML attribute (where nnnn is the adapter name).
294 | /// The name of the jQuery Validate rule to be used when you only
295 | /// have a minimum value.
296 | /// The name of the jQuery Validate rule to be used when you only
297 | /// have a maximum value.
298 | /// The name of the jQuery Validate rule to be used when you
299 | /// have both a minimum and maximum value.
300 | /// [Optional] The name of the HTML attribute that
301 | /// contains the minimum value. The default is "min".
302 | /// [Optional] The name of the HTML attribute that
303 | /// contains the maximum value. The default is "max".
304 | ///
305 | return this.add(adapterName, [minAttribute || "min", maxAttribute || "max"], function (options) {
306 | var min = options.params.min,
307 | max = options.params.max;
308 |
309 | if (min && max) {
310 | setValidationValues(options, minMaxRuleName, [min, max]);
311 | }
312 | else if (min) {
313 | setValidationValues(options, minRuleName, min);
314 | }
315 | else if (max) {
316 | setValidationValues(options, maxRuleName, max);
317 | }
318 | });
319 | };
320 |
321 | adapters.addSingleVal = function (adapterName, attribute, ruleName) {
322 | /// Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation, where
323 | /// the jQuery Validate validation rule has a single value.
324 | /// The name of the adapter to be added. This matches the name used
325 | /// in the data-val-nnnn HTML attribute(where nnnn is the adapter name).
326 | /// [Optional] The name of the HTML attribute that contains the value.
327 | /// The default is "val".
328 | /// [Optional] The name of the jQuery Validate rule. If not provided, the value
329 | /// of adapterName will be used instead.
330 | ///
331 | return this.add(adapterName, [attribute || "val"], function (options) {
332 | setValidationValues(options, ruleName || adapterName, options.params[attribute]);
333 | });
334 | };
335 |
336 | $jQval.addMethod("__dummy__", function (value, element, params) {
337 | return true;
338 | });
339 |
340 | $jQval.addMethod("regex", function (value, element, params) {
341 | var match;
342 | if (this.optional(element)) {
343 | return true;
344 | }
345 |
346 | match = new RegExp(params).exec(value);
347 | return (match && (match.index === 0) && (match[0].length === value.length));
348 | });
349 |
350 | $jQval.addMethod("nonalphamin", function (value, element, nonalphamin) {
351 | var match;
352 | if (nonalphamin) {
353 | match = value.match(/\W/g);
354 | match = match && match.length >= nonalphamin;
355 | }
356 | return match;
357 | });
358 |
359 | if ($jQval.methods.extension) {
360 | adapters.addSingleVal("accept", "mimtype");
361 | adapters.addSingleVal("extension", "extension");
362 | } else {
363 | // for backward compatibility, when the 'extension' validation method does not exist, such as with versions
364 | // of JQuery Validation plugin prior to 1.10, we should use the 'accept' method for
365 | // validating the extension, and ignore mime-type validations as they are not supported.
366 | adapters.addSingleVal("extension", "extension", "accept");
367 | }
368 |
369 | adapters.addSingleVal("regex", "pattern");
370 | adapters.addBool("creditcard").addBool("date").addBool("digits").addBool("email").addBool("number").addBool("url");
371 | adapters.addMinMax("length", "minlength", "maxlength", "rangelength").addMinMax("range", "min", "max", "range");
372 | adapters.addMinMax("minlength", "minlength").addMinMax("maxlength", "minlength", "maxlength");
373 | adapters.add("equalto", ["other"], function (options) {
374 | var prefix = getModelPrefix(options.element.name),
375 | other = options.params.other,
376 | fullOtherName = appendModelPrefix(other, prefix),
377 | element = $(options.form).find(":input").filter("[name='" + escapeAttributeValue(fullOtherName) + "']")[0];
378 |
379 | setValidationValues(options, "equalTo", element);
380 | });
381 | adapters.add("required", function (options) {
382 | // jQuery Validate equates "required" with "mandatory" for checkbox elements
383 | if (options.element.tagName.toUpperCase() !== "INPUT" || options.element.type.toUpperCase() !== "CHECKBOX") {
384 | setValidationValues(options, "required", true);
385 | }
386 | });
387 | adapters.add("remote", ["url", "type", "additionalfields"], function (options) {
388 | var value = {
389 | url: options.params.url,
390 | type: options.params.type || "GET",
391 | data: {}
392 | },
393 | prefix = getModelPrefix(options.element.name);
394 |
395 | $.each(splitAndTrim(options.params.additionalfields || options.element.name), function (i, fieldName) {
396 | var paramName = appendModelPrefix(fieldName, prefix);
397 | value.data[paramName] = function () {
398 | var field = $(options.form).find(":input").filter("[name='" + escapeAttributeValue(paramName) + "']");
399 | // For checkboxes and radio buttons, only pick up values from checked fields.
400 | if (field.is(":checkbox")) {
401 | return field.filter(":checked").val() || field.filter(":hidden").val() || '';
402 | }
403 | else if (field.is(":radio")) {
404 | return field.filter(":checked").val() || '';
405 | }
406 | return field.val();
407 | };
408 | });
409 |
410 | setValidationValues(options, "remote", value);
411 | });
412 | adapters.add("password", ["min", "nonalphamin", "regex"], function (options) {
413 | if (options.params.min) {
414 | setValidationValues(options, "minlength", options.params.min);
415 | }
416 | if (options.params.nonalphamin) {
417 | setValidationValues(options, "nonalphamin", options.params.nonalphamin);
418 | }
419 | if (options.params.regex) {
420 | setValidationValues(options, "regex", options.params.regex);
421 | }
422 | });
423 | adapters.add("fileextensions", ["extensions"], function (options) {
424 | setValidationValues(options, "extension", options.params.extensions);
425 | });
426 |
427 | $(function () {
428 | $jQval.unobtrusive.parse(document);
429 | });
430 |
431 | return $jQval.unobtrusive;
432 | }));
433 |
--------------------------------------------------------------------------------
/src/NdcBingo/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});
--------------------------------------------------------------------------------