diff --git a/BTCPayServer/BTCPayServer.csproj b/BTCPayServer/BTCPayServer.csproj index fd5d78792..7212c1379 100644 --- a/BTCPayServer/BTCPayServer.csproj +++ b/BTCPayServer/BTCPayServer.csproj @@ -124,6 +124,7 @@ + diff --git a/BTCPayServer/Controllers/AppsPublicController.cs b/BTCPayServer/Controllers/AppsPublicController.cs index 5034804e7..9acbc4f4d 100644 --- a/BTCPayServer/Controllers/AppsPublicController.cs +++ b/BTCPayServer/Controllers/AppsPublicController.cs @@ -7,6 +7,7 @@ using System.Security.Claims; using System.Threading.Tasks; using BTCPayServer.Data; using BTCPayServer.Filters; +using BTCPayServer.Hubs; using BTCPayServer.Models.AppViewModels; using BTCPayServer.Rating; using BTCPayServer.Security; @@ -27,22 +28,16 @@ namespace BTCPayServer.Controllers { public AppsPublicController(AppsHelper appsHelper, InvoiceController invoiceController, - RateFetcher rateFetcher, - BTCPayNetworkProvider btcPayNetworkProvider, - InvoiceRepository invoiceRepository) + CrowdfundHubStreamer crowdfundHubStreamer) { _AppsHelper = appsHelper; _InvoiceController = invoiceController; - _rateFetcher = rateFetcher; - _btcPayNetworkProvider = btcPayNetworkProvider; - _invoiceRepository = invoiceRepository; + _CrowdfundHubStreamer = crowdfundHubStreamer; } private AppsHelper _AppsHelper; private InvoiceController _InvoiceController; - private readonly RateFetcher _rateFetcher; - private readonly BTCPayNetworkProvider _btcPayNetworkProvider; - private readonly InvoiceRepository _invoiceRepository; + private readonly CrowdfundHubStreamer _CrowdfundHubStreamer; [HttpGet] [Route("/apps/{appId}/pos")] @@ -92,10 +87,8 @@ namespace BTCPayServer.Controllers var app = await _AppsHelper.GetApp(appId, AppType.Crowdfund, true); if (app == null) return NotFound(); - var settings = app.GetSettings(); - var currency = _AppsHelper.GetCurrencyData(settings.TargetCurrency, false); - return View(await CrowdfundHelper.GetInfo(app, _invoiceRepository, _rateFetcher, _btcPayNetworkProvider, statusMessage )); + return View(await _CrowdfundHubStreamer.GetCrowdfundInfo(appId)); } [HttpPost] @@ -114,13 +107,15 @@ namespace BTCPayServer.Controllers store.AdditionalClaims.Add(new Claim(Policies.CanCreateInvoice.Key, store.Id)); var invoice = await _InvoiceController.CreateInvoiceCore(new Invoice() { - OrderId = appId, + OrderId = $"{CrowdfundHubStreamer.CrowdfundInvoiceOrderIdPrefix}{appId}", Currency = settings.TargetCurrency, BuyerEmail = request.Email, Price = request.Amount, NotificationURL = settings.NotificationUrl, FullNotifications = true, ExtendedNotifications = true, + RedirectURL = HttpContext.Request.GetAbsoluteRoot(), + }, store, HttpContext.Request.GetAbsoluteRoot()); if (request.RedirectToCheckout) { @@ -129,10 +124,7 @@ namespace BTCPayServer.Controllers } else { - return Json(new - { - InvoiceId = invoice.Data.Id - }); + return Ok(invoice.Data.Id); } } @@ -199,94 +191,6 @@ namespace BTCPayServer.Controllers } } - public class CrowdfundHelper - { - private static async Task GetCurrentContributionAmount(InvoiceEntity[] invoices, string primaryCurrency, - RateFetcher rateFetcher, RateRules rateRules) - { - decimal result = 0; - - var groupingByCurrency = invoices.GroupBy(entity => entity.ProductInformation.Currency); - - var ratesTask = rateFetcher.FetchRates( - groupingByCurrency - .Select((entities) => new CurrencyPair(entities.Key, primaryCurrency)) - .ToHashSet(), - rateRules); - - var finalTasks = new List(); - foreach (var rateTask in ratesTask) - { - finalTasks.Add(Task.Run(async () => - { - var tResult = await rateTask.Value; - var rate = tResult.BidAsk?.Bid; - if (rate == null) return; - var currencyGroup = groupingByCurrency.Single(entities => entities.Key == rateTask.Key.Left); - result += currencyGroup.Sum(entity => entity.ProductInformation.Price / rate.Value); - })); - } - - await Task.WhenAll(finalTasks); - - return result; - - } - - public static async Task GetInfo(AppData appData, InvoiceRepository invoiceRepository, - RateFetcher rateFetcher, BTCPayNetworkProvider btcPayNetworkProvider, string statusMessage= null) - { - var settings = appData.GetSettings(); - var invoices = await GetPaidInvoicesForApp(appData, invoiceRepository); - var rateRules = appData.StoreData.GetStoreBlob().GetRateRules(btcPayNetworkProvider); - var currentAmount = await GetCurrentContributionAmount( - invoices, - settings.TargetCurrency, rateFetcher, rateRules); - var paidInvoices = invoices.Length; - var active = (settings.StartDate == null || DateTime.UtcNow >= settings.StartDate) && - (settings.EndDate == null || DateTime.UtcNow <= settings.EndDate) && - (!settings.EnforceTargetAmount || settings.TargetAmount > currentAmount); - - return new ViewCrowdfundViewModel() - { - Title = settings.Title, - Tagline = settings.Tagline, - Description = settings.Description, - CustomCSSLink = settings.CustomCSSLink, - MainImageUrl = settings.MainImageUrl, - EmbeddedCSS = settings.EmbeddedCSS, - StoreId = appData.StoreDataId, - AppId = appData.Id, - StartDate = settings.StartDate, - EndDate = settings.EndDate, - TargetAmount = settings.TargetAmount, - TargetCurrency = settings.TargetCurrency, - EnforceTargetAmount = settings.EnforceTargetAmount, - StatusMessage = statusMessage, - Info = new ViewCrowdfundViewModel.CrowdfundInfo() - { - TotalContributors = paidInvoices, - CurrentAmount = currentAmount, - Active = active, - DaysLeft = settings.EndDate.HasValue? (settings.EndDate - DateTime.UtcNow).Value.Days: (int?) null, - DaysLeftToStart = settings.StartDate.HasValue? (settings.StartDate - DateTime.UtcNow).Value.Days: (int?) null, - ShowProgress =active && settings.TargetAmount.HasValue, - ProgressPercentage = currentAmount/ settings.TargetAmount * 100 - } - }; - } - - private static async Task GetPaidInvoicesForApp(AppData appData, InvoiceRepository invoiceRepository) - { - return await invoiceRepository.GetInvoices(new InvoiceQuery() - { - OrderId = appData.Id, - Status = new string[]{ InvoiceState.ToString(InvoiceStatus.Complete)} - }); - } - } - - public class AppsHelper { ApplicationDbContextFactory _ContextFactory; diff --git a/BTCPayServer/Controllers/InvoiceController.UI.cs b/BTCPayServer/Controllers/InvoiceController.UI.cs index b9ebdaecb..69d1ef708 100644 --- a/BTCPayServer/Controllers/InvoiceController.UI.cs +++ b/BTCPayServer/Controllers/InvoiceController.UI.cs @@ -638,13 +638,13 @@ namespace BTCPayServer.Controllers if (newState == "invalid") { await _InvoiceRepository.UpdatePaidInvoiceToInvalid(invoiceId); - _EventAggregator.Publish(new InvoiceEvent(invoice.EntityToDTO(_NetworkProvider), 1008, "invoice_markedInvalid")); + _EventAggregator.Publish(new InvoiceEvent(invoice.EntityToDTO(_NetworkProvider), 1008, InvoiceEvent.MarkedInvalid)); StatusMessage = "Invoice marked invalid"; } else if(newState == "complete") { await _InvoiceRepository.UpdatePaidInvoiceToComplete(invoiceId); - _EventAggregator.Publish(new InvoiceEvent(invoice.EntityToDTO(_NetworkProvider), 2008, "invoice_markedComplete")); + _EventAggregator.Publish(new InvoiceEvent(invoice.EntityToDTO(_NetworkProvider), 2008, InvoiceEvent.MarkedCompleted)); StatusMessage = "Invoice marked complete"; } return RedirectToAction(nameof(ListInvoices)); diff --git a/BTCPayServer/Events/InvoiceEvent.cs b/BTCPayServer/Events/InvoiceEvent.cs index c3d0f60a3..616b5c404 100644 --- a/BTCPayServer/Events/InvoiceEvent.cs +++ b/BTCPayServer/Events/InvoiceEvent.cs @@ -8,6 +8,18 @@ namespace BTCPayServer.Events { public class InvoiceEvent { + public const string Created = "invoice_created"; + public const string ReceivedPayment = "invoice_receivedPayment"; + public const string MarkedCompleted = "invoice_markedComplete"; + public const string MarkedInvalid= "invoice_markedInvalid"; + public const string Expired= "invoice_expired"; + public const string ExpiredPaidPartial= "invoice_expiredPaidPartial"; + public const string PaidInFull= "invoice_paidInFull"; + public const string PaidAfterExpiration= "invoice_paidAfterExpiration"; + public const string FailedToConfirm= "invoice_failedToConfirm"; + public const string Confirmed= "invoice_confirmed"; + public const string Completed= "invoice_completed"; + public InvoiceEvent(Models.InvoiceResponse invoice, int code, string name) { Invoice = invoice; diff --git a/BTCPayServer/HostedServices/InvoiceWatcher.cs b/BTCPayServer/HostedServices/InvoiceWatcher.cs index c037a9724..7c9687bfc 100644 --- a/BTCPayServer/HostedServices/InvoiceWatcher.cs +++ b/BTCPayServer/HostedServices/InvoiceWatcher.cs @@ -66,10 +66,10 @@ namespace BTCPayServer.HostedServices context.MarkDirty(); await _InvoiceRepository.UnaffectAddress(invoice.Id); - context.Events.Add(new InvoiceEvent(invoice.EntityToDTO(_NetworkProvider), 1004, "invoice_expired")); + context.Events.Add(new InvoiceEvent(invoice.EntityToDTO(_NetworkProvider), 1004, InvoiceEvent.Expired)); invoice.Status = InvoiceStatus.Expired; if(invoice.ExceptionStatus == InvoiceExceptionStatus.PaidPartial) - context.Events.Add(new InvoiceEvent(invoice.EntityToDTO(_NetworkProvider), 2000, "invoice_expiredPaidPartial")); + context.Events.Add(new InvoiceEvent(invoice.EntityToDTO(_NetworkProvider), 2000, InvoiceEvent.ExpiredPaidPartial)); } var payments = invoice.GetPayments().Where(p => p.Accounted).ToArray(); @@ -84,7 +84,7 @@ namespace BTCPayServer.HostedServices { if (invoice.Status == InvoiceStatus.New) { - context.Events.Add(new InvoiceEvent(invoice.EntityToDTO(_NetworkProvider), 1003, "invoice_paidInFull")); + context.Events.Add(new InvoiceEvent(invoice.EntityToDTO(_NetworkProvider), 1003, InvoiceEvent.PaidInFull)); invoice.Status = InvoiceStatus.Paid; invoice.ExceptionStatus = accounting.Paid > accounting.TotalDue ? InvoiceExceptionStatus.PaidOver : InvoiceExceptionStatus.None; await _InvoiceRepository.UnaffectAddress(invoice.Id); @@ -93,7 +93,7 @@ namespace BTCPayServer.HostedServices else if (invoice.Status == InvoiceStatus.Expired && invoice.ExceptionStatus != InvoiceExceptionStatus.PaidLate) { invoice.ExceptionStatus = InvoiceExceptionStatus.PaidLate; - context.Events.Add(new InvoiceEvent(invoice.EntityToDTO(_NetworkProvider), 1009, "invoice_paidAfterExpiration")); + context.Events.Add(new InvoiceEvent(invoice.EntityToDTO(_NetworkProvider), 1009, InvoiceEvent.PaidAfterExpiration)); context.MarkDirty(); } } @@ -139,14 +139,14 @@ namespace BTCPayServer.HostedServices (confirmedAccounting.Paid < accounting.MinimumTotalDue)) { await _InvoiceRepository.UnaffectAddress(invoice.Id); - context.Events.Add(new InvoiceEvent(invoice.EntityToDTO(_NetworkProvider), 1013, "invoice_failedToConfirm")); + context.Events.Add(new InvoiceEvent(invoice.EntityToDTO(_NetworkProvider), 1013, InvoiceEvent.FailedToConfirm)); invoice.Status = InvoiceStatus.Invalid; context.MarkDirty(); } else if (confirmedAccounting.Paid >= accounting.MinimumTotalDue) { await _InvoiceRepository.UnaffectAddress(invoice.Id); - context.Events.Add(new InvoiceEvent(invoice.EntityToDTO(_NetworkProvider), 1005, "invoice_confirmed")); + context.Events.Add(new InvoiceEvent(invoice.EntityToDTO(_NetworkProvider), 1005, InvoiceEvent.Confirmed)); invoice.Status = InvoiceStatus.Confirmed; context.MarkDirty(); } @@ -157,7 +157,7 @@ namespace BTCPayServer.HostedServices var completedAccounting = paymentMethod.Calculate(p => p.GetCryptoPaymentData().PaymentCompleted(p, network)); if (completedAccounting.Paid >= accounting.MinimumTotalDue) { - context.Events.Add(new InvoiceEvent(invoice.EntityToDTO(_NetworkProvider), 1006, "invoice_completed")); + context.Events.Add(new InvoiceEvent(invoice.EntityToDTO(_NetworkProvider), 1006, InvoiceEvent.Completed)); invoice.Status = InvoiceStatus.Complete; context.MarkDirty(); } @@ -247,13 +247,13 @@ namespace BTCPayServer.HostedServices })); leases.Add(_EventAggregator.Subscribe(async b => { - if (b.Name == "invoice_created") + if (b.Name == InvoiceEvent.Created) { Watch(b.Invoice.Id); await Wait(b.Invoice.Id); } - if (b.Name == "invoice_receivedPayment") + if (b.Name == InvoiceEvent.ReceivedPayment) { Watch(b.Invoice.Id); } diff --git a/BTCPayServer/Hubs/CrowdfundHub.cs b/BTCPayServer/Hubs/CrowdfundHub.cs index 72a2a7d9f..1e7ccaa47 100644 --- a/BTCPayServer/Hubs/CrowdfundHub.cs +++ b/BTCPayServer/Hubs/CrowdfundHub.cs @@ -1,10 +1,221 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; using System.Threading.Tasks; +using BTCPayServer.Controllers; +using BTCPayServer.Data; +using BTCPayServer.Events; +using BTCPayServer.Models.AppViewModels; +using BTCPayServer.Rating; +using BTCPayServer.Services.Apps; +using BTCPayServer.Services.Invoices; +using BTCPayServer.Services.Rates; +using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.SignalR; +using Microsoft.Extensions.Caching.Memory; +using Microsoft.Extensions.Primitives; namespace BTCPayServer.Hubs { public class CrowdfundHub: Hub { + private readonly AppsPublicController _AppsPublicController; + + public CrowdfundHub(AppsPublicController appsPublicController) + { + _AppsPublicController = appsPublicController; + } + public async Task ListenToCrowdfundApp(string appId) + { + if (Context.Items.ContainsKey("app")) + { + await Groups.RemoveFromGroupAsync(Context.ConnectionId, Context.Items["app"].ToString()); + Context.Items.Remove("app"); + } + Context.Items.Add("app", appId); + await Groups.AddToGroupAsync(Context.ConnectionId, appId); + } + + public async Task PushUpdatedCrowdfundInfo() + { + + } + + public async Task CreateInvoice(ContributeToCrowdfund model) + { + model.RedirectToCheckout = false; + var result = await _AppsPublicController.ContributeToCrowdfund(Context.Items["app"].ToString(), model); + return (result as OkObjectResult)?.Value.ToString(); + } + + public async Task PaymentReceived() + { + + } + } + + public class CrowdfundHubStreamer + { + public const string CrowdfundInvoiceOrderIdPrefix = "crowdfund-app:"; + private readonly EventAggregator _EventAggregator; + private readonly IHubContext _HubContext; + private readonly IMemoryCache _MemoryCache; + private readonly AppsHelper _AppsHelper; + private readonly RateFetcher _RateFetcher; + private readonly BTCPayNetworkProvider _BtcPayNetworkProvider; + private readonly InvoiceRepository _InvoiceRepository; + + private Dictionary _CacheTokens = new Dictionary(); + public CrowdfundHubStreamer(EventAggregator eventAggregator, + IHubContext hubContext, + IMemoryCache memoryCache, + AppsHelper appsHelper, + RateFetcher rateFetcher, + BTCPayNetworkProvider btcPayNetworkProvider, + InvoiceRepository invoiceRepository) + { + _EventAggregator = eventAggregator; + _HubContext = hubContext; + _MemoryCache = memoryCache; + _AppsHelper = appsHelper; + _RateFetcher = rateFetcher; + _BtcPayNetworkProvider = btcPayNetworkProvider; + _InvoiceRepository = invoiceRepository; + SubscribeToEvents(); + } + + public Task GetCrowdfundInfo(string appId) + { + var key = GetCacheKey(appId); + return _MemoryCache.GetOrCreateAsync(key, async entry => + { + if (_CacheTokens.ContainsKey(key)) + { + _CacheTokens.Remove(key); + } + + var token = new CancellationTokenSource(); + _CacheTokens.Add(key, token); + entry.AddExpirationToken(new CancellationChangeToken(token.Token)); + entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(20); + + var app = await _AppsHelper.GetApp(appId, AppType.Crowdfund, true); + var result = await GetInfo(app, _InvoiceRepository, _RateFetcher, + _BtcPayNetworkProvider); + entry.SetValue(result); + return result; + }); + } + + private void SubscribeToEvents() + { + + _EventAggregator.Subscribe(Subscription); + } + + private string GetCacheKey(string appId) + { + return $"{CrowdfundInvoiceOrderIdPrefix}:{appId}"; + } + + private void Subscription(InvoiceEvent invoiceEvent) + { + if (!invoiceEvent.Invoice.OrderId.StartsWith(CrowdfundInvoiceOrderIdPrefix, StringComparison.InvariantCultureIgnoreCase)) + { + return; + } + var appId = invoiceEvent.Invoice.OrderId.Replace(CrowdfundInvoiceOrderIdPrefix, "", StringComparison.InvariantCultureIgnoreCase); + if (invoiceEvent.Name == InvoiceEvent.ReceivedPayment) + { + _HubContext.Clients.Group(appId).SendCoreAsync(nameof(CrowdfundHub.PaymentReceived), new object[]{ invoiceEvent.Invoice.AmountPaid } ); + } + } + + private static async Task GetCurrentContributionAmount(InvoiceEntity[] invoices, string primaryCurrency, + RateFetcher rateFetcher, RateRules rateRules) + { + decimal result = 0; + + var groupingByCurrency = invoices.GroupBy(entity => entity.ProductInformation.Currency); + + var ratesTask = rateFetcher.FetchRates( + groupingByCurrency + .Select((entities) => new CurrencyPair(entities.Key, primaryCurrency)) + .ToHashSet(), + rateRules); + + var finalTasks = new List(); + foreach (var rateTask in ratesTask) + { + finalTasks.Add(Task.Run(async () => + { + var tResult = await rateTask.Value; + var rate = tResult.BidAsk?.Bid; + if (rate == null) return; + var currencyGroup = groupingByCurrency.Single(entities => entities.Key == rateTask.Key.Left); + result += currencyGroup.Sum(entity => entity.ProductInformation.Price / rate.Value); + })); + } + + await Task.WhenAll(finalTasks); + + return result; + + } + + public static async Task GetInfo(AppData appData, InvoiceRepository invoiceRepository, + RateFetcher rateFetcher, BTCPayNetworkProvider btcPayNetworkProvider, string statusMessage= null) + { + var settings = appData.GetSettings(); + var invoices = await GetPaidInvoicesForApp(appData, invoiceRepository); + var rateRules = appData.StoreData.GetStoreBlob().GetRateRules(btcPayNetworkProvider); + var currentAmount = await GetCurrentContributionAmount( + invoices, + settings.TargetCurrency, rateFetcher, rateRules); + var paidInvoices = invoices.Length; + var active = (settings.StartDate == null || DateTime.UtcNow >= settings.StartDate) && + (settings.EndDate == null || DateTime.UtcNow <= settings.EndDate) && + (!settings.EnforceTargetAmount || settings.TargetAmount > currentAmount); + + return new ViewCrowdfundViewModel() + { + Title = settings.Title, + Tagline = settings.Tagline, + Description = settings.Description, + CustomCSSLink = settings.CustomCSSLink, + MainImageUrl = settings.MainImageUrl, + EmbeddedCSS = settings.EmbeddedCSS, + StoreId = appData.StoreDataId, + AppId = appData.Id, + StartDate = settings.StartDate, + EndDate = settings.EndDate, + TargetAmount = settings.TargetAmount, + TargetCurrency = settings.TargetCurrency, + EnforceTargetAmount = settings.EnforceTargetAmount, + StatusMessage = statusMessage, + Info = new ViewCrowdfundViewModel.CrowdfundInfo() + { + TotalContributors = paidInvoices, + CurrentAmount = currentAmount, + Active = active, + DaysLeft = settings.EndDate.HasValue? (settings.EndDate - DateTime.UtcNow).Value.Days: (int?) null, + DaysLeftToStart = settings.StartDate.HasValue? (settings.StartDate - DateTime.UtcNow).Value.Days: (int?) null, + ShowProgress =active && settings.TargetAmount.HasValue, + ProgressPercentage = currentAmount/ settings.TargetAmount * 100 + } + }; + } + + private static async Task GetPaidInvoicesForApp(AppData appData, InvoiceRepository invoiceRepository) + { + return await invoiceRepository.GetInvoices(new InvoiceQuery() + { + OrderId = appData.Id, + Status = new string[]{ InvoiceState.ToString(InvoiceStatus.Complete)} + }); + } + } } diff --git a/BTCPayServer/Payments/Lightning/LightningListener.cs b/BTCPayServer/Payments/Lightning/LightningListener.cs index abf56011b..b800f5d96 100644 --- a/BTCPayServer/Payments/Lightning/LightningListener.cs +++ b/BTCPayServer/Payments/Lightning/LightningListener.cs @@ -42,7 +42,7 @@ namespace BTCPayServer.Payments.Lightning { leases.Add(_Aggregator.Subscribe(async inv => { - if (inv.Name == "invoice_created") + if (inv.Name == InvoiceEvent.Created) { await EnsureListening(inv.Invoice.Id, false); } diff --git a/BTCPayServer/Views/AppsPublic/ContributeForm.cshtml b/BTCPayServer/Views/AppsPublic/Crowdfund/ContributeForm.cshtml similarity index 100% rename from BTCPayServer/Views/AppsPublic/ContributeForm.cshtml rename to BTCPayServer/Views/AppsPublic/Crowdfund/ContributeForm.cshtml diff --git a/BTCPayServer/Views/AppsPublic/MinimalCrowdfund.cshtml b/BTCPayServer/Views/AppsPublic/Crowdfund/MinimalCrowdfund.cshtml similarity index 97% rename from BTCPayServer/Views/AppsPublic/MinimalCrowdfund.cshtml rename to BTCPayServer/Views/AppsPublic/Crowdfund/MinimalCrowdfund.cshtml index 96b68800d..f33304ff5 100644 --- a/BTCPayServer/Views/AppsPublic/MinimalCrowdfund.cshtml +++ b/BTCPayServer/Views/AppsPublic/Crowdfund/MinimalCrowdfund.cshtml @@ -1,6 +1,6 @@ @using BTCPayServer.Models.AppViewModels @model BTCPayServer.Models.AppViewModels.ViewCrowdfundViewModel -
+
@@ -87,7 +87,7 @@ {

Contribute

- +
+
+ +
+
+ +
+
+
+
+
+ +

+ {{srvModel.title}} +

{{srvModel.tagline}}

+ + {{ srvModel.info.daysLeftToStart }} days left to start + + + +
+
    +
  • + + +
  • +
  • + + + +
  • +
  • + + +
  • +
+ +
+
+
+
+
{{srvModel.info.totalContributors}}
+
Contributors
+
+
+
+
+
{{srvModel.info.currentAmount}} {{srvModel.info.targetCurrency}}
+
Raised
+
+
+ +
+
+
{{srvModel.info.daysLeft}}
+
Days left
+
+
+
+ + +
+ +
+

Contribute

+ + +
+
+ + +
+
diff --git a/BTCPayServer/Views/AppsPublic/ViewCrowdfund.cshtml b/BTCPayServer/Views/AppsPublic/ViewCrowdfund.cshtml index adddc4d6b..31c843d3d 100644 --- a/BTCPayServer/Views/AppsPublic/ViewCrowdfund.cshtml +++ b/BTCPayServer/Views/AppsPublic/ViewCrowdfund.cshtml @@ -18,21 +18,35 @@ { } - - - - @if (!string.IsNullOrEmpty(Model.EmbeddedCSS)) - { - - } - - + } + - - + +@if (Context.Request.Query.ContainsKey("simple")) +{ + @await Html.PartialAsync("Crowdfund/MinimalCrowdfund", Model) +} +else +{ + + + @await Html.PartialAsync("Crowdfund/VueCrowdfund", Model) +} + diff --git a/BTCPayServer/bundleconfig.json b/BTCPayServer/bundleconfig.json index 04e6b9af7..9b105331d 100644 --- a/BTCPayServer/bundleconfig.json +++ b/BTCPayServer/bundleconfig.json @@ -53,6 +53,7 @@ "wwwroot/checkout/**/*.js" ] }, + { "outputFileName": "wwwroot/bundles/cart-bundle.min.js", "inputFiles": [ @@ -65,9 +66,21 @@ { "outputFileName": "wwwroot/bundles/crowdfund-bundle.min.js", "inputFiles": [ - "wwwroot/vendor/jquery/jquery.js", - "wwwroot/vendor/bootstrap4/js/bootstrap.js", - "wwwroot/modal/btcpay.js" + "wwwroot/vendor/vuejs/vue.min.js", + "wwwroot/vendor/babel-polyfill/polyfill.min.js", + "wwwroot/vendor/bootstrap-vue/bootstrap-vue.js", + "wwwroot/vendor/signalr/signalr.js", + "wwwroot/vendor/moment/moment.js", + "wwwroot/modal/btcpay.js", + "wwwroot/crowdfund/**/*.js" + ] + }, + { + "outputFileName": "wwwroot/bundles/crowdfund-bundle.min.css", + "inputFiles": [ + "wwwroot/vendor/font-awesome/css/font-awesome.min.css", + "wwwroot/vendor/bootstrap-vue/bootstrap-vue.css", + "wwwroot/crowdfund/**/*.css" ] } ] diff --git a/BTCPayServer/wwwroot/crowdfund/app.js b/BTCPayServer/wwwroot/crowdfund/app.js new file mode 100644 index 000000000..24294235e --- /dev/null +++ b/BTCPayServer/wwwroot/crowdfund/app.js @@ -0,0 +1,17 @@ +var app = null; +window.onload = function (ev) { + + + app = new Vue({ + el: '#app', + data: function () { + return { + srvModel: window.srvModel + } + }, + mounted: function () { + hubListener.connect(); + } + }); +}; + diff --git a/BTCPayServer/wwwroot/crowdfund/components/contribute.js b/BTCPayServer/wwwroot/crowdfund/components/contribute.js new file mode 100644 index 000000000..58386f9da --- /dev/null +++ b/BTCPayServer/wwwroot/crowdfund/components/contribute.js @@ -0,0 +1,7 @@ +Vue.component('contribute', { + data: function () { + return { + } + }, + template: '' +}); diff --git a/BTCPayServer/wwwroot/crowdfund/services/listener.js b/BTCPayServer/wwwroot/crowdfund/services/listener.js new file mode 100644 index 000000000..8e414b214 --- /dev/null +++ b/BTCPayServer/wwwroot/crowdfund/services/listener.js @@ -0,0 +1,42 @@ + +var hubListener = function(){ + + var statuses = { + DISCONNECTED: "disconnected", + CONNECTED: "connected", + CONNECTING: "connecting" + }; + var status = "disconnected"; + + + var connection = new signalR.HubConnectionBuilder().withUrl("/crowdfundHub").build(); + + connection.onclose(function(){ + this.status = statuses.DISCONNECTED; + console.error("Connection was closed. Attempting reconnect in 2s"); + setTimeout(connect, 2000); + }); + + + + function connect(){ + status = statuses.CONNECTING; + connection + .start() + .then(function(){ + this.status = statuses.CONNECTED; + }) + .catch(function (err) { + this.status = statuses.DISCONNECTED; + console.error("Could not connect to backend. Retrying in 2s", err ); + setTimeout(connect, 2000); + }); + } + + return { + statuses: statuses, + status: status, + connect: connect + }; +}(); + diff --git a/BTCPayServer/wwwroot/crowdfund/styles/main.css b/BTCPayServer/wwwroot/crowdfund/styles/main.css new file mode 100644 index 000000000..a0b5fa2e0 --- /dev/null +++ b/BTCPayServer/wwwroot/crowdfund/styles/main.css @@ -0,0 +1,2 @@ +[v-cloak] > * { display:none } +[v-cloak]::before { content: "loading…" } diff --git a/BTCPayServer/wwwroot/vendor/babel-polyfill/polyfill.min.js b/BTCPayServer/wwwroot/vendor/babel-polyfill/polyfill.min.js new file mode 100644 index 000000000..80922170f --- /dev/null +++ b/BTCPayServer/wwwroot/vendor/babel-polyfill/polyfill.min.js @@ -0,0 +1,4 @@ +!function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var c="function"==typeof require&&require;if(!u&&c)return c(o,!0);if(i)return i(o,!0);var a=new Error("Cannot find module '"+o+"'");throw a.code="MODULE_NOT_FOUND",a}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(n){var r=t[o][1][n];return s(r||n)},f,f.exports,e,t,n,r)}return n[o].exports}for(var i="function"==typeof require&&require,o=0;o2?arguments[2]:void 0,s=Math.min((void 0===f?u:i(f,u))-a,u-c),l=1;for(a0;)a in r?r[c]=r[a]:delete r[c],c+=l,a+=l;return r}},{114:114,118:118,119:119}],9:[function(t,n,r){"use strict";var e=t(119),i=t(114),o=t(118);n.exports=function fill(t){for(var n=e(this),r=o(n.length),u=arguments.length,c=i(u>1?arguments[1]:void 0,r),a=u>2?arguments[2]:void 0,f=void 0===a?r:i(a,r);f>c;)n[c++]=t;return n}},{114:114,118:118,119:119}],10:[function(t,n,r){var e=t(39);n.exports=function(t,n){var r=[];return e(t,!1,r.push,r,n),r}},{39:39}],11:[function(t,n,r){var e=t(117),i=t(118),o=t(114);n.exports=function(t){return function(n,r,u){var c,a=e(n),f=i(a.length),s=o(u,f);if(t&&r!=r){for(;f>s;)if((c=a[s++])!=c)return!0}else for(;f>s;s++)if((t||s in a)&&a[s]===r)return t||s||0;return!t&&-1}}},{114:114,117:117,118:118}],12:[function(t,n,r){var e=t(25),i=t(47),o=t(119),u=t(118),c=t(15);n.exports=function(t,n){var r=1==t,a=2==t,f=3==t,s=4==t,l=6==t,h=5==t||l,v=n||c;return function(n,c,p){for(var d,y,g=o(n),m=i(g),b=e(c,p,3),x=u(m.length),S=0,w=r?v(n,x):a?v(n,0):void 0;x>S;S++)if((h||S in m)&&(d=m[S],y=b(d,S,g),t))if(r)w[S]=y;else if(y)switch(t){case 3:return!0;case 5:return d;case 6:return S;case 2:w.push(d)}else if(s)return!1;return l?-1:f||s?s:w}}},{118:118,119:119,15:15,25:25,47:47}],13:[function(t,n,r){var e=t(3),i=t(119),o=t(47),u=t(118);n.exports=function(t,n,r,c,a){e(n);var f=i(t),s=o(f),l=u(f.length),h=a?l-1:0,v=a?-1:1;if(r<2)for(;;){if(h in s){c=s[h],h+=v;break}if(h+=v,a?h<0:l<=h)throw TypeError("Reduce of empty array with no initial value")}for(;a?h>=0:l>h;h+=v)h in s&&(c=n(c,s[h],h,f));return c}},{118:118,119:119,3:3,47:47}],14:[function(t,n,r){var e=t(51),i=t(49),o=t(128)("species");n.exports=function(t){var n;return i(t)&&(n=t.constructor,"function"!=typeof n||n!==Array&&!i(n.prototype)||(n=void 0),e(n)&&null===(n=n[o])&&(n=void 0)),void 0===n?Array:n}},{128:128,49:49,51:51}],15:[function(t,n,r){var e=t(14);n.exports=function(t,n){return new(e(t))(n)}},{14:14}],16:[function(t,n,r){"use strict";var e=t(3),i=t(51),o=t(46),u=[].slice,c={},a=function(t,n,r){if(!(n in c)){for(var e=[],i=0;i1?arguments[1]:void 0,3);r=r?r.n:this._f;)for(e(r.v,r.k,this);r&&r.r;)r=r.p},has:function has(t){return!!y(p(this,n),t)}}),h&&e(s.prototype,"size",{get:function(){return p(this,n)[d]}}),s},def:function(t,n,r){var e,i,o=y(t,n);return o?o.v=r:(t._l=o={i:i=v(n,!0),k:n,v:r,p:e=t._l,n:void 0,r:!1},t._f||(t._f=o),e&&(e.n=o),t[d]++,"F"!==i&&(t._i[i]=o)),t},getEntry:y,setStrong:function(t,n,r){f(t,n,function(t,r){this._t=p(t,n),this._k=r,this._l=void 0},function(){for(var t=this,n=t._k,r=t._l;r&&r.r;)r=r.p;return t._t&&(t._l=r=r?r.n:t._t._f)?"keys"==n?s(0,r.k):"values"==n?s(0,r.v):s(0,[r.k,r.v]):(t._t=void 0,s(1))},r?"entries":"values",!r,!0),l(n)}}},{100:100,125:125,25:25,29:29,39:39,55:55,57:57,6:6,66:66,71:71,72:72,93:93}],20:[function(t,n,r){var e=t(17),i=t(10);n.exports=function(t){return function toJSON(){if(e(this)!=t)throw TypeError(t+"#toJSON isn't generic");return i(this)}}},{10:10,17:17}],21:[function(t,n,r){"use strict";var e=t(93),i=t(66).getWeak,o=t(7),u=t(51),c=t(6),a=t(39),f=t(12),s=t(41),l=t(125),h=f(5),v=f(6),p=0,d=function(t){return t._l||(t._l=new y)},y=function(){this.a=[]},g=function(t,n){return h(t.a,function(t){return t[0]===n})};y.prototype={get:function(t){var n=g(this,t);if(n)return n[1]},has:function(t){return!!g(this,t)},set:function(t,n){var r=g(this,t);r?r[1]=n:this.a.push([t,n])},delete:function(t){var n=v(this.a,function(n){return n[0]===t});return~n&&this.a.splice(n,1),!!~n}},n.exports={getConstructor:function(t,n,r,o){var f=t(function(t,e){c(t,f,n,"_i"),t._t=n,t._i=p++,t._l=void 0,void 0!=e&&a(e,r,t[o],t)});return e(f.prototype,{delete:function(t){if(!u(t))return!1;var r=i(t);return!0===r?d(l(this,n)).delete(t):r&&s(r,this._i)&&delete r[this._i]},has:function has(t){if(!u(t))return!1;var r=i(t);return!0===r?d(l(this,n)).has(t):r&&s(r,this._i)}}),f},def:function(t,n,r){var e=i(o(n),!0);return!0===e?d(t).set(n,r):e[t._i]=r,t},ufstore:d}},{12:12,125:125,39:39,41:41,51:51,6:6,66:66,7:7,93:93}],22:[function(t,n,r){"use strict";var e=t(40),i=t(33),o=t(94),u=t(93),c=t(66),a=t(39),f=t(6),s=t(51),l=t(35),h=t(56),v=t(101),p=t(45);n.exports=function(t,n,r,d,y,g){var m=e[t],b=m,x=y?"set":"add",S=b&&b.prototype,w={},_=function(t){var n=S[t];o(S,t,"delete"==t?function(t){return!(g&&!s(t))&&n.call(this,0===t?0:t)}:"has"==t?function has(t){return!(g&&!s(t))&&n.call(this,0===t?0:t)}:"get"==t?function get(t){return g&&!s(t)?void 0:n.call(this,0===t?0:t)}:"add"==t?function add(t){return n.call(this,0===t?0:t),this}:function set(t,r){return n.call(this,0===t?0:t,r),this})};if("function"==typeof b&&(g||S.forEach&&!l(function(){(new b).entries().next()}))){var E=new b,O=E[x](g?{}:-0,1)!=E,P=l(function(){E.has(1)}),M=h(function(t){new b(t)}),F=!g&&l(function(){for(var t=new b,n=5;n--;)t[x](n,n);return!t.has(-0)});M||(b=n(function(n,r){f(n,b,t);var e=p(new m,n,b);return void 0!=r&&a(r,y,e[x],e),e}),b.prototype=S,S.constructor=b),(P||F)&&(_("delete"),_("has"),y&&_("get")),(F||O)&&_(x),g&&S.clear&&delete S.clear}else b=d.getConstructor(n,t,y,x),u(b.prototype,r),c.NEED=!0;return v(b,t),w[t]=b,i(i.G+i.W+i.F*(b!=m),w),g||d.setStrong(b,t,y),b}},{101:101,33:33,35:35,39:39,40:40,45:45,51:51,56:56,6:6,66:66,93:93,94:94}],23:[function(t,n,r){var e=n.exports={version:"2.5.0"};"number"==typeof __e&&(__e=e)},{}],24:[function(t,n,r){"use strict";var e=t(72),i=t(92);n.exports=function(t,n,r){n in t?e.f(t,n,i(0,r)):t[n]=r}},{72:72,92:92}],25:[function(t,n,r){var e=t(3);n.exports=function(t,n,r){if(e(t),void 0===n)return t;switch(r){case 1:return function(r){return t.call(n,r)};case 2:return function(r,e){return t.call(n,r,e)};case 3:return function(r,e,i){return t.call(n,r,e,i)}}return function(){return t.apply(n,arguments)}}},{3:3}],26:[function(t,n,r){"use strict";var e=t(35),i=Date.prototype.getTime,o=Date.prototype.toISOString,u=function(t){return t>9?t:"0"+t};n.exports=e(function(){return"0385-07-25T07:06:39.999Z"!=o.call(new Date(-5e13-1))})||!e(function(){o.call(new Date(NaN))})?function toISOString(){if(!isFinite(i.call(this)))throw RangeError("Invalid time value");var t=this,n=t.getUTCFullYear(),r=t.getUTCMilliseconds(),e=n<0?"-":n>9999?"+":"";return e+("00000"+Math.abs(n)).slice(e?-6:-4)+"-"+u(t.getUTCMonth()+1)+"-"+u(t.getUTCDate())+"T"+u(t.getUTCHours())+":"+u(t.getUTCMinutes())+":"+u(t.getUTCSeconds())+"."+(r>99?r:"0"+u(r))+"Z"}:o},{35:35}],27:[function(t,n,r){"use strict";var e=t(7),i=t(120);n.exports=function(t){if("string"!==t&&"number"!==t&&"default"!==t)throw TypeError("Incorrect hint");return i(e(this),"number"!=t)}},{120:120,7:7}],28:[function(t,n,r){n.exports=function(t){if(void 0==t)throw TypeError("Can't call method on "+t);return t}},{}],29:[function(t,n,r){n.exports=!t(35)(function(){return 7!=Object.defineProperty({},"a",{get:function(){return 7}}).a})},{35:35}],30:[function(t,n,r){var e=t(51),i=t(40).document,o=e(i)&&e(i.createElement);n.exports=function(t){return o?i.createElement(t):{}}},{40:40,51:51}],31:[function(t,n,r){n.exports="constructor,hasOwnProperty,isPrototypeOf,propertyIsEnumerable,toLocaleString,toString,valueOf".split(",")},{}],32:[function(t,n,r){var e=t(81),i=t(78),o=t(82);n.exports=function(t){var n=e(t),r=i.f;if(r)for(var u,c=r(t),a=o.f,f=0;c.length>f;)a.call(t,u=c[f++])&&n.push(u);return n}},{78:78,81:81,82:82}],33:[function(t,n,r){var e=t(40),i=t(23),o=t(42),u=t(94),c=t(25),a=function(t,n,r){var f,s,l,h,v=t&a.F,p=t&a.G,d=t&a.S,y=t&a.P,g=t&a.B,m=p?e:d?e[n]||(e[n]={}):(e[n]||{}).prototype,b=p?i:i[n]||(i[n]={}),x=b.prototype||(b.prototype={});p&&(r=n);for(f in r)s=!v&&m&&void 0!==m[f],l=(s?m:r)[f],h=g&&s?c(l,e):y&&"function"==typeof l?c(Function.call,l):l,m&&u(m,f,l,t&a.U),b[f]!=l&&o(b,f,h),y&&x[f]!=l&&(x[f]=l)};e.core=i,a.F=1,a.G=2,a.S=4,a.P=8,a.B=16,a.W=32,a.U=64,a.R=128,n.exports=a},{23:23,25:25,40:40,42:42,94:94}],34:[function(t,n,r){var e=t(128)("match");n.exports=function(t){var n=/./;try{"/./"[t](n)}catch(r){try{return n[e]=!1,!"/./"[t](n)}catch(t){}}return!0}},{128:128}],35:[function(t,n,r){n.exports=function(t){try{return!!t()}catch(t){return!0}}},{}],36:[function(t,n,r){"use strict";var e=t(42),i=t(94),o=t(35),u=t(28),c=t(128);n.exports=function(t,n,r){var a=c(t),f=r(u,a,""[t]),s=f[0],l=f[1];o(function(){var n={};return n[a]=function(){return 7},7!=""[t](n)})&&(i(String.prototype,t,s),e(RegExp.prototype,a,2==n?function(t,n){return l.call(t,this,n)}:function(t){return l.call(t,this)}))}},{128:128,28:28,35:35,42:42,94:94}],37:[function(t,n,r){"use strict";var e=t(7);n.exports=function(){var t=e(this),n="";return t.global&&(n+="g"),t.ignoreCase&&(n+="i"),t.multiline&&(n+="m"),t.unicode&&(n+="u"),t.sticky&&(n+="y"),n}},{7:7}],38:[function(t,n,r){"use strict";function flattenIntoArray(t,n,r,a,f,s,l,h){for(var v,p,d=f,y=0,g=!!l&&u(l,h,3);y0)d=flattenIntoArray(t,n,v,o(v.length),d,s-1)-1;else{if(d>=9007199254740991)throw TypeError();t[d]=v}d++}y++}return d}var e=t(49),i=t(51),o=t(118),u=t(25),c=t(128)("isConcatSpreadable");n.exports=flattenIntoArray},{118:118,128:128,25:25,49:49,51:51}],39:[function(t,n,r){var e=t(25),i=t(53),o=t(48),u=t(7),c=t(118),a=t(129),f={},s={},r=n.exports=function(t,n,r,l,h){var v,p,d,y,g=h?function(){return t}:a(t),m=e(r,l,n?2:1),b=0;if("function"!=typeof g)throw TypeError(t+" is not iterable!");if(o(g)){for(v=c(t.length);v>b;b++)if((y=n?m(u(p=t[b])[0],p[1]):m(t[b]))===f||y===s)return y}else for(d=g.call(t);!(p=d.next()).done;)if((y=i(d,m,p.value,n))===f||y===s)return y};r.BREAK=f,r.RETURN=s},{118:118,129:129,25:25,48:48,53:53,7:7}],40:[function(t,n,r){var e=n.exports="undefined"!=typeof window&&window.Math==Math?window:"undefined"!=typeof self&&self.Math==Math?self:Function("return this")();"number"==typeof __g&&(__g=e)},{}],41:[function(t,n,r){var e={}.hasOwnProperty;n.exports=function(t,n){return e.call(t,n)}},{}],42:[function(t,n,r){var e=t(72),i=t(92);n.exports=t(29)?function(t,n,r){return e.f(t,n,i(1,r))}:function(t,n,r){return t[n]=r,t}},{29:29,72:72,92:92}],43:[function(t,n,r){var e=t(40).document;n.exports=e&&e.documentElement},{40:40}],44:[function(t,n,r){n.exports=!t(29)&&!t(35)(function(){return 7!=Object.defineProperty(t(30)("div"),"a",{get:function(){return 7}}).a})},{29:29,30:30,35:35}],45:[function(t,n,r){var e=t(51),i=t(99).set;n.exports=function(t,n,r){var o,u=n.constructor;return u!==r&&"function"==typeof u&&(o=u.prototype)!==r.prototype&&e(o)&&i&&i(t,o),t}},{51:51,99:99}],46:[function(t,n,r){n.exports=function(t,n,r){var e=void 0===r;switch(n.length){case 0:return e?t():t.call(r);case 1:return e?t(n[0]):t.call(r,n[0]);case 2:return e?t(n[0],n[1]):t.call(r,n[0],n[1]);case 3:return e?t(n[0],n[1],n[2]):t.call(r,n[0],n[1],n[2]);case 4:return e?t(n[0],n[1],n[2],n[3]):t.call(r,n[0],n[1],n[2],n[3])}return t.apply(r,n)}},{}],47:[function(t,n,r){var e=t(18);n.exports=Object("z").propertyIsEnumerable(0)?Object:function(t){return"String"==e(t)?t.split(""):Object(t)}},{18:18}],48:[function(t,n,r){var e=t(58),i=t(128)("iterator"),o=Array.prototype;n.exports=function(t){return void 0!==t&&(e.Array===t||o[i]===t)}},{128:128,58:58}],49:[function(t,n,r){var e=t(18);n.exports=Array.isArray||function isArray(t){return"Array"==e(t)}},{18:18}],50:[function(t,n,r){var e=t(51),i=Math.floor;n.exports=function isInteger(t){return!e(t)&&isFinite(t)&&i(t)===t}},{51:51}],51:[function(t,n,r){n.exports=function(t){return"object"==typeof t?null!==t:"function"==typeof t}},{}],52:[function(t,n,r){var e=t(51),i=t(18),o=t(128)("match");n.exports=function(t){var n;return e(t)&&(void 0!==(n=t[o])?!!n:"RegExp"==i(t))}},{128:128,18:18,51:51}],53:[function(t,n,r){var e=t(7);n.exports=function(t,n,r,i){try{return i?n(e(r)[0],r[1]):n(r)}catch(n){var o=t.return;throw void 0!==o&&e(o.call(t)),n}}},{7:7}],54:[function(t,n,r){"use strict";var e=t(71),i=t(92),o=t(101),u={};t(42)(u,t(128)("iterator"),function(){return this}),n.exports=function(t,n,r){t.prototype=e(u,{next:i(1,r)}),o(t,n+" Iterator")}},{101:101,128:128,42:42,71:71,92:92}],55:[function(t,n,r){"use strict";var e=t(60),i=t(33),o=t(94),u=t(42),c=t(41),a=t(58),f=t(54),s=t(101),l=t(79),h=t(128)("iterator"),v=!([].keys&&"next"in[].keys()),p=function(){return this};n.exports=function(t,n,r,d,y,g,m){f(r,n,d);var b,x,S,w=function(t){if(!v&&t in P)return P[t];switch(t){case"keys":return function keys(){return new r(this,t)};case"values":return function values(){return new r(this,t)}}return function entries(){return new r(this,t)}},_=n+" Iterator",E="values"==y,O=!1,P=t.prototype,M=P[h]||P["@@iterator"]||y&&P[y],F=M||w(y),I=y?E?w("entries"):F:void 0,A="Array"==n?P.entries||M:M;if(A&&(S=l(A.call(new t)))!==Object.prototype&&S.next&&(s(S,_,!0),e||c(S,h)||u(S,h,p)),E&&M&&"values"!==M.name&&(O=!0,F=function values(){return M.call(this)}),e&&!m||!v&&!O&&P[h]||u(P,h,F),a[n]=F,a[_]=p,y)if(b={values:E?F:w("values"),keys:g?F:w("keys"),entries:I},m)for(x in b)x in P||o(P,x,b[x]);else i(i.P+i.F*(v||O),n,b);return b}},{101:101,128:128,33:33,41:41,42:42,54:54,58:58,60:60,79:79,94:94}],56:[function(t,n,r){var e=t(128)("iterator"),i=!1;try{var o=[7][e]();o.return=function(){i=!0},Array.from(o,function(){throw 2})}catch(t){}n.exports=function(t,n){if(!n&&!i)return!1;var r=!1;try{var o=[7],u=o[e]();u.next=function(){return{done:r=!0}},o[e]=function(){return u},t(o)}catch(t){}return r}},{128:128}],57:[function(t,n,r){n.exports=function(t,n){return{value:n,done:!!t}}},{}],58:[function(t,n,r){n.exports={}},{}],59:[function(t,n,r){var e=t(81),i=t(117);n.exports=function(t,n){for(var r,o=i(t),u=e(o),c=u.length,a=0;c>a;)if(o[r=u[a++]]===n)return r}},{117:117,81:81}],60:[function(t,n,r){n.exports=!1},{}],61:[function(t,n,r){var e=Math.expm1;n.exports=!e||e(10)>22025.465794806718||e(10)<22025.465794806718||-2e-17!=e(-2e-17)?function expm1(t){return 0==(t=+t)?t:t>-1e-6&&t<1e-6?t+t*t/2:Math.exp(t)-1}:e},{}],62:[function(t,n,r){var e=t(65),i=Math.pow,o=i(2,-52),u=i(2,-23),c=i(2,127)*(2-u),a=i(2,-126),f=function(t){return t+1/o-1/o};n.exports=Math.fround||function fround(t){var n,r,i=Math.abs(t),s=e(t);return ic||r!=r?s*(1/0):s*r)}},{65:65}],63:[function(t,n,r){n.exports=Math.log1p||function log1p(t){return(t=+t)>-1e-8&&t<1e-8?t-t*t/2:Math.log(1+t)}},{}],64:[function(t,n,r){n.exports=Math.scale||function scale(t,n,r,e,i){return 0===arguments.length||t!=t||n!=n||r!=r||e!=e||i!=i?NaN:t===1/0||t===-1/0?t:(t-n)*(i-e)/(r-n)+e}},{}],65:[function(t,n,r){n.exports=Math.sign||function sign(t){return 0==(t=+t)||t!=t?t:t<0?-1:1}},{}],66:[function(t,n,r){var e=t(124)("meta"),i=t(51),o=t(41),u=t(72).f,c=0,a=Object.isExtensible||function(){return!0},f=!t(35)(function(){return a(Object.preventExtensions({}))}),s=function(t){u(t,e,{value:{i:"O"+ ++c,w:{}}})},l=function(t,n){if(!i(t))return"symbol"==typeof t?t:("string"==typeof t?"S":"P")+t;if(!o(t,e)){if(!a(t))return"F";if(!n)return"E";s(t)}return t[e].i},h=function(t,n){if(!o(t,e)){if(!a(t))return!0;if(!n)return!1;s(t)}return t[e].w},v=function(t){return f&&p.NEED&&a(t)&&!o(t,e)&&s(t),t},p=n.exports={KEY:e,NEED:!1,fastKey:l,getWeak:h,onFreeze:v}},{124:124,35:35,41:41,51:51,72:72}],67:[function(t,n,r){var e=t(160),i=t(33),o=t(103)("metadata"),u=o.store||(o.store=new(t(266))),c=function(t,n,r){var i=u.get(t);if(!i){if(!r)return;u.set(t,i=new e)}var o=i.get(n);if(!o){if(!r)return;i.set(n,o=new e)}return o},a=function(t,n,r){var e=c(n,r,!1);return void 0!==e&&e.has(t)},f=function(t,n,r){var e=c(n,r,!1);return void 0===e?void 0:e.get(t)},s=function(t,n,r,e){c(r,e,!0).set(t,n)},l=function(t,n){var r=c(t,n,!1),e=[];return r&&r.forEach(function(t,n){e.push(n)}),e},h=function(t){return void 0===t||"symbol"==typeof t?t:String(t)},v=function(t){i(i.S,"Reflect",t)};n.exports={store:u,map:c,has:a,get:f,set:s,keys:l,key:h,exp:v}},{103:103,160:160,266:266,33:33}],68:[function(t,n,r){var e=t(40),i=t(113).set,o=e.MutationObserver||e.WebKitMutationObserver,u=e.process,c=e.Promise,a="process"==t(18)(u);n.exports=function(){var t,n,r,f=function(){var e,i;for(a&&(e=u.domain)&&e.exit();t;){i=t.fn,t=t.next;try{i()}catch(e){throw t?r():n=void 0,e}}n=void 0,e&&e.enter()};if(a)r=function(){u.nextTick(f)};else if(o){var s=!0,l=document.createTextNode("");new o(f).observe(l,{characterData:!0}),r=function(){l.data=s=!s}}else if(c&&c.resolve){var h=c.resolve();r=function(){h.then(f)}}else r=function(){i.call(e,f)};return function(e){var i={fn:e,next:void 0};n&&(n.next=i),t||(t=i,r()),n=i}}},{113:113,18:18,40:40}],69:[function(t,n,r){"use strict";function PromiseCapability(t){var n,r;this.promise=new t(function(t,e){if(void 0!==n||void 0!==r)throw TypeError("Bad Promise constructor");n=t,r=e}),this.resolve=e(n),this.reject=e(r)}var e=t(3);n.exports.f=function(t){return new PromiseCapability(t)}},{3:3}],70:[function(t,n,r){"use strict";var e=t(81),i=t(78),o=t(82),u=t(119),c=t(47),a=Object.assign;n.exports=!a||t(35)(function(){var t={},n={},r=Symbol(),e="abcdefghijklmnopqrst";return t[r]=7,e.split("").forEach(function(t){n[t]=t}),7!=a({},t)[r]||Object.keys(a({},n)).join("")!=e})?function assign(t,n){for(var r=u(t),a=arguments.length,f=1,s=i.f,l=o.f;a>f;)for(var h,v=c(arguments[f++]),p=s?e(v).concat(s(v)):e(v),d=p.length,y=0;d>y;)l.call(v,h=p[y++])&&(r[h]=v[h]);return r}:a},{119:119,35:35,47:47,78:78,81:81,82:82}],71:[function(t,n,r){var e=t(7),i=t(73),o=t(31),u=t(102)("IE_PROTO"),c=function(){},a=function(){var n,r=t(30)("iframe"),e=o.length;for(r.style.display="none",t(43).appendChild(r),r.src="javascript:",n=r.contentWindow.document,n.open(),n.write("