diff --git a/.travis.yml b/.travis.yml index 840596d0f1..37b2c625cb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -44,7 +44,10 @@ before_script: - echo "EMAIL_QUEUE_LOG_METRICS_EVERY=0" >> local.env - psql -U postgres -c 'CREATE DATABASE "gratipay";' - - if [ "${TRAVIS_BRANCH}" = "master" -a "${TRAVIS_PULL_REQUEST}" = "false" ]; then rm -rfv tests/py/fixtures; fi + - if [ "${TRAVIS_BRANCH}" = "master" -a "${TRAVIS_PULL_REQUEST}" = "false" ]; then + rm -rfv tests/py/fixtures; + echo "LOAD_BRAINTREE_FORM_ON_HOMEPAGE=yes" >> local.env; + fi script: LD_LIBRARY_PATH=/usr/local/lib xvfb-run make test-schema bgrun test doc notifications: email: false diff --git a/Makefile b/Makefile index ec91275920..ab710a47b1 100644 --- a/Makefile +++ b/Makefile @@ -6,7 +6,7 @@ bin_dir := $(shell $(python) -c 'import sys; bin = "Scripts" if sys.platform == env_bin := env/$(bin_dir) venv := "./vendor/virtualenv-15.1.0.py" doc_env_files := defaults.env,docs/doc.env,docs/local.env -test_env_files := defaults.env,tests/defaults.env,tests/local.env +test_env_files := defaults.env,local.env,tests/defaults.env,tests/local.env pip := $(env_bin)/pip honcho := $(env_bin)/honcho honcho_run := $(honcho) run -e defaults.env,local.env diff --git a/README.md b/README.md index b2786823af..df71b88293 100644 --- a/README.md +++ b/README.md @@ -278,8 +278,13 @@ You should then find this in your browser at ![Success](https://raw.github.com/gratipay/gratipay.com/master/img-src/success.png) -Congratulations! Sign in using Twitter or GitHub and you're off and -running. At some point, try [running the test suite](#testing-). +Congratulations! Now enter a dollar amount [less than +2000](https://developers.braintreepayments.com/reference/general/testing/python#test-amounts) +(ironically), and submit the form to complete the basic flow: + +![More Success](https://raw.github.com/gratipay/gratipay.com/master/img-src/more-success.png) + +You're off and running! At some point, try [running the test suite](#testing-). Help! diff --git a/defaults.env b/defaults.env index 1a5c35a887..cad3021187 100644 --- a/defaults.env +++ b/defaults.env @@ -31,6 +31,7 @@ BRAINTREE_SANDBOX_MODE=true BRAINTREE_MERCHANT_ID=bk8h97tqzyqjhtfn BRAINTREE_PUBLIC_KEY=xbty5dc9bgxpv5nb BRAINTREE_PRIVATE_KEY=9d8646957c982bb0fb1aac764b582f7a +BRAINTREE_CLIENT_AUTHORIZATION=sandbox_cr9dyy9c_bk8h97tqzyqjhtfn COINBASE_API_KEY=uETKVUrnPuXzVaVj COINBASE_API_SECRET=32zAkQCcHHYkGGn29VkvEZvn21PM1lgO @@ -105,3 +106,5 @@ PROJECT_REVIEW_USERNAME= PROJECT_REVIEW_TOKEN= RAISE_SIGNIN_NOTIFICATIONS=no + +LOAD_BRAINTREE_FORM_ON_HOMEPAGE=no diff --git a/deploy/before.sql b/deploy/before.sql new file mode 100644 index 0000000000..93534e6ade --- /dev/null +++ b/deploy/before.sql @@ -0,0 +1,23 @@ +BEGIN; + CREATE TYPE follow_up AS ENUM ('monthly', 'quarterly', 'yearly', 'never'); + CREATE TABLE payments_for_open_source + ( uuid text PRIMARY KEY + , ctime timestamptz NOT NULL DEFAULT now() + + -- card charge + , amount bigint NOT NULL + , braintree_transaction_id text UNIQUE DEFAULT NULL + , braintree_result_message text DEFAULT NULL + + -- contact info + , name text NOT NULL + , follow_up follow_up NOT NULL + , email_address text NOT NULL + + -- promotion details + , promotion_name text NOT NULL DEFAULT '' + , promotion_url text NOT NULL DEFAULT '' + , promotion_twitter text NOT NULL DEFAULT '' + , promotion_message text NOT NULL DEFAULT '' + ); +END; diff --git a/emails/paid-for-open-source.spt b/emails/paid-for-open-source.spt new file mode 100644 index 0000000000..5316449431 --- /dev/null +++ b/emails/paid-for-open-source.spt @@ -0,0 +1,18 @@ +{{ _("Invoice from Gratipay") }} + +[---] text/html +{{ _( "Thank you for your payment of {amount} for open source!" + , amount=format_currency(amount, 'USD') + ) }} +
+
+{{ _("View Invoice") }} + +[---] text/plain +{{ _( "Thank you for your payment of {amount} for open source!" + , amount=format_currency(amount, 'USD') + ) }} + +{{ _("Follow this link to view your invoice:") }} + +{{ invoice_url }} diff --git a/gratipay/application.py b/gratipay/application.py index 0f97ee8e27..da89211f60 100644 --- a/gratipay/application.py +++ b/gratipay/application.py @@ -6,6 +6,7 @@ from . import email, sync_npm, utils from .cron import Cron from .models import GratipayDB +from .card_charger import CardCharger from .payday_runner import PaydayRunner from .project_review_process import ProjectReviewProcess from .website import Website @@ -47,6 +48,7 @@ def __init__(self): self.website = website self.payday_runner = PaydayRunner(self) self.project_review_process = ProjectReviewProcess(env, db, self.email_queue) + self.pfos_card_charger = CardCharger(online=env.load_braintree_form_on_homepage) def install_periodic_jobs(self, website, env, db): diff --git a/gratipay/card_charger.py b/gratipay/card_charger.py new file mode 100644 index 0000000000..db6016dd04 --- /dev/null +++ b/gratipay/card_charger.py @@ -0,0 +1,74 @@ +# -*- coding: utf-8 -*- +from __future__ import absolute_import, division, print_function, unicode_literals + +import braintree +from uuid import uuid4 +from decimal import Decimal as D + + +class CardCharger(object): + + def __init__(self, online=False): + self.implementation = Braintree() if online else FakeBraintree() + + def charge(self, params): + return self.implementation.charge(params) + + +# Online +# ====== + +class Braintree(object): + """Sends data to Braintree. + """ + + def charge(self, params): + """Charge using the Braintree APi, returning a result. + """ + return braintree.Transaction.sale(params) + + +# Offline +# ======= + +class FakeTransaction(object): + def __init__(self): + self.id = uuid4().hex + +class FakeSuccessResult(object): + def __init__(self): + self.is_success = True + self.transaction = FakeTransaction() + +class FakeFailureResult(object): + def __init__(self): + self.is_success = False + self.message = 'Not a success.' + self.transaction = FakeTransaction() + +class FakeErrorResult(object): + def __init__(self): + self.is_success = False + self.message = 'Not even a success.' + self.transaction = None + + +class FakeBraintree(object): + """For offline use. + """ + + def charge(self, params): + """Return a fake result. Partially implements Braintree's testing logic: + + - fake-valid-nonce returns a success result + - amount >= 2000 returns a failure result + - otherwise return an error result + + https://developers.braintreepayments.com/reference/general/testing/python + + """ + if params['payment_method_nonce'] == 'fake-valid-nonce': + if D(params['amount']) < 2000: + return FakeSuccessResult() + return FakeFailureResult() + return FakeErrorResult() diff --git a/gratipay/homepage.py b/gratipay/homepage.py new file mode 100644 index 0000000000..698f66999e --- /dev/null +++ b/gratipay/homepage.py @@ -0,0 +1,118 @@ +# -*- coding: utf-8 -*- +"""This is the Python library behind gratipay.com. +""" +from __future__ import absolute_import, division, print_function, unicode_literals + +from gratipay import utils +from gratipay.models.payment_for_open_source import PaymentForOpenSource + + +def _parse(raw): + """Given a POST request.body, return (parsed, errors). + """ + + errors = [] + x = lambda f: raw[f].strip() # KeyError -> 400 + + # amount + amount = x('amount') + if (not amount.isdigit()) or (int(amount) < 10): + errors.append('amount') + amount = ''.join(x for x in amount.split('.')[0] if x.isdigit()) + + # credit card nonce + payment_method_nonce = x('payment_method_nonce') + if len(payment_method_nonce) > 36: + errors.append('payment_method_nonce') + payment_method_nonce = '' + + # name + name = x('name') + if len(name) > 255: + name = name[:255] + errors.append('name') + + # email address + email_address = x('email_address') + if email_address and not utils.is_valid_email_address(email_address): + email_address = email_address[:255] + errors.append('email_address') + + # follow_up + follow_up = x('follow_up') + if follow_up not in ('monthly', 'quarterly', 'yearly', 'never'): + follow_up = 'monthly' + errors.append('follow_up') + + promotion_name = x('promotion_name') + if len(promotion_name) > 32: + promotion_name = promotion_name[:32] + errors.append('promotion_name') + + promotion_url = x('promotion_url') + is_link = lambda x: (x.startswith('http://') or x.startswith('https://')) and '.' in x + if len(promotion_url) > 255 or (promotion_url and not is_link(promotion_url)): + promotion_url = promotion_url[:255] + errors.append('promotion_url') + + promotion_twitter = x('promotion_twitter') + if len(promotion_twitter) > 32: + promotion_twitter = promotion_twitter[:32] + # TODO What are Twitter's rules? + errors.append('promotion_twitter') + + promotion_message = x('promotion_message') + if len(promotion_message) > 128: + promotion_message = promotion_message[:128] + errors.append('promotion_message') + + parsed = { 'amount': amount + , 'payment_method_nonce': payment_method_nonce + , 'name': name + , 'email_address': email_address + , 'follow_up': follow_up + , 'promotion_name': promotion_name + , 'promotion_url': promotion_url + , 'promotion_twitter': promotion_twitter + , 'promotion_message': promotion_message + } + return parsed, errors + + +def _store(parsed): + return PaymentForOpenSource.insert(**parsed) + + +def _charge(app, pfos, nonce): + params = { 'amount': pfos.amount + , 'payment_method_nonce': nonce + , 'options': {'submit_for_settlement': True} + , 'custom_fields': {'pfos_uuid': pfos.uuid} + } + result = app.pfos_card_charger.charge(params) + pfos.process_result(result) + + +def _send(app, pfos): + app.email_queue.put( to=None + , template='paid-for-open-source' + , email=pfos.email_address + , amount=pfos.amount + , invoice_url=pfos.invoice_url + ) + + +def pay_for_open_source(app, raw): + parsed, errors = _parse(raw) + out = {'errors': errors, 'invoice_url': None} + if not errors: + payment_method_nonce = parsed.pop('payment_method_nonce') + pfos = _store(parsed) + _charge(app, pfos, payment_method_nonce) + if pfos.succeeded: + out['invoice_url'] = pfos.invoice_url + if pfos.email_address: + _send(app, pfos) + else: + out['errors'].append('charging') + return out diff --git a/gratipay/models/__init__.py b/gratipay/models/__init__.py index 4ae554ec56..9660fa8606 100644 --- a/gratipay/models/__init__.py +++ b/gratipay/models/__init__.py @@ -16,10 +16,12 @@ from .exchange_route import ExchangeRoute from .package import Package from .participant import Participant +from .payment_for_open_source import PaymentForOpenSource from .team import Team -MODELS = (AccountElsewhere, Community, Country, ExchangeRoute, Package, Participant, Team) +MODELS = (AccountElsewhere, Community, Country, ExchangeRoute, Package, Participant, + PaymentForOpenSource, Team) @contextmanager diff --git a/gratipay/models/payment_for_open_source.py b/gratipay/models/payment_for_open_source.py new file mode 100644 index 0000000000..1c34baf981 --- /dev/null +++ b/gratipay/models/payment_for_open_source.py @@ -0,0 +1,80 @@ +# -*- coding: utf-8 -*- +from __future__ import absolute_import, division, print_function, unicode_literals + +import gratipay +from uuid import uuid4 +from postgres.orm import Model + + +class PaymentForOpenSource(Model): + + typname = "payments_for_open_source" + + def __repr__(self): + return ''.format(repr(self.amount)) + + + @property + def succeeded(self): + return self.braintree_result_message == '' + + + @property + def invoice_url(self): + if not self.succeeded: + return None + return '{}/browse/payments/{}/invoice.html'.format(gratipay.base_url, self.uuid) + + + @classmethod + def from_uuid(cls, uuid, cursor=None): + """Take a uuid and return an object. + """ + return (cursor or cls.db).one(""" + SELECT pfos.*::payments_for_open_source + FROM payments_for_open_source pfos + WHERE uuid = %s + """, (uuid,)) + + + @classmethod + def insert(cls, amount, name, follow_up, email_address, + promotion_name, promotion_url, promotion_twitter, promotion_message, + cursor=None): + """Take baseline info and insert into the database. + """ + uuid = uuid4().hex + return (cursor or cls.db).one(""" + INSERT INTO payments_for_open_source + (uuid, amount, name, follow_up, email_address, + promotion_name, promotion_url, promotion_twitter, promotion_message) + VALUES (%s, %s, %s, %s, %s, + %s, %s, %s, %s) + RETURNING payments_for_open_source.*::payments_for_open_source + """, (uuid, amount, name, follow_up, email_address, + promotion_name, promotion_url, promotion_twitter, promotion_message)) + + + def process_result(self, result): + """Take a Braintree API result and update the database. + """ + result_message = '' if result.is_success else result.message + transaction_id = None + if result.transaction: + transaction_id = result.transaction.id + + # Verify that Braintree is sending us the right payload. + # TODO This is hard to test and it should be a pretty tight guarantee, + # so I am commenting out for now. :( + #pfos_uuid = result.transaction.custom_fields['pfos_uuid'] + #assert pfos_uuid == self.uuid, (pfos_uuid, transaction_id) + + self.db.run(""" + UPDATE payments_for_open_source + SET braintree_result_message=%s + , braintree_transaction_id=%s + WHERE uuid=%s + """, (result_message, transaction_id, self.uuid)) + self.set_attributes( braintree_result_message=result_message + , braintree_transaction_id=transaction_id + ) diff --git a/gratipay/testing/harness.py b/gratipay/testing/harness.py index ce5e7b0872..eb8f8ae9f9 100644 --- a/gratipay/testing/harness.py +++ b/gratipay/testing/harness.py @@ -21,6 +21,7 @@ from gratipay.models.exchange_route import ExchangeRoute from gratipay.models.package import NPM, Package from gratipay.models.participant import Participant, MAX_TIP, MIN_TIP +from gratipay.models.payment_for_open_source import PaymentForOpenSource from gratipay.models.team import Team from gratipay.security import user from gratipay.testing import P @@ -142,6 +143,22 @@ def clear_tables(self): self.db.run("INSERT INTO worker_coordination DEFAULT VALUES") + def make_payment_for_open_source(self, **info): + defaults = dict( amount='1000' + , name='Alice Liddell' + , email_address='alice@example.com' + , follow_up='monthly' + , promotion_name='Wonderland' + , promotion_url='http://www.example.com/' + , promotion_twitter='thebestbutter' + , promotion_message='Love me! Love me! Say that you love me!' + ) + for key, value in defaults.items(): + if key not in info: + info[key] = value + return PaymentForOpenSource.insert(**info) + + def make_elsewhere(self, platform, user_id, user_name, **kw): """Factory for :py:class:`~gratipay.models.account_elsewhere.AccountElsewhere`. """ @@ -318,6 +335,7 @@ def make_exchange(self, route, amount, fee, participant, status='succeeded', err record_exchange_result(self.db, e_id, status, error, participant) return e_id + def make_payment(self, participant, team, amount, direction, payday, timestamp=utcnow()): """Factory for payment""" diff --git a/gratipay/utils/__init__.py b/gratipay/utils/__init__.py index c6e33dc4d7..76cd0ea750 100644 --- a/gratipay/utils/__init__.py +++ b/gratipay/utils/__init__.py @@ -4,6 +4,7 @@ import fnmatch import random import os +import re from base64 import urlsafe_b64encode, urlsafe_b64decode from datetime import datetime, timedelta @@ -20,6 +21,11 @@ # card is considered as expiring EXPIRING_DELTA = timedelta(days = 30) +_email_re = re.compile(r'^[^@]+@[^@]+\.[^@]+$') +# exactly one @, and at least one . after @ -- simple validation, send to be sure +def is_valid_email_address(email_address): + return len(email_address) < 255 and _email_re.match(email_address) + def dict_to_querystring(mapping): if not mapping: diff --git a/gratipay/utils/http_caching.py b/gratipay/utils/http_caching.py index f2eb7284e9..2ce3c0e9c5 100644 --- a/gratipay/utils/http_caching.py +++ b/gratipay/utils/http_caching.py @@ -38,7 +38,7 @@ def concat_files(files, root): catted.append('/*' + filepath.center(68) + '*/\n') catted.append('/' + ('*'*70) + '/' + '\n\n') content = open(os.path.join(root, filepath)).read() - content = content.decode('ascii') + content = content.decode('utf8') catted.append(content + '\n') return "".join(catted) diff --git a/gratipay/wireup.py b/gratipay/wireup.py index cb48f778f5..7bf70cc698 100644 --- a/gratipay/wireup.py +++ b/gratipay/wireup.py @@ -256,7 +256,7 @@ def compile_assets(website): headers[b'HTTP_HOST'] = str(url.netloc) content = client.GET(urlpath, **headers).body tmpfd, tmpfpath = mkstemp(dir='.') - os.write(tmpfd, content) + os.write(tmpfd, content.encode('utf8')) os.close(tmpfd) os.rename(tmpfpath, filepath) atexit.register(lambda: clean_assets(website.www_root)) @@ -351,6 +351,7 @@ def env(): BRAINTREE_MERCHANT_ID = unicode, BRAINTREE_PUBLIC_KEY = unicode, BRAINTREE_PRIVATE_KEY = unicode, + BRAINTREE_CLIENT_AUTHORIZATION = unicode, GITHUB_CLIENT_ID = unicode, GITHUB_CLIENT_SECRET = unicode, GITHUB_CALLBACK = unicode, @@ -394,6 +395,7 @@ def env(): PROJECT_REVIEW_USERNAME = unicode, PROJECT_REVIEW_TOKEN = unicode, RAISE_SIGNIN_NOTIFICATIONS = is_yesish, + LOAD_BRAINTREE_FORM_ON_HOMEPAGE = is_yesish, GUNICORN_OPTS = unicode, ) diff --git a/img-src/more-success.png b/img-src/more-success.png new file mode 100644 index 0000000000..9374fad926 Binary files /dev/null and b/img-src/more-success.png differ diff --git a/img-src/success.png b/img-src/success.png index afba54ccd3..c8e34f8c78 100644 Binary files a/img-src/success.png and b/img-src/success.png differ diff --git a/js/gratipay/homepage.js b/js/gratipay/homepage.js new file mode 100644 index 0000000000..15775a0b7b --- /dev/null +++ b/js/gratipay/homepage.js @@ -0,0 +1,82 @@ +Gratipay.homepage = {} + +Gratipay.homepage.initForm = function(clientAuthorization) { + var self = this; + self.$form = $('#homepage #content form'); + self.$submit = self.$form.find('button[type=submit]'); + + function disable(e) { + e.preventDefault(); + self.$submit.prop('disabled', true); + self.$submit.addClass('processing'); + } + + if (clientAuthorization === undefined) { // Offline mode + + $('#braintree-container').addClass('offline').html(Gratipay.jsonml(['div', + ['div', {'class': 'field amount'}, + ['label', {'for': 'nonce'}, 'Nonce'], + ['input', {'id': 'nonce', 'value': 'fake-valid-nonce', 'required': true}, 'Nonce'], + ], + ['p', {'class': 'fine-print'}, "If you're seeing this on gratipay.com, we screwed up."] + ])); + + self.$submit.click(function(e) { + disable(e); + nonce = $('#braintree-container input').val(); + self.submitFormWithNonce(nonce); + }); + + } else { // Online mode (sandbox or production) + + function braintreeInitCallback(createErr, instance) { + if (createErr) { + $('#braintree-container').addClass('failed').text('Failed to load Braintree.'); + } else { + self.$submit.click(function(e) { + disable(e); + instance.requestPaymentMethod(function(requestPaymentMethodErr, payload) { + self.submitFormWithNonce(payload ? payload.nonce : ''); + }); + }); + } + } + + braintree.dropin.create({ + authorization: clientAuthorization, + container: '#braintree-container' + }, braintreeInitCallback); + } +}; + + +Gratipay.homepage.submitFormWithNonce = function(nonce) { + var self = this; + var data = new FormData(self.$form[0]); + data.set('payment_method_nonce', nonce); + + $.ajax({ + url: self.$form.attr('action'), + type: 'POST', + data: data, + processData: false, + contentType: false, + dataType: 'json', + success: function(data) { + // Due to Aspen limitations we use 200 for both success and failure. :/ + if (data.errors.length > 0) { + self.$submit.prop('disabled', false); + self.$submit.removeClass('processing'); + Gratipay.notification(data.msg, 'error'); + for (var i=0, fieldName; fieldName=data.errors[i]; i++) { + $('.'+fieldName, self.$form).addClass('error'); + } + } else { + $('.payment-complete a.invoice').attr('href', data.invoice_url); + $('form').slideUp(500, function() { + $('.payment-complete').fadeIn(500); + }); + } + } + }); +}; diff --git a/js/vendor/braintree.min.js b/js/vendor/braintree.min.js new file mode 100644 index 0000000000..02f57db3f7 --- /dev/null +++ b/js/vendor/braintree.min.js @@ -0,0 +1,6 @@ +!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var t;t="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,(t.braintree||(t.braintree={})).dropin=e()}}(function(){var e;return function e(t,i,r){function n(o,s){if(!i[o]){if(!t[o]){var l="function"==typeof require&&require;if(!s&&l)return l(o,!0);if(a)return a(o,!0);var d=new Error("Cannot find module '"+o+"'");throw d.code="MODULE_NOT_FOUND",d}var c=i[o]={exports:{}};t[o][0].call(c.exports,function(e){var i=t[o][1][e];return n(i?i:e)},c,c.exports,e,t,i,r)}return i[o].exports}for(var a="function"==typeof require&&require,o=0;o=500?i=new s(m.CLIENT_GATEWAY_NETWORK):(e<200||e>=400)&&(i=l(t,{type:m.CLIENT_REQUEST_ERROR.type,code:m.CLIENT_REQUEST_ERROR.code,message:m.CLIENT_REQUEST_ERROR.message})),i)return i.details=i.details||{},i.details.httpStatus=e,i}var a=e("./request"),o=e("../lib/is-whitelisted-domain"),s=e("../lib/braintree-error"),l=e("../lib/convert-to-braintree-error"),d=e("../lib/add-metadata"),c=e("../lib/promise"),p=e("../lib/once"),h=e("../lib/deferred"),u=e("../lib/assign").assign,y=e("./constants"),m=e("./errors"),f=e("../lib/errors"),v=e("../lib/constants").VERSION;r.prototype.request=function(e,t){var i=this,r=new c(function(t,r){var a,o,l,c;if(e.method?e.endpoint||(a="options.endpoint"):a="options.method",a)throw new s({type:m.CLIENT_OPTION_REQUIRED.type,code:m.CLIENT_OPTION_REQUIRED.code,message:a+" is required when making a request."});if(o="api"in e?e.api:"clientApi",c={method:e.method,timeout:e.timeout},"clientApi"===o)l=i._clientApiBaseUrl,c.data=d(i._configuration,e.data);else{if("braintreeApi"!==o)throw new s({type:m.CLIENT_OPTION_INVALID.type,code:m.CLIENT_OPTION_INVALID.code,message:"options.api is invalid."});if(!i._braintreeApi)throw new s(f.BRAINTREE_API_ACCESS_RESTRICTED);l=i._braintreeApi.baseUrl,c.data=e.data,c.headers={"Braintree-Version":y.BRAINTREE_API_VERSION_HEADER,Authorization:"Bearer "+i._braintreeApi.accessToken}}c.url=l+e.endpoint,i._request(c,function(e,i,a){var o,s;return(s=n(a,e))?void r(s):(o=u({_httpStatus:a},i),void t(o))})});return"function"==typeof t?(t=p(h(t)),void r.then(function(e){t(null,e,e._httpStatus)}).catch(function(e){var i=e&&e.details&&e.details.httpStatus;t(e,null,i)})):r},r.prototype.toJSON=function(){return this.getConfiguration()},r.prototype.getVersion=function(){return v},t.exports=r},{"../lib/add-metadata":40,"../lib/assign":42,"../lib/braintree-error":44,"../lib/constants":49,"../lib/convert-to-braintree-error":51,"../lib/deferred":53,"../lib/errors":56,"../lib/is-whitelisted-domain":58,"../lib/once":61,"../lib/promise":63,"./constants":20,"./errors":21,"./request":26}],20:[function(e,t,i){"use strict";t.exports={BRAINTREE_API_VERSION_HEADER:"2017-04-03"}},{}],21:[function(e,t,i){"use strict";var r=e("../lib/braintree-error");t.exports={CLIENT_GATEWAY_CONFIGURATION_INVALID_DOMAIN:{type:r.types.MERCHANT,code:"CLIENT_GATEWAY_CONFIGURATION_INVALID_DOMAIN"},CLIENT_OPTION_REQUIRED:{type:r.types.MERCHANT,code:"CLIENT_OPTION_REQUIRED"},CLIENT_OPTION_INVALID:{type:r.types.MERCHANT,code:"CLIENT_OPTION_INVALID"},CLIENT_MISSING_GATEWAY_CONFIGURATION:{type:r.types.INTERNAL,code:"CLIENT_MISSING_GATEWAY_CONFIGURATION",message:"Missing gatewayConfiguration."},CLIENT_INVALID_AUTHORIZATION:{type:r.types.MERCHANT,code:"CLIENT_INVALID_AUTHORIZATION",message:"Authorization is invalid. Make sure your client token or tokenization key is valid."},CLIENT_GATEWAY_NETWORK:{type:r.types.NETWORK,code:"CLIENT_GATEWAY_NETWORK",message:"Cannot contact the gateway at this time."},CLIENT_REQUEST_TIMEOUT:{type:r.types.NETWORK,code:"CLIENT_REQUEST_TIMEOUT",message:"Request timed out waiting for a reply."},CLIENT_REQUEST_ERROR:{type:r.types.NETWORK,code:"CLIENT_REQUEST_ERROR",message:"There was a problem with your request."},CLIENT_RATE_LIMITED:{type:r.types.MERCHANT,code:"CLIENT_RATE_LIMITED",message:"You are being rate-limited; please try again in a few minutes."},CLIENT_AUTHORIZATION_INSUFFICIENT:{type:r.types.MERCHANT,code:"CLIENT_AUTHORIZATION_INSUFFICIENT",message:"The authorization used has insufficient privileges."}}},{"../lib/braintree-error":44}],22:[function(e,t,i){(function(i){"use strict";function r(e){return new a(function(t,r){var a,o,h,u,y=l(),m={merchantAppId:i.location.host,platform:d.PLATFORM,sdkVersion:d.VERSION,source:d.SOURCE,integration:d.INTEGRATION,integrationType:d.INTEGRATION,sessionId:y};try{o=c(e.authorization)}catch(e){return void r(new n(p.CLIENT_INVALID_AUTHORIZATION))}h=o.attrs,u=o.configUrl,h._meta=m,h.braintreeLibraryVersion=d.BRAINTREE_LIBRARY_VERSION,h.configVersion="3",s({url:u,method:"GET",data:h},function(i,o,s){var l;return i?(l=403===s?p.CLIENT_AUTHORIZATION_INSUFFICIENT:p.CLIENT_GATEWAY_NETWORK,void r(new n({type:l.type,code:l.code,message:l.message,details:{originalError:i}}))):(a={authorization:e.authorization,authorizationType:h.tokenizationKey?"TOKENIZATION_KEY":"CLIENT_TOKEN",analyticsMetadata:m,gatewayConfiguration:o},void t(a))})})}var n=e("../lib/braintree-error"),a=e("../lib/promise"),o=e("@braintree/wrap-promise"),s=e("./request"),l=e("../lib/uuid"),d=e("../lib/constants"),c=e("../lib/create-authorization-data"),p=e("./errors");t.exports={getConfiguration:o(r)}}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{"../lib/braintree-error":44,"../lib/constants":49,"../lib/create-authorization-data":52,"../lib/promise":63,"../lib/uuid":66,"./errors":21,"./request":26,"@braintree/wrap-promise":17}],23:[function(e,t,i){"use strict";function r(e){return e.authorization?h[e.authorization]?d.resolve(h[e.authorization]):s(e).then(function(t){var i;return e.debug&&(t.isDebug=!0),i=new o(t),h[e.authorization]=i,i}):d.reject(new a({type:p.INSTANTIATION_OPTION_REQUIRED.type,code:p.INSTANTIATION_OPTION_REQUIRED.code,message:"options.authorization is required when instantiating a client."}))}function n(){h={}}var a=e("../lib/braintree-error"),o=e("./client"),s=e("./get-configuration").getConfiguration,l="3.22.2",d=e("../lib/promise"),c=e("@braintree/wrap-promise"),p=e("../lib/errors"),h={};t.exports={create:c(r),VERSION:l,_clearCache:n}},{"../lib/braintree-error":44,"../lib/errors":56,"../lib/promise":63,"./client":19,"./get-configuration":22,"@braintree/wrap-promise":17}],24:[function(e,t,i){(function(i){"use strict";function r(){return h?new XMLHttpRequest:new XDomainRequest}function n(e){return(!e||e===y)&&l.isIe()}function a(e,t,i){var o,l,y=e.method,m=e.url,f=e.data,v=e.timeout,b=d({"Content-Type":"application/json"},e.headers),g=r(),E=i;"GET"===y&&(m=s.queryify(m,f),f=null),h?g.onreadystatechange=function(){if(4===g.readyState)if(o=g.status,l=p(g.responseText),o>=400||o<200){if(t=400||o<200?s=i:l=i,a(n),r(e),clearTimeout(h[n]),t(s,l,o)}}function l(e,t){var i,r="callback_json_"+c().replace(/-/g,""),a=e.url,l=e.data,h=e.method,u=e.timeout;a=p.queryify(a,l),a=p.queryify(a,{_method:h,callback:r}),i=n(a,r),s(i,t,r),o(u,r),d||(d=document.getElementsByTagName("head")[0]),d.appendChild(i)}var d,c=e("../../lib/uuid"),p=e("../../lib/querystring"),h={};t.exports={request:l}}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{"../../lib/querystring":64,"../../lib/uuid":66}],29:[function(e,t,i){"use strict";t.exports=function(e){try{e=JSON.parse(e)}catch(e){}return e}},{}],30:[function(e,t,i){"use strict";t.exports=function(e,t){if("string"!=typeof e)throw new Error("Method must be a string");return"get"!==e.toLowerCase()&&null!=t&&(t="string"==typeof t?t:JSON.stringify(t)),t}},{}],31:[function(e,t,i){"use strict";function r(e,t){var i;return s.hasOwnProperty(e)?null==t||n(e,t)||(i=new a({type:o.HOSTED_FIELDS_ATTRIBUTE_VALUE_NOT_ALLOWED.type,code:o.HOSTED_FIELDS_ATTRIBUTE_VALUE_NOT_ALLOWED.code,message:'Value "'+t+'" is not allowed for "'+e+'" attribute.'})):i=new a({type:o.HOSTED_FIELDS_ATTRIBUTE_NOT_SUPPORTED.type,code:o.HOSTED_FIELDS_ATTRIBUTE_NOT_SUPPORTED.code,message:'The "'+e+'" attribute is not supported in Hosted Fields.'}),i}function n(e,t){return"string"===s[e]?"string"==typeof t||"number"==typeof t:"boolean"===s[e]&&("true"===String(t)||"false"===String(t))}var a=e("../../lib/braintree-error"),o=e("../shared/errors"),s=e("../shared/constants").whitelistedAttributes;t.exports=r},{"../../lib/braintree-error":44,"../shared/constants":37,"../shared/errors":38}],32:[function(e,t,i){"use strict";var r=e("../shared/constants"),n=e("../../lib/use-min");t.exports=function(e,t,i){return e+"/web/"+r.VERSION+"/html/hosted-fields-frame"+n(i)+".html#"+t}},{"../../lib/use-min":65,"../shared/constants":37}],33:[function(e,t,i){(function(i){"use strict";function r(e){return function(t){var i,r=t.merchantPayload,a=r.emittedBy,o=e[a].containerElement;Object.keys(r.fields).forEach(function(t){r.fields[t].container=e[t].containerElement}),i=r.fields[a],"blur"===t.type&&n(o),s.toggle(o,h.externalClasses.FOCUSED,i.isFocused),s.toggle(o,h.externalClasses.VALID,i.isValid),s.toggle(o,h.externalClasses.INVALID,!i.isPotentiallyValid),this._state={cards:r.cards,fields:r.fields},this._emit(t.type,r)}}function n(e){var t;v.isIos()&&document.activeElement===document.body&&(t=e.querySelector("input"),t||(t=document.createElement("input"),t.type="button",t.style.height="0px",t.style.width="0px",t.style.opacity="0",t.style.padding="0",t.style.position="absolute",t.style.left="-200%",t.style.top="0px",e.insertBefore(t,e.firstChild)),t.focus(),t.blur())}function a(e){var t,n,f,v=this,P={},F=0,N=m();if(!e.client)throw new c({type:D.INSTANTIATION_OPTION_REQUIRED.type,code:D.INSTANTIATION_OPTION_REQUIRED.code,message:"options.client is required when instantiating Hosted Fields."});if(f=e.client.getConfiguration(),n=e.client.getVersion(),n!==C)throw new c({type:D.INCOMPATIBLE_VERSIONS.type,code:D.INCOMPATIBLE_VERSIONS.code,message:"Client (version "+n+") and Hosted Fields (version "+C+") components must be from the same SDK version."});if(!e.fields)throw new c({type:D.INSTANTIATION_OPTION_REQUIRED.type,code:D.INSTANTIATION_OPTION_REQUIRED.code,message:"options.fields is required when instantiating Hosted Fields."});g.call(this),this._injectedNodes=[],this._destructor=new o,this._fields=P,this._state={fields:{},cards:A("")},this._bus=new d({channel:N,merchantUrl:location.href}),this._destructor.registerFunctionForTeardown(function(){v._bus.teardown()}),this._client=e.client,_.sendEvent(this._client,"custom.hosted-fields.initialized"),Object.keys(e.fields).forEach(function(t){var r,n,a;if(!h.whitelistedFields.hasOwnProperty(t))throw new c({type:u.HOSTED_FIELDS_INVALID_FIELD_KEY.type,code:u.HOSTED_FIELDS_INVALID_FIELD_KEY.code,message:'"'+t+'" is not a valid field.'});if(r=e.fields[t],n=document.querySelector(r.selector),!n)throw new c({type:u.HOSTED_FIELDS_INVALID_FIELD_SELECTOR.type,code:u.HOSTED_FIELDS_INVALID_FIELD_SELECTOR.code,message:u.HOSTED_FIELDS_INVALID_FIELD_SELECTOR.message,details:{fieldSelector:r.selector,fieldKey:t}});if(n.querySelector('iframe[name^="braintree-"]'))throw new c({type:u.HOSTED_FIELDS_FIELD_DUPLICATE_IFRAME.type,code:u.HOSTED_FIELDS_FIELD_DUPLICATE_IFRAME.code,message:u.HOSTED_FIELDS_FIELD_DUPLICATE_IFRAME.message,details:{fieldSelector:r.selector,fieldKey:t}});if(r.maxlength&&"number"!=typeof r.maxlength)throw new c({type:u.HOSTED_FIELDS_FIELD_PROPERTY_INVALID.type,code:u.HOSTED_FIELDS_FIELD_PROPERTY_INVALID.code,message:"The value for maxlength must be a number.",details:{fieldKey:t}});if(r.minlength&&"number"!=typeof r.minlength)throw new c({type:u.HOSTED_FIELDS_FIELD_PROPERTY_INVALID.type,code:u.HOSTED_FIELDS_FIELD_PROPERTY_INVALID.code,message:"The value for minlength must be a number.",details:{fieldKey:t}});a=l({type:t,name:"braintree-hosted-field-"+t,style:h.defaultIFrameStyle}),this._injectedNodes=this._injectedNodes.concat(E(a,n)),this._setupLabelFocus(t,n),P[t]={frameElement:a,containerElement:n},F++,this._state.fields[t]={isEmpty:!0,isValid:!1,isPotentiallyValid:!0,isFocused:!1,container:n},setTimeout(function(){i.navigator&&i.navigator.vendor&&i.navigator.vendor.indexOf("Apple")===-1&&(a.src="about:blank"),setTimeout(function(){a.src=p(f.gatewayConfiguration.assetsUrl,N,f.isDebug)},0)},0)}.bind(this)),t=setTimeout(function(){_.sendEvent(v._client,"custom.hosted-fields.load.timed-out")},y),this._bus.on(b.FRAME_READY,function(i){F--,0===F&&(clearTimeout(t),i(e),v._emit("ready"))}),this._bus.on(b.INPUT_EVENT,r(P).bind(this)),this._destructor.registerFunctionForTeardown(function(){var e,t,i;for(e=0;e>4&3,i=(15&a)<<4|o>>2&15,r=(3&o)<<6|63&s,p+=String.fromCharCode(t)+(i?String.fromCharCode(i):"")+(r?String.fromCharCode(r):"");while(l=0;r--)n=_[r],n.closed===!0?_=_.slice(r,1):i!==n&&m(n.top,e,t)}function v(e,t){function i(n,a){e(n,a),E.target(t).unsubscribe(r,i)}var r=p();return E.target(t).subscribe(r,i),r}function b(e,t,i){return!!s(e)||("function"!=typeof t||!!s(i))}var g,E,_=[],P={},C="/*framebus*/";return c(),E={target:i,include:t,publish:r,pub:r,trigger:r,emit:r,subscribe:n,sub:n,on:n,unsubscribe:a,unsub:a,off:a}})}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{}],73:[function(e,t,i){!function(e){function i(){}function r(e,t){return function(){e.apply(t,arguments)}}function n(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._state=0,this._handled=!1,this._value=void 0,this._deferreds=[],c(e,this)}function a(e,t){for(;3===e._state;)e=e._value;return 0===e._state?void e._deferreds.push(t):(e._handled=!0,void n._immediateFn(function(){var i=1===e._state?t.onFulfilled:t.onRejected;if(null===i)return void(1===e._state?o:s)(t.promise,e._value);var r;try{r=i(e._value)}catch(e){return void s(t.promise,e)}o(t.promise,r)}))}function o(e,t){try{if(t===e)throw new TypeError("A promise cannot be resolved with itself.");if(t&&("object"==typeof t||"function"==typeof t)){var i=t.then;if(t instanceof n)return e._state=3,e._value=t,void l(e);if("function"==typeof i)return void c(r(i,t),e)}e._state=1,e._value=t,l(e)}catch(t){s(e,t)}}function s(e,t){e._state=2,e._value=t,l(e)}function l(e){2===e._state&&0===e._deferreds.length&&n._immediateFn(function(){e._handled||n._unhandledRejectionFn(e._value)});for(var t=0,i=e._deferreds.length;t-1}function n(e){var t=e||s;return l(t)&&h.test(t)}function a(e){var t=e||s;return l(t)&&d(t)}function o(e){return e=e||s,/SamsungBrowser/.test(e)||r(e)}var s=i.navigator&&i.navigator.userAgent,l=e("@braintree/browser-detection/is-android"),d=e("@braintree/browser-detection/is-chrome"),c=e("@braintree/browser-detection/is-ios"),p=e("@braintree/browser-detection/is-ie9"),h=/Version\/\d\.\d* Chrome\/\d*\.0\.0\.0/;t.exports={isIE9:p,isAndroidChrome:a,isIos:c,isKitKatWebview:n,isSamsungBrowser:o}}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{"@braintree/browser-detection/is-android":1,"@braintree/browser-detection/is-chrome":2,"@braintree/browser-detection/is-ie9":6,"@braintree/browser-detection/is-ios":8}],75:[function(e,t,i){"use strict";var r=e("./lib/device");t.exports=function(){return!r.isSamsungBrowser()}},{"./lib/device":74}],76:[function(e,t,i){"use strict";t.exports={paymentOptionIDs:{card:"card",paypal:"paypal",paypalCredit:"paypalCredit"},paymentMethodTypes:{card:"CreditCard",paypal:"PayPalAccount",paypalCredit:"PayPalAccount"},analyticsKinds:{CreditCard:"card",PayPalAccount:"paypal"},paymentMethodCardTypes:{Visa:"visa",MasterCard:"master-card","American Express":"american-express","Diners Club":"diners-club",Discover:"discover",JCB:"jcb",UnionPay:"unionpay",Maestro:"maestro"},configurationCardTypes:{visa:"Visa","master-card":"MasterCard","american-express":"American Express","diners-club":"Discover",discover:"Discover",jcb:"JCB",unionpay:"UnionPay",maestro:"Maestro"},errors:{NO_PAYMENT_METHOD_ERROR:"No payment method is available.",PAYPAL_NON_LINKED_SANDBOX:'A linked sandbox account is required to use PayPal Checkout in sandbox.'},ANALYTICS_REQUEST_TIMEOUT_MS:2e3,ANALYTICS_PREFIX:"web.dropin.",CHANGE_ACTIVE_PAYMENT_METHOD_TIMEOUT:200,CHECKOUT_JS_SOURCE:"https://www.paypalobjects.com/api/checkout.4.0.110.min.js",INTEGRATION:"dropin2",PAYPAL_CHECKOUT_SCRIPT_ID:"braintree-dropin-paypal-checkout-script",DATA_COLLECTOR_SCRIPT_ID:"braintree-dropin-data-collector-script",STYLESHEET_ID:"braintree-dropin-stylesheet"}},{}],77:[function(e,t,i){"use strict";function r(e){this.componentID=e.componentID,this.merchantConfiguration=e.merchantConfiguration,this.isGuestCheckout=p(e.client),this.dependenciesInitializing=0,this.dependencySuccessCount=0,this.failedDependencies={},this.supportedPaymentOptions=n(e),this._paymentMethods=this._getSupportedPaymentMethods(e.paymentMethods),this._paymentMethodIsRequestable=this._paymentMethods.length>0,s.call(this)}function n(e){var t=[],i=e.merchantConfiguration.paymentOptionPriority||["card","paypal","paypalCredit"];if(!(i instanceof Array))throw new o("paymentOptionPriority must be an array.");if(i=i.filter(function(e,t){return i.indexOf(e)===t}),i.forEach(function(i){a(i,e)&&t.push(c[i])}),0===t.length)throw new o("No valid payment options available.");return t}function a(e,t){var i=t.client.getConfiguration().gatewayConfiguration;if("card"===e)return i.creditCards.supportedCardTypes.length>0;if("paypal"===e)return i.paypalEnabled&&Boolean(t.merchantConfiguration.paypal);if("paypalCredit"===e)return i.paypalEnabled&&Boolean(t.merchantConfiguration.paypalCredit);throw new o("paymentOptionPriority: Invalid payment option specified.")}var o=e("./lib/dropin-error"),s=e("./lib/event-emitter"),l=e("./constants"),d=l.paymentMethodTypes,c=l.paymentOptionIDs,p=e("./lib/is-guest-checkout");r.prototype=Object.create(s.prototype,{constructor:r}),r.prototype.isPaymentMethodRequestable=function(){return Boolean(this._paymentMethodIsRequestable)},r.prototype.addPaymentMethod=function(e){this._paymentMethods.push(e),this._emit("addPaymentMethod",e),this.changeActivePaymentMethod(e)},r.prototype.removePaymentMethod=function(e){var t=this._paymentMethods.indexOf(e);t!==-1&&(this._paymentMethods.splice(t,1),this._emit("removePaymentMethod",e))},r.prototype.changeActivePaymentMethod=function(e){this._activePaymentMethod=e,this._emit("changeActivePaymentMethod",e)},r.prototype.changeActivePaymentView=function(e){this._activePaymentView=e,this._emit("changeActivePaymentView",e)},r.prototype.removeActivePaymentMethod=function(){this._activePaymentMethod=null,this._emit("removeActivePaymentMethod"),this.setPaymentMethodRequestable({isRequestable:!1})},r.prototype.selectPaymentOption=function(e){this._emit("paymentOptionSelected",{paymentOption:e})},r.prototype._shouldEmitRequestableEvent=function(e){var t=this.isPaymentMethodRequestable()===e.isRequestable,i=e.type===this._paymentMethodRequestableType;return!(t&&(!e.isRequestable||i))},r.prototype.setPaymentMethodRequestable=function(e){var t=this._shouldEmitRequestableEvent(e),i={paymentMethodIsSelected:Boolean(e.selectedPaymentMethod),type:e.type};this._paymentMethodIsRequestable=e.isRequestable,e.isRequestable?this._paymentMethodRequestableType=e.type:delete this._paymentMethodRequestableType,t&&(e.isRequestable?this._emit("paymentMethodRequestable",i):this._emit("noPaymentMethodRequestable"))},r.prototype.getPaymentMethods=function(){return this._paymentMethods.slice()},r.prototype.getActivePaymentMethod=function(){return this._activePaymentMethod},r.prototype.getActivePaymentView=function(){return this._activePaymentView},r.prototype.asyncDependencyStarting=function(){this.dependenciesInitializing++},r.prototype.asyncDependencyReady=function(){this.dependencySuccessCount++,this.dependenciesInitializing--,this._checkAsyncDependencyFinished()},r.prototype.asyncDependencyFailed=function(e){this.failedDependencies.hasOwnProperty(e.view)||(this.failedDependencies[e.view]=e.error,this.dependenciesInitializing--,this._checkAsyncDependencyFinished())},r.prototype._checkAsyncDependencyFinished=function(){0===this.dependenciesInitializing&&this._emit("asyncDependenciesReady")},r.prototype.cancelInitialization=function(e){this._emit("cancelInitialization",e)},r.prototype.reportError=function(e){this._emit("errorOccurred",e)},r.prototype.clearError=function(){this._emit("errorCleared")},r.prototype._getSupportedPaymentMethods=function(e){var t=this.supportedPaymentOptions.reduce(function(e,t){var i=d[t];return i&&e.push(i),e},[]);return e.filter(function(e){return t.indexOf(e.type)>-1})},t.exports=r},{"./constants":76,"./lib/dropin-error":86,"./lib/event-emitter":87,"./lib/is-guest-checkout":89}],78:[function(e,t,i){(function(i){"use strict";function r(e){this._client=e.client,this._componentID=v(),this._dropinWrapper=document.createElement("div"),this._dropinWrapper.id="braintree--dropin__"+this._componentID,this._dropinWrapper.setAttribute("data-braintree-id","wrapper"),this._dropinWrapper.style.display="none",this._dropinWrapper.className="braintree-loading", +this._merchantConfiguration=e.merchantConfiguration,c.call(this)}function n(e){var t={nonce:e.nonce,details:e.details,type:e.type,vaulted:!0};return e.type===s.paymentMethodTypes.card&&(t.description=e.description),e.deviceData&&(t.deviceData=e.deviceData),e.binData&&(t.binData=e.binData),t}var a=e("./lib/assign").assign,o=e("./lib/analytics"),s=e("./constants"),l=e("./lib/dropin-error"),d=e("./dropin-model"),c=e("./lib/event-emitter"),p=e("./lib/is-guest-checkout"),h=e("./views/main-view"),u=e("./views/payment-methods-view").ID,y=e("./views/payment-options-view").ID,m=s.paymentOptionIDs,f=e("./translations"),v=e("./lib/uuid"),b=e("./lib/promise"),g=e("@braintree/wrap-promise").wrapPrototype,E='
\n
 
\n
{{chooseAWayToPay}}
\n
 
\n\n
\n
\n
\n \n \n \n
\n
\n\n
\n
\n
\n\n
\n
\n
\n\n
\n
\n
\n
\n
\n \n \n \n
\n
{{PayPal}}
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n \n \n \n
\n
{{PayPal Credit}}
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n \n \n \n
\n
{{payWithCard}}
\n
\n
\n
\n
\n
\n
{{cardholderNameLabel}}
\n
\n
\n \n
\n
\n
\n \n \n \n
\n
\n
\n
{{fieldEmptyForCardholderName}}
\n
\n
\n
{{cardNumberLabel}}
\n
\n
\n
\n
\n \n \n \n
\n
\n \n \n \n
\n
\n
\n
\n
\n\n
\n
\n
{{expirationDateLabel}}\n {{expirationDateLabelSubheading}}\n
\n
\n
\n
\n
\n \n \n \n
\n
\n
\n\n
\n
\n\n
\n
{{cvvLabel}}\n {{cvvThreeDigitLabelSubheading}}\n
\n
\n
\n
\n
\n \n \n \n
\n
\n \n \n \n
\n
\n
\n
\n
\n\n
\n
{{postalCodeLabel}}
\n
\n
\n
\n
\n \n \n \n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n \n \n \n
\n
\n
\n
\n
\n\n
\n
{{otherWaysToPay}}
\n
\n\n
\n {{chooseAnotherWayToPay}}\n
\n
\n',_='\n \n \n Visa\n \n \n \n \n\n \n MasterCard\n \n \n \n \n \n \n\n \n Union Pay\n \n \n \n \n \n \n \n \n \n \n\n \n American Express\n \n \n \n \n\n \n JCB\n \n \n \n \n \n\n \n Discover\n \n \n \n \n \n\n \n Diners Club\n \n \n \n \n \n\n \n Maestro\n \n \n \n \n \n \n\n \n PayPal Logo\n \n \n \n \n \n \n\n \n PayPal Credit Logo\n \n \n \n \n \n \n \n \n\n \n Generic Card\n \n \n \n \n \n \n \n\n \n CVV Back\n \n \n \n \n \n \n \n\n \n CVV Front\n \n \n \n \n \n \n \n \n\n \n Check\n \n \n\n \n Lock Loader\n \n \n\n \n \n \n \n \n\n',P=[m.paypal,m.paypalCredit],C=[m.paypal,m.paypalCredit],T="warn",I="1.7.0"; +r.prototype=Object.create(c.prototype,{constructor:r}),r.prototype._initialize=function(e){var t,i,r,n=this,c=this._merchantConfiguration.container||this._merchantConfiguration.selector;return this._injectStylesheet(),c?this._merchantConfiguration.container&&this._merchantConfiguration.selector?(o.sendEvent(this._client,"configuration-error"),void e(new l("Must only have one options.selector or options.container."))):("string"==typeof c&&(c=document.querySelector(c)),c&&1===c.nodeType?c.innerHTML.trim()?(o.sendEvent(this._client,"configuration-error"),void e(new l("options.selector or options.container must reference an empty DOM node."))):(this._strings=a({},f.en),this._merchantConfiguration.locale&&(t=f[this._merchantConfiguration.locale]||f[this._merchantConfiguration.locale.split("_")[0]],this._strings=a(this._strings,t)),this._merchantConfiguration.translations&&(this._strings=a(this._strings,this._merchantConfiguration.translations)),i=Object.keys(this._strings).reduce(function(e,t){var i=this._strings[t];return e.replace(RegExp("{{"+t+"}}","g"),i)}.bind(this),E),this._dropinWrapper.innerHTML=_+i,c.appendChild(this._dropinWrapper),void this._getVaultedPaymentMethods(function(t){var i;try{this._model=new d({client:this._client,componentID:this._componentID,merchantConfiguration:this._merchantConfiguration,paymentMethods:t})}catch(t){return void n.teardown().then(function(){e(t)})}this._model.on("cancelInitialization",function(t){o.sendEvent(this._client,"load-error"),this._dropinWrapper.innerHTML="",e(t)}.bind(this)),this._model.on("asyncDependenciesReady",function(){this._model.dependencySuccessCount>=1?(o.sendEvent(this._client,"appeared"),this._disableErroredPaymentMethods(),e(null,n)):this._model.cancelInitialization(new l("All payment options failed to load."))}.bind(this)),this._model.on("paymentMethodRequestable",function(e){this._emit("paymentMethodRequestable",e)}.bind(this)),this._model.on("noPaymentMethodRequestable",function(){this._emit("noPaymentMethodRequestable")}.bind(this)),this._model.on("paymentOptionSelected",function(e){this._emit("paymentOptionSelected",e)}.bind(this)),i=this._supportsPaymentOption(m.paypal)||this._supportsPaymentOption(m.paypalCredit),i&&!document.querySelector("#"+s.PAYPAL_CHECKOUT_SCRIPT_ID)?(r={src:s.CHECKOUT_JS_SOURCE,id:s.PAYPAL_CHECKOUT_SCRIPT_ID,logLevel:this._merchantConfiguration.paypal&&this._merchantConfiguration.paypal.logLevel||T},this._loadScript(r,function(){this._setUpDependenciesAndViews()}.bind(this))):this._setUpDependenciesAndViews()}.bind(this))):(o.sendEvent(this._client,"configuration-error"),void e(new l("options.selector or options.container must reference a valid DOM node.")))):(o.sendEvent(this._client,"configuration-error"),void e(new l("options.container is required.")))},r.prototype.updateConfiguration=function(e,t,i){P.indexOf(e)!==-1&&(this._mainView.getView(e).updateConfiguration(t,i),C.indexOf(e)!==-1&&(this._removeUnvaultedPaymentMethods(function(t){return t.type===s.paymentMethodTypes[e]}),this._navigateToInitialView()))},r.prototype.clearSelectedPaymentMethod=function(){this._removeUnvaultedPaymentMethods(),this._navigateToInitialView(),this._model.removeActivePaymentMethod()},r.prototype._setUpDataCollector=function(){var e=this,t=a({},e._merchantConfiguration.dataCollector,{client:e._client});this._model.asyncDependencyStarting(),i.braintree.dataCollector.create(t).then(function(t){e._dataCollectorInstance=t,e._model.asyncDependencyReady()}).catch(function(t){e._model.cancelInitialization(new l({message:"Data Collector failed to set up.",braintreeWebError:t}))})},r.prototype._setUpDependenciesAndViews=function(){var e,t;this._merchantConfiguration.dataCollector&&!document.querySelector("#"+s.DATA_COLLECTOR_SCRIPT_ID)&&(e=this._client.getVersion(),t={src:"https://js.braintreegateway.com/web/"+e+"/js/data-collector.min.js",id:s.DATA_COLLECTOR_SCRIPT_ID},this._loadScript(t,this._setUpDataCollector.bind(this))),this._mainView=new h({client:this._client,element:this._dropinWrapper,model:this._model,strings:this._strings})},r.prototype._removeUnvaultedPaymentMethods=function(e){e=e||function(){return!0},this._model.getPaymentMethods().forEach(function(t){e(t)&&!t.vaulted&&this._model.removePaymentMethod(t)}.bind(this))},r.prototype._navigateToInitialView=function(){var e,t,i=this._mainView.primaryView.ID===u;i&&(e=0===this._model.getPaymentMethods().length,e&&(t=1===this._model.supportedPaymentOptions.length,t?this._mainView.setPrimaryView(this._model.supportedPaymentOptions[0]):this._mainView.setPrimaryView(y)))},r.prototype._supportsPaymentOption=function(e){return this._model.supportedPaymentOptions.indexOf(e)!==-1},r.prototype._loadScript=function(e,t){var i=document.createElement("script");i.src=e.src,i.id=e.id,i.async=!0,e.logLevel&&i.setAttribute("data-log-level",e.logLevel),i.addEventListener("load",t),this._dropinWrapper.appendChild(i)},r.prototype._disableErroredPaymentMethods=function(){var e,t=Object.keys(this._model.failedDependencies);0!==t.length&&(e=this._mainView.getOptionsElements(),t.forEach(function(t){var i=e[t],r=i.div,n=i.clickHandler,a=this._model.failedDependencies[t],o=r.querySelector(".braintree-option__disabled-message");r.classList.add("braintree-disabled"),r.removeEventListener("click",n),"PAYPAL_SANDBOX_ACCOUNT_NOT_LINKED"===a.code?o.innerHTML=s.errors.PAYPAL_NON_LINKED_SANDBOX:o.textContent=a.message}.bind(this)))},r.prototype.requestPaymentMethod=function(){return this._mainView.requestPaymentMethod().then(function(e){return this._dataCollectorInstance&&(e.deviceData=this._dataCollectorInstance.deviceData),n(e)}.bind(this))},r.prototype._removeStylesheet=function(){var e=document.getElementById(s.STYLESHEET_ID);e&&e.parentNode.removeChild(e)},r.prototype._injectStylesheet=function(){var e,t,i,r;document.getElementById(s.STYLESHEET_ID)||(r=this._client.getConfiguration().gatewayConfiguration.assetsUrl,t=r+"/web/dropin/"+I+"/css/dropin.min.css",e=document.createElement("link"),i=document.head,e.setAttribute("rel","stylesheet"),e.setAttribute("type","text/css"),e.setAttribute("href",t),e.setAttribute("id",s.STYLESHEET_ID),i.firstChild?i.insertBefore(e,i.firstChild):i.appendChild(e))},r.prototype._getVaultedPaymentMethods=function(e){p(this._client)?e([]):this._client.request({endpoint:"payment_methods",method:"get",data:{defaultFirst:1}},function(t,i){var r;r=t?[]:i.paymentMethods.map(n),e(r)})},r.prototype.teardown=function(){var e,t,i=b.resolve(),r=this;return this._removeStylesheet(),this._mainView&&i.then(function(){return r._mainView.teardown().catch(function(t){e=t})}),this._dataCollectorInstance&&i.then(function(){return this._dataCollectorInstance.teardown().catch(function(e){t=new l({message:"Drop-in errored tearing down Data Collector.",braintreeWebError:e})})}.bind(this)),i.then(function(){return r._removeDropinWrapper()}).then(function(){return e?b.reject(e):t?b.reject(t):b.resolve()})},r.prototype.isPaymentMethodRequestable=function(){return this._model.isPaymentMethodRequestable()},r.prototype._removeDropinWrapper=function(){return this._dropinWrapper.parentNode.removeChild(this._dropinWrapper),b.resolve()},t.exports=g(r)}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{"./constants":76,"./dropin-model":77,"./lib/analytics":81,"./lib/assign":82,"./lib/dropin-error":86,"./lib/event-emitter":87,"./lib/is-guest-checkout":89,"./lib/promise":92,"./lib/uuid":95,"./translations":105,"./views/main-view":121,"./views/payment-methods-view":123,"./views/payment-options-view":124,"@braintree/wrap-promise":17}],79:[function(e,t,i){"use strict";function r(e){return e.authorization?o.create({authorization:e.authorization}).catch(function(e){return p.reject(new c({message:"There was an error creating Drop-in.",braintreeWebError:e}))}).then(function(t){return t=n(t),"TOKENIZATION_KEY"===t.getConfiguration().authorizationType?d.sendEvent(t,"started.tokenization-key"):d.sendEvent(t,"started.client-token"),new p(function(i,r){new a({merchantConfiguration:e,client:t})._initialize(function(e,t){return e?void r(e):void i(t)})})}):p.reject(new c("options.authorization is required."))}function n(e){var t=e.getConfiguration();return t.analyticsMetadata.integration=l.INTEGRATION,t.analyticsMetadata.integrationType=l.INTEGRATION,t.analyticsMetadata.dropinVersion=u,e.getConfiguration=function(){return t},e}var a=e("./dropin"),o=e("braintree-web/client"),s=e("./lib/create-from-script-tag"),l=e("./constants"),d=e("./lib/analytics"),c=e("./lib/dropin-error"),p=e("./lib/promise"),h=e("@braintree/wrap-promise"),u="1.7.0";s(r,"undefined"!=typeof document&&document.querySelector("script[data-braintree-dropin-authorization]")),t.exports={create:h(r),VERSION:u}},{"./constants":76,"./dropin":78,"./lib/analytics":81,"./lib/create-from-script-tag":85,"./lib/dropin-error":86,"./lib/promise":92,"@braintree/wrap-promise":17,"braintree-web/client":23}],80:[function(e,t,i){"use strict";function r(e,t){e.addEventListener("click",t),e.addEventListener("keyup",function(e){13===e.keyCode&&t()})}t.exports=r},{}],81:[function(e,t,i){"use strict";function r(e){return Math.floor(e/1e3)}function n(e,t,i){var n=e.getConfiguration(),l=e._request,d=r(Date.now()),c=n.gatewayConfiguration.analytics.url,p={analytics:[{kind:o.ANALYTICS_PREFIX+t,timestamp:d}],_meta:n.analyticsMetadata,braintreeLibraryVersion:s};"TOKENIZATION_KEY"===n.authorizationType?p.tokenizationKey=n.authorization:p.authorizationFingerprint=JSON.parse(a(n.authorization)).authorizationFingerprint,l({url:c,method:"post",data:p,timeout:o.ANALYTICS_REQUEST_TIMEOUT_MS},i)}var a=e("./polyfill").atob,o=e("../constants"),s=e("braintree-web/client").VERSION;t.exports={sendEvent:n}},{"../constants":76,"./polyfill":91,"braintree-web/client":23}],82:[function(e,t,i){arguments[4][42][0].apply(i,arguments)},{dup:42}],83:[function(e,t,i){"use strict";var r=e("@braintree/browser-detection/is-ie9");t.exports={isIe9:r}},{"@braintree/browser-detection/is-ie9":6}],84:[function(e,t,i){"use strict";function r(e){return e.className.trim().split(/\s+/)}function n(e,t){return new RegExp("\\b"+t+"\\b").test(e.className)}function a(e){var t=Array.prototype.slice.call(arguments,1),i=r(e).filter(function(e){return t.indexOf(e)===-1}).concat(t).join(" ");e.className=i}function o(e){var t=Array.prototype.slice.call(arguments,1),i=r(e).filter(function(e){return t.indexOf(e)===-1}).join(" ");e.className=i}function s(e,t,i){arguments.length<3?n(e,t)?o(e,t):a(e,t):i?a(e,t):o(e,t)}t.exports={add:a,remove:o,toggle:s}},{}],85:[function(e,t,i){"use strict";function r(e,t,i){var r=i.querySelector('[name="'+e+'"]');r||(r=document.createElement("input"),r.type="hidden",r.name=e,i.appendChild(r)),r.value=t}function n(e,t,i){var r=t.split("."),o=p(r[0]);1===r.length?e[o]=a(i):(e[o]=e[o]||{},n(e[o],r.slice(1).join("."),i))}function a(e){try{return JSON.parse(e)}catch(t){return e}}function o(e,t){var i,a,o,p;if(t){if(i=t.getAttribute("data-braintree-dropin-authorization"),!i)throw new c("Authorization not found in data-braintree-dropin-authorization attribute");if(a=document.createElement("div"),a.id="braintree-dropin-"+d(),p=l.findParentForm(t),!p)throw new c("No form found for script tag integration.");p.addEventListener("submit",function(e){e.preventDefault()}),p.insertBefore(a,t),o={authorization:i,container:a},h.forEach(function(e){var i=t.getAttribute("data-"+e);null!=i&&n(o,e,i)}),e(o).then(function(e){s.sendEvent(e._client,"integration-type.script-tag"),p.addEventListener("submit",function(){e.requestPaymentMethod(function(e,t){e||(r("payment_method_nonce",t.nonce,p),t.deviceData&&r("device_data",t.deviceData,p),p.submit())})})})}}var s=e("./analytics"),l=e("./find-parent-form"),d=e("./uuid"),c=e("./dropin-error"),p=e("./kebab-case-to-camel-case"),h=["locale","payment-option-priority","data-collector.kount","data-collector.paypal","card.cardholderName","card.cardholderName.required","paypal.amount","paypal.currency","paypal.flow","paypal-credit.amount","paypal-credit.currency","paypal-credit.flow"];t.exports=o},{"./analytics":81,"./dropin-error":86,"./find-parent-form":88,"./kebab-case-to-camel-case":90,"./uuid":95}],86:[function(e,t,i){"use strict";function r(e){return"BraintreeError"===e.name}function n(e){this.name="DropinError","string"==typeof e?this.message=e:this.message=e.message,r(e)?this._braintreeWebError=e:this._braintreeWebError=e.braintreeWebError}n.prototype=Object.create(Error.prototype),n.prototype.constructor=n,t.exports=n},{}],87:[function(e,t,i){arguments[4][57][0].apply(i,arguments)},{dup:57}],88:[function(e,t,i){"use strict";function r(e){var t=e.parentNode;return t&&"FORM"!==t.nodeName?r(t):t}t.exports={findParentForm:r}},{}],89:[function(e,t,i){"use strict";var r=e("./polyfill").atob;t.exports=function(e){var t,i=e.getConfiguration();return"TOKENIZATION_KEY"===i.authorizationType||(t=JSON.parse(r(i.authorization)).authorizationFingerprint,!t||t.indexOf("customer_id=")===-1)}},{"./polyfill":91}],90:[function(e,t,i){"use strict";function r(e){var t=e.split("-"),i=t.shift(),r=t.map(function(e){return e.charAt(0).toUpperCase()+e.substring(1)});return[i].concat(r).join("")}t.exports=r},{}],91:[function(e,t,i){(function(e){"use strict";function i(e){var t,i,r,n,a,o,s,l,d=new RegExp("^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{4})([=]{1,2})?$"),c="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",p="";if(!d.test(e))throw new Error("Non base64 encoded input passed to window.atob polyfill");l=0;do n=c.indexOf(e.charAt(l++)),a=c.indexOf(e.charAt(l++)),o=c.indexOf(e.charAt(l++)),s=c.indexOf(e.charAt(l++)),t=(63&n)<<2|a>>4&3,i=(15&a)<<4|o>>2&15,r=(3&o)<<6|63&s,p+=String.fromCharCode(t)+(i?String.fromCharCode(i):"")+(r?String.fromCharCode(r):"");while(l1,i=this.model.getPaymentMethods();this._views={},this.sheetContainer=this.getElementById("sheet-container"),this.sheetErrorText=this.getElementById("sheet-error-text"),this.toggle=this.getElementById("toggle"),this.lowerContainer=this.getElementById("lower-container"),this.loadingContainer=this.getElementById("loading-container"),this.loadingIndicator=this.getElementById("loading-indicator"),this.dropinContainer=this.element.querySelector(".braintree-dropin"),this.supportsFlexbox=m(),this.model.on("asyncDependenciesReady",this.hideLoadingIndicator.bind(this)),this.model.on("errorOccurred",this.showSheetError.bind(this)),this.model.on("errorCleared",this.hideSheetError.bind(this)),this.paymentSheetViewIDs=Object.keys(c).reduce(function(e,t){var i,r;return this.model.supportedPaymentOptions.indexOf(t)!==-1&&(i=c[t],r=new i({element:this.getElementById(i.ID),mainView:this,model:this.model,client:this.client,strings:this.strings}),r.initialize(),this.addView(r),e.push(r.ID)),e}.bind(this),[]),this.paymentMethodsViews=new p({element:this.element,model:this.model,strings:this.strings}),this.addView(this.paymentMethodsViews),u(this.toggle,this.toggleAdditionalOptions.bind(this)),this.model.on("changeActivePaymentMethod",function(){setTimeout(function(){this.setPrimaryView(p.ID)}.bind(this),v)}.bind(this)),this.model.on("changeActivePaymentView",function(e){var t=this.getView(e);e===p.ID?(d.add(this.paymentMethodsViews.container,"braintree-methods--active"),d.remove(this.sheetContainer,"braintree-sheet--active")):(setTimeout(function(){d.add(this.sheetContainer,"braintree-sheet--active")}.bind(this),0),d.remove(this.paymentMethodsViews.container,"braintree-methods--active"),this.getView(e).getPaymentMethod()||this.model.setPaymentMethodRequestable({isRequestable:!1})),t.onSelection()}.bind(this)),this.model.on("removeActivePaymentMethod",function(){var e=this.getView(this.model.getActivePaymentView());e&&"function"==typeof e.removeActivePaymentMethod&&e.removeActivePaymentMethod()}.bind(this)),t&&(e=new h({client:this.client,element:this.getElementById(h.ID),mainView:this,model:this.model,strings:this.strings}),this.addView(e)),i.length>0?this.model.changeActivePaymentMethod(i[0]):t?this.setPrimaryView(e.ID):this.setPrimaryView(this.paymentSheetViewIDs[0])},r.prototype.addView=function(e){this._views[e.ID]=e},r.prototype.getView=function(e){return this._views[e]},r.prototype.setPrimaryView=function(e,t){var i;setTimeout(function(){this.element.className=a(e),t&&d.add(this.element,a(t))}.bind(this),0),this.primaryView=this.getView(e),this.model.changeActivePaymentView(e),this.paymentSheetViewIDs.indexOf(e)!==-1?this.model.getPaymentMethods().length>0||this.getView(h.ID)?this.showToggle():this.hideToggle():e===p.ID?(this.showToggle(),this.getElementById("lower-container").appendChild(this.getElementById("options"))):e===h.ID&&this.hideToggle(),this.supportsFlexbox||this.element.setAttribute("data-braintree-no-flexbox",!0),i=this.primaryView.getPaymentMethod(),this.model.setPaymentMethodRequestable({isRequestable:Boolean(i),type:i&&i.type,selectedPaymentMethod:i}),this.model.clearError()},r.prototype.requestPaymentMethod=function(){var e=this.getView(this.model.getActivePaymentView());return e.requestPaymentMethod().then(function(e){return o.sendEvent(this.client,"request-payment-method."+s[e.type]),e}.bind(this)).catch(function(e){return o.sendEvent(this.client,"request-payment-method.error"),y.reject(e)}.bind(this))},r.prototype.hideLoadingIndicator=function(){d.add(this.dropinContainer,"braintree-loaded"),f.onTransitionEnd(this.loadingIndicator,"transform",function(){this.loadingContainer.parentNode.removeChild(this.loadingContainer)}.bind(this))},r.prototype.toggleAdditionalOptions=function(){var e,t=this.model.supportedPaymentOptions.length>1,i=this.paymentSheetViewIDs.indexOf(this.primaryView.ID)!==-1;this.hideToggle(),t?i?0===this.model.getPaymentMethods().length?this.setPrimaryView(h.ID):(this.setPrimaryView(p.ID,h.ID),this.hideToggle()):d.add(this.element,a(h.ID)):(e=this.paymentSheetViewIDs[0],d.add(this.element,a(e)),this.model.changeActivePaymentView(e))},r.prototype.showToggle=function(){d.remove(this.toggle,"braintree-hidden"),d.add(this.lowerContainer,"braintree-hidden")},r.prototype.hideToggle=function(){d.add(this.toggle,"braintree-hidden"),d.remove(this.lowerContainer,"braintree-hidden")},r.prototype.showSheetError=function(e){var t,i=this.strings.genericError;this.strings.hasOwnProperty(e)?t=this.strings[e]:e&&e.code&&(t=this.strings[n(e.code)+"Error"]),t&&(i=t),d.add(this.sheetContainer,"braintree-sheet--has-error"),this.sheetErrorText.textContent=i},r.prototype.hideSheetError=function(){d.remove(this.sheetContainer,"braintree-sheet--has-error")},r.prototype.getOptionsElements=function(){return this._views.options.elements},r.prototype.teardown=function(){var e,t=Object.keys(this._views),i=t.map(function(t){return this._views[t].teardown().catch(function(t){e=t})}.bind(this));return y.all(i).then(function(){return e?y.reject(e):y.resolve()})},t.exports=r},{"../constants":76,"../lib/add-selection-event-handler":80,"../lib/analytics":81,"../lib/classlist":84,"../lib/promise":92,"../lib/supports-flexbox":93,"../lib/transition-helper":94,"./base-view":120,"./payment-methods-view":123,"./payment-options-view":124,"./payment-sheet-views":127}],122:[function(e,t,i){"use strict";function r(){n.apply(this,arguments),this._initialize()}var n=e("./base-view"),a=e("../lib/classlist"),o=e("../constants"),s=e("../lib/add-selection-event-handler"),l='\n\n
@TITLE
@SUBTITLE
\n\n
\n
\n \n \n \n
\n
\n';r.prototype=Object.create(n.prototype),r.prototype.constructor=r,r.prototype._initialize=function(){var e,t=l,i=o.paymentMethodCardTypes,r=o.paymentMethodTypes;switch(this.element=document.createElement("div"),this.element.className="braintree-method",this.element.setAttribute("tabindex","0"),s(this.element,function(){this.model.changeActivePaymentMethod(this.paymentMethod)}.bind(this)),this.paymentMethod.type){case r.card:e=this.strings.endingIn.replace("{{lastTwoCardDigits}}",this.paymentMethod.details.lastTwo),t=t.replace(/@ICON/g,"icon-"+i[this.paymentMethod.details.cardType]).replace(/@CLASSNAME/g," braintree-icon--bordered").replace(/@TITLE/g,e).replace(/@SUBTITLE/g,this.strings[this.paymentMethod.details.cardType]);break;case r.paypal:t=t.replace(/@ICON/g,"logoPayPal").replace(/@CLASSNAME/g,"").replace(/@TITLE/g,this.paymentMethod.details.email).replace(/@SUBTITLE/g,this.strings.PayPal)}this.element.innerHTML=t},r.prototype.setActive=function(e){setTimeout(function(){a.toggle(this.element,"braintree-method--active",e)}.bind(this),0)},t.exports=r},{"../constants":76,"../lib/add-selection-event-handler":80,"../lib/classlist":84,"./base-view":120}],123:[function(e,t,i){"use strict";function r(){n.apply(this,arguments),this._initialize()}var n=e("./base-view"),a=e("./payment-method-view"),o=e("../lib/dropin-error"),s=e("../lib/classlist"),l=e("../constants").errors,d=e("../lib/promise"),c={CreditCard:"Card",PayPalAccount:"PayPal"};r.prototype=Object.create(n.prototype),r.prototype.constructor=r,r.ID=r.prototype.ID="methods",r.prototype._initialize=function(){var e,t=this.model.getPaymentMethods();for(this.views=[],this.container=this.getElementById("methods-container"),this._headingLabel=this.getElementById("methods-label"),this.model.on("addPaymentMethod",this._addPaymentMethod.bind(this)),this.model.on("removePaymentMethod",this._removePaymentMethod.bind(this)),this.model.on("changeActivePaymentMethod",this._changeActivePaymentMethodView.bind(this)),e=t.length-1;e>=0;e--)this._addPaymentMethod(t[e])},r.prototype.removeActivePaymentMethod=function(){this.activeMethodView&&(this.activeMethodView.setActive(!1),this.activeMethodView=null,s.add(this._headingLabel,"braintree-no-payment-method-selected"))},r.prototype._getPaymentMethodString=function(){var e=c[this.activeMethodView.paymentMethod.type],t=this.strings[e];return this.strings.payingWith.replace("{{paymentSource}}",t)},r.prototype._addPaymentMethod=function(e){var t=new a({model:this.model,paymentMethod:e,strings:this.strings});this.model.isGuestCheckout&&this.container.firstChild&&(this.container.removeChild(this.container.firstChild),this.views.pop()),this.container.firstChild?this.container.insertBefore(t.element,this.container.firstChild):this.container.appendChild(t.element),this.views.push(t)},r.prototype._removePaymentMethod=function(e){var t;for(t=0;t