From 7e8b59cbb388ac646df3645d28bd979c4081cbb5 Mon Sep 17 00:00:00 2001 From: Henry Oswald Date: Fri, 13 Apr 2018 15:57:34 +0100 Subject: [PATCH 01/13] wip form loads as ifram --- services/web/app/views/subscriptions/new.pug | 208 +----------------- .../coffee/main/new-subscription.coffee | 4 +- 2 files changed, 13 insertions(+), 199 deletions(-) diff --git a/services/web/app/views/subscriptions/new.pug b/services/web/app/views/subscriptions/new.pug index 8995af6192..9a3206f205 100644 --- a/services/web/app/views/subscriptions/new.pug +++ b/services/web/app/views/subscriptions/new.pug @@ -1,7 +1,7 @@ extends ../layout block scripts - script(src="https://js.recurly.com/v3/recurly.js") + script(src="https://js.recurly.com/v4/recurly.js") script(type='text/javascript'). window.countryCode = '#{countryCode}' @@ -49,205 +49,17 @@ block content .row div() .col-md-12() - form( - ng-if="planName" - name="simpleCCForm" - novalidate - ) - div.payment-method-toggle - a.payment-method-toggle-switch( - href - ng-click="setPaymentMethod('credit_card');" - ng-class="paymentMethod.value === 'credit_card' ? 'payment-method-toggle-switch-selected' : ''" - ) - i.fa.fa-cc-mastercard.fa-2x - span   - i.fa.fa-cc-visa.fa-2x - span   - i.fa.fa-cc-amex.fa-2x - a.payment-method-toggle-switch( - href - ng-click="setPaymentMethod('paypal');" - ng-class="paymentMethod.value === 'paypal' ? 'payment-method-toggle-switch-selected' : ''" - ) - i.fa.fa-cc-paypal.fa-2x - - .alert.alert-warning.small(ng-show="genericError") - strong {{genericError}} - - div(ng-if="paymentMethod.value === 'credit_card'") - .row - .col-xs-6 - .form-group(ng-class="validation.errorFields.first_name || inputHasError(simpleCCForm.firstName) ? 'has-error' : ''") - label(for="first-name") #{translate('first_name')} - input#first-name.form-control( - type="text" - maxlength='255' - data-recurly="first_name" - name="firstName" - ng-model="data.first_name" - required - ) - span.input-feedback-message {{ simpleCCForm.firstName.$error.required ? 'This field is required' : '' }} - .col-xs-6 - .form-group(for="last-name",ng-class="validation.errorFields.last_name || inputHasError(simpleCCForm.lastName)? 'has-error' : ''") - label(for="last-name") #{translate('last_name')} - input#last-name.form-control( - type="text" - maxlength='255' - data-recurly="last_name" - name="lastName" - ng-model="data.last_name" - required - ) - span.input-feedback-message {{ simpleCCForm.lastName.$error.required ? 'This field is required' : '' }} - - .form-group(ng-class="validation.correctCardNumber == false || validation.errorFields.number || inputHasError(simpleCCForm.ccNumber) ? 'has-error' : ''") - label(for="card-no") #{translate("credit_card_number")} - input#card-no.form-control( - type="text" - ng-model="data.number" - name="ccNumber" - ng-focus="validation.correctCardNumber = true; validation.errorFields.number = false;" - ng-blur="validateCardNumber();" - required - cc-format-card-number - ) - span.input-feedback-message {{ simpleCCForm.ccNumber.$error.required ? 'This field is required' : 'Please re-check the card number' }} - - .row - .col-xs-6 - .form-group.has-feedback(ng-class="validation.correctExpiry == false || validation.errorFields.expiry || inputHasError(simpleCCForm.expiry) ? 'has-error' : ''") - label #{translate("expiry")} - input.form-control( - type="text" - ng-model="data.mmYY" - name="expiry" - placeholder="MM / YY" - ng-focus="validation.correctExpiry = true; validation.errorFields.expiry = false;" - ng-blur="updateExpiry(); validateExpiry()" - required - cc-format-expiry - ) - span.input-feedback-message {{ simpleCCForm.expiry.$error.required ? 'This field is required' : 'Please re-check the expiry date' }} - - .col-xs-6 - .form-group.has-feedback(ng-class="validation.correctCvv == false || validation.errorFields.cvv || inputHasError(simpleCCForm.cvv) ? 'has-error' : ''") - label #{translate("security_code")} - input.form-control( - type="text" - ng-model="data.cvv" - ng-focus="validation.correctCvv = true; validation.errorFields.cvv = false;" - ng-blur="validateCvv()" - name="cvv" - required - cc-format-sec-code - ) - .form-control-feedback - a.form-helper( - href - tabindex="-1" - tooltip-template="'cvv-tooltip-tpl.html'" - tooltip-trigger="mouseenter" - tooltip-append-to-body="true" - ) ? - span.input-feedback-message {{ simpleCCForm.cvv.$error.required ? 'This field is required' : 'Please re-check the security code' }} - - - div - .form-group(ng-class="validation.errorFields.country || inputHasError(simpleCCForm.country) ? 'has-error' : ''") - label(for="country") #{translate('country')} - select#country.form-control( - data-recurly="country" - ng-model="data.country" - name="country" - ng-change="updateCountry()" - required - ) - +countries_options() - span.input-feedback-message {{ simpleCCForm.country.$error.required ? 'This field is required' : '' }} - - if (showVatField) - .form-group - label(for="vat-no") #{translate('vat_number')} - input#vat-no.form-control( - type="text" - ng-blur="applyVatNumber()" - ng-model="data.vat_number" - ) - if (showCouponField) - .form-group - label(for="coupon-code") #{translate('coupon_code')} - input#coupon-code.form-control( - type="text" - ng-blur="applyCoupon()" - ng-model="data.coupon" - ) - - p(ng-if="paymentMethod.value === 'paypal'") #{translate("paypal_upgrade")} - - div.price-breakdown(ng-if="price.next.tax !== '0.00'") - hr.thin - span Total: - strong {{price.currency.symbol}}{{price.next.total}} - span ({{price.currency.symbol}}{{price.next.subtotal}} + {{price.currency.symbol}}{{price.next.tax}} tax) - span(ng-if="monthlyBilling") #{translate("every")} #{translate("month")} - span(ng-if="!monthlyBilling") #{translate("every")} #{translate("year")} - hr.thin - - div.payment-submit - button.btn.btn-success.btn-block( - ng-click="submit()" - ng-disabled="processing || !isFormValid(simpleCCForm);" - ) - span(ng-show="processing") - i.fa.fa-spinner.fa-spin - |   - | {{ paymentMethod.value === 'credit_card' ? '#{translate("upgrade_cc_btn")}' : '#{translate("upgrade_paypal_btn")}' }} + form(method='post', action='/api/subscriptions/new') + label(for='number') Card Number + #number(data-recurly='number') + label(for='month') Month + #month(data-recurly='month') + label(for='year') Year + #year(data-recurly='year') + button#subscribe Subscribe - .col-md-3.col-md-pull-4 - if showStudentPlan == 'true' - a.btn-primary.btn.plansPageStudentLink( - href, - ng-click="switchToStudent()" - ) #{translate("half_price_student")} - - .card.card-first - .paymentPageFeatures - h3 #{translate("unlimited_projects")} - p #{translate("create_unlimited_projects")} - - h3 - if plan.features.collaborators == -1 - - var collaboratorCount = 'Unlimited' - else - - var collaboratorCount = plan.features.collaborators - | #{translate("collabs_per_proj", {collabcount:collaboratorCount})} - p #{translate("work_on_single_version")}. #{translate("view_collab_edits")} in real time. - - h3 #{translate("full_doc_history")} - p #{translate("see_what_has_been")} - span.added #{translate("added")} - | #{translate("and")} - span.removed #{translate("removed")}. - | #{translate("restore_to_any_older_version")}. - - h3 #{translate("sync_to_dropbox")} - p - | #{translate("acces_work_from_anywhere")}. - | #{translate("work_offline_and_sync_with_dropbox")}. - - hr - - p.small.text-center We're confident that you'll love ShareLaTeX, but if not you can cancel anytime. We'll give you your money back, no questions asked, if you let us know within 30 days. - hr - span                   - a(href="https://www.positivessl.com" style="font-family: arial; font-size: 10px; color: #212121; text-decoration: none;") - img(src="https://www.positivessl.com/images-new/PositiveSSL_tl_trans.png" alt="SSL Certificate" title="SSL Certificate" border="0") - div(style="font-family: arial;font-weight:bold;font-size:15px;color:#86BEE0;") - a(href="https://www.positivessl.com" style="color:#86BEE0; text-decoration: none;") - + script(type="text/javascript"). ga('send', 'event', 'pageview', 'payment_form', "#{plan_code}") diff --git a/services/web/public/coffee/main/new-subscription.coffee b/services/web/public/coffee/main/new-subscription.coffee index 6e8af93156..a2d5428c67 100644 --- a/services/web/public/coffee/main/new-subscription.coffee +++ b/services/web/public/coffee/main/new-subscription.coffee @@ -43,7 +43,7 @@ define [ $scope.processing = false - recurly.configure window.recurlyApiKey + recurly.configure publicKey:window.recurlyApiKey pricing = recurly.Pricing() window.pricing = pricing @@ -73,6 +73,8 @@ define [ $scope.normalPrice += (basePrice * pricing.price.taxes[0].rate) $scope.$apply() + + $scope.applyCoupon = -> pricing.coupon($scope.data.coupon).done() From ae3858bcd07bd658d464ca891e07edf7cb6f8776 Mon Sep 17 00:00:00 2001 From: Henry Oswald Date: Fri, 13 Apr 2018 16:29:01 +0100 Subject: [PATCH 02/13] can subscribe using new form. terrible styling --- services/web/app/views/subscriptions/new.pug | 219 +++++++++++++++++- .../coffee/main/new-subscription.coffee | 18 +- 2 files changed, 227 insertions(+), 10 deletions(-) diff --git a/services/web/app/views/subscriptions/new.pug b/services/web/app/views/subscriptions/new.pug index 9a3206f205..987009fc0d 100644 --- a/services/web/app/views/subscriptions/new.pug +++ b/services/web/app/views/subscriptions/new.pug @@ -49,17 +49,218 @@ block content .row div() .col-md-12() - form(method='post', action='/api/subscriptions/new') - label(for='number') Card Number - #number(data-recurly='number') - label(for='month') Month - #month(data-recurly='month') - label(for='year') Year - #year(data-recurly='year') - button#subscribe Subscribe + form( + name="simpleCCForm" + novalidate + ) + + + div.payment-method-toggle + a.payment-method-toggle-switch( + href + ng-click="setPaymentMethod('credit_card');" + ng-class="paymentMethod.value === 'credit_card' ? 'payment-method-toggle-switch-selected' : ''" + ) + i.fa.fa-cc-mastercard.fa-2x + span   + i.fa.fa-cc-visa.fa-2x + span   + i.fa.fa-cc-amex.fa-2x + a.payment-method-toggle-switch( + href + ng-click="setPaymentMethod('paypal');" + ng-class="paymentMethod.value === 'paypal' ? 'payment-method-toggle-switch-selected' : ''" + ) + i.fa.fa-cc-paypal.fa-2x + + .alert.alert-warning.small(ng-show="genericError") + strong {{genericError}} + + div() + .row + .col-xs-6 + .form-group(ng-class="validation.errorFields.first_name || inputHasError(simpleCCForm.firstName) ? 'has-error' : ''") + label(for="first-name") #{translate('first_name')} + input#first-name.form-control( + type="text" + maxlength='255' + data-recurly="first_name" + name="firstName" + ng-model="data.first_name" + required + ) + span.input-feedback-message {{ simpleCCForm.firstName.$error.required ? 'This field is required' : '' }} + .col-xs-6 + .form-group(for="last-name",ng-class="validation.errorFields.last_name || inputHasError(simpleCCForm.lastName)? 'has-error' : ''") + label(for="last-name") #{translate('last_name')} + input#last-name.form-control( + type="text" + maxlength='255' + data-recurly="last_name" + name="lastName" + ng-model="data.last_name" + required + ) + span.input-feedback-message {{ simpleCCForm.lastName.$error.required ? 'This field is required' : '' }} + + .form-group(ng-class="validation.correctCardNumber == false || validation.errorFields.number || inputHasError(simpleCCForm.ccNumber) ? 'has-error' : ''") + label(for="card-no") #{translate("credit_card_number")} + div#card-no.form-control( + type="text" + name="ccNumber" + data-recurly='number' + ng-focus="validation.correctCardNumber = true; validation.errorFields.number = false;" + ng-blur="validateCardNumber();" + required + ) + span.input-feedback-message {{ simpleCCForm.ccNumber.$error.required ? 'This field is required' : 'Please re-check the card number' }} + + .row + .col-xs-3 + .form-group.has-feedback(ng-class="validation.correctExpiry == false || validation.errorFields.expiry || inputHasError(simpleCCForm.expiry) ? 'has-error' : ''") + label(for="month") #{translate("month")} + div.form-control( + type="text" + name="month" + ng-focus="validation.correctExpiry = true; validation.errorFields.expiry = false;" + ng-blur="updateExpiry(); validateExpiry()" + data-recurly="month" + required + ) + span.input-feedback-message {{ simpleCCForm.expiry.$error.required ? 'This field is required' : 'Please re-check the expiry date' }} + .col-xs-3 + .form-group.has-feedback(ng-class="validation.correctExpiry == false || validation.errorFields.expiry || inputHasError(simpleCCForm.expiry) ? 'has-error' : ''") + label(for="year") #{translate("year")} + div.form-control( + type="text" + name="year" + data-recurly="year" + ng-focus="validation.correctExpiry = true; validation.errorFields.expiry = false;" + ng-blur="updateExpiry(); validateExpiry()" + required + ) + span.input-feedback-message {{ simpleCCForm.expiry.$error.required ? 'This field is required' : 'Please re-check the expiry date' }} + - + .col-xs-6 + .form-group.has-feedback(ng-class="validation.correctCvv == false || validation.errorFields.cvv || inputHasError(simpleCCForm.cvv) ? 'has-error' : ''") + label #{translate("security_code")} + div.form-control( + type="text" + ng-model="data.cvv" + ng-focus="validation.correctCvv = true; validation.errorFields.cvv = false;" + ng-blur="validateCvv()" + data-recurly="cvv" + name="cvv" + required + cc-format-sec-code + ) + .form-control-feedback + a.form-helper( + href + tabindex="-1" + tooltip-template="'cvv-tooltip-tpl.html'" + tooltip-trigger="mouseenter" + tooltip-append-to-body="true" + ) ? + span.input-feedback-message {{ simpleCCForm.cvv.$error.required ? 'This field is required' : 'Please re-check the security code' }} + + + div + .form-group(ng-class="validation.errorFields.country || inputHasError(simpleCCForm.country) ? 'has-error' : ''") + label(for="country") #{translate('country')} + select#country.form-control( + data-recurly="country" + ng-model="data.country" + name="country" + ng-change="updateCountry()" + required + ) + +countries_options() + span.input-feedback-message {{ simpleCCForm.country.$error.required ? 'This field is required' : '' }} + + if (showVatField) + .form-group + label(for="vat-no") #{translate('vat_number')} + input#vat-no.form-control( + type="text" + ng-blur="applyVatNumber()" + ng-model="data.vat_number" + ) + if (showCouponField) + .form-group + label(for="coupon-code") #{translate('coupon_code')} + input#coupon-code.form-control( + type="text" + ng-blur="applyCoupon()" + ng-model="data.coupon" + ) + + p(ng-if="paymentMethod.value === 'paypal'") #{translate("paypal_upgrade")} + + div.price-breakdown(ng-if="price.next.tax !== '0.00'") + hr.thin + span Total: + strong {{price.currency.symbol}}{{price.next.total}} + span ({{price.currency.symbol}}{{price.next.subtotal}} + {{price.currency.symbol}}{{price.next.tax}} tax) + span(ng-if="monthlyBilling") #{translate("every")} #{translate("month")} + span(ng-if="!monthlyBilling") #{translate("every")} #{translate("year")} + hr.thin + + div.payment-submit + button.btn.btn-success.btn-block( + ng-click="submit()" + ng-disabled="processing" + ) + span(ng-show="processing") + i.fa.fa-spinner.fa-spin + |   + | {{ paymentMethod.value === 'credit_card' ? '#{translate("upgrade_cc_btn")}' : '#{translate("upgrade_paypal_btn")}' }} + + + .col-md-3.col-md-pull-4 + if showStudentPlan == 'true' + a.btn-primary.btn.plansPageStudentLink( + href, + ng-click="switchToStudent()" + ) #{translate("half_price_student")} + + .card.card-first + .paymentPageFeatures + h3 #{translate("unlimited_projects")} + p #{translate("create_unlimited_projects")} + + h3 + if plan.features.collaborators == -1 + - var collaboratorCount = 'Unlimited' + else + - var collaboratorCount = plan.features.collaborators + | #{translate("collabs_per_proj", {collabcount:collaboratorCount})} + p #{translate("work_on_single_version")}. #{translate("view_collab_edits")} in real time. + + h3 #{translate("full_doc_history")} + p #{translate("see_what_has_been")} + span.added #{translate("added")} + | #{translate("and")} + span.removed #{translate("removed")}. + | #{translate("restore_to_any_older_version")}. + + h3 #{translate("sync_to_dropbox")} + p + | #{translate("acces_work_from_anywhere")}. + | #{translate("work_offline_and_sync_with_dropbox")}. + + hr + + p.small.text-center We're confident that you'll love ShareLaTeX, but if not you can cancel anytime. We'll give you your money back, no questions asked, if you let us know within 30 days. + hr + span                   + a(href="https://www.positivessl.com" style="font-family: arial; font-size: 10px; color: #212121; text-decoration: none;") + img(src="https://www.positivessl.com/images-new/PositiveSSL_tl_trans.png" alt="SSL Certificate" title="SSL Certificate" border="0") + div(style="font-family: arial;font-weight:bold;font-size:15px;color:#86BEE0;") + a(href="https://www.positivessl.com" style="color:#86BEE0; text-decoration: none;") + script(type="text/javascript"). ga('send', 'event', 'pageview', 'payment_form', "#{plan_code}") diff --git a/services/web/public/coffee/main/new-subscription.coffee b/services/web/public/coffee/main/new-subscription.coffee index a2d5428c67..2925b280f4 100644 --- a/services/web/public/coffee/main/new-subscription.coffee +++ b/services/web/public/coffee/main/new-subscription.coffee @@ -43,7 +43,23 @@ define [ $scope.processing = false - recurly.configure publicKey:window.recurlyApiKey + recurly.configure + publicKey: window.recurlyApiKey + style: + all: + fontFamily: 'Open Sans', + fontSize: '1rem', + fontWeight: 'bold', + fontColor: '#2c0730' + number: + placeholder: 'Card number' + month: + placeholder: 'mm' + year: + placeholder: 'yy' + cvv: + placeholder: 'cvv' + pricing = recurly.Pricing() window.pricing = pricing From ccef0760aede3422453ff644edb2b9249cd16679 Mon Sep 17 00:00:00 2001 From: Henry Oswald Date: Fri, 13 Apr 2018 16:51:55 +0100 Subject: [PATCH 03/13] remove the form control, it just breaks the iframe styling --- services/web/app/views/subscriptions/new.pug | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/services/web/app/views/subscriptions/new.pug b/services/web/app/views/subscriptions/new.pug index 987009fc0d..5f679d0d8e 100644 --- a/services/web/app/views/subscriptions/new.pug +++ b/services/web/app/views/subscriptions/new.pug @@ -105,7 +105,7 @@ block content .form-group(ng-class="validation.correctCardNumber == false || validation.errorFields.number || inputHasError(simpleCCForm.ccNumber) ? 'has-error' : ''") label(for="card-no") #{translate("credit_card_number")} - div#card-no.form-control( + div#card-no( type="text" name="ccNumber" data-recurly='number' @@ -119,7 +119,7 @@ block content .col-xs-3 .form-group.has-feedback(ng-class="validation.correctExpiry == false || validation.errorFields.expiry || inputHasError(simpleCCForm.expiry) ? 'has-error' : ''") label(for="month") #{translate("month")} - div.form-control( + div( type="text" name="month" ng-focus="validation.correctExpiry = true; validation.errorFields.expiry = false;" @@ -131,7 +131,7 @@ block content .col-xs-3 .form-group.has-feedback(ng-class="validation.correctExpiry == false || validation.errorFields.expiry || inputHasError(simpleCCForm.expiry) ? 'has-error' : ''") label(for="year") #{translate("year")} - div.form-control( + div( type="text" name="year" data-recurly="year" @@ -146,7 +146,7 @@ block content .col-xs-6 .form-group.has-feedback(ng-class="validation.correctCvv == false || validation.errorFields.cvv || inputHasError(simpleCCForm.cvv) ? 'has-error' : ''") label #{translate("security_code")} - div.form-control( + div( type="text" ng-model="data.cvv" ng-focus="validation.correctCvv = true; validation.errorFields.cvv = false;" From c050791905aa52f7b1ec66c35fad75d8ec1777ee Mon Sep 17 00:00:00 2001 From: Henry Oswald Date: Fri, 13 Apr 2018 16:57:33 +0100 Subject: [PATCH 04/13] change ng to use show/hide ng-if doesn't render html until evaulated to true, need the form to be there at time of recurly.configure --- services/web/app/views/subscriptions/new.pug | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/web/app/views/subscriptions/new.pug b/services/web/app/views/subscriptions/new.pug index 5f679d0d8e..27908d4c2c 100644 --- a/services/web/app/views/subscriptions/new.pug +++ b/services/web/app/views/subscriptions/new.pug @@ -76,7 +76,7 @@ block content .alert.alert-warning.small(ng-show="genericError") strong {{genericError}} - div() + div(ng-show="paymentMethod.value === 'credit_card'") .row .col-xs-6 .form-group(ng-class="validation.errorFields.first_name || inputHasError(simpleCCForm.firstName) ? 'has-error' : ''") From e19a118ef4d4355d0585880463df564986f36a12 Mon Sep 17 00:00:00 2001 From: Henry Oswald Date: Fri, 13 Apr 2018 17:26:05 +0100 Subject: [PATCH 05/13] poorly styled but almost viable --- services/web/public/stylesheets/app/recurly.less | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/services/web/public/stylesheets/app/recurly.less b/services/web/public/stylesheets/app/recurly.less index c953f34bd1..49221f913d 100644 --- a/services/web/public/stylesheets/app/recurly.less +++ b/services/web/public/stylesheets/app/recurly.less @@ -1,3 +1,10 @@ +.recurly-hosted-field { + height: 2em; + border: 1px solid #ccc; + +} + + .recurly { display: block; position: relative; From b1ee05de3ea34f3c74f218d2955dadd793f0897e Mon Sep 17 00:00:00 2001 From: Henry Oswald Date: Fri, 13 Apr 2018 17:32:20 +0100 Subject: [PATCH 06/13] better styling, close to being deployable --- services/web/public/coffee/main/new-subscription.coffee | 8 ++------ services/web/public/stylesheets/app/recurly.less | 4 +--- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/services/web/public/coffee/main/new-subscription.coffee b/services/web/public/coffee/main/new-subscription.coffee index 2925b280f4..e5e0165163 100644 --- a/services/web/public/coffee/main/new-subscription.coffee +++ b/services/web/public/coffee/main/new-subscription.coffee @@ -47,12 +47,8 @@ define [ publicKey: window.recurlyApiKey style: all: - fontFamily: 'Open Sans', - fontSize: '1rem', - fontWeight: 'bold', - fontColor: '#2c0730' - number: - placeholder: 'Card number' + fontFamily: '"Open Sans", sans-serif', + fontSize: '16px', month: placeholder: 'mm' year: diff --git a/services/web/public/stylesheets/app/recurly.less b/services/web/public/stylesheets/app/recurly.less index 49221f913d..2e88d6742d 100644 --- a/services/web/public/stylesheets/app/recurly.less +++ b/services/web/public/stylesheets/app/recurly.less @@ -1,7 +1,5 @@ .recurly-hosted-field { - height: 2em; - border: 1px solid #ccc; - + &:extend(.form-control); } From a1be0e95b421934f4a6d91bb1f327b18cf20ba33 Mon Sep 17 00:00:00 2001 From: Henry Oswald Date: Mon, 16 Apr 2018 10:10:25 +0100 Subject: [PATCH 07/13] remove the dead validation --- services/web/app/views/subscriptions/new.pug | 22 +++------ .../coffee/main/new-subscription.coffee | 46 ++++--------------- 2 files changed, 15 insertions(+), 53 deletions(-) diff --git a/services/web/app/views/subscriptions/new.pug b/services/web/app/views/subscriptions/new.pug index 27908d4c2c..5644710723 100644 --- a/services/web/app/views/subscriptions/new.pug +++ b/services/web/app/views/subscriptions/new.pug @@ -101,9 +101,8 @@ block content ng-model="data.last_name" required ) - span.input-feedback-message {{ simpleCCForm.lastName.$error.required ? 'This field is required' : '' }} - .form-group(ng-class="validation.correctCardNumber == false || validation.errorFields.number || inputHasError(simpleCCForm.ccNumber) ? 'has-error' : ''") + .form-group() label(for="card-no") #{translate("credit_card_number")} div#card-no( type="text" @@ -113,41 +112,36 @@ block content ng-blur="validateCardNumber();" required ) - span.input-feedback-message {{ simpleCCForm.ccNumber.$error.required ? 'This field is required' : 'Please re-check the card number' }} .row .col-xs-3 - .form-group.has-feedback(ng-class="validation.correctExpiry == false || validation.errorFields.expiry || inputHasError(simpleCCForm.expiry) ? 'has-error' : ''") + .form-group.has-feedback() label(for="month") #{translate("month")} div( - type="text" + type="number" name="month" ng-focus="validation.correctExpiry = true; validation.errorFields.expiry = false;" ng-blur="updateExpiry(); validateExpiry()" data-recurly="month" required ) - span.input-feedback-message {{ simpleCCForm.expiry.$error.required ? 'This field is required' : 'Please re-check the expiry date' }} .col-xs-3 - .form-group.has-feedback(ng-class="validation.correctExpiry == false || validation.errorFields.expiry || inputHasError(simpleCCForm.expiry) ? 'has-error' : ''") + .form-group.has-feedback() label(for="year") #{translate("year")} div( - type="text" + type="number" name="year" data-recurly="year" ng-focus="validation.correctExpiry = true; validation.errorFields.expiry = false;" ng-blur="updateExpiry(); validateExpiry()" required ) - span.input-feedback-message {{ simpleCCForm.expiry.$error.required ? 'This field is required' : 'Please re-check the expiry date' }} - - .col-xs-6 - .form-group.has-feedback(ng-class="validation.correctCvv == false || validation.errorFields.cvv || inputHasError(simpleCCForm.cvv) ? 'has-error' : ''") + .form-group.has-feedback() label #{translate("security_code")} div( - type="text" + type="number" ng-model="data.cvv" ng-focus="validation.correctCvv = true; validation.errorFields.cvv = false;" ng-blur="validateCvv()" @@ -164,9 +158,7 @@ block content tooltip-trigger="mouseenter" tooltip-append-to-body="true" ) ? - span.input-feedback-message {{ simpleCCForm.cvv.$error.required ? 'This field is required' : 'Please re-check the security code' }} - div .form-group(ng-class="validation.errorFields.country || inputHasError(simpleCCForm.country) ? 'has-error' : ''") label(for="country") #{translate('country')} diff --git a/services/web/public/coffee/main/new-subscription.coffee b/services/web/public/coffee/main/new-subscription.coffee index e5e0165163..ab1128ed33 100644 --- a/services/web/public/coffee/main/new-subscription.coffee +++ b/services/web/public/coffee/main/new-subscription.coffee @@ -21,10 +21,6 @@ define [ value: "credit_card" $scope.data = - number: "" - month: "" - year: "" - cvv: "" first_name: "" last_name: "" postal_code: "" @@ -34,12 +30,8 @@ define [ city:"" country:window.countryCode coupon: window.couponCode - mmYY: "" - - $scope.validation = - correctCardNumber : true - correctExpiry: true - correctCvv: true + + $scope.validation = {} $scope.processing = false @@ -49,13 +41,14 @@ define [ all: fontFamily: '"Open Sans", sans-serif', fontSize: '16px', + fontColor: '#7a7a7a' month: - placeholder: 'mm' + placeholder: 'MM' year: - placeholder: 'yy' + placeholder: 'YY' cvv: - placeholder: 'cvv' - + placeholder: 'CVV' + pricing = recurly.Pricing() window.pricing = pricing @@ -97,26 +90,6 @@ define [ $scope.currencyCode = newCurrency pricing.currency(newCurrency).done() - $scope.updateExpiry = () -> - parsedDateObj = ccUtils.parseExpiry $scope.data.mmYY - if parsedDateObj? - $scope.data.month = parsedDateObj.month - $scope.data.year = parsedDateObj.year - - $scope.validateCardNumber = validateCardNumber = -> - $scope.validation.errorFields = {} - if $scope.data.number?.length != 0 - $scope.validation.correctCardNumber = recurly.validate.cardNumber($scope.data.number) - - $scope.validateExpiry = validateExpiry = -> - $scope.validation.errorFields = {} - if $scope.data.month?.length != 0 and $scope.data.year?.length != 0 - $scope.validation.correctExpiry = recurly.validate.expiry($scope.data.month, $scope.data.year) - - $scope.validateCvv = validateCvv = -> - $scope.validation.errorFields = {} - if $scope.data.cvv?.length != 0 - $scope.validation.correctCvv = recurly.validate.cvv($scope.data.cvv) $scope.inputHasError = inputHasError = (formItem) -> if !formItem? @@ -128,10 +101,7 @@ define [ if $scope.paymentMethod.value == 'paypal' return $scope.data.country != "" else - return (form.$valid and - $scope.validation.correctCardNumber and - $scope.validation.correctExpiry and - $scope.validation.correctCvv) + return form.$valid $scope.updateCountry = -> pricing.address({country:$scope.data.country}).done() From 903a9db936fae37c75d7ff2f4d016cc7c4761010 Mon Sep 17 00:00:00 2001 From: Henry Oswald Date: Mon, 16 Apr 2018 10:10:43 +0100 Subject: [PATCH 08/13] upgrade static recurly lib to 4.8.5 for plans page --- services/web/public/coffee/main/plans.coffee | 2 +- services/web/public/js/libs/recurly-3.0.5.js | 4218 ------------------ services/web/public/js/libs/recurly-4.8.5.js | 6 + services/web/public/js/libs/recurly.min.js | 1 - 4 files changed, 7 insertions(+), 4220 deletions(-) delete mode 100644 services/web/public/js/libs/recurly-3.0.5.js create mode 100644 services/web/public/js/libs/recurly-4.8.5.js delete mode 100755 services/web/public/js/libs/recurly.min.js diff --git a/services/web/public/coffee/main/plans.coffee b/services/web/public/coffee/main/plans.coffee index b74a4d1da9..9a62420d66 100644 --- a/services/web/public/coffee/main/plans.coffee +++ b/services/web/public/coffee/main/plans.coffee @@ -1,6 +1,6 @@ define [ "base" - "libs/recurly-3.0.5" + "libs/recurly-4.8.5" ], (App, recurly) -> diff --git a/services/web/public/js/libs/recurly-3.0.5.js b/services/web/public/js/libs/recurly-3.0.5.js deleted file mode 100644 index 9ae06622aa..0000000000 --- a/services/web/public/js/libs/recurly-3.0.5.js +++ /dev/null @@ -1,4218 +0,0 @@ -;(function(){ - -/** - * Require the given path. - * - * @param {String} path - * @return {Object} exports - * @api public - */ - -function require(path, parent, orig) { - var resolved = require.resolve(path); - - // lookup failed - if (null == resolved) { - orig = orig || path; - parent = parent || 'root'; - var err = new Error('Failed to require "' + orig + '" from "' + parent + '"'); - err.path = orig; - err.parent = parent; - err.require = true; - throw err; - } - - var module = require.modules[resolved]; - - // perform real require() - // by invoking the module's - // registered function - if (!module._resolving && !module.exports) { - var mod = {}; - mod.exports = {}; - mod.client = mod.component = true; - module._resolving = true; - module.call(this, mod.exports, require.relative(resolved), mod); - delete module._resolving; - module.exports = mod.exports; - } - - return module.exports; -} - -/** - * Registered modules. - */ - -require.modules = {}; - -/** - * Registered aliases. - */ - -require.aliases = {}; - -/** - * Resolve `path`. - * - * Lookup: - * - * - PATH/index.js - * - PATH.js - * - PATH - * - * @param {String} path - * @return {String} path or null - * @api private - */ - -require.resolve = function(path) { - if (path.charAt(0) === '/') path = path.slice(1); - - var paths = [ - path, - path + '.js', - path + '.json', - path + '/index.js', - path + '/index.json' - ]; - - for (var i = 0; i < paths.length; i++) { - var path = paths[i]; - if (require.modules.hasOwnProperty(path)) return path; - if (require.aliases.hasOwnProperty(path)) return require.aliases[path]; - } -}; - -/** - * Normalize `path` relative to the current path. - * - * @param {String} curr - * @param {String} path - * @return {String} - * @api private - */ - -require.normalize = function(curr, path) { - var segs = []; - - if ('.' != path.charAt(0)) return path; - - curr = curr.split('/'); - path = path.split('/'); - - for (var i = 0; i < path.length; ++i) { - if ('..' == path[i]) { - curr.pop(); - } else if ('.' != path[i] && '' != path[i]) { - segs.push(path[i]); - } - } - - return curr.concat(segs).join('/'); -}; - -/** - * Register module at `path` with callback `definition`. - * - * @param {String} path - * @param {Function} definition - * @api private - */ - -require.register = function(path, definition) { - require.modules[path] = definition; -}; - -/** - * Alias a module definition. - * - * @param {String} from - * @param {String} to - * @api private - */ - -require.alias = function(from, to) { - if (!require.modules.hasOwnProperty(from)) { - throw new Error('Failed to alias "' + from + '", it does not exist'); - } - require.aliases[to] = from; -}; - -/** - * Return a require function relative to the `parent` path. - * - * @param {String} parent - * @return {Function} - * @api private - */ - -require.relative = function(parent) { - var p = require.normalize(parent, '..'); - - /** - * lastIndexOf helper. - */ - - function lastIndexOf(arr, obj) { - var i = arr.length; - while (i--) { - if (arr[i] === obj) return i; - } - return -1; - } - - /** - * The relative require() itself. - */ - - function localRequire(path) { - var resolved = localRequire.resolve(path); - return require(resolved, parent, path); - } - - /** - * Resolve relative to the parent. - */ - - localRequire.resolve = function(path) { - var c = path.charAt(0); - if ('/' == c) return path.slice(1); - if ('.' == c) return require.normalize(p, path); - - // resolve deps by returning - // the dep in the nearest "deps" - // directory - var segs = parent.split('/'); - var i = lastIndexOf(segs, 'deps') + 1; - if (!i) i = 0; - path = segs.slice(0, i + 1).join('/') + '/deps/' + path; - return path; - }; - - /** - * Check if module is defined at `path`. - */ - - localRequire.exists = function(path) { - return require.modules.hasOwnProperty(localRequire.resolve(path)); - }; - - return localRequire; -}; -require.register("visionmedia-node-querystring/index.js", function(exports, require, module){ -/** - * Object#toString() ref for stringify(). - */ - -var toString = Object.prototype.toString; - -/** - * Object#hasOwnProperty ref - */ - -var hasOwnProperty = Object.prototype.hasOwnProperty; - -/** - * Array#indexOf shim. - */ - -var indexOf = typeof Array.prototype.indexOf === 'function' - ? function(arr, el) { return arr.indexOf(el); } - : function(arr, el) { - for (var i = 0; i < arr.length; i++) { - if (arr[i] === el) return i; - } - return -1; - }; - -/** - * Array.isArray shim. - */ - -var isArray = Array.isArray || function(arr) { - return toString.call(arr) == '[object Array]'; -}; - -/** - * Object.keys shim. - */ - -var objectKeys = Object.keys || function(obj) { - var ret = []; - for (var key in obj) { - if (obj.hasOwnProperty(key)) { - ret.push(key); - } - } - return ret; -}; - -/** - * Array#forEach shim. - */ - -var forEach = typeof Array.prototype.forEach === 'function' - ? function(arr, fn) { return arr.forEach(fn); } - : function(arr, fn) { - for (var i = 0; i < arr.length; i++) fn(arr[i]); - }; - -/** - * Array#reduce shim. - */ - -var reduce = function(arr, fn, initial) { - if (typeof arr.reduce === 'function') return arr.reduce(fn, initial); - var res = initial; - for (var i = 0; i < arr.length; i++) res = fn(res, arr[i]); - return res; -}; - -/** - * Cache non-integer test regexp. - */ - -var isint = /^[0-9]+$/; - -function promote(parent, key) { - if (parent[key].length == 0) return parent[key] = {} - var t = {}; - for (var i in parent[key]) { - if (hasOwnProperty.call(parent[key], i)) { - t[i] = parent[key][i]; - } - } - parent[key] = t; - return t; -} - -function parse(parts, parent, key, val) { - var part = parts.shift(); - - // illegal - if (Object.getOwnPropertyDescriptor(Object.prototype, key)) return; - - // end - if (!part) { - if (isArray(parent[key])) { - parent[key].push(val); - } else if ('object' == typeof parent[key]) { - parent[key] = val; - } else if ('undefined' == typeof parent[key]) { - parent[key] = val; - } else { - parent[key] = [parent[key], val]; - } - // array - } else { - var obj = parent[key] = parent[key] || []; - if (']' == part) { - if (isArray(obj)) { - if ('' != val) obj.push(val); - } else if ('object' == typeof obj) { - obj[objectKeys(obj).length] = val; - } else { - obj = parent[key] = [parent[key], val]; - } - // prop - } else if (~indexOf(part, ']')) { - part = part.substr(0, part.length - 1); - if (!isint.test(part) && isArray(obj)) obj = promote(parent, key); - parse(parts, obj, part, val); - // key - } else { - if (!isint.test(part) && isArray(obj)) obj = promote(parent, key); - parse(parts, obj, part, val); - } - } -} - -/** - * Merge parent key/val pair. - */ - -function merge(parent, key, val){ - if (~indexOf(key, ']')) { - var parts = key.split('[') - , len = parts.length - , last = len - 1; - parse(parts, parent, 'base', val); - // optimize - } else { - if (!isint.test(key) && isArray(parent.base)) { - var t = {}; - for (var k in parent.base) t[k] = parent.base[k]; - parent.base = t; - } - set(parent.base, key, val); - } - - return parent; -} - -/** - * Compact sparse arrays. - */ - -function compact(obj) { - if ('object' != typeof obj) return obj; - - if (isArray(obj)) { - var ret = []; - - for (var i in obj) { - if (hasOwnProperty.call(obj, i)) { - ret.push(obj[i]); - } - } - - return ret; - } - - for (var key in obj) { - obj[key] = compact(obj[key]); - } - - return obj; -} - -/** - * Parse the given obj. - */ - -function parseObject(obj){ - var ret = { base: {} }; - - forEach(objectKeys(obj), function(name){ - merge(ret, name, obj[name]); - }); - - return compact(ret.base); -} - -/** - * Parse the given str. - */ - -function parseString(str){ - var ret = reduce(String(str).split('&'), function(ret, pair){ - var eql = indexOf(pair, '=') - , brace = lastBraceInKey(pair) - , key = pair.substr(0, brace || eql) - , val = pair.substr(brace || eql, pair.length) - , val = val.substr(indexOf(val, '=') + 1, val.length); - - // ?foo - if ('' == key) key = pair, val = ''; - if ('' == key) return ret; - - return merge(ret, decode(key), decode(val)); - }, { base: {} }).base; - - return compact(ret); -} - -/** - * Parse the given query `str` or `obj`, returning an object. - * - * @param {String} str | {Object} obj - * @return {Object} - * @api public - */ - -exports.parse = function(str){ - if (null == str || '' == str) return {}; - return 'object' == typeof str - ? parseObject(str) - : parseString(str); -}; - -/** - * Turn the given `obj` into a query string - * - * @param {Object} obj - * @return {String} - * @api public - */ - -var stringify = exports.stringify = function(obj, prefix) { - if (isArray(obj)) { - return stringifyArray(obj, prefix); - } else if ('[object Object]' == toString.call(obj)) { - return stringifyObject(obj, prefix); - } else if ('string' == typeof obj) { - return stringifyString(obj, prefix); - } else { - return prefix + '=' + encodeURIComponent(String(obj)); - } -}; - -/** - * Stringify the given `str`. - * - * @param {String} str - * @param {String} prefix - * @return {String} - * @api private - */ - -function stringifyString(str, prefix) { - if (!prefix) throw new TypeError('stringify expects an object'); - return prefix + '=' + encodeURIComponent(str); -} - -/** - * Stringify the given `arr`. - * - * @param {Array} arr - * @param {String} prefix - * @return {String} - * @api private - */ - -function stringifyArray(arr, prefix) { - var ret = []; - if (!prefix) throw new TypeError('stringify expects an object'); - for (var i = 0; i < arr.length; i++) { - ret.push(stringify(arr[i], prefix + '[' + i + ']')); - } - return ret.join('&'); -} - -/** - * Stringify the given `obj`. - * - * @param {Object} obj - * @param {String} prefix - * @return {String} - * @api private - */ - -function stringifyObject(obj, prefix) { - var ret = [] - , keys = objectKeys(obj) - , key; - - for (var i = 0, len = keys.length; i < len; ++i) { - key = keys[i]; - if ('' == key) continue; - if (null == obj[key]) { - ret.push(encodeURIComponent(key) + '='); - } else { - ret.push(stringify(obj[key], prefix - ? prefix + '[' + encodeURIComponent(key) + ']' - : encodeURIComponent(key))); - } - } - - return ret.join('&'); -} - -/** - * Set `obj`'s `key` to `val` respecting - * the weird and wonderful syntax of a qs, - * where "foo=bar&foo=baz" becomes an array. - * - * @param {Object} obj - * @param {String} key - * @param {String} val - * @api private - */ - -function set(obj, key, val) { - var v = obj[key]; - if (Object.getOwnPropertyDescriptor(Object.prototype, key)) return; - if (undefined === v) { - obj[key] = val; - } else if (isArray(v)) { - v.push(val); - } else { - obj[key] = [v, val]; - } -} - -/** - * Locate last brace in `str` within the key. - * - * @param {String} str - * @return {Number} - * @api private - */ - -function lastBraceInKey(str) { - var len = str.length - , brace - , c; - for (var i = 0; i < len; ++i) { - c = str[i]; - if (']' == c) brace = false; - if ('[' == c) brace = true; - if ('=' == c && !brace) return i; - } -} - -/** - * Decode `str`. - * - * @param {String} str - * @return {String} - * @api private - */ - -function decode(str) { - try { - return decodeURIComponent(str.replace(/\+/g, ' ')); - } catch (err) { - return str; - } -} - -}); -require.register("component-emitter/index.js", function(exports, require, module){ - -/** - * Expose `Emitter`. - */ - -module.exports = Emitter; - -/** - * Initialize a new `Emitter`. - * - * @api public - */ - -function Emitter(obj) { - if (obj) return mixin(obj); -}; - -/** - * Mixin the emitter properties. - * - * @param {Object} obj - * @return {Object} - * @api private - */ - -function mixin(obj) { - for (var key in Emitter.prototype) { - obj[key] = Emitter.prototype[key]; - } - return obj; -} - -/** - * Listen on the given `event` with `fn`. - * - * @param {String} event - * @param {Function} fn - * @return {Emitter} - * @api public - */ - -Emitter.prototype.on = -Emitter.prototype.addEventListener = function(event, fn){ - this._callbacks = this._callbacks || {}; - (this._callbacks[event] = this._callbacks[event] || []) - .push(fn); - return this; -}; - -/** - * Adds an `event` listener that will be invoked a single - * time then automatically removed. - * - * @param {String} event - * @param {Function} fn - * @return {Emitter} - * @api public - */ - -Emitter.prototype.once = function(event, fn){ - var self = this; - this._callbacks = this._callbacks || {}; - - function on() { - self.off(event, on); - fn.apply(this, arguments); - } - - on.fn = fn; - this.on(event, on); - return this; -}; - -/** - * Remove the given callback for `event` or all - * registered callbacks. - * - * @param {String} event - * @param {Function} fn - * @return {Emitter} - * @api public - */ - -Emitter.prototype.off = -Emitter.prototype.removeListener = -Emitter.prototype.removeAllListeners = -Emitter.prototype.removeEventListener = function(event, fn){ - this._callbacks = this._callbacks || {}; - - // all - if (0 == arguments.length) { - this._callbacks = {}; - return this; - } - - // specific event - var callbacks = this._callbacks[event]; - if (!callbacks) return this; - - // remove all handlers - if (1 == arguments.length) { - delete this._callbacks[event]; - return this; - } - - // remove specific handler - var cb; - for (var i = 0; i < callbacks.length; i++) { - cb = callbacks[i]; - if (cb === fn || cb.fn === fn) { - callbacks.splice(i, 1); - break; - } - } - return this; -}; - -/** - * Emit `event` with the given args. - * - * @param {String} event - * @param {Mixed} ... - * @return {Emitter} - */ - -Emitter.prototype.emit = function(event){ - this._callbacks = this._callbacks || {}; - var args = [].slice.call(arguments, 1) - , callbacks = this._callbacks[event]; - - if (callbacks) { - callbacks = callbacks.slice(0); - for (var i = 0, len = callbacks.length; i < len; ++i) { - callbacks[i].apply(this, args); - } - } - - return this; -}; - -/** - * Return array of callbacks for `event`. - * - * @param {String} event - * @return {Array} - * @api public - */ - -Emitter.prototype.listeners = function(event){ - this._callbacks = this._callbacks || {}; - return this._callbacks[event] || []; -}; - -/** - * Check if this emitter has `event` handlers. - * - * @param {String} event - * @return {Boolean} - * @api public - */ - -Emitter.prototype.hasListeners = function(event){ - return !! this.listeners(event).length; -}; - -}); -require.register("component-indexof/index.js", function(exports, require, module){ -module.exports = function(arr, obj){ - if (arr.indexOf) return arr.indexOf(obj); - for (var i = 0; i < arr.length; ++i) { - if (arr[i] === obj) return i; - } - return -1; -}; -}); -require.register("component-object/index.js", function(exports, require, module){ - -/** - * HOP ref. - */ - -var has = Object.prototype.hasOwnProperty; - -/** - * Return own keys in `obj`. - * - * @param {Object} obj - * @return {Array} - * @api public - */ - -exports.keys = Object.keys || function(obj){ - var keys = []; - for (var key in obj) { - if (has.call(obj, key)) { - keys.push(key); - } - } - return keys; -}; - -/** - * Return own values in `obj`. - * - * @param {Object} obj - * @return {Array} - * @api public - */ - -exports.values = function(obj){ - var vals = []; - for (var key in obj) { - if (has.call(obj, key)) { - vals.push(obj[key]); - } - } - return vals; -}; - -/** - * Merge `b` into `a`. - * - * @param {Object} a - * @param {Object} b - * @return {Object} a - * @api public - */ - -exports.merge = function(a, b){ - for (var key in b) { - if (has.call(b, key)) { - a[key] = b[key]; - } - } - return a; -}; - -/** - * Return length of `obj`. - * - * @param {Object} obj - * @return {Number} - * @api public - */ - -exports.length = function(obj){ - return exports.keys(obj).length; -}; - -/** - * Check if `obj` is empty. - * - * @param {Object} obj - * @return {Boolean} - * @api public - */ - -exports.isEmpty = function(obj){ - return 0 == exports.length(obj); -}; -}); -require.register("component-event/index.js", function(exports, require, module){ -var bind = window.addEventListener ? 'addEventListener' : 'attachEvent', - unbind = window.removeEventListener ? 'removeEventListener' : 'detachEvent', - prefix = bind !== 'addEventListener' ? 'on' : ''; - -/** - * Bind `el` event `type` to `fn`. - * - * @param {Element} el - * @param {String} type - * @param {Function} fn - * @param {Boolean} capture - * @return {Function} - * @api public - */ - -exports.bind = function(el, type, fn, capture){ - el[bind](prefix + type, fn, capture || false); - return fn; -}; - -/** - * Unbind `el` event `type`'s callback `fn`. - * - * @param {Element} el - * @param {String} type - * @param {Function} fn - * @param {Boolean} capture - * @return {Function} - * @api public - */ - -exports.unbind = function(el, type, fn, capture){ - el[unbind](prefix + type, fn, capture || false); - return fn; -}; -}); -require.register("component-clone/index.js", function(exports, require, module){ -/** - * Module dependencies. - */ - -var type; -try { - type = require('component-type'); -} catch (_) { - type = require('type'); -} - -/** - * Module exports. - */ - -module.exports = clone; - -/** - * Clones objects. - * - * @param {Mixed} any object - * @api public - */ - -function clone(obj){ - switch (type(obj)) { - case 'object': - var copy = {}; - for (var key in obj) { - if (obj.hasOwnProperty(key)) { - copy[key] = clone(obj[key]); - } - } - return copy; - - case 'array': - var copy = new Array(obj.length); - for (var i = 0, l = obj.length; i < l; i++) { - copy[i] = clone(obj[i]); - } - return copy; - - case 'regexp': - // from millermedeiros/amd-utils - MIT - var flags = ''; - flags += obj.multiline ? 'm' : ''; - flags += obj.global ? 'g' : ''; - flags += obj.ignoreCase ? 'i' : ''; - return new RegExp(obj.source, flags); - - case 'date': - return new Date(obj.getTime()); - - default: // string, number, boolean, … - return obj; - } -} - -}); -require.register("component-bind/index.js", function(exports, require, module){ - -/** - * Slice reference. - */ - -var slice = [].slice; - -/** - * Bind `obj` to `fn`. - * - * @param {Object} obj - * @param {Function|String} fn or string - * @return {Function} - * @api public - */ - -module.exports = function(obj, fn){ - if ('string' == typeof fn) fn = obj[fn]; - if ('function' != typeof fn) throw new Error('bind() requires a function'); - var args = [].slice.call(arguments, 2); - return function(){ - return fn.apply(obj, args.concat(slice.call(arguments))); - } -}; - -}); -require.register("component-props/index.js", function(exports, require, module){ -/** - * Global Names - */ - -var globals = /\b(this|Array|Date|Object|Math|JSON)\b/g; - -/** - * Return immediate identifiers parsed from `str`. - * - * @param {String} str - * @param {String|Function} map function or prefix - * @return {Array} - * @api public - */ - -module.exports = function(str, fn){ - var p = unique(props(str)); - if (fn && 'string' == typeof fn) fn = prefixed(fn); - if (fn) return map(str, p, fn); - return p; -}; - -/** - * Return immediate identifiers in `str`. - * - * @param {String} str - * @return {Array} - * @api private - */ - -function props(str) { - return str - .replace(/\.\w+|\w+ *\(|"[^"]*"|'[^']*'|\/([^/]+)\//g, '') - .replace(globals, '') - .match(/[$a-zA-Z_]\w*/g) - || []; -} - -/** - * Return `str` with `props` mapped with `fn`. - * - * @param {String} str - * @param {Array} props - * @param {Function} fn - * @return {String} - * @api private - */ - -function map(str, props, fn) { - var re = /\.\w+|\w+ *\(|"[^"]*"|'[^']*'|\/([^/]+)\/|[a-zA-Z_]\w*/g; - return str.replace(re, function(_){ - if ('(' == _[_.length - 1]) return fn(_); - if (!~props.indexOf(_)) return _; - return fn(_); - }); -} - -/** - * Return unique array. - * - * @param {Array} arr - * @return {Array} - * @api private - */ - -function unique(arr) { - var ret = []; - - for (var i = 0; i < arr.length; i++) { - if (~ret.indexOf(arr[i])) continue; - ret.push(arr[i]); - } - - return ret; -} - -/** - * Map with prefix `str`. - */ - -function prefixed(str) { - return function(_){ - return str + _; - }; -} - -}); -require.register("component-to-function/index.js", function(exports, require, module){ -/** - * Module Dependencies - */ - -var expr = require('props'); - -/** - * Expose `toFunction()`. - */ - -module.exports = toFunction; - -/** - * Convert `obj` to a `Function`. - * - * @param {Mixed} obj - * @return {Function} - * @api private - */ - -function toFunction(obj) { - switch ({}.toString.call(obj)) { - case '[object Object]': - return objectToFunction(obj); - case '[object Function]': - return obj; - case '[object String]': - return stringToFunction(obj); - case '[object RegExp]': - return regexpToFunction(obj); - default: - return defaultToFunction(obj); - } -} - -/** - * Default to strict equality. - * - * @param {Mixed} val - * @return {Function} - * @api private - */ - -function defaultToFunction(val) { - return function(obj){ - return val === obj; - } -} - -/** - * Convert `re` to a function. - * - * @param {RegExp} re - * @return {Function} - * @api private - */ - -function regexpToFunction(re) { - return function(obj){ - return re.test(obj); - } -} - -/** - * Convert property `str` to a function. - * - * @param {String} str - * @return {Function} - * @api private - */ - -function stringToFunction(str) { - // immediate such as "> 20" - if (/^ *\W+/.test(str)) return new Function('_', 'return _ ' + str); - - // properties such as "name.first" or "age > 18" or "age > 18 && age < 36" - return new Function('_', 'return ' + get(str)); -} - -/** - * Convert `object` to a function. - * - * @param {Object} object - * @return {Function} - * @api private - */ - -function objectToFunction(obj) { - var match = {} - for (var key in obj) { - match[key] = typeof obj[key] === 'string' - ? defaultToFunction(obj[key]) - : toFunction(obj[key]) - } - return function(val){ - if (typeof val !== 'object') return false; - for (var key in match) { - if (!(key in val)) return false; - if (!match[key](val[key])) return false; - } - return true; - } -} - -/** - * Built the getter function. Supports getter style functions - * - * @param {String} str - * @return {String} - * @api private - */ - -function get(str) { - var props = expr(str); - if (!props.length) return '_.' + str; - - var val; - for(var i = 0, prop; prop = props[i]; i++) { - val = '_.' + prop; - val = "('function' == typeof " + val + " ? " + val + "() : " + val + ")"; - str = str.replace(new RegExp(prop, 'g'), val); - } - - return str; -} - -}); -require.register("component-each/index.js", function(exports, require, module){ - -/** - * Module dependencies. - */ - -var type = require('type'); -var toFunction = require('to-function'); - -/** - * HOP reference. - */ - -var has = Object.prototype.hasOwnProperty; - -/** - * Iterate the given `obj` and invoke `fn(val, i)` - * in optional context `ctx`. - * - * @param {String|Array|Object} obj - * @param {Function} fn - * @param {Object} [ctx] - * @api public - */ - -module.exports = function(obj, fn, ctx){ - fn = toFunction(fn); - ctx = ctx || this; - switch (type(obj)) { - case 'array': - return array(obj, fn, ctx); - case 'object': - if ('number' == typeof obj.length) return array(obj, fn, ctx); - return object(obj, fn, ctx); - case 'string': - return string(obj, fn, ctx); - } -}; - -/** - * Iterate string chars. - * - * @param {String} obj - * @param {Function} fn - * @param {Object} ctx - * @api private - */ - -function string(obj, fn, ctx) { - for (var i = 0; i < obj.length; ++i) { - fn.call(ctx, obj.charAt(i), i); - } -} - -/** - * Iterate object keys. - * - * @param {Object} obj - * @param {Function} fn - * @param {Object} ctx - * @api private - */ - -function object(obj, fn, ctx) { - for (var key in obj) { - if (has.call(obj, key)) { - fn.call(ctx, key, obj[key]); - } - } -} - -/** - * Iterate array-ish. - * - * @param {Array|Object} obj - * @param {Function} fn - * @param {Object} ctx - * @api private - */ - -function array(obj, fn, ctx) { - for (var i = 0; i < obj.length; ++i) { - fn.call(ctx, obj[i], i); - } -} - -}); -require.register("component-find/index.js", function(exports, require, module){ - -/** - * Module dependencies. - */ - -var toFunction = require('to-function'); - -/** - * Find the first value in `arr` with when `fn(val, i)` is truthy. - * - * @param {Array} arr - * @param {Function} fn - * @return {Array} - * @api public - */ - -module.exports = function(arr, fn){ - // callback - if ('function' != typeof fn) { - if (Object(fn) === fn) fn = objectToFunction(fn); - else fn = toFunction(fn); - } - - // filter - for (var i = 0, len = arr.length; i < len; ++i) { - if (fn(arr[i], i)) return arr[i]; - } -}; - -/** - * Convert `obj` into a match function. - * - * @param {Object} obj - * @return {Function} - * @api private - */ - -function objectToFunction(obj) { - return function(o){ - for (var key in obj) { - if (o[key] != obj[key]) return false; - } - return true; - } -} -}); -require.register("component-json/index.js", function(exports, require, module){ - -module.exports = 'undefined' == typeof JSON - ? require('component-json-fallback') - : JSON; - -}); -require.register("component-type/index.js", function(exports, require, module){ - -/** - * toString ref. - */ - -var toString = Object.prototype.toString; - -/** - * Return the type of `val`. - * - * @param {Mixed} val - * @return {String} - * @api public - */ - -module.exports = function(val){ - switch (toString.call(val)) { - case '[object Function]': return 'function'; - case '[object Date]': return 'date'; - case '[object RegExp]': return 'regexp'; - case '[object Arguments]': return 'arguments'; - case '[object Array]': return 'array'; - case '[object String]': return 'string'; - } - - if (val === null) return 'null'; - if (val === undefined) return 'undefined'; - if (val && val.nodeType === 1) return 'element'; - if (val === Object(val)) return 'object'; - - return typeof val; -}; - -}); -require.register("component-trim/index.js", function(exports, require, module){ - -exports = module.exports = trim; - -function trim(str){ - if (str.trim) return str.trim(); - return str.replace(/^\s*|\s*$/g, ''); -} - -exports.left = function(str){ - if (str.trimLeft) return str.trimLeft(); - return str.replace(/^\s*/, ''); -}; - -exports.right = function(str){ - if (str.trimRight) return str.trimRight(); - return str.replace(/\s*$/, ''); -}; - -}); -require.register("component-map/index.js", function(exports, require, module){ - -/** - * Module dependencies. - */ - -var toFunction = require('to-function'); - -/** - * Map the given `arr` with callback `fn(val, i)`. - * - * @param {Array} arr - * @param {Function} fn - * @return {Array} - * @api public - */ - -module.exports = function(arr, fn){ - var ret = []; - fn = toFunction(fn); - for (var i = 0; i < arr.length; ++i) { - ret.push(fn(arr[i], i)); - } - return ret; -}; -}); -require.register("yields-merge/index.js", function(exports, require, module){ - -/** - * merge `b`'s properties with `a`'s. - * - * example: - * - * var user = {}; - * merge(user, console); - * // > { log: fn, dir: fn ..} - * - * @param {Object} a - * @param {Object} b - * @return {Object} - */ - -module.exports = function (a, b) { - for (var k in b) a[k] = b[k]; - return a; -}; - -}); -require.register("learnboost-jsonp/index.js", function(exports, require, module){ -/** - * Module dependencies - */ - -var debug = require('debug')('jsonp'); - -/** - * Module exports. - */ - -module.exports = jsonp; - -/** - * Callback index. - */ - -var count = 0; - -/** - * Noop function. - */ - -function noop(){} - -/** - * JSONP handler - * - * Options: - * - param {String} qs parameter (`callback`) - * - timeout {Number} how long after a timeout error is emitted (`60000`) - * - * @param {String} url - * @param {Object|Function} optional options / callback - * @param {Function} optional callback - */ - -function jsonp(url, opts, fn){ - if ('function' == typeof opts) { - fn = opts; - opts = {}; - } - if (!opts) opts = {}; - - var prefix = opts.prefix || '__jp'; - var param = opts.param || 'callback'; - var timeout = null != opts.timeout ? opts.timeout : 60000; - var enc = encodeURIComponent; - var target = document.getElementsByTagName('script')[0] || document.head; - var script; - var timer; - - // generate a unique id for this request - var id = prefix + (count++); - - if (timeout) { - timer = setTimeout(function(){ - cleanup(); - if (fn) fn(new Error('Timeout')); - }, timeout); - } - - function cleanup(){ - script.parentNode.removeChild(script); - window[id] = noop; - } - - window[id] = function(data){ - debug('jsonp got', data); - if (timer) clearTimeout(timer); - cleanup(); - if (fn) fn(null, data); - }; - - // add qs component - url += (~url.indexOf('?') ? '&' : '?') + param + '=' + enc(id); - url = url.replace('?&', '?'); - - debug('jsonp req "%s"', url); - - // create script - script = document.createElement('script'); - script.src = url; - target.parentNode.insertBefore(script, target); -} - -}); -require.register("visionmedia-debug/debug.js", function(exports, require, module){ - -/** - * Expose `debug()` as the module. - */ - -module.exports = debug; - -/** - * Create a debugger with the given `name`. - * - * @param {String} name - * @return {Type} - * @api public - */ - -function debug(name) { - if (!debug.enabled(name)) return function(){}; - - return function(fmt){ - fmt = coerce(fmt); - - var curr = new Date; - var ms = curr - (debug[name] || curr); - debug[name] = curr; - - fmt = name - + ' ' - + fmt - + ' +' + debug.humanize(ms); - - // This hackery is required for IE8 - // where `console.log` doesn't have 'apply' - window.console - && console.log - && Function.prototype.apply.call(console.log, console, arguments); - } -} - -/** - * The currently active debug mode names. - */ - -debug.names = []; -debug.skips = []; - -/** - * Enables a debug mode by name. This can include modes - * separated by a colon and wildcards. - * - * @param {String} name - * @api public - */ - -debug.enable = function(name) { - try { - localStorage.debug = name; - } catch(e){} - - var split = (name || '').split(/[\s,]+/) - , len = split.length; - - for (var i = 0; i < len; i++) { - name = split[i].replace('*', '.*?'); - if (name[0] === '-') { - debug.skips.push(new RegExp('^' + name.substr(1) + '$')); - } - else { - debug.names.push(new RegExp('^' + name + '$')); - } - } -}; - -/** - * Disable debug output. - * - * @api public - */ - -debug.disable = function(){ - debug.enable(''); -}; - -/** - * Humanize the given `ms`. - * - * @param {Number} m - * @return {String} - * @api private - */ - -debug.humanize = function(ms) { - var sec = 1000 - , min = 60 * 1000 - , hour = 60 * min; - - if (ms >= hour) return (ms / hour).toFixed(1) + 'h'; - if (ms >= min) return (ms / min).toFixed(1) + 'm'; - if (ms >= sec) return (ms / sec | 0) + 's'; - return ms + 'ms'; -}; - -/** - * Returns true if the given mode name is enabled, false otherwise. - * - * @param {String} name - * @return {Boolean} - * @api public - */ - -debug.enabled = function(name) { - for (var i = 0, len = debug.skips.length; i < len; i++) { - if (debug.skips[i].test(name)) { - return false; - } - } - for (var i = 0, len = debug.names.length; i < len; i++) { - if (debug.names[i].test(name)) { - return true; - } - } - return false; -}; - -/** - * Coerce `val`. - */ - -function coerce(val) { - if (val instanceof Error) return val.stack || val.message; - return val; -} - -// persist - -try { - if (window.localStorage) debug.enable(localStorage.debug); -} catch(e){} - -}); -require.register("johntron-asap/asap.js", function(exports, require, module){ -"use strict"; - -// Use the fastest possible means to execute a task in a future turn -// of the event loop. - -// linked list of tasks (single, with head node) -var head = {task: void 0, next: null}; -var tail = head; -var flushing = false; -var requestFlush = void 0; -var hasSetImmediate = typeof setImmediate === "function"; -var domain; - -if (typeof global != 'undefined') { - // Avoid shims from browserify. - // The existence of `global` in browsers is guaranteed by browserify. - var process = global.process; -} - -// Note that some fake-Node environments, -// like the Mocha test runner, introduce a `process` global. -var isNodeJS = !!process && ({}).toString.call(process) === "[object process]"; - -function flush() { - /* jshint loopfunc: true */ - - while (head.next) { - head = head.next; - var task = head.task; - head.task = void 0; - - try { - task(); - - } catch (e) { - if (isNodeJS) { - // In node, uncaught exceptions are considered fatal errors. - // Re-throw them to interrupt flushing! - - // Ensure continuation if an uncaught exception is suppressed - // listening process.on("uncaughtException") or domain("error"). - requestFlush(); - - throw e; - - } else { - // In browsers, uncaught exceptions are not fatal. - // Re-throw them asynchronously to avoid slow-downs. - throw e; - } - } - } - - flushing = false; -} - -if (isNodeJS) { - // Node.js - requestFlush = function () { - // Ensure flushing is not bound to any domain. - var currentDomain = process.domain; - if (currentDomain) { - domain = domain || (1,require)("domain"); - domain.active = process.domain = null; - } - - // Avoid tick recursion - use setImmediate if it exists. - if (flushing && hasSetImmediate) { - setImmediate(flush); - } else { - process.nextTick(flush); - } - - if (currentDomain) { - domain.active = process.domain = currentDomain; - } - }; - -} else if (hasSetImmediate) { - // In IE10, or https://github.com/NobleJS/setImmediate - requestFlush = function () { - setImmediate(flush); - }; - -} else if (typeof MessageChannel !== "undefined") { - // modern browsers - // http://www.nonblocking.io/2011/06/windownexttick.html - var channel = new MessageChannel(); - // At least Safari Version 6.0.5 (8536.30.1) intermittently cannot create - // working message ports the first time a page loads. - channel.port1.onmessage = function () { - requestFlush = requestPortFlush; - channel.port1.onmessage = flush; - flush(); - }; - var requestPortFlush = function () { - // Opera requires us to provide a message payload, regardless of - // whether we use it. - channel.port2.postMessage(0); - }; - requestFlush = function () { - setTimeout(flush, 0); - requestPortFlush(); - }; - -} else { - // old browsers - requestFlush = function () { - setTimeout(flush, 0); - }; -} - -function asap(task) { - if (isNodeJS && process.domain) { - task = process.domain.bind(task); - } - - tail = tail.next = {task: task, next: null}; - - if (!flushing) { - requestFlush(); - flushing = true; - } -}; - -module.exports = asap; - -}); -require.register("chrissrogers-promise/index.js", function(exports, require, module){ -'use strict'; - -//This file contains then/promise specific extensions to the core promise API - -var Promise = require('./core.js') -var asap = require('asap') - -module.exports = Promise - -/* Static Functions */ - -function ValuePromise(value) { - this.then = function (onFulfilled) { - if (typeof onFulfilled !== 'function') return this - return new Promise(function (resolve, reject) { - asap(function () { - try { - resolve(onFulfilled(value)) - } catch (ex) { - reject(ex); - } - }) - }) - } -} -ValuePromise.prototype = Promise.prototype - -var TRUE = new ValuePromise(true) -var FALSE = new ValuePromise(false) -var NULL = new ValuePromise(null) -var UNDEFINED = new ValuePromise(undefined) -var ZERO = new ValuePromise(0) -var EMPTYSTRING = new ValuePromise('') - -Promise.resolve = function (value) { - if (value instanceof Promise) return value - - if (value === null) return NULL - if (value === undefined) return UNDEFINED - if (value === true) return TRUE - if (value === false) return FALSE - if (value === 0) return ZERO - if (value === '') return EMPTYSTRING - - if (typeof value === 'object' || typeof value === 'function') { - try { - var then = value.then - if (typeof then === 'function') { - return new Promise(then.bind(value)) - } - } catch (ex) { - return new Promise(function (resolve, reject) { - reject(ex) - }) - } - } - - return new ValuePromise(value) -} - -Promise.from = Promise.cast = function (value) { - var err = new Error('Promise.from and Promise.cast are deprecated, use Promise.resolve instead') - err.name = 'Warning' - console.warn(err.stack) - return Promise.resolve(value) -} - -Promise.denodeify = function (fn, argumentCount) { - argumentCount = argumentCount || Infinity - return function () { - var self = this - var args = Array.prototype.slice.call(arguments) - return new Promise(function (resolve, reject) { - while (args.length && args.length > argumentCount) { - args.pop() - } - args.push(function (err, res) { - if (err) reject(err) - else resolve(res) - }) - fn.apply(self, args) - }) - } -} -Promise.nodeify = function (fn) { - return function () { - var args = Array.prototype.slice.call(arguments) - var callback = typeof args[args.length - 1] === 'function' ? args.pop() : null - try { - return fn.apply(this, arguments).nodeify(callback) - } catch (ex) { - if (callback === null || typeof callback == 'undefined') { - return new Promise(function (resolve, reject) { reject(ex) }) - } else { - asap(function () { - callback(ex) - }) - } - } - } -} - -Promise.all = function () { - var calledWithArray = arguments.length === 1 && Array.isArray(arguments[0]) - var args = Array.prototype.slice.call(calledWithArray ? arguments[0] : arguments) - - if (!calledWithArray) { - var err = new Error('Promise.all should be called with a single array, calling it with multiple arguments is deprecated') - err.name = 'Warning' - console.warn(err.stack) - } - - return new Promise(function (resolve, reject) { - if (args.length === 0) return resolve([]) - var remaining = args.length - function res(i, val) { - try { - if (val && (typeof val === 'object' || typeof val === 'function')) { - var then = val.then - if (typeof then === 'function') { - then.call(val, function (val) { res(i, val) }, reject) - return - } - } - args[i] = val - if (--remaining === 0) { - resolve(args); - } - } catch (ex) { - reject(ex) - } - } - for (var i = 0; i < args.length; i++) { - res(i, args[i]) - } - }) -} - -Promise.reject = function (value) { - return new Promise(function (resolve, reject) { - reject(value); - }); -} - -Promise.race = function (values) { - return new Promise(function (resolve, reject) { - values.forEach(function(value){ - Promise.resolve(value).then(resolve, reject); - }) - }); -} - -/* Prototype Methods */ - -Promise.prototype.done = function (onFulfilled, onRejected) { - var self = arguments.length ? this.then.apply(this, arguments) : this - self.then(null, function (err) { - asap(function () { - throw err - }) - }) -} - -Promise.prototype.nodeify = function (callback) { - if (typeof callback != 'function') return this - - this.then(function (value) { - asap(function () { - callback(null, value) - }) - }, function (err) { - asap(function () { - callback(err) - }) - }) -} - -Promise.prototype['catch'] = function (onRejected) { - return this.then(null, onRejected); -} - -}); -require.register("chrissrogers-promise/core.js", function(exports, require, module){ -'use strict'; - -var asap = require('asap') - -module.exports = Promise -function Promise(fn) { - if (typeof this !== 'object') throw new TypeError('Promises must be constructed via new') - if (typeof fn !== 'function') throw new TypeError('not a function') - var state = null - var value = null - var deferreds = [] - var self = this - - this.then = function(onFulfilled, onRejected) { - return new self.constructor(function(resolve, reject) { - handle(new Handler(onFulfilled, onRejected, resolve, reject)) - }) - } - - function handle(deferred) { - if (state === null) { - deferreds.push(deferred) - return - } - asap(function() { - var cb = state ? deferred.onFulfilled : deferred.onRejected - if (cb === null) { - (state ? deferred.resolve : deferred.reject)(value) - return - } - var ret - try { - ret = cb(value) - } - catch (e) { - deferred.reject(e) - return - } - deferred.resolve(ret) - }) - } - - function resolve(newValue) { - try { //Promise Resolution Procedure: https://github.com/promises-aplus/promises-spec#the-promise-resolution-procedure - if (newValue === self) throw new TypeError('A promise cannot be resolved with itself.') - if (newValue && (typeof newValue === 'object' || typeof newValue === 'function')) { - var then = newValue.then - if (typeof then === 'function') { - doResolve(then.bind(newValue), resolve, reject) - return - } - } - state = true - value = newValue - finale() - } catch (e) { reject(e) } - } - - function reject(newValue) { - state = false - value = newValue - finale() - } - - function finale() { - for (var i = 0, len = deferreds.length; i < len; i++) - handle(deferreds[i]) - deferreds = null - } - - doResolve(fn, resolve, reject) -} - - -function Handler(onFulfilled, onRejected, resolve, reject){ - this.onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : null - this.onRejected = typeof onRejected === 'function' ? onRejected : null - this.resolve = resolve - this.reject = reject -} - -/** - * Take a potentially misbehaving resolver function and make sure - * onFulfilled and onRejected are only called once. - * - * Makes no guarantees about asynchrony. - */ -function doResolve(fn, onFulfilled, onRejected) { - var done = false; - try { - fn(function (value) { - if (done) return - done = true - onFulfilled(value) - }, function (reason) { - if (done) return - done = true - onRejected(reason) - }) - } catch (ex) { - if (done) return - done = true - onRejected(ex) - } -} - -}); -require.register("kewah-mixin/index.js", function(exports, require, module){ -if (typeof Object.keys === 'function') { - module.exports = function(to, from) { - Object.keys(from).forEach(function(property) { - Object.defineProperty(to, property, Object.getOwnPropertyDescriptor(from, property)); - }); - }; -} else { - module.exports = function(to, from) { - for (var property in from) { - if (from.hasOwnProperty(property)) { - to[property] = from[property]; - } - } - }; -} - -}); -require.register("pluma-par/dist/par.js", function(exports, require, module){ -/*! par 0.3.0 Original author Alan Plum . Released into the Public Domain under the UNLICENSE. @preserve */ -var slice = Array.prototype.slice; - -function par(fn) { - var args0 = slice.call(arguments, 1); - return function() { - var argsN = slice.call(arguments, 0), - args = []; - args.push.apply(args, args0); - args.push.apply(args, argsN); - return fn.apply(this, args); - }; -} - -function rpartial(fn) { - var argsN = slice.call(arguments, 1); - return function() { - var args = slice.call(arguments, 0); - args.push.apply(args, argsN); - return fn.apply(this, args); - }; -} - -par.rpartial = rpartial; -par.lpartial = par; - -module.exports = par; - -}); -require.register("ianstormtaylor-to-no-case/index.js", function(exports, require, module){ - -/** - * Expose `toNoCase`. - */ - -module.exports = toNoCase; - - -/** - * Test whether a string is camel-case. - */ - -var hasSpace = /\s/; -var hasCamel = /[a-z][A-Z]/; -var hasSeparator = /[\W_]/; - - -/** - * Remove any starting case from a `string`, like camel or snake, but keep - * spaces and punctuation that may be important otherwise. - * - * @param {String} string - * @return {String} - */ - -function toNoCase (string) { - if (hasSpace.test(string)) return string.toLowerCase(); - - if (hasSeparator.test(string)) string = unseparate(string); - if (hasCamel.test(string)) string = uncamelize(string); - return string.toLowerCase(); -} - - -/** - * Separator splitter. - */ - -var separatorSplitter = /[\W_]+(.|$)/g; - - -/** - * Un-separate a `string`. - * - * @param {String} string - * @return {String} - */ - -function unseparate (string) { - return string.replace(separatorSplitter, function (m, next) { - return next ? ' ' + next : ''; - }); -} - - -/** - * Camelcase splitter. - */ - -var camelSplitter = /(.)([A-Z]+)/g; - - -/** - * Un-camelcase a `string`. - * - * @param {String} string - * @return {String} - */ - -function uncamelize (string) { - return string.replace(camelSplitter, function (m, previous, uppers) { - return previous + ' ' + uppers.toLowerCase().split('').join(' '); - }); -} -}); -require.register("ianstormtaylor-to-space-case/index.js", function(exports, require, module){ - -var clean = require('to-no-case'); - - -/** - * Expose `toSpaceCase`. - */ - -module.exports = toSpaceCase; - - -/** - * Convert a `string` to space case. - * - * @param {String} string - * @return {String} - */ - - -function toSpaceCase (string) { - return clean(string).replace(/[\W_]+(.|$)/g, function (matches, match) { - return match ? ' ' + match : ''; - }); -} -}); -require.register("ianstormtaylor-to-slug-case/index.js", function(exports, require, module){ - -var toSpace = require('to-space-case'); - - -/** - * Expose `toSlugCase`. - */ - -module.exports = toSlugCase; - - -/** - * Convert a `string` to slug case. - * - * @param {String} string - * @return {String} - */ - - -function toSlugCase (string) { - return toSpace(string).replace(/\s/g, '-'); -} -}); -require.register("recurly/lib/index.js", function(exports, require, module){ - -/*! - * Module dependencies. - */ - -var Recurly = require('./recurly'); - -/** - * Export a single instance. - */ - -module.exports = exports = new Recurly(); - -/** - * Hack for testing. - */ - -exports.Recurly = Recurly; - -}); -require.register("recurly/lib/recurly.js", function(exports, require, module){ - -/*! - * Module dependencies. - */ - -var bind = require('bind'); -var json = require('json'); -var each = require('each'); -var type = require('type'); -var merge = require('merge'); -var mixin = require('mixin'); -var jsonp = require('jsonp'); -var qs = require('querystring'); -var Emitter = require('emitter'); -var errors = require('./errors'); -var version = require('./version'); -var debug = require('debug')('recurly'); - -/** - * Default configuration values. - * - * @private - * @type {Object} - */ - -var defaults = { - currency: 'USD' - , timeout: 60000 - , publicKey: '' - , api: 'https://api.recurly.com/js/v1' -}; - -/** - * API mixins. - * - * @type {Array} - * @private - */ - -var mixins = [ - 'open' - , 'coupon' - , 'paypal' - , 'plan' - , 'tax' - , 'token' - , 'pricing' - , 'validate' -]; - -/** - * Export `Recurly`. - */ - -module.exports = Recurly; - -/** - * Initialize defaults. - * - * @param {Object} options - * @constructor - * @public - */ - -function Recurly (options) { - this.id = 0; - this.version = version; - this.configured = false; - this.config = merge({}, defaults); - if (options) this.configure(options); -} - -/** - * Inherits `Emitter`. - */ - -Emitter(Recurly.prototype); - -/** - * Configure settings. - * - * @param {String|Object} options Either publicKey or object containing - * publicKey and other optional members - * @param {String} options.publicKey - * @param {String} [options.currency] - * @param {String} [options.api] - * @public - */ - -Recurly.prototype.configure = function configure (options) { - if (this.configured) throw errors('already-configured'); - - debug('configure'); - - if (type(options) === 'string') options = { publicKey: options }; - - if ('publicKey' in options) { - this.config.publicKey = options.publicKey; - } else { - throw errors('missing-public-key'); - } - - if ('api' in options) { - this.config.api = options.api; - } - - if ('currency' in options) { - this.config.currency = options.currency; - } - - this.configured = true; -}; - -/** - * Assembles the API endpoint. - * - * @return {String} route - * @private - */ - -Recurly.prototype.url = function url (route) { - return this.config.api + route; -}; - -/** - * Issues an API request. - * - * @param {String} route - * @param {Object} [data] - * @param {Function} done - * @throws {Error} If `configure` has not been called. - * @private - */ - -Recurly.prototype.request = function request (route, data, done) { - debug('request'); - - if (false === this.configured) { - throw errors('not-configured'); - } - - if ('function' == type(data)) { - done = data; - data = {}; - } - - var url = this.url(route); - var timeout = this.config.timeout; - - data.version = this.version; - data.key = this.config.publicKey; - - url += '?' + qs.stringify(data); - - this.cache(url, function (res, set) { - if (res) return done(null, res); - jsonp(url, { timeout: timeout }, function (err, res) { - if (err) return done(err); - if (res.error) { - done(errors('api-error', res.error)); - } else { - done(null, set(res)); - } - }); - }); -}; - -/** - * Caches an object - * - * TODO: figure out invalidation & expiry - * - * @param {String} url - * @param {Function} done - * @private - */ - -Recurly.prototype.cache = function cache (url, done) { - debug('cache'); - var stored = localStorage.getItem(url); - if (stored) { - debug('cache found ' + url); - return done(json.parse(stored)); - } else { - debug('cache set ' + url); - return done(null, set); - } - function set (obj) { - // disabled for now - // localStorage.setItem(url, json.stringify(obj)); - return obj; - } -}; - -/** - * Load the `mixins` onto Recurly.prototype. - */ - -each(mixins, function (name) { - mixin(Recurly.prototype, require('./recurly/' + name)); -}); - -}); -require.register("recurly/lib/version.js", function(exports, require, module){ - -/** - * Current package/component version. - */ - -module.exports = '3.0.5'; - -}); -require.register("recurly/lib/errors.js", function(exports, require, module){ -/** - * dependencies - */ - -var mixin = require('mixin'); - -/** - * Export `errors`. - */ - -module.exports = exports = errors; - -/** - * Error accessor. - * - * @param {String} name - * @param {Object} options - * @return {Error} - */ - -function errors (name, options) { - return errors.get(name, options); -} - -/** - * Defined errors. - * - * @type {Object} - * @private - */ - -errors.map = {}; - -/** - * Base url for documention. - * - * @type {String} - * @private - */ - -errors.baseURL = ''; - -/** - * Sets the `baseURL` for docs. - * - * @param {String} url - * @public - */ - -errors.doc = function (baseURL) { - errors.baseURL = baseURL; -}; - -/** - * Gets errors defined by `name`. - * - * @param {String} name - * @param {Object} context - * @return {Error} - * @public - */ - -errors.get = function (name, context) { - if (!(name in errors.map)) { - throw new Error('invalid error'); - } else { - return new errors.map[name](context); - } -}; - -/** - * Registers an error defined by `name` with `config`. - * - * @param {String} name - * @param {Object} config - * @return {Error} - * @public - */ - -errors.add = function (name, config) { - config = config || {}; - - function RecurlyError (context) { - Error.call(this); - - this.name = this.code = name; - this.message = config.message; - mixin(this, context || {}); - - if (config.help) { - this.help = errors.baseURL + config.help; - this.message += ' (need help? ' + this.help + ')'; - } - }; - - RecurlyError.prototype = new Error(); - return errors.map[name] = RecurlyError; -}; - -/** - * Internal definations. - * - * TODO(gjohnson): open source this as a component - * and move these out. - */ - -errors.doc('https://docs.recurly.com/js'); - -errors.add('already-configured', { - message: 'Configuration may only be set once.', - help: '#identify-your-site' -}); - -errors.add('not-configured', { - message: 'Not configured. You must first call recurly.configure().', - help: '#identify-your-site' -}); - -errors.add('missing-public-key', { - message: 'The publicKey setting is required.', - help: '#identify-your-site' -}); - -errors.add('api-error', { - message: 'There was an error with your request.' -}); - -errors.add('validation', { - message: 'There was an error validating your request.' -}); - -errors.add('missing-callback', { - message: 'Missing callback' -}); - -errors.add('invalid-options', { - message: 'Options must be an object' -}); - -errors.add('missing-plan', { - message: 'A plan must be specified.' -}); - -errors.add('missing-coupon', { - message: 'A coupon must be specified.' -}); - -errors.add('invalid-item', { - message: 'The given item does not appear to be a valid recurly plan, coupon, addon, or taxable address.' -}); - -errors.add('invalid-addon', { - message: 'The given addon_code is not among the valid addons for the specified plan.' -}); - -errors.add('invalid-currency', { - message: 'The given currency is not among the valid codes for the specified plan.' -}); - -errors.add('unremovable-item', { - message: 'The given item cannot be removed.' -}); - -}); -require.register("recurly/lib/util/dom.js", function(exports, require, module){ -/** - * dependencies - */ - -var slug = require('to-slug-case'); -var type = require('type'); -var each = require('each'); -var map = require('map'); - -/** - * expose - */ - -module.exports = { - element: element, - value: value, - data: data -}; - -/** - * Detects whether an object is an html element. - * - * @param {Mixed} node - * @return {HTMLElement|Boolean} node - */ - -function element (node) { - var isJQuery = window.jQuery && node instanceof jQuery; - var isArray = type(node) === 'array'; - if (isJQuery || isArray) node = node[0]; - - var isElem = typeof HTMLElement !== 'undefined' - ? node instanceof HTMLElement - : node && node.nodeType === 1; - - return isElem && node; -}; - -/** - * Gets or sets the value of a given HTML form element - * - * supports text inputs, radio inputs, and selects - * - * @param {HTMLElement} node - * @return {String} value of the element - */ - -function value (node, value) { - if (!element(node)) return null; - return typeof value !== 'undefined' - ? valueSet(node, value) - : valueGet(node); -} - -/** - * Gets an HTMLElement's value property in the context of a form - * - * @param {HTMLElement} node - * @return {String} node's value - */ - -function valueGet (node) { - node = element(node); - - var nodeType = node && node.type && node.type.toLowerCase(); - var value; - - if (!nodeType) { - value = ''; - } else if ('options' in node) { - value = node.options[node.selectedIndex].value; - } else if (nodeType === 'checkbox') { - if (node.checked) value = node.value; - } else if (nodeType === 'radio') { - var radios = document.querySelectorAll('input[data-recurly="' + data(node, 'recurly') + '"]'); - each(radios, function (radio) { - if (radio.checked) value = radio.value; - }); - } else if ('value' in node) { - value = node.value; - } - - return value; -} - -/** - * Updates an element's value property if - * one exists; else innerText if it exists - * - * @param {Array[HTMLElement]} nodes - * @param {Mixed} value - */ - -function valueSet (nodes, value) { - if (type(nodes) !== 'array') nodes = [nodes]; - each(nodes, function (node) { - if (!node) return; - else if ('value' in node) - node.value = value; - else if ('textContent' in node) - node.textContent = value; - else if ('innerText' in node) - node.innerText = value; - }); -} - -/** - * Gets or sets a node's data attribute - * - * @param {HTMLElement} node - * @param {String} key - * @param {Mixed} [value] - */ - -function data (node, key, value) { - node = element(node); - if (!node) return; - return typeof value !== 'undefined' - ? dataSet(node, key, value) - : dataGet(node, key); -} - -/** - * Gets a node's data attribute - * - * @param {HTMLElement} node - * @param {String} key - */ - -function dataGet (node, key) { - return node.dataset - ? node.dataset[key] - : node.getAttribute('data-' + slug(key)); -} - -/** - * sets a node's data attribute - * - * @param {HTMLElement} node - * @param {String} key - * @param {Mixed} value - */ - -function dataSet (node, key, value) { - if (node.dataset) node.dataset[key] = value; - else node.setAttribute('data-' + slug(key), value); -} - -}); -require.register("recurly/lib/util/parse-card.js", function(exports, require, module){ - -/** - * Removes dashes and spaces from a card number. - * - * @param {Number|String} number - * @return {String} parsed card number - */ - -module.exports = function parseCard (number) { - return number && number.toString().replace(/[-\s]/g, ''); -}; - -}); -require.register("recurly/lib/recurly/open.js", function(exports, require, module){ - -/*! - * Module dependencies. - */ - -var bind = require('bind'); -var type = require('type'); -var json = require('json'); -var events = require('event'); -var qs = require('querystring'); -var errors = require('../errors'); -var debug = require('debug')('recurly:open'); - -/** - * Issues an API request to a popup window. - * - * TODO(*): configurable window name? - * TODO(*): configurable window properties? - * - * @param {String} url - * @param {Object} [data] - * @param {Function} [done] - * @throws {Error} If `configure` has not been called. - * @return {Window} - * @private - */ - -exports.open = function (url, data, done) { - debug('open'); - - if (false === this.configured) { - throw errors('not-configured'); - } - - if ('function' == type(data)) { - done = data; - data = {}; - } - - data = data || {}; - data.version = this.version; - data.event = 'recurly-open-' + this.id++; - data.key = this.config.publicKey; - this.once(data.event, done); - - if (!/^https?:\/\//.test(url)) url = this.url(url); - url += (~url.indexOf('?') ? '&' : '?') + qs.stringify(data); - - this.relay(function () { - window.open(url); - }); -}; - -/** - * Relay mixin. - * - * Inspects the window for intent to relay a message, - * then attempts to send it off. closes the window once - * dispatched. - * - * @param {Function} done - * @private - */ - -exports.relay = function (done) { - var self = this; - - if (false === this.configured) { - throw errors('not-configured'); - } - - events.bind(window, 'message', function listener (event) { - var data = json.parse(event.data); - var name = data.recurly_event; - var body = data.recurly_message; - var err = body.error ? errors('api-error', body.error) : null; - events.unbind(window, 'message', listener); - if (name) self.emit(name, err, body); - if (frame) document.body.removeChild(frame); - }); - - if ('documentMode' in document) { - var frame = document.createElement('iframe'); - frame.width = frame.height = 0; - frame.src = this.url('/relay'); - frame.name = 'recurly-relay'; - frame.style.display = 'none'; - frame.onload = bind(this, done); - document.body.appendChild(frame); - } else { - done(); - } -}; - -}); -require.register("recurly/lib/recurly/coupon.js", function(exports, require, module){ - -/*! - * Module dependencies. - */ - -var type = require('type'); -var debug = require('debug')('recurly:coupon'); -var errors = require('../errors'); - -/** - * Coupon mixin. - * - * Retrieves coupon information for the `plan`. The `callback` signature - * is `err, plan` where `err` may be a request or server error, and `plan` - * is a representation of the requested plan. - * - * @param {Object} options - * @param {Function} callback - */ - -exports.coupon = function (options, callback) { - debug('%j', options); - - if ('function' !== type(callback)) { - throw errors('missing-callback'); - } - - if ('object' !== type(options)) { - throw errors('invalid-options'); - } - - if (!('plan' in options)) { - throw errors('missing-plan'); - } - - if (!('coupon' in options)) { - throw errors('missing-coupon'); - } - - this.request('/plans/' + options.plan + '/coupons/' + options.coupon, options, callback); -}; - -}); -require.register("recurly/lib/recurly/paypal.js", function(exports, require, module){ - -/*! - * Module dependencies. - */ - -var debug = require('debug')('recurly:paypal'); - -/** - * Paypal mixin. - * - * @param {Object} data - * @param {Function} done callback - */ - -exports.paypal = function (data, done) { - debug('start'); - this.open('/paypal/start', data, done); -}; - -}); -require.register("recurly/lib/recurly/plan.js", function(exports, require, module){ - -/*! - * Module dependencies. - */ - -var type = require('type'); -var debug = require('debug')('recurly:plan'); - -/** - * Plan mixin. - * - * Retrieves information for the `plan`. The `callback` signature - * is `err, plan` where `err` may be a request or server error, and `plan` - * is a representation of the requested plan. - * - * @param {String} code - * @param {Function} callback - */ - -exports.plan = function (code, callback) { - debug('%s', code); - - if ('function' != type(callback)) { - throw new Error('Missing callback'); - } - - if ('undefined' == type(code)) { - return callback(new Error('Missing plan code')); - } - - this.request('/plans/' + code, callback); -}; - -}); -require.register("recurly/lib/recurly/tax.js", function(exports, require, module){ - -/*! - * Module dependencies. - */ - -var type = require('type'); -var clone = require('clone'); -var debug = require('debug')('recurly:tax'); - -/** - * Tax mixin. - * - * Provides a tax estiamte for the given address. - * - * @param {Object} options - * @param {Object} options.postal_code - * @param {Object} options.country - * @param {Object} [options.vat_number] Used for VAT exemptions - * @param {Function} callback - */ - -exports.tax = function (options, callback) { - var request = clone(options); - - if ('function' != type(callback)) { - throw new Error('Missing callback'); - } - - if (!('currency' in request)) { - request.currency = this.config.currency; - } - - this.request('/tax', request, callback); -}; - -}); -require.register("recurly/lib/recurly/token.js", function(exports, require, module){ - -/*! - * Module dependencies. - */ - -var bind = require('bind'); -var each = require('each'); -var type = require('type'); -var index = require('indexof'); -var debug = require('debug')('recurly:token'); -var dom = require('../util/dom'); -var parseCard = require('../util/parse-card'); -var errors = require('../errors'); - -/** - * Fields that are sent to API. - * - * @type {Array} - * @private - */ - -var fields = [ - 'first_name' - , 'last_name' - , 'number' - , 'month' - , 'year' - , 'cvv' - , 'address1' - , 'address2' - , 'country' - , 'city' - , 'state' - , 'postal_code' - , 'phone' - , 'vat_number' - , 'token' -]; - -/** - * Generates a token from customer data. - * - * The callback signature: `err, response` where `err` is a - * connection, request, or server error, and `response` is the - * recurly service response. The generated token is accessed - * at `response.token`. - * - * @param {Object|HTMLFormElement} options Billing properties or an HTMLFormElement - * with children corresponding to billing properties via 'data-reurly' attributes. - * @param {String} options.first_name customer first name - * @param {String} options.last_name customer last name - * @param {String|Number} options.number card number - * @param {String|Number} options.month card expiration month - * @param {String|Number} options.year card expiration year - * @param {String|Number} options.cvv card verification value - * @param {String} [options.address1] - * @param {String} [options.address2] - * @param {String} [options.country] - * @param {String} [options.city] - * @param {String} [options.state] - * @param {String|Number} [options.postal_code] - * @param {Function} done callback - */ - -exports.token = function (options, done) { - var open = bind(this, this.open); - var data = normalize(options); - var input = data.values; - var userErrors = validate.call(this, input); - - if ('function' !== type(done)) { - throw errors('missing-callback'); - } - - if (userErrors.length) { - return done(errors('validation', { fields: userErrors })); - } - - this.request('/token', input, function (err, res) { - if (err) return done(err); - if (data.fields.token && res.id) { - data.fields.token.value = res.id; - } - done(null, res); - }); -}; - -/** - * Parses options out of a form element and normalizes according to rules. - * - * @param {Object|HTMLFormElement} options - * @return {Object} - */ - -function normalize (options) { - var el = dom.element(options); - var data = { fields: {}, values: {} }; - - if (el && 'form' === el.nodeName.toLowerCase()) { - each(el.querySelectorAll('[data-recurly]'), function (field) { - var name = dom.data(field, 'recurly'); - if (~index(fields, name)) { - data.fields[name] = field; - data.values[name] = dom.value(field); - } - }); - } else { - data.values = options; - } - - data.values.number = parseCard(data.values.number); - - return data; -} - -/** - * Checks user input on a token call - * - * @param {Object} input - * @return {Array} indicates which fields are not valid - */ - -function validate (input) { - var errors = []; - - if (!this.validate.cardNumber(input.number)) { - errors.push('number'); - } - - if (!this.validate.expiry(input.month, input.year)) { - errors.push('month', 'year'); - } - - if (!input.first_name) { - errors.push('first_name'); - } - - if (!input.last_name) { - errors.push('last_name'); - } - - return errors; -} - -}); -require.register("recurly/lib/recurly/validate.js", function(exports, require, module){ - -/*! - * Module dependencies. - */ - -var find = require('find'); -var trim = require('trim'); -var index = require('indexof'); -var parseCard = require('../util/parse-card'); - -/** - * Card patterns. - * - * @private - */ - -var types = [ - { - type: 'discover', - pattern: /^(6011|622|64[4-9]|65)/, - lengths: [16] - } - , { - type: 'master', - pattern: /^5[0-5]/, - lengths: [16] - } - , { - type: 'american_express', - pattern: /^3[47]/, - lengths: [15] - } - , { - type: 'visa', - pattern: /^4/, - lengths: [13, 16] - } - , { - type: 'jcb', - pattern: /^35[2-8]\d/, - lengths: [16] - } - , { - type: 'diners_club', - pattern: /^(30[0-5]|309|36|3[89]|54|55|2014|2149)/, - lengths: [14] - } -]; - -/** - * Validate mixin. - * - * @public - */ - -exports.validate = { - - /** - * Validates a credit card number via luhn algorithm. - * - * @param {Number|String} number The card number. - * @return {Boolean} - * @see https://sites.google.com/site/abapexamples/javascript/luhn-validation - */ - - cardNumber: function (number) { - var str = parseCard(number); - var ca, sum = 0, mul = 1; - var i = str.length; - - while (i--) { - ca = parseInt(str.charAt(i), 10) * mul; - sum += ca - (ca > 9) * 9; - mul ^= 3; - } - - return sum % 10 === 0 && sum > 0; - }, - - /** - * Returns the type of the card number as a string. - * - * TODO(chrissrogers): Maybe undefined instread of "unknown"? - * - * @param {Number|String} number The card number - * @return {String} card type - */ - - cardType: function (number) { - var str = parseCard(number); - var card = find(types, function (card) { - return card.pattern.test(str) && ~index(card.lengths, str.length); - }); - return card && card.type || 'unknown'; - }, - - /** - * Validates whether an expiry month is present or future. - * - * @param {Numer|String} month The 2 digit month - * @param {Numer|String} year The 2 or 4 digit year - * @return {Boolean} - */ - - expiry: function (month, year) { - month = parseInt(month, 10) - 1; - if (month < 0 || month > 11) return false; - year = parseInt(year, 10); - year += year < 100 ? 2000 : 0; - - var expiry = new Date; - expiry.setYear(year); - expiry.setDate(1); - expiry.setHours(0); - expiry.setMinutes(0); - expiry.setSeconds(0); - expiry.setMonth(month + 1); - return new Date < expiry; - }, - - /** - * Validates whether a number looks like a cvv. - * - * e.g.: '123', '0321' - * - * @param {Number|String} number The card verification value - * @return {Boolean} - */ - - cvv: function (number) { - number = trim(number + ''); - return /^\d+$/.test(number) && (number.length === 3 || number.length === 4); - } - -}; - -}); -require.register("recurly/lib/recurly/pricing/index.js", function(exports, require, module){ -/** - * dependencies - */ - -var Emitter = require('emitter'); -var index = require('indexof'); -var each = require('each'); -var type = require('type'); -var bind = require('bind'); -var find = require('find'); -var mixin = require('mixin'); -var keys = require('object').keys; -var json = require('json'); -var debug = require('debug')('recurly:pricing'); -var PricingPromise = require('./promise'); -var Calculations = require('./calculations'); -var errors = require('../../errors'); - -/** - * expose - */ - -exports.Pricing = Pricing; - -/** - * Pricing - * - * @constructor - * @param {Recurly} recurly - * @public - */ - -function Pricing (recurly) { - if (this instanceof require('../../recurly')) return new Pricing(this); - this.recurly = recurly; - this.reset(); -} - -Emitter(Pricing.prototype); - -/** - * Subscription properties - */ - -Pricing.properties = [ - 'plan' - , 'addon' - , 'coupon' - , 'address' - , 'currency' -]; - -/** - * Resets the pricing calculator - * - * @public - */ - -Pricing.prototype.reset = function () { - this.items = {}; - this.items.addons = []; - this.currency(this.recurly.config.currency); -}; - -/** - * Removes an object from the pricing model - * - * example - * - * .remove({ plan: 'plan_code' }); - * .remove({ addon: 'addon_code' }); - * .remove({ coupon: 'coupon_code' }); - * .remove({ address: true }); // to remove without specifying a code - * - * @param {Object} opts - * @param {Function} [done] callback - * @public - */ - -Pricing.prototype.remove = function (opts, done) { - var self = this; - var item; - debug('remove'); - - return new PricingPromise(function (resolve, reject) { - var prop = keys(opts)[0]; - var id = opts[prop]; - if (!~index(Pricing.properties, prop)) return reject(errors('invalid-item')); - if (prop === 'addon') { - var pos = index(self.items.addons, findAddon(self.items.addons, { code: id })); - if (~pos) { - item = self.items.addons.splice(pos); - } - } else if (self.items[prop] && (id === self.items[prop].code || id === true)) { - item = self.items[prop] - delete self.items[prop]; - } else { - return reject(errors('unremovable-item', { - type: prop - , id: id - , reason: 'does not exist on this pricing instance.' - })); - } - }, this).nodeify(done); -}; - -/** - * Provides a subscription price estimate using current state - * - * @param {Function} [done] callback - * @public - */ - -Pricing.prototype.reprice = function (done) { - var self = this; - debug('reprice'); - - return new PricingPromise(function (resolve, reject) { - if (!self.items.plan) return reject(errors('missing-plan')); - - Calculations(self, function (price) { - if (json.stringify(price) === json.stringify(self.price)) return resolve(price); - self.price = price; - self.emit('change', price); - resolve(price); - }); - }, this).nodeify(done); -}; - -/** - * Updates plan - * - * @param {String} planCode - * @param {Object} [meta] - * @param {Number} [meta.quantity] - * @param {Function} [done] callback - * @public - */ - -Pricing.prototype.plan = function (planCode, meta, done) { - var self = this; - var plan = this.items.plan; - var quantity; - - if (type(meta) === 'function') { - done = meta; - meta = undefined; - } - - meta = meta || {}; - - // meta.quantity, plan.quantity, 1 - if (plan && plan.quantity) quantity = plan.quantity; - if (meta.quantity) quantity = parseInt(meta.quantity, 10); - if (!quantity || quantity < 1) quantity = 1; - - return new PricingPromise(function (resolve, reject) { - if (plan && plan.code === planCode) { - plan.quantity = quantity; - return resolve(plan); - } - - self.recurly.plan(planCode, function (err, plan) { - if (err) return reject(err); - - plan.quantity = quantity; - self.items.plan = plan; - - if (!(self.items.currency in plan.price)) { - self.currency(keys(plan.price)[0]); - } - - debug('set.plan'); - self.emit('set.plan', plan); - resolve(plan); - }); - }, this).nodeify(done); -}; - -/** - * Updates addon - * - * @param {String} addonCode - * @param {Object} [meta] - * @param {Number} [meta.quantity] - * @param {Function} [done] callback - * @public - */ - -Pricing.prototype.addon = function (addonCode, meta, done) { - var self = this; - - if (type(meta) === 'function') { - done = meta; - meta = undefined; - } - - meta = meta || {}; - - return new PricingPromise(function (resolve, reject) { - if (!self.items.plan) return reject(errors('missing-plan')); - - var planAddon = findAddon(self.items.plan.addons, addonCode); - if (!planAddon) { - return reject(errors('invalid-addon', { - planCode: self.items.plan.code - , addonCode: addonCode - })); - } - - var quantity = addonQuantity(meta, planAddon); - var addon = findAddon(self.items.addons, addonCode); - - if (quantity === 0) { - self.remove({ addon: addonCode }); - } - - if (addon) { - addon.quantity = quantity; - } else { - addon = json.parse(json.stringify(planAddon)); - addon.quantity = quantity; - self.items.addons.push(addon); - } - - debug('set.addon'); - self.emit('set.addon', addon); - resolve(addon); - }, this).nodeify(done); -}; - -/** - * Updates coupon - * - * @param {String} couponCode - * @param {Function} [done] callback - * @public - */ - -Pricing.prototype.coupon = function (couponCode, done) { - var self = this; - var coupon = this.items.coupon; - - return new PricingPromise(function (resolve, reject) { - if (!self.items.plan) return reject(errors('missing-plan')); - if (coupon) { - if (coupon.code === couponCode) return resolve(coupon); - else self.remove({ coupon: coupon.code }); - } - if (!couponCode) return resolve(); - - self.recurly.coupon({ plan: self.items.plan.code, coupon: couponCode }, function (err, coupon) { - if (err && err.code !== 'not_found') return reject(err); - - self.items.coupon = coupon; - - debug('set.coupon'); - self.emit('set.coupon', coupon); - resolve(coupon); - }); - }, this).nodeify(done); -}; - -/** - * Updates address - * - * @param {Object} address - * @param {String} address.country - * @param {String|Number} address.postal_code - * @param {String} address.vat_number - * @param {Function} [done] callback - * @public - */ - -Pricing.prototype.address = function (address, done) { - var self = this; - - return new PricingPromise(function (resolve, reject) { - if (json.stringify(address) === json.stringify(self.items.address)) { - return resolve(self.items.address); - } - - self.items.address = address; - - debug('set.address'); - self.emit('set.address', address); - resolve(address); - }, this).nodeify(done); -}; - -/** - * Updates or retrieves currency code - * - * @param {String} code - * @param {Function} [done] callback - * @public - */ - -Pricing.prototype.currency = function (code, done) { - var self = this; - var plan = this.items.plan - var currency = this.items.currency; - - return new PricingPromise(function (resolve, reject) { - if (currency === code) return resolve(currency); - if (plan && !(code in plan.price)) { - return reject(errors('invalid-currency', { - currencyCode: code - , planCurrencies: keys(plan.price) - })); - } - - self.items.currency = code; - - debug('set.currency'); - self.emit('set.currency', code); - resolve(code); - }, this).nodeify(done); -}; - -/** - * DOM attachment mixin - */ - -mixin(Pricing.prototype, require('./attach')); - -/** - * Utility functions - */ - -function addonQuantity (meta, planAddon) { - var qty = 1; - if ('quantity' in planAddon) qty = planAddon.quantity; - if ('quantity' in meta) qty = meta.quantity; - return parseInt(qty, 10) || 0; -} - -function findAddon (addons, code) { - return addons && find(addons, { code: code }); -} - -}); -require.register("recurly/lib/recurly/pricing/promise.js", function(exports, require, module){ -/** - * Dependencies - */ - -var Promise = require('promise'); -var mixin = require('mixin'); -var bind = require('bind'); -var each = require('each'); -var type = require('type'); -var par = require('par'); -var debug = require('debug')('recurly:pricing:promise'); - -/** - * Expose - */ - -module.exports = PricingPromise; - -/** - * PricingPromise - * - * issues repricing when .done - * - * contains .then wrappers for Pricing property methods - * - * Usage - * - * var pricing = recurly.Pricing(); - * - * pricing - * .plan('basic') - * .addon('addon1') - * .then(process) - * .catch(errors) - * .done(); - * - * @param {Function} resolver - * @param {Pricing} pricing bound instance - * @constructor - * @public - */ - -function PricingPromise (resolver, pricing) { - if (!(this instanceof PricingPromise)) return new PricingPromise(resolver, pricing); - - var self = this; - this.pricing = pricing; - this.constructor = par.rpartial(this.constructor, pricing); - - Promise.call(this, resolver); - - // for each pricing method, create a promise wrapper method - each(require('./').Pricing.prototype, function (method) { - self[method] = function () { - var args = arguments; - return self.then(function () { - return self.pricing[method].apply(self.pricing, args); - }); - }; - }); -} - -mixin(PricingPromise.prototype, Promise.prototype); -PricingPromise.prototype.constructor = PricingPromise; - -/** - * Adds a reprice and completes the control flow - * - * @param {Function} onFulfilled - * @param {Function} onRejected - * @return {Pricing} bound pricing instance - * @public - */ - -PricingPromise.prototype.done = function () { - Promise.prototype.done.apply(this.then(this.reprice), arguments); - return this.pricing; -}; - -/** - * Adds a reprice if a callback is passed - * - * @param {Function} [done] callback - * @public - */ - -PricingPromise.prototype.nodeify = function (done) { - if (type(done) === 'function') this.reprice(); - return Promise.prototype.nodeify.apply(this, arguments); -}; - -}); -require.register("recurly/lib/recurly/pricing/calculations.js", function(exports, require, module){ -/** - * dependencies - */ - -var each = require('each'); -var bind = require('bind'); -var find = require('find'); - -/** - * expose - */ - -module.exports = Calculations; - -/** - * Subscription calculation calculation - * - * @param {Pricing} pricing - * @constructor - * @public - */ - -function Calculations (pricing, done) { - if (!(this instanceof Calculations)) { - return new Calculations(pricing, done); - } - - this.pricing = pricing; - this.items = pricing.items; - - this.price = { - now: {}, - next: {}, - addons: {}, - currency: { - code: this.items.currency, - symbol: this.planPrice().symbol - } - }; - - this.subtotal(); - - this.tax(function () { - this.total(); - each(this.price.now, decimal, this.price.now); - each(this.price.next, decimal, this.price.next); - each(this.price.addons, decimal, this.price.addons); - done(this.price); - }); -} - -/** - * Calculates subtotal - * - * @private - */ - -Calculations.prototype.subtotal = function () { - var subtotal = this.planPrice().amount; - - this.price.now.subtotal = subtotal; - this.price.next.subtotal = subtotal; - - if (this.items.plan.trial) this.price.now.subtotal = 0; - - this.addons(); - this.price.now.subtotal += this.price.now.addons; - this.price.next.subtotal += this.price.next.addons; - - this.discount(); - this.price.now.subtotal -= this.price.now.discount; - this.price.next.subtotal -= this.price.next.discount; - - this.setupFee(); - this.price.now.subtotal += this.price.now.setup_fee; -}; - -/** - * Calculates tax - * - * @param {Function} done - * @private - */ - -Calculations.prototype.tax = function (done) { - this.price.now.tax = 0; - this.price.next.tax = 0; - - if (this.items.address) { - var self = this; - this.pricing.recurly.tax(this.items.address, function applyTax (err, taxes) { - if (err) { - self.pricing.emit('error', err); - } else { - each(taxes, function (tax) { - if (tax.type === 'usst' && self.items.plan.tax_exempt) return; - self.price.now.tax += self.price.now.subtotal * tax.rate; - self.price.next.tax += self.price.next.subtotal * tax.rate; - }); - - // tax estimation prefers partial cents to always round up - self.price.now.tax = Math.ceil(self.price.now.tax * 100) / 100; - self.price.next.tax = Math.ceil(self.price.next.tax * 100) / 100; - } - done.call(self); - }); - } else done.call(this); -}; - -/** - * Calculates total - * - * @private - */ - -Calculations.prototype.total = function () { - this.price.now.total = this.price.now.subtotal + this.price.now.tax; - this.price.next.total = this.price.next.subtotal + this.price.next.tax; -}; - -/** - * Computes addon prices and applies addons to the subtotal - * - * @private - */ - -Calculations.prototype.addons = function () { - this.price.now.addons = 0; - this.price.next.addons = 0; - - each(this.items.plan.addons, function (addon) { - var price = addon.price[this.items.currency].unit_amount; - - this.price.addons[addon.code] = price; - - var selected = find(this.items.addons, { code: addon.code }); - if (selected) { - price = price * selected.quantity; - if (!this.items.plan.trial) this.price.now.addons += price; - this.price.next.addons += price; - } - }, this); -}; - -/** - * Applies coupon discount to the subtotal - * - * @private - */ - -Calculations.prototype.discount = function () { - var coupon = this.items.coupon; - - this.price.now.discount = 0; - this.price.next.discount = 0; - - if (coupon) { - if (coupon.discount.rate) { - this.price.now.discount = Math.round(this.price.now.subtotal * coupon.discount.rate * 100) / 100; - this.price.next.discount = Math.round(this.price.next.subtotal * coupon.discount.rate * 100) / 100; - } else { - this.price.now.discount = coupon.discount.amount[this.items.currency]; - this.price.next.discount = coupon.discount.amount[this.items.currency]; - } - } -}; - -/** - * Applies plan setup fee to the subtotal - * - * @private - */ - -Calculations.prototype.setupFee = function () { - this.price.now.setup_fee = this.planPrice().setup_fee; - this.price.next.setup_fee = 0; -}; - -/** - * Get the price structure of a plan based on currency - * - * @return {Object} - * @private - */ - -Calculations.prototype.planPrice = function () { - var plan = this.items.plan; - var price = plan.price[this.items.currency]; - price.amount = price.unit_amount * (plan.quantity || 1); - return price; -}; - -/** - * Applies a decimal transform on an object's member - * - * @param {String} prop Property on {this} to transform - * @this {Object} on which to apply decimal transformation - * @private - */ - -function decimal (prop) { - this[prop] = (Math.round(Math.max(this[prop], 0) * 100) / 100).toFixed(2); -} - -}); -require.register("recurly/lib/recurly/pricing/attach.js", function(exports, require, module){ -/** - * dependencies - */ - -var each = require('each'); -var events = require('event'); -var find = require('find'); -var type = require('type'); -var dom = require('../../util/dom'); -var debug = require('debug')('recurly:pricing:attach'); - -/** - * bind a dom element to pricing values - * - * @param {HTMLElement} el - */ - -exports.attach = function (el) { - var self = this; - var elems = {}; - var el = dom.element(el); - - if (!el) throw new Error('invalid dom element'); - - if (this.attach.detatch) this.attach.detatch(); - - self.on('change', update); - - each(el.querySelectorAll('[data-recurly]'), function (elem) { - // 'zip' -> 'postal_code' - if (dom.data(elem, 'recurly') === 'zip') dom.data(elem, 'recurly', 'postal_code'); - - var name = dom.data(elem, 'recurly'); - if (!elems[name]) elems[name] = []; - elems[name].push(elem); - events.bind(elem, 'change', change); - events.bind(elem, 'propertychange', change); - }); - - this.attach.detatch = detatch; - - change(); - - function change (event) { - debug('change'); - - var targetName = event && event.target && dom.data(event.target, 'recurly'); - targetName = targetName || window.event && window.event.srcElement; - - var pricing = self.plan(dom.value(elems.plan), { quantity: dom.value(elems.plan_quantity) }); - - if (target('currency')) { - pricing = pricing.currency(dom.value(elems.currency)); - } - - if (target('addon') && elems.addon) { - addons(); - } - - if (target('coupon') && elems.coupon) { - pricing = pricing.coupon(dom.value(elems.coupon)).then(null, ignoreBadCoupons); - } - - if (target('country') || target('postal_code') || target('vat_number')) { - pricing = pricing.address({ - country: dom.value(elems.country), - postal_code: dom.value(elems.postal_code), - vat_number: dom.value(elems.vat_number) - }); - } - - pricing.done(); - - function addons () { - each(elems.addon, function (node) { - var plan = self.items.plan; - var addonCode = dom.data(node, 'recurlyAddon'); - if (plan.addons && find(plan.addons, { code: addonCode })) { - pricing = pricing.addon(addonCode, { quantity: dom.value(node) }); - } - }); - } - - function target (name) { - if (!targetName) return true; - if (targetName === name) return true; - return false - } - }; - - function update (price) { - dom.value(elems.currency_code, price.currency.code); - dom.value(elems.currency_symbol, price.currency.symbol); - each(['addons', 'discount', 'setup_fee', 'subtotal', 'tax', 'total'], function (value) { - dom.value(elems[value + '_now'], price.now[value]); - dom.value(elems[value + '_next'], price.next[value]); - }); - if (elems.addonPrice) { - each(elems.addonPrice, function (elem) { - var addonPrice = price.addons[dom.data(elem, 'recurlyAddon')]; - if (addonPrice) dom.value(elem, addonPrice); - }); - } - } - - function detatch () { - each(elems, function (name, elems) { - each(elems, function (elem) { - events.unbind(elem, 'change', change); - events.unbind(elem, 'propertychange', change); - }, this); - }, this); - } -}; - -function ignoreBadCoupons (err) { - if (err.code === 'not-found') return; - else throw err; -} - -/** - * Backward-compatibility - * - * @deprecated - */ - -exports.binding = exports.attach; - -}); - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -require.alias("visionmedia-node-querystring/index.js", "recurly/deps/querystring/index.js"); -require.alias("visionmedia-node-querystring/index.js", "querystring/index.js"); - -require.alias("component-emitter/index.js", "recurly/deps/emitter/index.js"); -require.alias("component-emitter/index.js", "emitter/index.js"); - -require.alias("component-indexof/index.js", "recurly/deps/indexof/index.js"); -require.alias("component-indexof/index.js", "indexof/index.js"); - -require.alias("component-object/index.js", "recurly/deps/object/index.js"); -require.alias("component-object/index.js", "object/index.js"); - -require.alias("component-event/index.js", "recurly/deps/event/index.js"); -require.alias("component-event/index.js", "event/index.js"); - -require.alias("component-clone/index.js", "recurly/deps/clone/index.js"); -require.alias("component-clone/index.js", "clone/index.js"); -require.alias("component-type/index.js", "component-clone/deps/type/index.js"); - -require.alias("component-bind/index.js", "recurly/deps/bind/index.js"); -require.alias("component-bind/index.js", "bind/index.js"); - -require.alias("component-each/index.js", "recurly/deps/each/index.js"); -require.alias("component-each/index.js", "each/index.js"); -require.alias("component-to-function/index.js", "component-each/deps/to-function/index.js"); -require.alias("component-props/index.js", "component-to-function/deps/props/index.js"); - -require.alias("component-type/index.js", "component-each/deps/type/index.js"); - -require.alias("component-find/index.js", "recurly/deps/find/index.js"); -require.alias("component-find/index.js", "find/index.js"); -require.alias("component-to-function/index.js", "component-find/deps/to-function/index.js"); -require.alias("component-props/index.js", "component-to-function/deps/props/index.js"); - -require.alias("component-json/index.js", "recurly/deps/json/index.js"); -require.alias("component-json/index.js", "json/index.js"); - -require.alias("component-type/index.js", "recurly/deps/type/index.js"); -require.alias("component-type/index.js", "type/index.js"); - -require.alias("component-trim/index.js", "recurly/deps/trim/index.js"); -require.alias("component-trim/index.js", "trim/index.js"); - -require.alias("component-map/index.js", "recurly/deps/map/index.js"); -require.alias("component-map/index.js", "map/index.js"); -require.alias("component-to-function/index.js", "component-map/deps/to-function/index.js"); -require.alias("component-props/index.js", "component-to-function/deps/props/index.js"); - -require.alias("yields-merge/index.js", "recurly/deps/merge/index.js"); -require.alias("yields-merge/index.js", "merge/index.js"); - -require.alias("learnboost-jsonp/index.js", "recurly/deps/jsonp/index.js"); -require.alias("learnboost-jsonp/index.js", "recurly/deps/jsonp/index.js"); -require.alias("learnboost-jsonp/index.js", "jsonp/index.js"); -require.alias("visionmedia-debug/debug.js", "learnboost-jsonp/deps/debug/debug.js"); -require.alias("visionmedia-debug/debug.js", "learnboost-jsonp/deps/debug/index.js"); -require.alias("visionmedia-debug/debug.js", "visionmedia-debug/index.js"); -require.alias("learnboost-jsonp/index.js", "learnboost-jsonp/index.js"); -require.alias("visionmedia-debug/debug.js", "recurly/deps/debug/debug.js"); -require.alias("visionmedia-debug/debug.js", "recurly/deps/debug/index.js"); -require.alias("visionmedia-debug/debug.js", "debug/index.js"); -require.alias("visionmedia-debug/debug.js", "visionmedia-debug/index.js"); -require.alias("chrissrogers-promise/index.js", "recurly/deps/promise/index.js"); -require.alias("chrissrogers-promise/core.js", "recurly/deps/promise/core.js"); -require.alias("chrissrogers-promise/index.js", "promise/index.js"); -require.alias("johntron-asap/asap.js", "chrissrogers-promise/deps/asap/asap.js"); -require.alias("johntron-asap/asap.js", "chrissrogers-promise/deps/asap/index.js"); -require.alias("johntron-asap/asap.js", "johntron-asap/index.js"); -require.alias("kewah-mixin/index.js", "recurly/deps/mixin/index.js"); -require.alias("kewah-mixin/index.js", "recurly/deps/mixin/index.js"); -require.alias("kewah-mixin/index.js", "mixin/index.js"); -require.alias("kewah-mixin/index.js", "kewah-mixin/index.js"); -require.alias("pluma-par/dist/par.js", "recurly/deps/par/dist/par.js"); -require.alias("pluma-par/dist/par.js", "recurly/deps/par/index.js"); -require.alias("pluma-par/dist/par.js", "par/index.js"); -require.alias("pluma-par/dist/par.js", "pluma-par/index.js"); -require.alias("ianstormtaylor-to-slug-case/index.js", "recurly/deps/to-slug-case/index.js"); -require.alias("ianstormtaylor-to-slug-case/index.js", "to-slug-case/index.js"); -require.alias("ianstormtaylor-to-space-case/index.js", "ianstormtaylor-to-slug-case/deps/to-space-case/index.js"); -require.alias("ianstormtaylor-to-no-case/index.js", "ianstormtaylor-to-space-case/deps/to-no-case/index.js"); - -require.alias("recurly/lib/index.js", "recurly/index.js");if (typeof exports == "object") { - module.exports = require("recurly"); -} else if (typeof define == "function" && define.amd) { - define([], function(){ return require("recurly"); }); -} else { - this["recurly"] = require("recurly"); -}})(); \ No newline at end of file diff --git a/services/web/public/js/libs/recurly-4.8.5.js b/services/web/public/js/libs/recurly-4.8.5.js new file mode 100644 index 0000000000..f638c14904 --- /dev/null +++ b/services/web/public/js/libs/recurly-4.8.5.js @@ -0,0 +1,6 @@ +var recurly=function(e){function t(r){if(n[r])return n[r].exports;var i=n[r]={i:r,l:!1,exports:{}};return e[r].call(i.exports,i,i.exports,t),i.l=!0,i.exports}var n={};return t.m=e,t.c=n,t.d=function(e,n,r){t.o(e,n)||Object.defineProperty(e,n,{configurable:!1,enumerable:!0,get:r})},t.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return t.d(n,"a",n),n},t.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},t.p="/build/",t(t.s=36)}([function(e,t,n){(function(r){function i(){return!("undefined"==typeof window||!window.process||"renderer"!==window.process.type)||("undefined"==typeof navigator||!navigator.userAgent||!navigator.userAgent.toLowerCase().match(/(edge|trident)\/(\d+)/))&&("undefined"!=typeof document&&document.documentElement&&document.documentElement.style&&document.documentElement.style.WebkitAppearance||"undefined"!=typeof window&&window.console&&(window.console.firebug||window.console.exception&&window.console.table)||"undefined"!=typeof navigator&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/)&&parseInt(RegExp.$1,10)>=31||"undefined"!=typeof navigator&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/))}function o(e){var n=this.useColors;if(e[0]=(n?"%c":"")+this.namespace+(n?" %c":" ")+e[0]+(n?"%c ":" ")+"+"+t.humanize(this.diff),n){var r="color: "+this.color;e.splice(1,0,r,"color: inherit");var i=0,o=0;e[0].replace(/%[a-zA-Z%]/g,function(e){"%%"!==e&&(i++,"%c"===e&&(o=i))}),e.splice(o,0,r)}}function a(){return"object"==typeof console&&console.log&&Function.prototype.apply.call(console.log,console,arguments)}function u(e){try{null==e?t.storage.removeItem("debug"):t.storage.debug=e}catch(e){}}function s(){var e;try{e=t.storage.debug}catch(e){}return!e&&void 0!==r&&"env"in r&&(e=r.env.DEBUG),e}t=e.exports=n(40),t.log=a,t.formatArgs=o,t.save=u,t.load=s,t.useColors=i,t.storage="undefined"!=typeof chrome&&void 0!==chrome.storage?chrome.storage.local:function(){try{return window.localStorage}catch(e){}}(),t.colors=["#0000CC","#0000FF","#0033CC","#0033FF","#0066CC","#0066FF","#0099CC","#0099FF","#00CC00","#00CC33","#00CC66","#00CC99","#00CCCC","#00CCFF","#3300CC","#3300FF","#3333CC","#3333FF","#3366CC","#3366FF","#3399CC","#3399FF","#33CC00","#33CC33","#33CC66","#33CC99","#33CCCC","#33CCFF","#6600CC","#6600FF","#6633CC","#6633FF","#66CC00","#66CC33","#9900CC","#9900FF","#9933CC","#9933FF","#99CC00","#99CC33","#CC0000","#CC0033","#CC0066","#CC0099","#CC00CC","#CC00FF","#CC3300","#CC3333","#CC3366","#CC3399","#CC33CC","#CC33FF","#CC6600","#CC6633","#CC9900","#CC9933","#CCCC00","#CCCC33","#FF0000","#FF0033","#FF0066","#FF0099","#FF00CC","#FF00FF","#FF3300","#FF3333","#FF3366","#FF3399","#FF33CC","#FF33FF","#FF6600","#FF6633","#FF9900","#FF9933","#FFCC00","#FFCC33"],t.formatters.j=function(e){try{return JSON.stringify(e)}catch(e){return"[UnexpectedJSONParseError]: "+e.message}},t.enable(s())}).call(t,n(39))},function(e,t,n){"use strict";function r(e,t){return r.get(e,t)}var i=n(23);e.exports=r,r.map={},r.baseURL="",r.doc=function(e){r.baseURL=e},r.get=function(e,t){if(e in r.map)return new r.map[e](t);throw new Error("invalid error: "+e)},r.add=function(e,t){function n(n){Error.call(this),this.name=this.code=e,t.message instanceof Function?this.message=t.message(n):this.message=t.message,i(this,n||{}),t.help&&(this.help=r.baseURL+t.help,this.message+=" (need help? "+this.help+")")}return t=t||{},n.prototype=new Error,r.map[e]=n},r.doc("https://docs.recurly.com/js"),r.add("already-configured",{message:"Configuration may only be set once.",help:"#identify-your-site"}),r.add("config-missing-public-key",{message:"The publicKey setting is required.",help:"#identify-your-site"}),r.add("config-missing-fields",{message:"The fields setting is required."}),r.add("missing-hosted-field-target",{message:function(e){return"Target element not found for "+e.type+" field using selector '"+e.selector+"'"}}),r.add("api-error",{message:"There was an error with your request."}),r.add("api-timeout",{message:"The API request timed out."}),r.add("validation",{message:"There was an error validating your request."}),r.add("missing-callback",{message:"Missing callback"}),r.add("invalid-options",{message:"Options must be an object"}),r.add("invalid-option",{message:function(e){return"Option "+e.name+" must be "+e.expect}}),r.add("missing-plan",{message:"A plan must be specified."}),r.add("missing-coupon",{message:"A coupon must be specified."}),r.add("invalid-item",{message:"The given item does not appear to be a valid recurly plan, coupon, addon, or taxable address."}),r.add("invalid-addon",{message:"The given addon_code is not among the valid addons for the specified plan."}),r.add("invalid-currency",{message:function(e){return"The given currency ("+e.currency+") is not among the valid codes for the specified plan(s): "+e.allowed+"."}}),r.add("invalid-plan-currency",{message:function(e){return"The requested plan ("+e.planCode+") does not support the possible checkout currencies: "+e.currencies+"."}}),r.add("invalid-subscription-currency",{message:"The given subscription does not support the currencies of this Checkout instance's existing subscriptions"}),r.add("unremovable-item",{message:"The given item cannot be removed."}),r.add("fraud-data-collector-request-failed",{message:function(e){return"There was an error getting the data collector fields: "+e.error}}),r.add("fraud-data-collector-missing-form",{message:function(e){return"There was an error finding a form to inject the data collector fields using selector '"+e.selector+"'"}}),r.add("gift-card-currency-mismatch",{message:"The giftcard currency does not match the given currency."}),r.add("apple-pay-not-supported",{message:"Apple Pay is not supported by this device or browser."}),r.add("apple-pay-not-available",{message:"Apple Pay is supported by this device, but the customer has not configured Apple Pay."}),r.add("apple-pay-config-missing",{message:function(e){return"Missing Apple Pay configuration option: '"+e.opt+"'"}}),r.add("apple-pay-config-invalid",{message:function(e){return"Apple Pay configuration option '"+e.opt+"' is not among your available options: "+e.set+".\n Please refer to your site configuration if the available options is incorrect."}}),r.add("apple-pay-factory-only",{message:"Apple Pay must be initialized by calling recurly.ApplePay"}),r.add("apple-pay-init-error",{message:function(e){var t="Apple Pay did not initialize due to a fatal error";return e.err&&(t+=": "+e.err.message),t}}),r.add("apple-pay-payment-failure",{message:"Apply Pay could not charge the customer"}),r.add("paypal-factory-only",{message:"PayPal must be initialized by calling recurly.PayPal"}),r.add("paypal-config-missing",{message:function(e){return"Missing PayPal configuration option: '"+e.opt+"'"}}),r.add("paypal-load-error",{message:"Client libraries failed to load"}),r.add("paypal-client-error",{message:"PayPal encountered an unexpected error"}),r.add("paypal-tokenize-error",{message:"An error occurred while attempting to generate the PayPal token"}),r.add("paypal-tokenize-recurly-error",{message:"An error occurred while attempting to generate the Recurly token"}),r.add("paypal-braintree-not-ready",{message:"Braintree PayPal is not yet ready to create a checkout flow"}),r.add("paypal-braintree-api-error",{message:"Braintree API experienced an error"}),r.add("paypal-braintree-tokenize-braintree-error",{message:"An error occurred while attempting to generate the Braintree token"}),r.add("paypal-braintree-tokenize-recurly-error",{message:"An error occurred while attempting to generate the Braintree token within Recurly"})},function(e,t){function n(e){if(e)return r(e)}function r(e){for(var t in n.prototype)e[t]=n.prototype[t];return e}e.exports=n,n.prototype.on=n.prototype.addEventListener=function(e,t){return this._callbacks=this._callbacks||{},(this._callbacks[e]=this._callbacks[e]||[]).push(t),this},n.prototype.once=function(e,t){function n(){r.off(e,n),t.apply(this,arguments)}var r=this;return this._callbacks=this._callbacks||{},n.fn=t,this.on(e,n),this},n.prototype.off=n.prototype.removeListener=n.prototype.removeAllListeners=n.prototype.removeEventListener=function(e,t){if(this._callbacks=this._callbacks||{},0==arguments.length)return this._callbacks={},this;var n=this._callbacks[e];if(!n)return this;if(1==arguments.length)return delete this._callbacks[e],this;for(var r,i=0;i0&&void 0!==arguments[0]?arguments[0]:12;return Math.random().toString(36).substr(2,e)}Object.defineProperty(t,"__esModule",{value:!0}),t.default=r},function(e,t,n){"use strict";e.exports=n(44)},function(e,t,n){"use strict";function r(){}function i(e){try{return e.then}catch(e){return m=e,b}}function o(e,t){try{return e(t)}catch(e){return m=e,b}}function a(e,t,n){try{e(t,n)}catch(e){return m=e,b}}function u(e){if("object"!=typeof this)throw new TypeError("Promises must be constructed via new");if("function"!=typeof e)throw new TypeError("not a function");this._45=0,this._81=0,this._65=null,this._54=null,e!==r&&y(e,this)}function s(e,t,n){return new e.constructor(function(i,o){var a=new u(r);a.then(i,o),c(e,new h(t,n,a))})}function c(e,t){for(;3===e._81;)e=e._65;if(u._10&&u._10(e),0===e._81)return 0===e._45?(e._45=1,void(e._54=t)):1===e._45?(e._45=2,void(e._54=[e._54,t])):void e._54.push(t);l(e,t)}function l(e,t){v(function(){var n=1===e._81?t.onFulfilled:t.onRejected;if(null===n)return void(1===e._81?f(t.promise,e._65):d(t.promise,e._65));var r=o(n,e._65);r===b?d(t.promise,m):f(t.promise,r)})}function f(e,t){if(t===e)return d(e,new TypeError("A promise cannot be resolved with itself."));if(t&&("object"==typeof t||"function"==typeof t)){var n=i(t);if(n===b)return d(e,m);if(n===e.then&&t instanceof u)return e._81=3,e._65=t,void p(e);if("function"==typeof n)return void y(n.bind(t),e)}e._81=1,e._65=t,p(e)}function d(e,t){e._81=2,e._65=t,u._97&&u._97(e,t),p(e)}function p(e){if(1===e._45&&(c(e,e._54),e._54=null),2===e._45){for(var t=0;t0&&void 0!==arguments[0]?arguments[0]:{},n="input";~["button","select"].indexOf(e.type)&&(n=e.type,delete e.type);var r=t.document.createElement(n);return"type"in e||(e.type="text"),"style"in e||(e.style="position: absolute; top: 0px; left: -1000px; opacity: 0;"),Object.keys(e).forEach(function(t){return r.setAttribute(t,e[t])}),r}var d=n(54),p=n(4);e.exports={createHiddenInput:f,data:u,element:r,findNodeInParents:l,value:i}}).call(t,n(3))},function(e,t,n){function r(e){return function(t){for(var n in e)if(t[n]!=e[n])return!1;return!0}}var i=n(64);e.exports=function(e,t){"function"!=typeof t&&(t=Object(t)===t?r(t):i(t));for(var n=0,o=e.length;n1&&void 0!==arguments[1]?arguments[1]:{},r=n.internal,i=void 0!==r&&r;return this.debug("reprice"),new v.default(function(e,n){new t.Calculations(t,function(n){if(JSON.stringify(n)===JSON.stringify(t.price))return e(n);t.price=n,i||t.emit("change:external",n),t.emit("change",n),e(n)})},this).nodeify(e)}},{key:"remove",value:function(e,t){var n=this,r=void 0;return this.debug("remove"),new v.default(function(t,i){var o=Object.keys(e)[0],a=e[o];if(!~Object.keys(n.items).indexOf(o))return n.error((0,b.default)("invalid-item"),i);if(Array.isArray(n.items[o])){var s=n.items[o].indexOf(u(n.items[o],{code:a}));~s&&(r=n.items[o].splice(s))}else{if(!n.items[o]||a!==n.items[o].code&&!0!==a)return n.error((0,b.default)("unremovable-item",{type:o,id:a,reason:"does not exist on this pricing instance."}),i);r=n.items[o],delete n.items[o]}t()},this).nodeify(t)}},{key:"itemUpdateFactory",value:function(e,t){var n=this;return function(r,i){if(JSON.stringify(t)===JSON.stringify(n.items[e]))return r(n.items[e]);n.items[e]=t,_("set."+e),n.emit("set."+e,t),r(t)}}},{key:"error",value:function(e){var t=this,n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:function(){},r=arguments[2];return r&&r.split(".").reduce(function(n,r){return t.emit(n+"."+r,e)},"error"),this.emit("error",e),n(e)}},{key:"Calculations",get:function(){throw new Error("Not implemented")}},{key:"PRICING_METHODS",get:function(){return["reset","remove","reprice"]}},{key:"hasPrice",get:function(){return!!this.price}},{key:"totalNow",get:function(){return(0,w.default)(this.hasPrice?this.price.now.total:0)}},{key:"subtotalPreDiscountNow",get:function(){var e=parseFloat(this.price.now.subtotal)+parseFloat(this.price.now.discount);return(0,w.default)(this.hasPrice?e:0)}},{key:"currencyCode",get:function(){return this.items.currency||""}},{key:"currencySymbol",get:function(){return(0,l.default)(this.currencyCode)}}]),t}(d.default);t.Pricing=O},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function i(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function o(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function a(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}Object.defineProperty(t,"__esModule",{value:!0});var u=function(){function e(e,t){for(var n=0;n1?r-1:0),o=1;o1&&void 0!==arguments[1]?arguments[1]:{},r=n.id,a=void 0===r?(0,w.default)():r;i(this,t);var u=o(this,(t.__proto__||Object.getPrototypeOf(t)).call(this,e));return u.id=a,u.debug=_,u}return a(t,e),s(t,[{key:"reset",value:function(){c(t.prototype.__proto__||Object.getPrototypeOf(t.prototype),"reset",this).call(this),this.items.addons=[]}},{key:"attach",value:function(e){var t=this;return this.attachment&&this.attachment.detach(),this.attachment=new v.default(this,e),this.attachment.once("ready",function(){return t.emit("attached")}),this.attachment}},{key:"plan",value:function(){var e=this,t=this.resolvePlanOptions.apply(this,arguments),n=t.currentPlan,r=t.quantity,i=t.planCode,o=(t.options,t.done);return new d.default(function(t,o){if(n&&n.code===i)return n.quantity=r,t(n);e.recurly.plan(i,function(n,i){if(n)return e.error(n,o,"plan");var a=function(){_("set.plan"),e.emit("set.plan",i),t(i)};i.quantity=r,e.items.plan=i,e.items.currency in i.price||e.currency(Object.keys(i.price)[0]),e.items.coupon?e.coupon(e.items.coupon.code).then(a,a):a()})},this).nodeify(o)}},{key:"addon",value:function(e,t,n){var r=this;return"function"==typeof t&&(n=t,t=void 0),t=t||{},new d.default(function(n,i){if(!r.items.plan)return r.error((0,b.default)("missing-plan"),i,"addon");var o=(0,l.findByCode)(r.items.plan.addons,e);if(!o)return r.error((0,b.default)("invalid-addon",{planCode:r.items.plan.code,addonCode:e}),i,"addon");var a=u(t,o),s=(0,l.findByCode)(r.items.addons,e);0===a&&r.remove({addon:e}),s?s.quantity=a:(s=JSON.parse(JSON.stringify(o)),s.quantity=a,r.items.addons.push(s)),_("set.addon"),r.emit("set.addon",s),n(s)},this).nodeify(n)}},{key:"giftcard",value:function(e,t){function n(e){_("set.gift_card"),i.items.gift_card=e,i.emit("set.gift_card",e)}function r(e){_("unset.gift_card"),delete i.items.gift_card,i.emit("unset.gift_card")}var i=this;return new d.default(function(t,o){if(r(),!e)return t();i.recurly.giftcard({giftcard:e},function(e,a){return e&&"not-found"===e.code&&r(),e?i.error(e,o,"gift_card"):i.items.currency!==a.currency?(r(),i.error((0,b.default)("gift-card-currency-mismatch"),o,"gift_card")):(n(a),void t(a))})},this).nodeify(t)}},{key:"coupon",value:function(e,t){var n=this,r=function(){_("unset.coupon"),delete n.items.coupon,n.emit("unset.coupon")};return new d.default(function(t,i){if(!n.items.plan)return n.error((0,b.default)("missing-plan"),i,"coupon");if(n.items.coupon&&n.remove({coupon:n.items.coupon.code}),!e)return r(),t();var o=function(e,o){return e&&"not-found"===e.code&&r(),e?n.error(e,i,"coupon"):n.couponIsValidForSubscription(o)?(_("set.coupon"),n.items.coupon=o,n.emit("set.coupon",o),t(o),void 0):n.error("invalid-coupon-for-subscription",i,"coupon")};"string"==typeof e?n.recurly.coupon({plan:n.items.plan.code,coupon:e},o):o(null,e)},this).nodeify(t)}},{key:"address",value:function(e,t){return new d.default(this.itemUpdateFactory("address",e),this).nodeify(t)}},{key:"shippingAddress",value:function(e,t){return new d.default(this.itemUpdateFactory("shipping_address",e),this).nodeify(t)}},{key:"tax",value:function(e,t){return new d.default(this.itemUpdateFactory("tax",e),this).nodeify(t)}},{key:"currency",value:function(e,t){var n=this,r=this.items.plan,i=this.items.currency;return new d.default(function(t,o){return i===e?t(i):!r||e in r.price?(n.items.currency=e,_("set.currency"),n.emit("set.currency",e),void t(e)):n.error((0,b.default)("invalid-currency",{currency:e,allowed:Object.keys(r.price)}),o,"currency")},this).nodeify(t)}},{key:"couponIsValidForSubscription",value:function(e){return!!e&&(!!e.applies_to_plans&&(!!e.applies_to_all_plans||!!~e.plans.indexOf(this.items.plan.code)))}},{key:"resolvePlanOptions",value:function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n=arguments[2],r=this.items.plan,i=void 0;return"function"==typeof t&&(n=t,t={}),r&&r.quantity&&(i=r.quantity),t.quantity&&(i=parseInt(t.quantity,10)),(!i||i<1)&&(i=1),{currentPlan:r,quantity:i,planCode:e,options:t,done:n}}},{key:"Calculations",get:function(){return h.default}},{key:"PRICING_METHODS",get:function(){return c(t.prototype.__proto__||Object.getPrototypeOf(t.prototype),"PRICING_METHODS",this).concat(["addon","address","coupon","currency","giftcard","plan","shippingAddress","tax"])}},{key:"isValid",get:function(){return!(!this.items.plan||!this.price)}},{key:"taxCode",get:function(){if(this.items.tax)return this.items.tax.taxCode||this.items.tax.tax_code}},{key:"taxExempt",get:function(){return this.items.plan&&this.items.plan.tax_exempt}}]),t}(l.Pricing);t.default=O},function(e,t,n){function r(e){switch(i(e)){case"object":var t={};for(var n in e)e.hasOwnProperty(n)&&(t[n]=r(e[n]));return t;case"array":for(var t=new Array(e.length),o=0,a=e.length;o-1&&e%1==0&&e<=w}function m(e){var t=typeof e;return!!e&&("object"==t||"function"==t)}function b(e){return!!e&&"object"==typeof e}function g(){return!1}var w=9007199254740991,_="[object Arguments]",O="[object Function]",j="[object GeneratorFunction]",x="[object Map]",k="[object Set]",C=/[\\^$.*+?()[\]{}|]/g,P=/^\[object .+?Constructor\]$/,S="object"==typeof e&&e&&e.Object===Object&&e,E="object"==typeof self&&self&&self.Object===Object&&self,F=S||E||Function("return this")(),A="object"==typeof t&&t&&!t.nodeType&&t,T=A&&"object"==typeof n&&n&&!n.nodeType&&n,M=T&&T.exports===A,I=Function.prototype,N=Object.prototype,R=F["__core-js_shared__"],L=function(){var e=/[^.]+$/.exec(R&&R.keys&&R.keys.IE_PROTO||"");return e?"Symbol(src)_1."+e:""}(),D=I.toString,q=N.hasOwnProperty,B=N.toString,z=RegExp("^"+D.call(q).replace(C,"\\$&").replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g,"$1.*?")+"$"),U=M?F.Buffer:void 0,V=N.propertyIsEnumerable,$=U?U.isBuffer:void 0,H=function(e,t){return function(n){return e(t(n))}}(Object.keys,Object),K=u(F,"DataView"),G=u(F,"Map"),W=u(F,"Promise"),J=u(F,"Set"),Z=u(F,"WeakMap"),Y=!V.call({valueOf:1},"valueOf"),X=l(K),Q=l(G),ee=l(W),te=l(J),ne=l(Z),re=o;(K&&"[object DataView]"!=re(new K(new ArrayBuffer(1)))||G&&re(new G)!=x||W&&"[object Promise]"!=re(W.resolve())||J&&re(new J)!=k||Z&&"[object WeakMap]"!=re(new Z))&&(re=function(e){var t=B.call(e),n="[object Object]"==t?e.constructor:void 0,r=n?l(n):void 0;if(r)switch(r){case X:return"[object DataView]";case Q:return x;case ee:return"[object Promise]";case te:return k;case ne:return"[object WeakMap]"}return t});var ie=Array.isArray,oe=$||g;n.exports=h}).call(t,n(3),n(81)(e))},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e){if(Array.isArray(e)){for(var t=0,n=Array(e.length);t1?e():this.once("ready",e)}},{key:"configure",value:function(e){if(te("configure"),e=(0,h.default)(e),"string"==typeof e&&(e={publicKey:e}),e=c(e),e.publicKey)this.config.publicKey=e.publicKey;else if(!this.config.publicKey)throw(0,C.default)("config-missing-public-key");e.api&&(this.config.api=e.api),e.currency&&(this.config.currency=e.currency),"cors"in e&&(this.config.cors=e.cors),"fraud"in e&&(0,Y.default)(this.config.fraud,e.fraud),"parent"in e&&(this.config.parent=e.parent),"object"===f(e.fields)&&(0,Y.default)(this.config.fields,e.fields),this.config.required=e.required||this.config.required||[],this.config.parent?this.parent():e.parentVersion&&(this.config.parentVersion=e.parentVersion),this.configured=!0}},{key:"parent",value:function(){var e=this,t=!1;if(this.hostedFields&&this.readyState>1&&!this.hostedFields.integrityCheck(this.config.fields)&&(t=!0),t&&(this.readyState=0,this.hostedFields.reset()),this.readyState>0)return void this.bus.send("hostedFields:configure",{recurly:this.config});this.fraud||(this.fraud=new $.Fraud(this)),this.bus&&this.bus.stop(),this.bus=new V.Bus({api:this.config.api}),this.bus.add(this),this.hostedFields&&!t||(this.hostedFields=new H.HostedFields({recurly:this.config})),0===this.hostedFields.errors.length?(this.bus.add(this.hostedFields),this.once("hostedFields:ready",function(t){e.readyState=2,e.emit("ready")}),this.on("hostedFields:state:change",function(t){return e.emit("change",{fields:t})}),this.on("hostedField:submit",function(){return e.emit("field:submit")}),this.readyState=1):(this.readyState=3,this.emit("ready"))}},{key:"url",value:function(e){return this.config.api+e}},{key:"request",value:function(e,t,n,r){if(te("request",e,t,n),!this.configured)throw(0,C.default)("not-configured");return"function"==typeof n&&(r=n,n={}),this.config.parent?n.version=this.version:n.version=this.config.parentVersion,n.key=this.config.publicKey,this.config.cors?this.xhr(e,t,n,r):this.jsonp(t,n,r)}},{key:"cachedRequest",value:function(e,t,n,r){var i=this._cachedRequests=this._cachedRequests||{},a=[e,t,JSON.stringify(n)].join("-");i[a]?r.apply(void 0,[null].concat(o(i[a]))):this.request(e,t,n,function(e){for(var t=arguments.length,n=Array(t>1?t-1:0),o=1;o0?e(f.reduce(function(e,t){return e.concat(t)})):n(d[0]))};p.forEach(function(e){return t.request(r,o,e,i)})})}},{key:"xhr",value:function(e,t,n,r){function i(){"post"===e?(a.setRequestHeader&&a.setRequestHeader("Content-type","application/x-www-form-urlencoded"),a.send(s)):a.send()}te("xhr");var o=function(){var e=window.XMLHttpRequest,t=window.XDomainRequest;return e&&"withCredentials"in new e?e:t||void 0}(),a=new o,u=this.url(t),s=w.default.stringify(n,{encodeValuesOnly:!0});"get"===e&&(u+="?"+s),a.open(e,u),a.timeout=this.config.timeout,a.ontimeout=function(){r((0,C.default)("api-timeout"))},a.onerror=function(){r((0,C.default)("api-error"))},a.onprogress=function(){},a.onload=function(){var e;try{e=JSON.parse(this.responseText)}catch(e){return te(this.responseText,e),r((0,C.default)("api-error",{message:"There was a problem parsing the API response with: "+this.responseText}))}e&&e.error?r((0,C.default)("api-error",e.error)):r(null,e)},setTimeout(i,0)}},{key:"jsonp",value:function(e,t,n){te("jsonp");var r=this.url(e)+"?"+w.default.stringify(t,{encodeValuesOnly:!0});(0,b.default)(r,{timeout:this.config.timeout,prefix:"__rjs"},function(e,t){if(e)return n(e);t.error?n((0,C.default)("api-error",t.error)):n(null,t)})}}]),t}(O.default);re.prototype.Frame=D.factory,re.prototype.coupon=T.default,re.prototype.giftCard=I.default,re.prototype.giftcard=I.default,re.prototype.ApplePay=q.factory,re.prototype.PayPal=B.factory,re.prototype.paypal=U.deprecated,re.prototype.Adyen=z.factory,re.prototype.plan=n(89),re.prototype.tax=R.default,re.prototype.token=L.token,re.prototype.validate=n(90)},function(e,t,n){"use strict";var r=n(42),i=n(43),o=n(21);e.exports={formats:o,parse:i,stringify:r}},function(e,t,n){"use strict";var r=Object.prototype.hasOwnProperty,i=function(){for(var e=[],t=0;t<256;++t)e.push("%"+((t<16?"0":"")+t.toString(16)).toUpperCase());return e}(),o=function(e){for(var t;e.length;){var n=e.pop();if(t=n.obj[n.prop],Array.isArray(t)){for(var r=[],i=0;i=48&&o<=57||o>=65&&o<=90||o>=97&&o<=122?n+=t.charAt(r):o<128?n+=i[o]:o<2048?n+=i[192|o>>6]+i[128|63&o]:o<55296||o>=57344?n+=i[224|o>>12]+i[128|o>>6&63]+i[128|63&o]:(r+=1,o=65536+((1023&o)<<10|1023&t.charCodeAt(r)),n+=i[240|o>>18]+i[128|o>>12&63]+i[128|o>>6&63]+i[128|63&o])}return n},t.compact=function(e){for(var t=[{obj:{o:e},prop:"o"}],n=[],r=0;rc){for(var t=0,n=a.length-s;t0)throw this.hostedFields.errors[0];var a=(0,l.default)();this.bus.send("token:init",{id:a,inputs:i}),this.once("token:done:"+a,function(e){return n(e.err,e.token)})}else{var u=o.call(this,i);if(u.length)return t((0,d.default)("validation",{fields:u}));this.request("post","/token",i,n)}}function o(e){var t=[];return this.validate.cardNumber(e.number)||t.push("number"),this.validate.expiry(e.month,e.year)||t.push("month","year"),e.first_name||t.push("first_name"),e.last_name||t.push("last_name"),!~this.config.required.indexOf("cvv")&&!e.cvv||this.validate.cvv(e.cvv)||t.push("cvv"),(0,u.default)(this.config.required,function(n){!e[n]&&~h.indexOf(n)&&t.push(n)}),p("validate errors",t),t}Object.defineProperty(t,"__esModule",{value:!0}),t.FIELDS=void 0,t.token=i;var a=n(4),u=r(a),s=n(15),c=n(5),l=r(c),f=n(1),d=r(f),p=n(0)("recurly:token"),h=t.FIELDS=["first_name","last_name","address1","address2","company","country","city","state","postal_code","phone","vat_number","fraud_session_id","token"]},function(e,t){function n(e){return e.replace(/\.\w+|\w+ *\(|"[^"]*"|'[^']*'|\/([^\/]+)\//g,"").replace(a,"").match(/[a-zA-Z_]\w*/g)||[]}function r(e,t,n){var r=/\.\w+|\w+ *\(|"[^"]*"|'[^']*'|\/([^\/]+)\/|[a-zA-Z_]\w*/g;return e.replace(r,function(e){return"("==e[e.length-1]?n(e):~t.indexOf(e)?n(e):e})}function i(e){for(var t=[],n=0;n1?t-1:0),a=1;a1&&void 0!==arguments[1]?arguments[1]:function(e){return e};return e.reduce(function(e,n){var r=t(n);return(e[r]=e[r]||[]).push(n),e},{})}Object.defineProperty(t,"__esModule",{value:!0}),t.default=r},function(e,t,n){"use strict";var r=n(18);e.exports=t=new r.Recurly,t.Recurly=r.Recurly},function(e,t){function n(e,t,n){var r=-1,i=e.length;t<0&&(t=-t>i?0:i+t),n=n>i?i:n,n<0&&(n+=i),i=t>n?0:n-t>>>0,t>>>=0;for(var o=Array(i);++r-1&&e%1==0&&e-1&&e%1==0&&e<=m}function l(e){var t=typeof e;return!!e&&("object"==t||"function"==t)}function f(e){return!!e&&"object"==typeof e}function d(e){return"symbol"==typeof e||f(e)&&F.call(e)==O}function p(e){if(!e)return 0===e?e:0;if((e=y(e))===v||e===-v){return(e<0?-1:1)*b}return e===e?e:0}function h(e){var t=p(e),n=t%1;return t===t?n?t-n:t:0}function y(e){if("number"==typeof e)return e;if(d(e))return g;if(l(e)){var t="function"==typeof e.valueOf?e.valueOf():e;e=l(t)?t+"":t}if("string"!=typeof e)return 0===e?e:+e;e=e.replace(j,"");var n=k.test(e);return n||C.test(e)?S(e.slice(2),n?2:8):x.test(e)?g:+e}var v=1/0,m=9007199254740991,b=1.7976931348623157e308,g=NaN,w="[object Function]",_="[object GeneratorFunction]",O="[object Symbol]",j=/^\s+|\s+$/g,x=/^[-+]0x[0-9a-f]+$/i,k=/^0b[01]+$/i,C=/^0o[0-7]+$/i,P=/^(?:0|[1-9]\d*)$/,S=parseInt,E=Object.prototype,F=E.toString,A=Math.ceil,T=Math.max;e.exports=o},function(e,t,n){function r(){}function i(e,t,n){function i(){u.parentNode.removeChild(u),window[h]=r}"function"==typeof t&&(n=t,t={}),t||(t={});var u,s,c=t.prefix||"__jp",l=t.param||"callback",f=null!=t.timeout?t.timeout:6e4,d=encodeURIComponent,p=document.getElementsByTagName("script")[0]||document.head,h=c+a++;f&&(s=setTimeout(function(){i(),n&&n(new Error("Timeout"))},f)),window[h]=function(e){o("jsonp got",e),s&&clearTimeout(s),i(),n&&n(null,e)},e+=(~e.indexOf("?")?"&":"?")+l+"="+d(h),e=e.replace("?&","?"),o('jsonp req "%s"',e),u=document.createElement("script"),u.src=e,p.parentNode.insertBefore(u,p)}var o=n(0)("jsonp");e.exports=i;var a=0},function(e,t){function n(){throw new Error("setTimeout has not been defined")}function r(){throw new Error("clearTimeout has not been defined")}function i(e){if(l===setTimeout)return setTimeout(e,0);if((l===n||!l)&&setTimeout)return l=setTimeout,setTimeout(e,0);try{return l(e,0)}catch(t){try{return l.call(null,e,0)}catch(t){return l.call(this,e,0)}}}function o(e){if(f===clearTimeout)return clearTimeout(e);if((f===r||!f)&&clearTimeout)return f=clearTimeout,clearTimeout(e);try{return f(e)}catch(t){try{return f.call(null,e)}catch(t){return f.call(this,e)}}}function a(){y&&p&&(y=!1,p.length?h=p.concat(h):v=-1,h.length&&u())}function u(){if(!y){var e=i(a);y=!0;for(var t=h.length;t;){for(p=h,h=[];++v1)for(var n=1;n100)){var t=/^((?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|years?|yrs?|y)?$/i.exec(e);if(t){var n=parseFloat(t[1]);switch((t[2]||"ms").toLowerCase()){case"years":case"year":case"yrs":case"yr":case"y":return n*l;case"days":case"day":case"d":return n*c;case"hours":case"hour":case"hrs":case"hr":case"h":return n*s;case"minutes":case"minute":case"mins":case"min":case"m":return n*u;case"seconds":case"second":case"secs":case"sec":case"s":return n*a;case"milliseconds":case"millisecond":case"msecs":case"msec":case"ms":return n;default:return}}}}function r(e){return e>=c?Math.round(e/c)+"d":e>=s?Math.round(e/s)+"h":e>=u?Math.round(e/u)+"m":e>=a?Math.round(e/a)+"s":e+"ms"}function i(e){return o(e,c,"day")||o(e,s,"hour")||o(e,u,"minute")||o(e,a,"second")||e+" ms"}function o(e,t,n){if(!(e0)return n(e);if("number"===o&&!1===isNaN(e))return t.long?i(e):r(e);throw new Error("val is not a non-empty string or a valid number. val="+JSON.stringify(e))}},function(e,t,n){"use strict";var r=n(20),i=n(21),o={brackets:function(e){return e+"[]"},indices:function(e,t){return e+"["+t+"]"},repeat:function(e){return e}},a=Date.prototype.toISOString,u={delimiter:"&",encode:!0,encoder:r.encode,encodeValuesOnly:!1,serializeDate:function(e){return a.call(e)},skipNulls:!1,strictNullHandling:!1},s=function e(t,n,i,o,a,s,c,l,f,d,p,h){var y=t;if("function"==typeof c)y=c(n,y);else if(y instanceof Date)y=d(y);else if(null===y){if(o)return s&&!h?s(n,u.encoder):n;y=""}if("string"==typeof y||"number"==typeof y||"boolean"==typeof y||r.isBuffer(y)){if(s){return[p(h?n:s(n,u.encoder))+"="+p(s(y,u.encoder))]}return[p(n)+"="+p(String(y))]}var v=[];if(void 0===y)return v;var m;if(Array.isArray(c))m=c;else{var b=Object.keys(y);m=l?b.sort(l):b}for(var g=0;g0?P+C:""}},function(e,t,n){"use strict";var r=n(20),i=Object.prototype.hasOwnProperty,o={allowDots:!1,allowPrototypes:!1,arrayLimit:20,decoder:r.decode,delimiter:"&",depth:5,parameterLimit:1e3,plainObjects:!1,strictNullHandling:!1},a=function(e,t){for(var n={},r=t.ignoreQueryPrefix?e.replace(/^\?/,""):e,a=t.parameterLimit===1/0?void 0:t.parameterLimit,u=r.split(t.delimiter,a),s=0;s=0;--i){var o,a=e[i];if("[]"===a)o=[],o=o.concat(r);else{o=n.plainObjects?Object.create(null):{};var u="["===a.charAt(0)&&"]"===a.charAt(a.length-1)?a.slice(1,-1):a,s=parseInt(u,10);!isNaN(s)&&a!==u&&String(s)===u&&s>=0&&n.parseArrays&&s<=n.arrayLimit?(o=[],o[s]=r):o[u]=r}r=o}return r},s=function(e,t,n){if(e){var r=n.allowDots?e.replace(/\.([^.[]+)/g,"[$1]"):e,o=/(\[[^[\]]*])/,a=/(\[[^[\]]*])/g,s=o.exec(r),c=s?r.slice(0,s.index):r,l=[];if(c){if(!n.plainObjects&&i.call(Object.prototype,c)&&!n.allowPrototypes)return;l.push(c)}for(var f=0;null!==(s=a.exec(r))&&f "+t+") {","args = new Array(arguments.length + 1);","for (var i = 0; i < arguments.length; i++) {","args[i] = arguments[i];","}","}","return new Promise(function (rs, rj) {","var cb = "+u+";","var res;","switch (argLength) {",n.concat(["extra"]).map(function(e,t){return"case "+t+":res = fn.call("+["self"].concat(n.slice(0,t)).concat("cb").join(",")+");break;"}).join(""),"default:","args[argLength] = cb;","res = fn.apply(self, args);","}","if (res &&",'(typeof res === "object" || typeof res === "function") &&','typeof res.then === "function"',") {rs(res);}","});","};"].join("");return Function(["Promise","fn"],i)(o,e)}var o=n(7),a=n(49);e.exports=o,o.denodeify=function(e,t){return"number"==typeof t&&t!==1/0?r(e,t):i(e)};var u="function (err, res) {if (err) { rj(err); } else { rs(res); }}";o.nodeify=function(e){return function(){var t=Array.prototype.slice.call(arguments),n="function"==typeof t[t.length-1]?t.pop():null,r=this;try{return e.apply(this,arguments).nodeify(n,r)}catch(e){if(null===n||void 0===n)return new o(function(t,n){n(e)});a(function(){n.call(r,e)})}}},o.prototype.nodeify=function(e,t){if("function"!=typeof e)return this;this.then(function(n){a(function(){e.call(t,null,n)})},function(n){a(function(){e.call(t,n)})})}},function(e,t,n){"use strict";function r(){if(s.length)throw s.shift()}function i(e){var t;t=u.length?u.pop():new o,t.task=e,a(t)}function o(){this.task=null}var a=n(22),u=[],s=[],c=a.makeRequestCallFromTimer(r);e.exports=i,o.prototype.call=function(){try{this.task.call()}catch(e){i.onerror?i.onerror(e):(s.push(e),c())}finally{this.task=null,u[u.length]=this}}},function(e,t,n){"use strict";var r=n(7);e.exports=r,r.enableSynchronous=function(){r.prototype.isPending=function(){return 0==this.getState()},r.prototype.isFulfilled=function(){return 1==this.getState()},r.prototype.isRejected=function(){return 2==this.getState()},r.prototype.getValue=function(){if(3===this._81)return this._65.getValue();if(!this.isFulfilled())throw new Error("Cannot get a value of an unfulfilled promise.");return this._65},r.prototype.getReason=function(){if(3===this._81)return this._65.getReason();if(!this.isRejected())throw new Error("Cannot get a rejection reason of a non-rejected promise.");return this._65},r.prototype.getState=function(){return 3===this._81?this._65.getState():-1===this._81||-2===this._81?0:this._81}},r.disableSynchronous=function(){r.prototype.isPending=void 0,r.prototype.isFulfilled=void 0,r.prototype.isRejected=void 0,r.prototype.getValue=void 0,r.prototype.getReason=void 0,r.prototype.getState=void 0}},function(e,t,n){"use strict";e.exports="4.8.5"},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function i(e,t){d("token");var n=(0,c.normalize)(p,e),r=n.values,i=a(r);if("function"!=typeof t)throw(0,f.default)("missing-callback");if(i.length)return t((0,f.default)("validation",{fields:i}));this.request("post","/token",r,function(e,r){if(e)return t(e);n.fields.token&&r.id&&(n.fields.token.value=r.id),t(null,r)})}function o(e,t){if(d("bankInfo"),"function"!=typeof t)throw(0,f.default)("missing-callback");var n=e&&e.routingNumber;if(!n||"string"!=typeof n)return t((0,f.default)("validation",{fields:["routingNumber"]}));this.request("get","/bank",{routing_number:n},function(e,n){if(e)return t(e);t(null,n)})}function a(e){var t=[];return(0,s.default)(h,function(n){e[n]&&"string"==typeof e[n]||t.push(n)}),e.account_number!==e.account_number_confirmation&&t.push("account_number_confirmation"),d("validate errors",t),t}var u=n(4),s=r(u),c=n(15),l=n(1),f=r(l),d=n(0)("recurly:bankAccount");e.exports={token:i,bankInfo:o};var p=["account_number","account_number_confirmation","routing_number","name_on_account","account_type","address1","address2","company","country","city","state","postal_code","phone","vat_number","token"],h=["account_number","account_number_confirmation","routing_number","account_type","name_on_account","country"]},function(e,t,n){function r(e){switch({}.toString.call(e)){case"[object Object]":return u(e);case"[object Function]":return e;case"[object String]":return a(e);case"[object RegExp]":return o(e);default:return i(e)}}function i(e){return function(t){return e===t}}function o(e){return function(t){return e.test(t)}}function a(e){return/^ *\W+/.test(e)?new Function("_","return _ "+e):new Function("_","return "+s(e))}function u(e){var t={};for(var n in e)t[n]="string"==typeof e[n]?i(e[n]):r(e[n]);return function(e){if("object"!=typeof e)return!1;for(var n in t){if(!(n in e))return!1;if(!t[n](e[n]))return!1}return!0}}function s(e){var t=l(e);if(!t.length)return"_."+e;var n,r,i;for(r=0;r0&&void 0!==arguments[0]?arguments[0]:{},t=arguments[1];a("%j",e);var n=e.coupon,r=e.plans,i=e.plan,u=e.currency;if(!n)throw(0,o.default)("missing-coupon");if("function"!=typeof t)throw(0,o.default)("missing-callback");!r&&i&&(r=[i]),this.pipedRequest({route:"/coupons/"+n,data:{plan_codes:r,currency:u},by:"plan_codes"}).nodeify(t)}Object.defineProperty(t,"__esModule",{value:!0}),t.default=r;var i=n(1),o=function(e){return e&&e.__esModule?e:{default:e}}(i),a=n(0)("recurly:coupon")},function(e,t,n){"use strict";function r(e,t){if(u("%j",e),"function"!=typeof t)throw(0,a.default)("missing-callback");if("object"!==(void 0===e?"undefined":i(e)))throw(0,a.default)("invalid-options");if(!("giftcard"in e))throw(0,a.default)("missing-giftcard");this.request("get","/gift_cards/"+e.giftcard,e,t)}Object.defineProperty(t,"__esModule",{value:!0});var i="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e};t.default=r;var o=n(1),a=function(e){return e&&e.__esModule?e:{default:e}}(o),u=n(0)("recurly:giftcard")},function(e,t,n){"use strict";function r(e,t){if(e=i({},e),"function"!=typeof t)throw new Error("Missing callback");this.cachedRequest("get","/tax",{country:e.country,postal_code:e.postalCode||e.postal_code,tax_code:e.taxCode||e.tax_code,vat_number:e.vatNumber||e.vat_number},t)}Object.defineProperty(t,"__esModule",{value:!0});var i=Object.assign||function(e){for(var t=1;t1&&void 0!==arguments[1]?arguments[1]:{};b("creating request frame"),r.version=this.recurly.version,r.event=this.name,r.key=this.recurly.config.publicKey,this.once(r.event,function(t){n.relay&&e.document.body.removeChild(n.relay),t.error?n.emit("error",t.error):n.emit("done",t)}),this.url=this.recurly.url(t),this.url+=(~this.url.indexOf("?")?"&":"?")+d.default.stringify(r,{encodeValuesOnly:!0})}},{key:"listen",value:function(t){var n=this;if(this.recurly.bus.add(this),"documentMode"in document){b("Creating relay");var r=document.createElement("iframe");r.width=r.height=0,r.src=this.recurly.url("/relay"),r.name="recurly-relay-"+this.recurly.id+"-"+this.id,r.style.display="none",r.onload=function(){return n.create()},e.document.body.appendChild(r),this.relay=r,b("Created relay",r)}else this.create()}},{key:"create",value:function(){b("opening frame window",this.url,this.name,this.attributes),e.open(this.url,this.name,this.attributes)}},{key:"attributes",get:function(){return"\n resizable,scrollbars,\n width="+this.width+",\n height="+this.height+",\n top="+this.top+",\n left="+this.left+"\n "}},{key:"top",get:function(){var t=e.outerHeight||e.document.documentElement.clientHeight,n=null===e.screenY?e.screenTop:e.screenY;return s(t,this.height,n)}},{key:"left",get:function(){var t=e.outerWidth||e.document.documentElement.clientWidth,n=null===e.screenX?e.screenLeft:e.screenX;return s(t,this.width,n)}}]),n}(h.default)}).call(t,n(3))},function(e,t,n){"use strict";(function(e){function r(e){return e&&e.__esModule?e:{default:e}}function i(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function o(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function a(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}function u(e){return new j(l({},e,{recurly:this}))}function s(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"",t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0;return{label:e,amount:(0,b.default)(t)}}Object.defineProperty(t,"__esModule",{value:!0});var c=function(){function e(e,t){for(var n=0;n0||(this.config.lineItems.push(this.authorizationLineItem),this.config.total=this.authorizationLineItem.amount)}},{key:"onPricingChange",value:function(){var e=this.config.pricing,t=this.config.lineItems=[];if(this.config.total=e.totalNow,e.hasPrice){var n=e.price.now.taxes||e.price.now.tax;t.push(s(this.config.i18n.subtotalLineItemLabel,e.subtotalPreDiscountNow)),+e.price.now.discount&&t.push(s(this.config.i18n.discountLineItemLabel,-e.price.now.discount)),+n&&t.push(s(this.config.i18n.taxLineItemLabel,n)),+e.price.now.giftCard&&t.push(s(this.config.i18n.giftCardLineItemLabel,-e.price.now.giftCard)),this.config.lineItems=t}}},{key:"onValidateMerchant",value:function(e){var t=this;w("Validating Apple Pay merchant session",e);var n=e.validationURL;this.recurly.request("post","/apple_pay/start",{validationURL:n},function(e,n){if(e)return t.error(e);t.session.completeMerchantValidation(n)})}},{key:"onPaymentMethodSelected",value:function(e){w("Payment method selected",e),this.session.completePaymentMethodSelection(this.finalTotalLineItem,this.lineItems)}},{key:"onShippingContactSelected",value:function(e){var t=this.session.STATUS_SUCCESS,n=[];this.session.completeShippingContactSelection(t,n,this.finalTotalLineItem,this.lineItems)}},{key:"onShippingMethodSelected",value:function(e){this.session.completeShippingMethodSelection(this.finalTotalLineItem,this.lineItems)}},{key:"onPaymentAuthorized",value:function(e){var t=this;w("Payment authorization received",e);var n={};this.config.form&&(n=(0,v.normalize)(g.FIELDS,this.config.form,{parseCard:!1}).values),this.mapPaymentData(n,e.payment),this.recurly.request("post","/apple_pay/token",n,function(e,n){if(e)return t.session.completePayment(t.session.STATUS_FAILURE),t.error("apple-pay-payment-failure",e);w("Token received",n),t.session.completePayment(t.session.STATUS_SUCCESS),t.emit("token",n)})}},{key:"onCancel",value:function(e){w("User canceled Apple Pay payment",e),this.emit("cancel",e)}},{key:"error",value:function(){var e=(arguments.length<=0?void 0:arguments[0])instanceof Error?arguments.length<=0?void 0:arguments[0]:h.default.apply(void 0,arguments);return this.emit("error",e),e}},{key:"mapPaymentData",value:function(e,t){e.paymentData=t.token.paymentData,e.paymentMethod=t.token.paymentMethod,t.billingContact&&(g.FIELDS.some(function(t){return e[t]})||g.FIELDS.forEach(function(n){if(_[n]){var r=t.billingContact[_[n]];"address1"===n?r=r[0]:"address2"===n&&(r=r[1]),e[n]=r}}))}},{key:"session",get:function(){if(this._session)return this._session;w("Creating new Apple Pay session"),this.addAuthorizationLineItem();var t=new e.ApplePaySession(2,{countryCode:this.config.country,currencyCode:this.config.currency,supportedNetworks:this.config.supportedNetworks,merchantCapabilities:this.config.merchantCapabilities,requiredBillingContactFields:["postalAddress"],total:this.totalLineItem});return t.onvalidatemerchant=this.onValidateMerchant.bind(this),t.onshippingcontactselected=this.onShippingContactSelected.bind(this),t.onshippingmethodselected=this.onShippingMethodSelected.bind(this),t.onpaymentmethodselected=this.onPaymentMethodSelected.bind(this),t.onpaymentauthorized=this.onPaymentAuthorized.bind(this),t.oncancel=this.onCancel.bind(this),this._session=t}},{key:"lineItems",get:function(){return[].concat(this.config.lineItems)}},{key:"totalLineItem",get:function(){return s(this.config.label,this.config.total)}},{key:"finalTotalLineItem",get:function(){return l({},this.totalLineItem,{type:"final"})}},{key:"authorizationLineItem",get:function(){return s(this.config.i18n.authorizationLineItemLabel,1)}}]),n}(d.default)}).call(t,n(3))},function(e,t,n){var r=n(63);e.exports=function(e){if("string"==typeof e){var t=e.toUpperCase();if(r.hasOwnProperty(t))return r[t]}},e.exports.currencySymbolMap=r},function(e,t){e.exports={AED:"د.Ø¥",AFN:"Ø‹",ALL:"L",AMD:"֏",ANG:"Æ’",AOA:"Kz",ARS:"$",AUD:"$",AWG:"Æ’",AZN:"ман",BAM:"KM",BBD:"$",BDT:"৳",BGN:"лв",BHD:".د.ب",BIF:"FBu",BMD:"$",BND:"$",BOB:"$b",BRL:"R$",BSD:"$",BTC:"฿",BTN:"Nu.",BWP:"P",BYR:"p.",BZD:"BZ$",CAD:"$",CDF:"FC",CHF:"CHF",CLP:"$",CNY:"Â¥",COP:"$",CRC:"â‚¡",CUC:"$",CUP:"₱",CVE:"$",CZK:"Kč",DJF:"Fdj",DKK:"kr",DOP:"RD$",DZD:"دج",EEK:"kr",EGP:"£",ERN:"Nfk",ETB:"Br",ETH:"Ξ",EUR:"€",FJD:"$",FKP:"£",GBP:"£",GEL:"₾",GGP:"£",GHC:"₵",GHS:"GH₵",GIP:"£",GMD:"D",GNF:"FG",GTQ:"Q",GYD:"$",HKD:"$",HNL:"L",HRK:"kn",HTG:"G",HUF:"Ft",IDR:"Rp",ILS:"₪",IMP:"£",INR:"₹",IQD:"ع.د",IRR:"ï·¼",ISK:"kr",JEP:"£",JMD:"J$",JOD:"JD",JPY:"Â¥",KES:"KSh",KGS:"лв",KHR:"៛",KMF:"CF",KPW:"â‚©",KRW:"â‚©",KWD:"KD",KYD:"$",KZT:"лв",LAK:"â‚­",LBP:"£",LKR:"₨",LRD:"$",LSL:"M",LTC:"Ł",LTL:"Lt",LVL:"Ls",LYD:"LD",MAD:"MAD",MDL:"lei",MGA:"Ar",MKD:"ден",MMK:"K",MNT:"â‚®",MOP:"MOP$",MUR:"₨",MVR:"Rf",MWK:"MK",MXN:"$",MYR:"RM",MZN:"MT",NAD:"$",NGN:"₦",NIO:"C$",NOK:"kr",NPR:"₨",NZD:"$",OMR:"ï·¼",PAB:"B/.",PEN:"S/.",PGK:"K",PHP:"₱",PKR:"₨",PLN:"zÅ‚",PYG:"Gs",QAR:"ï·¼",RMB:"ï¿¥",RON:"lei",RSD:"Дин.",RUB:"₽",RWF:"Râ‚£",SAR:"ï·¼",SBD:"$",SCR:"₨",SDG:"ج.س.",SEK:"kr",SGD:"$",SHP:"£",SLL:"Le",SOS:"S",SRD:"$",SSP:"£",STD:"Db",SVC:"$",SYP:"£",SZL:"E",THB:"฿",TJS:"SM",TMT:"T",TND:"د.ت",TOP:"T$",TRL:"₤",TRY:"₺",TTD:"TT$",TVD:"$",TWD:"NT$",TZS:"TSh",UAH:"â‚´",UGX:"USh",USD:"$",UYU:"$U",UZS:"лв",VEF:"Bs",VND:"â‚«",VUV:"VT",WST:"WS$",XAF:"FCFA",XBT:"Ƀ",XCD:"$",XOF:"CFA",XPF:"â‚£",YER:"ï·¼",ZAR:"R",ZWD:"Z$"}},function(e,t,n){function r(e){switch({}.toString.call(e)){case"[object Object]":return u(e);case"[object Function]":return e;case"[object String]":return a(e);case"[object RegExp]":return o(e);default:return i(e)}}function i(e){return function(t){return e===t}}function o(e){return function(t){return e.test(t)}}function a(e){return/^ *\W+/.test(e)?new Function("_","return _ "+e):new Function("_","return "+s(e))}function u(e){var t={};for(var n in e)t[n]="string"==typeof e[n]?i(e[n]):r(e[n]);return function(e){if("object"!=typeof e)return!1;for(var n in t){if(!(n in e))return!1;if(!t[n](e[n]))return!1}return!0}}function s(e){var t=l(e);if(!t.length)return"_."+e;var n,r,i;for(r=0;r0&&n(l)?t>1?o(l,t-1,n,r,a):i(a,l):r||(a[a.length]=l)}return a}function a(e,t){return e=Object(e),u(e,t,function(t,n){return n in e})}function u(e,t,n){for(var r=-1,i=t.length,o={};++r-1&&e%1==0&&e<=g}function y(e){var t=typeof e;return!!e&&("object"==t||"function"==t)}function v(e){return!!e&&"object"==typeof e}function m(e){return"symbol"==typeof e||v(e)&&E.call(e)==j}var b=1/0,g=9007199254740991,w="[object Arguments]",_="[object Function]",O="[object GeneratorFunction]",j="[object Symbol]",x="object"==typeof t&&t&&t.Object===Object&&t,k="object"==typeof self&&self&&self.Object===Object&&self,C=x||k||Function("return this")(),P=Object.prototype,S=P.hasOwnProperty,E=P.toString,F=C.Symbol,A=P.propertyIsEnumerable,T=F?F.isConcatSpreadable:void 0,M=Math.max,I=Array.isArray,N=function(e,t){return t=M(void 0===t?e.length-1:t,0),function(){for(var r=arguments,i=-1,o=M(r.length-t,0),a=Array(o);++i1&&void 0!==arguments[1]?arguments[1]:function(){},r="https://js.braintreegateway.com/web/"+v+"/js/"+t+".min.js";(0,f.default)(r,function(t){t?e.error("paypal-load-error",{cause:t}):n()})},r=function(){e.braintreeClientAvailable("paypal")?t():n("paypal",t),e.braintreeClientAvailable("dataCollector")?t():n("data-collector",t)};this.braintreeClientAvailable()?r():n("client",r)}},{key:"initialize",value:function(){var t=this;y("Initializing Braintree client");var n=this.config.clientAuthorization,r=e.braintree;r.client.create({authorization:n},function(e,n){if(e)return t.fail("paypal-braintree-api-error",{cause:e});y("Braintree client created"),r.dataCollector.create({client:n,paypal:!0},function(e,i){if(e)return t.fail("paypal-braintree-api-error",{cause:e});y("Device data collector created"),t.deviceFingerprint=i.deviceData,r.paypal.create({client:n},function(e,n){if(e)return t.fail("paypal-braintree-api-error",{cause:e});y("PayPal client created"),t.paypal=n,t.emit("ready")})})})}},{key:"start",value:function(){var e=this,t=u({},this.config.display,{flow:"vault"});this.paypal.tokenize(t,function(t,n){if(t)return"PAYPAL_POPUP_CLOSED"===t.code?e.emit("cancel"):e.error("paypal-braintree-tokenize-braintree-error",{cause:t});y("Token payload received",n),e.deviceFingerprint&&(n.deviceFingerprint=e.deviceFingerprint),e.recurly.request("post","/paypal/token",{type:"braintree",payload:n},function(t,n){if(t)return e.error("paypal-braintree-tokenize-recurly-error",{cause:t});e.emit("token",n)})})}},{key:"braintreeClientAvailable",value:function(t){var n=e.braintree;return n&&n.client&&n.client.VERSION===v&&(!t||t in n)}}]),n}(h.PayPalStrategy)}).call(t,n(3))},function(e,t){function n(e,t){for(var n in t)e.setAttribute(n,t[n])}function r(e,t){e.onload=function(){this.onerror=this.onload=null,t(null,e)},e.onerror=function(){this.onerror=this.onload=null,t(new Error("Failed to load "+this.src),e)}}function i(e,t){e.onreadystatechange=function(){"complete"!=this.readyState&&"loaded"!=this.readyState||(this.onreadystatechange=null,t(null,e))}}e.exports=function(e,t,o){var a=document.head||document.getElementsByTagName("head")[0],u=document.createElement("script");"function"==typeof t&&(o=t,t={}),t=t||{},o=o||function(){},u.type=t.type||"text/javascript",u.charset=t.charset||"utf8",u.async=!("async"in t)||!!t.async,u.src=e,t.attrs&&n(u,t.attrs),t.text&&(u.text=""+t.text),("onload"in u?r:i)(u,o),u.onload||r(u,o),a.appendChild(u)}},function(e,t,n){"use strict";function r(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:0,t=arguments[1],n=0;return function(){return n++&&n===e&&t()}}Object.defineProperty(t,"__esModule",{value:!0}),t.default=r},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function i(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function o(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function a(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}function u(e){return new v(l({},e,{recurly:this}))}function s(e){var t=[];return e.skinCode&&8!=e.skinCode.length&&t.push("skinCode should be 8 characters"),e.countryCode&&2!=e.countryCode.length&&t.push("countryCode should be 2 characters"),e.shopperLocale&&5!=e.shopperLocale.length&&t.push("shopperLocale should be 5 characters"),e.invoiceUuid||t.push("invoiceUuid cannot be blank"),y("validate errors",t),t}Object.defineProperty(t,"__esModule",{value:!0});var c=function(){function e(e,t){for(var n=0;n0)return this.error("validation",{fields:r});var i=this.recurly.Frame({height:600,path:"/adyen/start",payload:n});i.once("error",function(e){return t.error("adyen-error",{cause:e})}),i.once("done",function(e){return t.emit("token",e)})}},{key:"error",value:function(){var e=(arguments.length<=0?void 0:arguments[0])instanceof Error?arguments.length<=0?void 0:arguments[0]:h.default.apply(void 0,arguments);return this.emit("error",e),e}}]),t}(d.default)},function(e,t,n){"use strict";(function(e){function r(e){return e&&e.__esModule?e:{default:e}}function i(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function o(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function a(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}function u(t){var n=e.document.createElement("a");return n.href=t,n.protocol+"//"+n.host}Object.defineProperty(t,"__esModule",{value:!0}),t.Bus=void 0;var s=function(){function e(e,t){for(var n=0;n0&&void 0!==arguments[0]?arguments[0]:{};i(this,t);var r=o(this,(t.__proto__||Object.getPrototypeOf(t)).call(this));return r.id=(0,p.default)(),r.debug=n(0)("recurly:bus:"+r.id),r.emitters=[],r.recipients=[],r.receive=r.receive.bind(r),r.config={api:e.api},r.connect(),r.send=r.send.bind(r),r}return a(t,e),s(t,[{key:"connect",value:function(){window.addEventListener("message",this.receive,!1),this.debug("listening for postMessage events on",window)}},{key:"receive",value:function(e){if(this.originMatches(e.origin))return"string"==typeof e.data?this.receiveFromRelay(e):void(e.data.event&&(this.debug("message received",e.data),this.send(new f.Message(e),null,{exclude:[e.srcElement]})))}},{key:"receiveFromRelay",value:function(e){var t=void 0;try{t=JSON.parse(e.data)}catch(t){this.debug("failed to parse a string message",t,e)}t&&this.send(new f.Message(t.recurly_event,t.recurly_message))}},{key:"add",value:function(e){~this.recipients.indexOf(e)||(this.recipients.push(e),"function"==typeof e.emit&&e.emit("bus:added",this),this.debug("added recipient",e))}},{key:"send",value:function(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{exclude:[]},r=new f.Message(e,t);n.exclude;this.debug("sending message to "+this.recipients.length+" recipients",r),this.recipients.forEach(function(e){e.postMessage?"function"==typeof e.postMessage&&e.postMessage(r,"*"):"function"==typeof e.emit&&e.emit(r.event,r.body)})}},{key:"stop",value:function(){this.recipients=[],window.removeEventListener("message",this.receive,!1)}},{key:"originMatches",value:function(e){return u(e)===u(this.config.api)}}]),t}(l.default)}).call(t,n(3))},function(e,t,n){"use strict";function r(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}Object.defineProperty(t,"__esModule",{value:!0});var i=function(){function e(e,t){for(var n=0;n1&&void 0!==arguments[1]?arguments[1]:{};if(r(this,e),t instanceof e)return t;t instanceof window.MessageEvent&&(n=t.data.body,t=t.data.event),this.event=t,this.body=n}return i(e,[{key:"format",value:function(){return{event:this.event,body:this.body}}}]),e}()},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function i(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function o(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function a(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}Object.defineProperty(t,"__esModule",{value:!0}),t.Fraud=void 0;var u=function(){function e(e,t){for(var n=0;n\n \n \n \n ',this.container=this.target.children[0],this.iframe=this.container.querySelector("iframe"),this.window=this.iframe.contentWindow,u()&&(this.tabbingProxy=y.default.createHiddenInput(),this.tabbingProxy.addEventListener("focus",this.focus),this.container.insertBefore(this.tabbingProxy,this.iframe))}},{key:"bindDeferredFocus",value:function(){var t=this;if(this.container.addEventListener("click",this.focus),this.target.id){var n=e.document.querySelectorAll("label[for="+this.target.id+"]");[].slice.apply(n).forEach(function(e){e.addEventListener("click",t.focus)})}}},{key:"reset",value:function(){this.off(),this.target.innerHTML="",delete this.target,delete this.iframe,delete this.window}},{key:"update",value:function(){this.container.className=this.classList,this.iframe.setAttribute("tabindex",this.tabIndex)}},{key:"onReady",value:function(e){e.type===this.type&&(this.ready=!0,this.off("hostedField:ready",this.onReady),this.update())}},{key:"onStateChange",value:function(e){if(e.type===this.type){var t=s({},e);delete t.type,this.state=t,this.update()}}},{key:"onChange",value:function(e){e.type===this.type&&this.update()}},{key:"onConfigure",value:function(e){e.type===this.type&&(this.configure(e),this.update())}},{key:"focus",value:function(){this.bus&&this.bus.send("hostedField:"+this.type+":focus!")}},{key:"type",get:function(){return this.config.type}},{key:"url",get:function(){var e=encodeURIComponent(JSON.stringify(this.config));return this.config.recurly.api+"/field.html#config="+e}},{key:"classList",get:function(){var e="recurly-hosted-field",t=[e];return this.ready&&(t.push(e+"-"+this.config.type),this.state.focus&&(t.push(e+"-focus"),t.push(e+"-"+this.config.type+"-focus")),this.state.valid?(t.push(e+"-valid"),t.push(e+"-"+this.config.type+"-valid")):this.state.focus||this.state.empty||(t.push(e+"-invalid"),t.push(e+"-"+this.config.type+"-invalid"))),t.join(" ")}},{key:"tabIndex",get:function(){var e=parseInt(this.config.tabIndex,10);return isNaN(e)?0:e}}]),n}(f.default)}).call(t,n(3))},function(e,t,n){/*! + * Bowser - a browser detector + * https://github.com/ded/bowser + * MIT License | (c) Dustin Diaz 2015 + */ +!function(t,r,i){void 0!==e&&e.exports?e.exports=i():n(78)("bowser",i)}(0,0,function(){function e(e){function t(t){var n=e.match(t);return n&&n.length>1&&n[1]||""}function n(t){var n=e.match(t);return n&&n.length>1&&n[2]||""}var r,i=t(/(ipod|iphone|ipad)/i).toLowerCase(),o=/like android/i.test(e),u=!o&&/android/i.test(e),s=/nexus\s*[0-6]\s*/i.test(e),c=!s&&/nexus\s*[0-9]+/i.test(e),l=/CrOS/.test(e),f=/silk/i.test(e),d=/sailfish/i.test(e),p=/tizen/i.test(e),h=/(web|hpw)os/i.test(e),y=/windows phone/i.test(e),v=(/SamsungBrowser/i.test(e),!y&&/windows/i.test(e)),m=!i&&!f&&/macintosh/i.test(e),b=!u&&!d&&!p&&!h&&/linux/i.test(e),g=n(/edg([ea]|ios)\/(\d+(\.\d+)?)/i),w=t(/version\/(\d+(\.\d+)?)/i),_=/tablet/i.test(e)&&!/tablet pc/i.test(e),O=!_&&/[^-]mobi/i.test(e),j=/xbox/i.test(e);/opera/i.test(e)?r={name:"Opera",opera:a,version:w||t(/(?:opera|opr|opios)[\s\/](\d+(\.\d+)?)/i)}:/opr\/|opios/i.test(e)?r={name:"Opera",opera:a,version:t(/(?:opr|opios)[\s\/](\d+(\.\d+)?)/i)||w}:/SamsungBrowser/i.test(e)?r={name:"Samsung Internet for Android",samsungBrowser:a,version:w||t(/(?:SamsungBrowser)[\s\/](\d+(\.\d+)?)/i)}:/coast/i.test(e)?r={name:"Opera Coast",coast:a,version:w||t(/(?:coast)[\s\/](\d+(\.\d+)?)/i)}:/yabrowser/i.test(e)?r={name:"Yandex Browser",yandexbrowser:a,version:w||t(/(?:yabrowser)[\s\/](\d+(\.\d+)?)/i)}:/ucbrowser/i.test(e)?r={name:"UC Browser",ucbrowser:a,version:t(/(?:ucbrowser)[\s\/](\d+(?:\.\d+)+)/i)}:/mxios/i.test(e)?r={name:"Maxthon",maxthon:a,version:t(/(?:mxios)[\s\/](\d+(?:\.\d+)+)/i)}:/epiphany/i.test(e)?r={name:"Epiphany",epiphany:a,version:t(/(?:epiphany)[\s\/](\d+(?:\.\d+)+)/i)}:/puffin/i.test(e)?r={name:"Puffin",puffin:a,version:t(/(?:puffin)[\s\/](\d+(?:\.\d+)?)/i)}:/sleipnir/i.test(e)?r={name:"Sleipnir",sleipnir:a,version:t(/(?:sleipnir)[\s\/](\d+(?:\.\d+)+)/i)}:/k-meleon/i.test(e)?r={name:"K-Meleon",kMeleon:a,version:t(/(?:k-meleon)[\s\/](\d+(?:\.\d+)+)/i)}:y?(r={name:"Windows Phone",osname:"Windows Phone",windowsphone:a},g?(r.msedge=a,r.version=g):(r.msie=a,r.version=t(/iemobile\/(\d+(\.\d+)?)/i))):/msie|trident/i.test(e)?r={name:"Internet Explorer",msie:a,version:t(/(?:msie |rv:)(\d+(\.\d+)?)/i)}:l?r={name:"Chrome",osname:"Chrome OS",chromeos:a,chromeBook:a,chrome:a,version:t(/(?:chrome|crios|crmo)\/(\d+(\.\d+)?)/i)}:/edg([ea]|ios)/i.test(e)?r={name:"Microsoft Edge",msedge:a,version:g}:/vivaldi/i.test(e)?r={name:"Vivaldi",vivaldi:a,version:t(/vivaldi\/(\d+(\.\d+)?)/i)||w}:d?r={name:"Sailfish",osname:"Sailfish OS",sailfish:a,version:t(/sailfish\s?browser\/(\d+(\.\d+)?)/i)}:/seamonkey\//i.test(e)?r={name:"SeaMonkey",seamonkey:a,version:t(/seamonkey\/(\d+(\.\d+)?)/i)}:/firefox|iceweasel|fxios/i.test(e)?(r={name:"Firefox",firefox:a,version:t(/(?:firefox|iceweasel|fxios)[ \/](\d+(\.\d+)?)/i)},/\((mobile|tablet);[^\)]*rv:[\d\.]+\)/i.test(e)&&(r.firefoxos=a,r.osname="Firefox OS")):f?r={name:"Amazon Silk",silk:a,version:t(/silk\/(\d+(\.\d+)?)/i)}:/phantom/i.test(e)?r={name:"PhantomJS",phantom:a,version:t(/phantomjs\/(\d+(\.\d+)?)/i)}:/slimerjs/i.test(e)?r={name:"SlimerJS",slimer:a,version:t(/slimerjs\/(\d+(\.\d+)?)/i)}:/blackberry|\bbb\d+/i.test(e)||/rim\stablet/i.test(e)?r={name:"BlackBerry",osname:"BlackBerry OS",blackberry:a,version:w||t(/blackberry[\d]+\/(\d+(\.\d+)?)/i)}:h?(r={name:"WebOS",osname:"WebOS",webos:a,version:w||t(/w(?:eb)?osbrowser\/(\d+(\.\d+)?)/i)},/touchpad\//i.test(e)&&(r.touchpad=a)):/bada/i.test(e)?r={name:"Bada",osname:"Bada",bada:a,version:t(/dolfin\/(\d+(\.\d+)?)/i)}:p?r={name:"Tizen",osname:"Tizen",tizen:a,version:t(/(?:tizen\s?)?browser\/(\d+(\.\d+)?)/i)||w}:/qupzilla/i.test(e)?r={name:"QupZilla",qupzilla:a,version:t(/(?:qupzilla)[\s\/](\d+(?:\.\d+)+)/i)||w}:/chromium/i.test(e)?r={name:"Chromium",chromium:a,version:t(/(?:chromium)[\s\/](\d+(?:\.\d+)?)/i)||w}:/chrome|crios|crmo/i.test(e)?r={name:"Chrome",chrome:a,version:t(/(?:chrome|crios|crmo)\/(\d+(\.\d+)?)/i)}:u?r={name:"Android",version:w}:/safari|applewebkit/i.test(e)?(r={name:"Safari",safari:a},w&&(r.version=w)):i?(r={name:"iphone"==i?"iPhone":"ipad"==i?"iPad":"iPod"},w&&(r.version=w)):r=/googlebot/i.test(e)?{name:"Googlebot",googlebot:a,version:t(/googlebot\/(\d+(\.\d+))/i)||w}:{name:t(/^(.*)\/(.*) /),version:n(/^(.*)\/(.*) /)},!r.msedge&&/(apple)?webkit/i.test(e)?(/(apple)?webkit\/537\.36/i.test(e)?(r.name=r.name||"Blink",r.blink=a):(r.name=r.name||"Webkit",r.webkit=a),!r.version&&w&&(r.version=w)):!r.opera&&/gecko\//i.test(e)&&(r.name=r.name||"Gecko",r.gecko=a,r.version=r.version||t(/gecko\/(\d+(\.\d+)?)/i)),r.windowsphone||!u&&!r.silk?!r.windowsphone&&i?(r[i]=a,r.ios=a,r.osname="iOS"):m?(r.mac=a,r.osname="macOS"):j?(r.xbox=a,r.osname="Xbox"):v?(r.windows=a,r.osname="Windows"):b&&(r.linux=a,r.osname="Linux"):(r.android=a,r.osname="Android");var x="";r.windows?x=function(e){switch(e){case"NT":return"NT";case"XP":return"XP";case"NT 5.0":return"2000";case"NT 5.1":return"XP";case"NT 5.2":return"2003";case"NT 6.0":return"Vista";case"NT 6.1":return"7";case"NT 6.2":return"8";case"NT 6.3":return"8.1";case"NT 10.0":return"10";default:return}}(t(/Windows ((NT|XP)( \d\d?.\d)?)/i)):r.windowsphone?x=t(/windows phone (?:os)?\s?(\d+(\.\d+)*)/i):r.mac?(x=t(/Mac OS X (\d+([_\.\s]\d+)*)/i),x=x.replace(/[_\s]/g,".")):i?(x=t(/os (\d+([_\s]\d+)*) like mac os x/i),x=x.replace(/[_\s]/g,".")):u?x=t(/android[ \/-](\d+(\.\d+)*)/i):r.webos?x=t(/(?:web|hpw)os\/(\d+(\.\d+)*)/i):r.blackberry?x=t(/rim\stablet\sos\s(\d+(\.\d+)*)/i):r.bada?x=t(/bada\/(\d+(\.\d+)*)/i):r.tizen&&(x=t(/tizen[\/\s](\d+(\.\d+)*)/i)),x&&(r.osversion=x);var k=!r.windows&&x.split(".")[0];return _||c||"ipad"==i||u&&(3==k||k>=4&&!O)||r.silk?r.tablet=a:(O||"iphone"==i||"ipod"==i||u||s||r.blackberry||r.webos||r.bada)&&(r.mobile=a),r.msedge||r.msie&&r.version>=10||r.yandexbrowser&&r.version>=15||r.vivaldi&&r.version>=1||r.chrome&&r.version>=20||r.samsungBrowser&&r.version>=4||r.firefox&&r.version>=20||r.safari&&r.version>=6||r.opera&&r.version>=10||r.ios&&r.osversion&&r.osversion.split(".")[0]>=6||r.blackberry&&r.version>=10.1||r.chromium&&r.version>=20?r.a=a:r.msie&&r.version<10||r.chrome&&r.version<20||r.firefox&&r.version<20||r.safari&&r.version<6||r.opera&&r.version<10||r.ios&&r.osversion&&r.osversion.split(".")[0]<6||r.chromium&&r.version<20?r.c=a:r.x=a,r}function t(e){return e.split(".").length}function n(e,t){var n,r=[];if(Array.prototype.map)return Array.prototype.map.call(e,t);for(n=0;n=0;){if(i[0][r]>i[1][r])return 1;if(i[0][r]!==i[1][r])return-1;if(0===r)return 0}}function i(t,n,i){var o=u;"string"==typeof n&&(i=n,n=void 0),void 0===n&&(n=!1),i&&(o=e(i));var a=""+o.version;for(var s in t)if(t.hasOwnProperty(s)&&o[s]){if("string"!=typeof t[s])throw new Error("Browser version in the minVersion map should be a string: "+s+": "+String(t));return r([a,t[s]])<0}return n}function o(e,t,n){return!i(e,t,n)}var a=!0,u=e("undefined"!=typeof navigator?navigator.userAgent||"":"");return u.test=function(e){for(var t=0;t1&&void 0!==arguments[1]?arguments[1]:{},n=t.commit,r=void 0===n||n,i=void 0;if(i=(0,v.default)(this.validSubscriptions)?e:(0,h.default)(this.subscriptionCurrencies,e),(0,v.default)(i))throw new Error("unresolvable");if(r)return this.currency(i[0])}},{key:"Calculations",get:function(){return N.default}},{key:"PRICING_METHODS",get:function(){return l(t.prototype.__proto__||Object.getPrototypeOf(t.prototype),"PRICING_METHODS",this).concat(["address","adjustment","coupon","currency","giftCard","shippingAddress","subscription","tax"])}},{key:"validAdjustments",get:function(){var e=this;return this.items.adjustments.filter(function(t){return t.currency===e.items.currency})}},{key:"validSubscriptions",get:function(){return this.items.subscriptions.filter(function(e){return e.isValid})}},{key:"subscriptionCurrencies",get:function(){return(0,h.default)(this.validSubscriptions.map(function(e){return Object.keys(e.items.plan.price)}))}},{key:"subscriptionPlanCodes",get:function(){return(0,O.default)(this.validSubscriptions.map(function(e){return e.items.plan.code}))}}]),t}(P.Pricing);t.default=q},function(e,t){function n(e){var t={},n=e.length-1,r=e[0],i=e[n];for(var o in r)t[r[o]]=0;for(var o=1;o<=n;o++){var a=e[o];for(var u in a){var s=a[u];t[s]===o-1&&(t[s]=o)}}var c=[];for(var o in i){var s=i[o];t[s]===n&&c.push(s)}return c}function r(e,t){if(!t)return n(e);for(var r=[],o=0;o-1&&r.push(e[o]);return r}function i(e,t){for(var n=0;ne?(n=e,r=t-e):n=t,{used:n,remains:r}}if(this.pricing.items.gift_card){var t=this.price.now.total,n=this.price.next.total,r=e(t,this.pricing.items.gift_card.unit_amount),i=e(n,r.remains);this.price.now.gift_card=r.used,this.price.next.gift_card=i.used,this.price.now.total=t-r.used,this.price.next.total=n-i.used}}},{key:"planPrice",value:function(){var e=this.items.plan;if(!e)return{amount:0,setup_fee:0};var t=e.price[this.items.currency];return t.amount=t.unit_amount*(e.quantity||1),t}},{key:"isTrial",value:function(){var e=this.items.coupon;return!(!e||"free_trial"!==e.discount.type)||this.items.plan.trial}}]),e}();t.default=m},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function i(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function o(e,t){return function(){return new l.default(function(e,t){return e()},t)}}Object.defineProperty(t,"__esModule",{value:!0}),t.DEFERRED_METHODS=t.DISABLED_METHODS=void 0;var a=function(){function e(e,t){for(var n=0;n1)try{t.checkout.resolveCurrency(Object.keys(o.price),{commit:!1})}catch(r){return n((0,s.default)("invalid-plan-currency",{planCode:o.code,currencies:t.checkout.subscriptionCurrencies}))}o.quantity=i,t.subscription.items.plan=o;var a=function(){t.subscription.emit("set.plan",o),e(o)};if(t.checkout.currencyCode in o.price)a();else try{t.checkout.resolveCurrency(Object.keys(o.price)).then(a)}catch(e){n(r)}})},this.subscription).nodeify(a)}},{key:"id",get:function(){return this.subscription.id}},{key:"isValid",get:function(){return this.subscription.isValid}},{key:"items",get:function(){return this.subscription.items}},{key:"price",get:function(){return this.subscription.price}},{key:"taxCode",get:function(){return this.subscription.taxCode}},{key:"taxExempt",get:function(){return this.subscription.taxExempt}}]),e}();t.default=h},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function i(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function o(e,t){var n=t.id,r=t.price;return{type:"subscription",id:n,amount:r[e].total,setupFee:r[e].setup_fee,addons:r[e].addons,plan:r[e].plan}}function a(e){if(!e.items.plan.trial)return 0;var t={days:86400,months:2678400}[e.items.plan.trial.interval]||0;return e.items.plan.trial.length*t}function u(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{},r=n.setupFees,i=void 0===r||r,o=t.price[e],a=parseFloat(o.subtotal)+parseFloat(o.discount);return i||(a-=parseFloat(o.setup_fee)),a}function s(e,t){return 0===e.length?e:t.applies_to_all_plans?e:e.filter(function(e){return e.couponIsValidForSubscription(t)})}function c(e){return parseFloat((Math.round(100*e)/100).toFixed(6))}Object.defineProperty(t,"__esModule",{value:!0});var l=Object.assign||function(e){for(var t=1;te?(n=e,r=t-e):n=t,{used:n,remains:r}}if(this.price.now.giftCard=0,this.price.next.giftCard=0,this.items.giftCard){var t=this.price.now.subtotal+this.price.now.taxes,n=this.price.next.subtotal+this.price.next.taxes,r=e(t,this.items.giftCard.unit_amount),i=r.used,o=r.remains,a=e(n,o),u=a.used;return this.price.now.giftCard=i,this.price.next.giftCard=u,m.default.resolve()}}},{key:"totals",value:function(){return this.price.now.total=this.price.now.subtotal+this.price.now.taxes-this.price.now.giftCard,this.price.next.total=this.price.next.subtotal+this.price.next.taxes-this.price.next.giftCard,m.default.resolve()}},{key:"itemizedSets",value:function(){return this.price.now.items=this._itemizedSets.now.subscriptions.concat(this._itemizedSets.now.adjustments),this.price.next.items=this._itemizedSets.next.subscriptions,m.default.resolve()}},{key:"applyFreeTrialCoupon",value:function(){var e=this,t=this.items.coupon;return this.hasValidSubscriptions?"subscription"===t.redemption_resource?this.mostValuableSubscriptionForFreeTrial().coupon(t).reprice(null,{internal:!0}).then(function(){return e.subscriptions()}):m.default.all(this.validSubscriptions.map(function(e){return e.coupon(t).reprice(null,{internal:!0})})).then(function(){return e.subscriptions()}):m.default.resolve()}},{key:"discountAmounts",value:function(){var e=(arguments.length>0&&void 0!==arguments[0]&&arguments[0],this.items.coupon),t=0,n=0;if(e)if("free_trial"===e.discount.type);else if(e.discount.rate){var r=this.discountableSubtotals(e,{setupFees:!1}),i=r.discountableNow,o=r.discountableNext;t=c(i*e.discount.rate),n=c(o*e.discount.rate)}else if(e.discount.amount){var a=this.discountableSubtotals(e),u=a.discountableNow,s=a.discountableNext,l=e.discount.amount[this.items.currency]||0;t=Math.min(u,l),n=Math.min(s,l)}return{discountNow:t,discountNext:n}}},{key:"discountableSubtotals",value:function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n=t.setupFees,r=void 0===n||n,i=t.taxExempt,o=void 0===i||i,a=0,c=0;if(e.applies_to_non_plan_charges&&(a+=o?this.price.now.adjustments:this.validAdjustments.reduce(function(e,t){return e+(t.taxExempt?0:t.amount*t.quantity)},0)),e.applies_to_plans&&this.hasValidSubscriptions){var l=void 0;l="subscription"===e.redemption_resource?[this.mostValuableSubscriptionForDiscount()]:this.validSubscriptions,l=s(l,e),l.forEach(function(e){!o&&e.taxExempt||(a+=u("now",e,{setupFees:r}),c+=u("next",e,{setupFees:r}))})}return{discountableNow:a,discountableNext:c}}},{key:"mostValuableSubscriptionForDiscount",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:this.validSubscriptions;return e=s(e,this.items.coupon),e.sort(function(e,t){var n=parseFloat(e.price.now.subtotal),r=parseFloat(t.price.now.subtotal);return n>r?-1:n0}},{key:"taxableAdjustments",get:function(){return this.validAdjustments.filter(function(e){return!e.taxExempt&&e.amount>0})}},{key:"taxableSubscriptions",get:function(){return this.validSubscriptions.filter(function(e){return!e.items.plan.tax_exempt})}},{key:"taxCodes",get:function(){var e=this.taxableAdjustments.concat(this.taxableSubscriptions);return(0,g.default)(e.map(function(e){return e.taxCode}))}}]),e}();t.default=C},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function i(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function o(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function a(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}Object.defineProperty(t,"__esModule",{value:!0});var u=function(){function e(e,t){for(var n=0;n19)return!1;for(;o--;)n=parseInt(t.charAt(o),10)*i,r+=n-9*(n>9),i^=3;return r%10==0&&r>0}function i(e){var t=arguments.length>1&&void 0!==arguments[1]&&arguments[1],n=(0,c.parseCard)(e),r=n.length,i=(0,s.default)(l,function(e){return e.pattern.test(n)&&(t||~e.lengths.indexOf(r))});return i&&i.type||"unknown"}function o(e,t){if((e=Number(e)-1)<0||e>11)return!1;t=Number(t),t+=t<100?2e3:0;var n=new Date;return n.setYear(t),n.setDate(1),n.setHours(0),n.setMinutes(0),n.setSeconds(0),n.setMonth(e+1),new Date=222100&&t<=272099}},lengths:[16]},{type:"american_express",pattern:/^3[47]/,lengths:[15]},{type:"visa",pattern:/^4/,lengths:[13,16]},{type:"jcb",pattern:/^35[2-8]\d/,lengths:[16]},{type:"diners_club",pattern:/^(30[0-5]|309|36|3[89]|54|55|2014|2149)/,lengths:[14]}]}]); \ No newline at end of file diff --git a/services/web/public/js/libs/recurly.min.js b/services/web/public/js/libs/recurly.min.js deleted file mode 100755 index 8d1833a20c..0000000000 --- a/services/web/public/js/libs/recurly.min.js +++ /dev/null @@ -1 +0,0 @@ -(function(f){function v(D){function C(){}C.prototype=D||this;return new C()}var h={};h.settings={enableGeoIP:true,acceptedCards:["visa","mastercard","discover","american_express"],oneErrorPerField:true};h.version="2.2.9";h.dom={};h.Error={toString:function(){return"RecurlyJS Error: "+this.message}};h.raiseError=function(C){var D=v(h.Error);D.message=C;throw D};h.config=function(C){f.extend(true,h.settings,C);if(!C.baseURL){var D=h.settings.subdomain||h.raiseError("company subdomain not configured");h.settings.baseURL="https://"+D+".recurly.com/jsonp/"+D+"/"}};function u(D,C){if(D==1){return C.substr(0,C.length-1)}return""+D+" "+C}(h.Cost=function(C){this._cents=C||0}).prototype={toString:function(){return h.formatCurrency(this.dollars())},cents:function(C){if(C===undefined){return this._cents}return new h.Cost(C)},dollars:function(C){if(C===undefined){return this._cents/100}return new h.Cost(C*100)},mult:function(C){return new h.Cost(this._cents*C)},add:function(C){if(C.cents){C=C.cents()}return new h.Cost(this._cents+C)},sub:function(C){if(C.cents){C=C.cents()}return new h.Cost(this._cents-C)}};h.Cost.FREE=new h.Cost(0);(h.TimePeriod=function(D,C){this.length=D;this.unit=C}).prototype={toString:function(){return""+u(this.length,this.unit)},toDate:function(){var C=new Date();switch(this.unit){case"month":C.setMonth(C.getMonth()+this.length);break;case"day":C.setDay(C.getDay()+this.length);break}return C},clone:function(){return new h.TimePeriod(this.length,this.unit)}};(h.RecurringCost=function(D,C){this.cost=D;this.interval=C}).prototype={toString:function(){return""+this.cost+" every "+this.interval},clone:function(){return new h.TimePeriod(this.length,this.unit)}};h.RecurringCost.FREE=new h.RecurringCost(0,null);(h.RecurringCostStage=function(C,D){this.recurringCost=C;this.duration=D}).prototype={toString:function(){this.recurringCost.toString()+" for "+this.duration.toString()}};h.locale={};h.locale.errors={emptyField:"Required field",missingFullAddress:"Please enter your full address.",invalidEmail:"Invalid",invalidCC:"Invalid",invalidCVV:"Invalid",invalidCoupon:"Invalid",cardDeclined:"Transaction declined",acceptTOS:"Please accept the Terms of Service.",invalidQuantity:"Invalid quantity"};h.locale.currencies={};h.locale.currency={format:"%u%n",separator:".",delimiter:",",precision:2};function s(C,D){var F=h.locale.currencies[C]=v(h.locale.currency);for(var E in D){F[E]=D[E]}}s("USD",{symbol:"$"});s("AUD",{symbol:"$"});s("CAD",{symbol:"$"});s("EUR",{symbol:"\u20ac"});s("GBP",{symbol:"\u00a3"});s("CZK",{symbol:"\u004b"});s("DKK",{symbol:"\u006b\u0072"});s("HUF",{symbol:"Ft"});s("JPY",{symbol:"\u00a5"});s("NOK",{symbol:"kr"});s("NZD",{symbol:"$"});s("PLN",{symbol:"\u007a"});s("SGD",{symbol:"$"});s("SEK",{symbol:"kr"});s("CHF",{symbol:"Fr"});s("ZAR",{symbol:"R"});h.settings.locale=h.locale;h.knownCards={visa:{prefixes:[4],name:"Visa"},mastercard:{prefixes:[51,52,53,54,55],name:"MasterCard"},american_express:{prefixes:[34,37],name:"American Express"},discover:{prefixes:[6011,62,64,65],name:"Discover"},diners_club:{prefixes:[305,36,38],name:"Diners Club"},carte_blanche:{prefixes:[300,301,302,303,304,305]},jcb:{prefixes:[35],name:"JCB"},enroute:{prefixes:[2014,2149],name:"EnRoute"},maestro:{prefixes:[5018,5020,5038,6304,6759,6761],name:"Maestro"},laser:{prefixes:[6304,6706,6771,6709],name:"Laser"}};h.detectCardType=function(E){E=E.replace(/\D/g,"");var H=h.knownCards;for(var C in H){if(H.hasOwnProperty(C)){var I=H[C];for(var G=0,D=I.prefixes.length;G").hide();F.attr("action",D).attr("method","POST").attr("enctype","application/x-www-form-urlencoded");f('').attr({name:"recurly_token",value:E}).appendTo(F);f("body").append(F);F.submit()};function k(F){var E=f("
');if(!P.displayQuantity){J.find(".quantity").remove()}J.data("add_on",P);J.appendTo(K)}K.delegate(".quantity input","change keyup recalculate",function(ac){var Y=f(this);var Z=Y.closest(".add_on");var ab=Z.data("add_on");var aa=Y.val()===""?1:parseInt(Y.val(),10);V.findAddOnByCode(ab.code).quantity=aa>0?aa:0;M()});K.delegate(".quantity input","blur",function(ab){var Y=f(this);var Z=Y.closest(".add_on");var aa=parseInt(Y.val(),10);if(aa<1){Y.trigger("recalculate")}if(aa===0){Z.trigger("actuate")}});K.bind("selectstart",function(Y){if(f(Y.target).is(".add_on")){Y.preventDefault()}});K.delegate(".add_on","click actuate",function(ac){if(f(ac.target).closest(".quantity").length){return}var aa=!f(this).hasClass("selected");f(this).toggleClass("selected",aa);var ab=f(this).data("add_on");if(aa){var Y=V.redeemAddOn(ab);var Z=f(this).find(".quantity input");var ad=parseInt(Z.val(),10);if(ad<1||isNaN(ad)){ad=1;Z.val(ad)}Y.quantity=ad;Z.focus()}else{V.removeAddOn(ab.code)}M()});K.find("input").trigger("init")}}else{K.remove()}var N=C.find(".coupon");var R=null;function W(){var Y=N.find("input").val();if(Y==R){return}R=Y;if(!Y){N.removeClass("invalid").removeClass("valid");N.find(".description").text("");V.coupon=undefined;M();return}N.addClass("checking");V.getCoupon(Y,function(Z){N.removeClass("checking");V.coupon=Z;N.removeClass("invalid").addClass("valid");N.find(".description").text(Z.description);M()},function(){V.coupon=undefined;N.removeClass("checking");N.removeClass("valid").addClass("invalid");N.find(".description").text(h.locale.errors.invalidCoupon);M()})}if(D.enableCoupons){N.find("input").bind("keyup change",function(Y){});N.find("input").keypress(function(Y){if(Y.charCode==13){Y.preventDefault();W()}});N.find(".check").click(function(){W()});N.find("input").blur(function(){N.find(".check").click()})}else{N.remove()}var I=C.find(".vat");var X=C.find(".vat_number");var Q=X.find("input");I.find(".title").text("VAT at "+h.settings.VATPercent+"%");function L(){var Z=C.find(".country select").val();var ab=h.isVATNumberApplicable(Z);X.toggleClass("applicable",ab);X.toggleClass("inapplicable",!ab);var aa=Q.val();var Y=h.isVATChargeApplicable(Z,aa);I.toggleClass("applicable",Y);I.toggleClass("inapplicable",!Y)}C.find(".country select").change(function(){O.country=f(this).val();M();L()}).change();Q.bind("keyup change",function(){O.vatNumber=f(this).val();M();L()});C.submit(function(Y){Y.preventDefault();a(C);C.find(".error").remove();C.find(".invalid").removeClass("invalid");B(function(Z){q(C,V.plan,D,Z);i(C,H,D,Z);d(C,O,D,Z);y(C,Z)},function(){C.addClass("submitting");var Z=C.find("button.submit").text();C.find("button.submit").attr("disabled",true).text("Please Wait");V.save({signature:D.signature,success:function(aa){if(D.successHandler){D.successHandler(h.getToken(aa))}if(D.successURL){var ab=D.successURL;h.postResult(ab,aa,D)}},error:function(aa){if(!D.onError||!D.onError(aa)){p(C,aa)}},complete:function(){C.removeClass("submitting");C.find("button.submit").removeAttr("disabled").text(Z)}})})});W();M();if(D.beforeInject){D.beforeInject(C.get(0))}f(function(){var Y=f(D.target);Y.html(C);if(D.afterInject){D.afterInject(C.get(0))}})}};h.paypal={start:function(G){var J=window.name;if(J.indexOf("recurly_result")>-1){window.name="";J=""}var H=f.extend(G.data,{post_message:true,referer:window.location.href}),E=G.url+"?"+f.param(H),C=window.open(E,"recurly_paypal","menubar=1,resizable=1");window.popup=C;f(window).on("message",I);var D=setInterval(function(){var L=decodeURIComponent(window.name),M=L.match(/recurly_result=(.*)[&$]?/),K=M&&f.parseJSON(M[1]);if(K){F(K);window.name=J}},1000);function F(K){try{C.close()}finally{G.success(K);G.complete();f(window).unbind("message",I);clearInterval(D)}}function I(M){var L=document.createElement("a");L.href=h.settings.baseURL;var K=L.protocol+"//"+L.host.replace(/:\d+$/,"");if(M.originalEvent.origin==K){F(M.originalEvent.data)}}}};h.states={};h.states.US={"-":"Select State","--":"------------",AL:"Alabama",AK:"Alaska",AS:"American Samoa",AZ:"Arizona",AR:"Arkansas",AA:"Armed Forces Americas",AE:"Armed Forces Europe, Middle East, & Canada",AP:"Armed Forces Pacific",CA:"California",CO:"Colorado",CT:"Connecticut",DE:"Delaware",DC:"District of Columbia",FM:"Federated States of Micronesia",FL:"Florida",GA:"Georgia",GU:"Guam",HI:"Hawaii",ID:"Idaho",IL:"Illinois",IN:"Indiana",IA:"Iowa",KS:"Kansas",KY:"Kentucky",LA:"Louisiana",ME:"Maine",MH:"Marshall Islands",MD:"Maryland",MA:"Massachusetts",MI:"Michigan",MN:"Minnesota",MS:"Mississippi",MO:"Missouri",MT:"Montana",NE:"Nebraska",NV:"Nevada",NH:"New Hampshire",NJ:"New Jersey",NM:"New Mexico",NY:"New York",NC:"North Carolina",ND:"North Dakota",MP:"Northern Mariana Islands",OH:"Ohio",OK:"Oklahoma",OR:"Oregon",PW:"Palau",PA:"Pennsylvania",PR:"Puerto Rico",RI:"Rhode Island",SC:"South Carolina",SD:"South Dakota",TN:"Tennessee",TX:"Texas",UT:"Utah",VT:"Vermont",VI:"Virgin Islands",VA:"Virginia",WA:"Washington",WV:"West Virginia",WI:"Wisconsin",WY:"Wyoming"};h.states.CA={"-":"Select State","--":"------------",AB:"Alberta",BC:"British Columbia",MB:"Manitoba",NB:"New Brunswick",NL:"Newfoundland",NT:"Northwest Territories",NS:"Nova Scotia",NU:"Nunavut",ON:"Ontario",PE:"Prince Edward Island",QC:"Quebec",SK:"Saskatchewan",YT:"Yukon Territory"};h.dom.contact_info_fields='
Contact Info
First Name
Last Name
Phone Number
Company/Organization Name
';h.dom.billing_info_fields='
Billing Info
First Name
Last Name
Credit Card Number
CVV
Expires
Address
Apt/Suite
City
State/Province
Zip/Postal
VAT Number
You will be taken to PayPal to authorize a billing agreement.

Please make sure pop-ups aren\'t blocked.
';h.dom.subscribe_form='';h.dom.update_billing_info_form='
';h.dom.one_time_transaction_form='
';h.dom.terms_of_service='';window.Recurly=h})(jQuery); \ No newline at end of file From 06fb31533fd68809cfa308db6ff68303c1c9dc42 Mon Sep 17 00:00:00 2001 From: Henry Oswald Date: Mon, 16 Apr 2018 10:26:39 +0100 Subject: [PATCH 09/13] add highlight for bad card/cvv/mmyy number in. --- services/web/app/views/subscriptions/new.pug | 8 ++------ services/web/public/stylesheets/components/forms.less | 1 + 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/services/web/app/views/subscriptions/new.pug b/services/web/app/views/subscriptions/new.pug index 5644710723..3755f359e7 100644 --- a/services/web/app/views/subscriptions/new.pug +++ b/services/web/app/views/subscriptions/new.pug @@ -19,7 +19,7 @@ block content .page-header .row .col-xs-9 - h2 {{planName}} + h2 {{planName}} {{validation.errorFields}} {{validation.errorFields.number}} .col-xs-3 div.dropdown.changePlanButton.pull-right(ng-cloak, dropdown) a.btn.btn-default.dropdown-toggle( @@ -102,13 +102,12 @@ block content required ) - .form-group() + .form-group(ng-class="validation.errorFields.number ? 'has-error' : ''") label(for="card-no") #{translate("credit_card_number")} div#card-no( type="text" name="ccNumber" data-recurly='number' - ng-focus="validation.correctCardNumber = true; validation.errorFields.number = false;" ng-blur="validateCardNumber();" required ) @@ -120,7 +119,6 @@ block content div( type="number" name="month" - ng-focus="validation.correctExpiry = true; validation.errorFields.expiry = false;" ng-blur="updateExpiry(); validateExpiry()" data-recurly="month" required @@ -132,7 +130,6 @@ block content type="number" name="year" data-recurly="year" - ng-focus="validation.correctExpiry = true; validation.errorFields.expiry = false;" ng-blur="updateExpiry(); validateExpiry()" required ) @@ -143,7 +140,6 @@ block content div( type="number" ng-model="data.cvv" - ng-focus="validation.correctCvv = true; validation.errorFields.cvv = false;" ng-blur="validateCvv()" data-recurly="cvv" name="cvv" diff --git a/services/web/public/stylesheets/components/forms.less b/services/web/public/stylesheets/components/forms.less index 4e32779d7b..8202be7c3f 100755 --- a/services/web/public/stylesheets/components/forms.less +++ b/services/web/public/stylesheets/components/forms.less @@ -311,6 +311,7 @@ input[type="checkbox"], } .has-error { .form-control-validation(@state-danger-text; @state-danger-text; @state-danger-bg); + color:@red; } .form-control.ng-dirty.ng-invalid:not(:focus) { From 7940b60144acab64fff68d1c0a241e98e6116a7a Mon Sep 17 00:00:00 2001 From: Henry Oswald Date: Mon, 16 Apr 2018 10:35:12 +0100 Subject: [PATCH 10/13] make a seperate external error class which is used on entire payment form --- services/web/app/views/subscriptions/new.pug | 16 ++++++++-------- .../web/public/stylesheets/components/forms.less | 3 +++ 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/services/web/app/views/subscriptions/new.pug b/services/web/app/views/subscriptions/new.pug index 3755f359e7..4b824e5739 100644 --- a/services/web/app/views/subscriptions/new.pug +++ b/services/web/app/views/subscriptions/new.pug @@ -19,7 +19,7 @@ block content .page-header .row .col-xs-9 - h2 {{planName}} {{validation.errorFields}} {{validation.errorFields.number}} + h2 {{planName}} .col-xs-3 div.dropdown.changePlanButton.pull-right(ng-cloak, dropdown) a.btn.btn-default.dropdown-toggle( @@ -79,7 +79,7 @@ block content div(ng-show="paymentMethod.value === 'credit_card'") .row .col-xs-6 - .form-group(ng-class="validation.errorFields.first_name || inputHasError(simpleCCForm.firstName) ? 'has-error' : ''") + .form-group(ng-class="validation.errorFields.first_name || inputHasError(simpleCCForm.firstName) ? 'has-external-error' : ''") label(for="first-name") #{translate('first_name')} input#first-name.form-control( type="text" @@ -91,7 +91,7 @@ block content ) span.input-feedback-message {{ simpleCCForm.firstName.$error.required ? 'This field is required' : '' }} .col-xs-6 - .form-group(for="last-name",ng-class="validation.errorFields.last_name || inputHasError(simpleCCForm.lastName)? 'has-error' : ''") + .form-group(for="last-name",ng-class="validation.errorFields.last_name || inputHasError(simpleCCForm.lastName)? 'has-external-error' : ''") label(for="last-name") #{translate('last_name')} input#last-name.form-control( type="text" @@ -102,7 +102,7 @@ block content required ) - .form-group(ng-class="validation.errorFields.number ? 'has-error' : ''") + .form-group(ng-class="validation.errorFields.number ? 'has-external-error' : ''") label(for="card-no") #{translate("credit_card_number")} div#card-no( type="text" @@ -114,7 +114,7 @@ block content .row .col-xs-3 - .form-group.has-feedback() + .form-group.has-feedback(ng-class="validation.errorFields.month ? 'has-external-error' : ''") label(for="month") #{translate("month")} div( type="number" @@ -124,7 +124,7 @@ block content required ) .col-xs-3 - .form-group.has-feedback() + .form-group.has-feedback(ng-class="validation.errorFields.year ? 'has-external-error' : ''") label(for="year") #{translate("year")} div( type="number" @@ -135,7 +135,7 @@ block content ) .col-xs-6 - .form-group.has-feedback() + .form-group.has-feedback(ng-class="validation.errorFields.cvv ? 'has-external-error' : ''") label #{translate("security_code")} div( type="number" @@ -156,7 +156,7 @@ block content ) ? div - .form-group(ng-class="validation.errorFields.country || inputHasError(simpleCCForm.country) ? 'has-error' : ''") + .form-group(ng-class="validation.errorFields.country || inputHasError(simpleCCForm.country) ? 'has-external-error' : ''") label(for="country") #{translate('country')} select#country.form-control( data-recurly="country" diff --git a/services/web/public/stylesheets/components/forms.less b/services/web/public/stylesheets/components/forms.less index 8202be7c3f..de13f1d48f 100755 --- a/services/web/public/stylesheets/components/forms.less +++ b/services/web/public/stylesheets/components/forms.less @@ -311,6 +311,9 @@ input[type="checkbox"], } .has-error { .form-control-validation(@state-danger-text; @state-danger-text; @state-danger-bg); +} +.has-external-error { + .form-control-validation(@state-danger-text; @state-danger-text; @state-danger-bg); color:@red; } From c3eeefdc5b91b68f9076c64870cb88e77be4d013 Mon Sep 17 00:00:00 2001 From: Henry Oswald Date: Mon, 16 Apr 2018 10:52:33 +0100 Subject: [PATCH 11/13] only use recurly.js from our public libs folder --- services/web/app/views/subscriptions/new.pug | 2 -- services/web/public/coffee/main/new-subscription.coffee | 1 + 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/services/web/app/views/subscriptions/new.pug b/services/web/app/views/subscriptions/new.pug index 4b824e5739..a29c03903b 100644 --- a/services/web/app/views/subscriptions/new.pug +++ b/services/web/app/views/subscriptions/new.pug @@ -1,8 +1,6 @@ extends ../layout block scripts - script(src="https://js.recurly.com/v4/recurly.js") - script(type='text/javascript'). window.countryCode = '#{countryCode}' window.plan_code = '#{plan_code}' diff --git a/services/web/public/coffee/main/new-subscription.coffee b/services/web/public/coffee/main/new-subscription.coffee index ab1128ed33..02939a3b9c 100644 --- a/services/web/public/coffee/main/new-subscription.coffee +++ b/services/web/public/coffee/main/new-subscription.coffee @@ -1,6 +1,7 @@ define [ "base", "directives/creditCards" + "libs/recurly-4.8.5" ], (App)-> App.controller "NewSubscriptionController", ($scope, MultiCurrencyPricing, abTestManager, $http, sixpack, event_tracking, ccUtils)-> From 985d05a2975c60eab8d013c847552ded25ae17c4 Mon Sep 17 00:00:00 2001 From: Henry Oswald Date: Mon, 16 Apr 2018 10:56:03 +0100 Subject: [PATCH 12/13] remove .has-error class, not used --- services/web/public/stylesheets/components/forms.less | 3 --- 1 file changed, 3 deletions(-) diff --git a/services/web/public/stylesheets/components/forms.less b/services/web/public/stylesheets/components/forms.less index de13f1d48f..8eb92411cd 100755 --- a/services/web/public/stylesheets/components/forms.less +++ b/services/web/public/stylesheets/components/forms.less @@ -309,9 +309,6 @@ input[type="checkbox"], .has-warning { .form-control-validation(@state-warning-text; @state-warning-text; @state-warning-bg); } -.has-error { - .form-control-validation(@state-danger-text; @state-danger-text; @state-danger-bg); -} .has-external-error { .form-control-validation(@state-danger-text; @state-danger-text; @state-danger-bg); color:@red; From 086f080ee4bd54175fcfe73165656a289fe19915 Mon Sep 17 00:00:00 2001 From: Henry Oswald Date: Mon, 16 Apr 2018 11:01:14 +0100 Subject: [PATCH 13/13] add `!isFormValid(simpleCCForm)` back in, was used during debugging --- services/web/app/views/subscriptions/new.pug | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/services/web/app/views/subscriptions/new.pug b/services/web/app/views/subscriptions/new.pug index a29c03903b..08aefd93af 100644 --- a/services/web/app/views/subscriptions/new.pug +++ b/services/web/app/views/subscriptions/new.pug @@ -106,8 +106,6 @@ block content type="text" name="ccNumber" data-recurly='number' - ng-blur="validateCardNumber();" - required ) .row @@ -117,9 +115,7 @@ block content div( type="number" name="month" - ng-blur="updateExpiry(); validateExpiry()" data-recurly="month" - required ) .col-xs-3 .form-group.has-feedback(ng-class="validation.errorFields.year ? 'has-external-error' : ''") @@ -128,8 +124,6 @@ block content type="number" name="year" data-recurly="year" - ng-blur="updateExpiry(); validateExpiry()" - required ) .col-xs-6 @@ -138,10 +132,8 @@ block content div( type="number" ng-model="data.cvv" - ng-blur="validateCvv()" data-recurly="cvv" name="cvv" - required cc-format-sec-code ) .form-control-feedback @@ -197,7 +189,7 @@ block content div.payment-submit button.btn.btn-success.btn-block( ng-click="submit()" - ng-disabled="processing" + ng-disabled="processing || !isFormValid(simpleCCForm);" ) span(ng-show="processing") i.fa.fa-spinner.fa-spin