diff --git a/.babelrc b/.babelrc new file mode 100644 index 0000000..4f06b0c --- /dev/null +++ b/.babelrc @@ -0,0 +1,6 @@ +{ + "presets": [ + "@babel/preset-env", + "@babel/preset-react" + ] +} diff --git a/.gitignore b/.gitignore index 59b30be..c0a6b32 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,10 @@ npm-debug.log ssl-keys dart-sass dump.rdb +formspree/static/bundle.js +formspree/static/bundle.min.js +formspree/static/main.css +*tmp-browserify* # C extensions *.so diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..2369f27 --- /dev/null +++ b/Makefile @@ -0,0 +1,19 @@ +all: formspree/static/bundle.js formspree/static/main.css + +watch: + find formspree/js/ formspree/scss/ -name '*.js' -o -name '*.scss' | entr make + +$(shell find formspree/js/): + ./node_modules/.bin/prettier "formspree/js/**/*.js" + +formspree/static/bundle.js: $(shell find formspree/js) + ./node_modules/.bin/browserify formspree/js/main.js -dv --outfile formspree/static/bundle.js + +formspree/static/bundle.min.js: $(shell find formspree/js) + ./node_modules/.bin/browserify formspree/js/main.js -g [ envify --NODE_ENV production ] -g uglifyify | ./node_modules/.bin/uglifyjs --compress --mangle > formspree/static/bundle.min.js + +formspree/static/main.css: $(shell find formspree/scss) dart-sass/src/dart + cd dart-sass && ./sass ../formspree/scss/main.scss ../formspree/static/main.css + +dart-sass/src/dart: + echo -e "\n\ninstall dart-sass from https://github.com/sass/dart-sass/releases\n\n" diff --git a/formspree/forms/api.py b/formspree/forms/api.py new file mode 100644 index 0000000..0d42c6d --- /dev/null +++ b/formspree/forms/api.py @@ -0,0 +1,203 @@ +from flask import request, jsonify, g +from flask_login import current_user, login_required + +from formspree import settings +from formspree.stuff import DB +from formspree.utils import jsonerror, IS_VALID_EMAIL +from .helpers import referrer_to_path, sitewide_file_check, remove_www, \ + referrer_to_baseurl +from .models import Form, Submission + + +@login_required +def list(): + # grab all the forms this user controls + if current_user.upgraded: + forms = current_user.forms.order_by(Form.id.desc()).all() + else: + forms = [] + + return jsonify({ + 'ok': True, + 'user': { + 'upgraded': current_user.upgraded, + 'email': current_user.email + }, + 'forms': [f.serialize() for f in forms] + }) + + +@login_required +def create(): + # check that this request came from user dashboard to prevent XSS and CSRF + referrer = referrer_to_baseurl(request.referrer) + service = referrer_to_baseurl(settings.SERVICE_URL) + if referrer != service: + return jsonerror(400, {'error': 'Improper request.'}) + + if not current_user.upgraded: + g.log.info('Failed to create form from dashboard. User is not upgraded.') + return jsonerror(402, {'error': "Please upgrade your account."}) + + email = request.get_json().get('email') + url = request.get_json().get('url') + sitewide = request.get_json().get('sitewide') + + g.log = g.log.bind(email=email, url=url, sitewide=sitewide) + + if not IS_VALID_EMAIL(email): + g.log.info('Failed to create form from dashboard. Invalid address.') + return jsonerror(400, {'error': "The provided email address is not valid."}) + + g.log.info('Creating a new form from the dashboard.') + + email = email.lower().strip() # case-insensitive + form = Form(email, owner=current_user) + if url: + url = 'http://' + url if not url.startswith('http') else url + form.host = referrer_to_path(url) + + # sitewide forms, verified with a file at the root of the target domain + if sitewide: + if sitewide_file_check(url, email): + form.host = remove_www(referrer_to_path(urljoin(url, '/'))[:-1]) + form.sitewide = True + else: + return jsonerror(403, { + 'error': u"Couldn't verify the file at {}.".format(url) + }) + + DB.session.add(form) + DB.session.commit() + + if form.host: + # when the email and url are provided, we can automatically confirm the form + # but only if the email is registered for this account + for email in current_user.emails: + if email.address == form.email: + g.log.info('No need for email confirmation.') + form.confirmed = True + DB.session.add(form) + DB.session.commit() + break + else: + # in case the email isn't registered for this user + # we automatically send the email confirmation + form.send_confirmation() + + return jsonify({ + 'ok': True, + 'hashid': form.hashid, + 'submission_url': settings.API_ROOT + '/' + form.hashid, + 'confirmed': form.confirmed + }) + + +@login_required +def get(hashid): + if not current_user.upgraded: + return jsonerror(402, {'error': "Please upgrade your account."}) + + form = Form.get_with_hashid(hashid) + if not form: + return jsonerror(404, {'error': "Form not found."}) + + for cont in form.controllers: + if cont.id == current_user.id: break + else: + return jsonerror(401, {'error': "You do not control this form."}) + + submissions, fields = form.submissions_with_fields() + + ret = form.serialize() + ret['submissions'] = submissions + ret['fields'] = fields + + return jsonify(ret) + + +@login_required +def update(hashid): + # check that this request came from user dashboard to prevent XSS and CSRF + referrer = referrer_to_baseurl(request.referrer) + service = referrer_to_baseurl(settings.SERVICE_URL) + if referrer != service: + return jsonerror(400, {'error': 'Improper request.'}) + + form = Form.get_with_hashid(hashid) + if not form: + return jsonerror(400, {'error': 'Not a valid form.'}) + + if form.owner_id != current_user.id and form not in current_user.forms: + return jsonerror(401, {'error': 'Wrong user.'}) + + patch = request.get_json() + + for attr in ['disable_storage', 'disabled', 'disable_email', 'captcha_disabled']: + if attr in patch: + setattr(form, attr, patch[attr]) + + DB.session.add(form) + DB.session.commit() + return jsonify({'ok': True}) + + +@login_required +def delete(hashid): + # check that this request came from user dashboard to prevent XSS and CSRF + referrer = referrer_to_baseurl(request.referrer) + service = referrer_to_baseurl(settings.SERVICE_URL) + + if referrer != service: + return jsonerror(400, {'error': 'Improper request.'}) + + form = Form.get_with_hashid(hashid) + if not form: + return jsonerror(400, {'error': 'Not a valid form.'}) + + if form.owner_id != current_user.id and form not in current_user.forms: + return jsonerror(401, {'error': 'Wrong user.'}) + + for submission in form.submissions: + DB.session.delete(submission) + DB.session.delete(form) + DB.session.commit() + + return jsonify({'ok': True}) + + +@login_required +def submission_delete(hashid, submissionid): + # check that this request came from user dashboard to prevent XSS and CSRF + referrer = referrer_to_baseurl(request.referrer) + service = referrer_to_baseurl(settings.SERVICE_URL) + if referrer != service: + return jsonerror(400, {'error': 'Improper request.'}) + + form = Form.get_with_hashid(hashid) + if not form: + return jsonerror(400, {'error': 'Not a valid form.'}) + + if form.owner_id != current_user.id and form not in current_user.forms: + return jsonerror(401, {'error': 'Wrong user.'}) + + submission = Submission.query.get(submissionid) + if not submission: + return jsonerror(401, 'Not a valid submission.') + + DB.session.delete(submission) + form.counter -= 1 + DB.session.add(form) + DB.session.commit() + return jsonify({'ok': True}) + + +@login_required +def sitewide_check(): + email = request.get_json().get('email') + url = request.get_json().get('url') + + if sitewide_file_check(url, email): + return jsonify({'ok': True}) + else: + return jsonify({'ok': False}) diff --git a/formspree/forms/helpers.py b/formspree/forms/helpers.py index 02c8f96..575f382 100644 --- a/formspree/forms/helpers.py +++ b/formspree/forms/helpers.py @@ -91,20 +91,22 @@ def sitewide_file_check(url, email): g.log = g.log.bind(url=url, email=email) - res = requests.get(url, timeout=3, headers={ - 'User-Agent': 'Mozilla/5.0 (X11; Linux i686) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/55.0.2883.87 Chrome/55.0.2883.87 Safari/537.36' - }) - if not res.ok: - g.log.debug('Sitewide file not found.', contents=res.text[:100]) - return False + try: + res = requests.get(url, timeout=3, headers={ + 'User-Agent': 'Mozilla/5.0 (X11; Linux i686) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/55.0.2883.87 Chrome/55.0.2883.87 Safari/537.36' + }) + if not res.ok: + g.log.debug('Sitewide file not found.', contents=res.text[:100]) + return False - for line in res.text.splitlines(): - line = line.strip(u'\xef\xbb\xbf ') - if line == email: - g.log.debug('Email found in sitewide file.') - return True + for line in res.text.splitlines(): + line = line.strip(u'\xef\xbb\xbf ') + if line == email: + g.log.debug('Email found in sitewide file.') + return True + except requests.exceptions.ConnectionError: + pass - g.log.warn('Email not found in sitewide file.', contents=res.text[:100]) return False @@ -119,14 +121,6 @@ def verify_captcha(form_data, request): return r.ok and r.json().get('success') -def valid_domain_request(request): - # check that this request came from user dashboard to prevent XSS and CSRF - referrer = referrer_to_baseurl(request.referrer) - service = referrer_to_baseurl(settings.SERVICE_URL) - - return referrer == service - - def assign_ajax(form, sent_using_ajax): if form.uses_ajax is None: form.uses_ajax = sent_using_ajax @@ -168,16 +162,3 @@ def fetch_first_submission(nonce): return json.loads(jsondata.decode('utf-8')) except: return None - -def check_valid_form_settings_request(form): - if not valid_domain_request(request): - return jsonify(error='The request you made is not valid.
Please visit your dashboard and try again.'), 400 - - if form.owner_id != current_user.id and form not in current_user.forms: - return jsonify( - error='You aren\'t the owner of that form.
Please log in as the form owner and try again.'), 400 - - if not form: - return jsonify(error='That form does not exist. Please check the link and try again.'), 400 - - return True diff --git a/formspree/forms/models.py b/formspree/forms/models.py index c204585..0e527ab 100644 --- a/formspree/forms/models.py +++ b/formspree/forms/models.py @@ -116,6 +116,47 @@ class Form(DB.Model): except IndexError: return None + def serialize(self): + return { + 'sitewide': self.sitewide, + 'hashid': self.hashid, + 'hash': self.hash, + 'counter': self.counter, + 'email': self.email, + 'host': self.host, + 'confirm_sent': self.confirm_sent, + 'confirmed': self.confirmed, + 'disabled': self.disabled, + 'captcha_disabled': self.captcha_disabled, + 'disable_email': self.disable_email, + 'disable_storage': self.disable_storage, + 'is_public': bool(self.hash), + 'url': '{S}/{E}'.format( + S=settings.SERVICE_URL, + E=self.hashid + ) + } + + def submissions_with_fields(self): + ''' + Fetch all submissions, extract all fields names from every submission + into a single fields list, excluding the KEYS_NOT_STORED values, because + they are worthless. + Add the special 'date' field to every submission entry, based on + .submitted_at, and use this as the first field on the fields array. + ''' + + fields = set() + submissions = [] + for s in self.submissions: + fields.update(s.data.keys()) + s.data['date'] = s.submitted_at.isoformat() + s.data['id'] = s.id + submissions.append(s.data) + + fields = ['date'] + sorted(fields - KEYS_NOT_STORED) + return submissions, fields + def send(self, data, keys, referrer): ''' Sends form to user's email. diff --git a/formspree/forms/views.py b/formspree/forms/views.py index 7d8fcb5..7c35df0 100644 --- a/formspree/forms/views.py +++ b/formspree/forms/views.py @@ -20,9 +20,7 @@ from formspree.utils import request_wants_json, jsonerror, IS_VALID_EMAIL, \ from .helpers import http_form_to_dict, ordered_storage, referrer_to_path, \ remove_www, referrer_to_baseurl, sitewide_file_check, \ verify_captcha, temp_store_hostname, get_temp_hostname, \ - HASH, assign_ajax, valid_domain_request, \ - KEYS_NOT_STORED, KEYS_EXCLUDED_FROM_EMAIL, \ - check_valid_form_settings_request + HASH, assign_ajax, KEYS_EXCLUDED_FROM_EMAIL from .models import Form, Submission @@ -486,349 +484,50 @@ def confirm_email(nonce): @login_required -def forms(): - ''' - A reminder: this is the /forms endpoint, but for GET requests - it is also the /dashboard endpoint. - - The /dashboard endpoint, the address gave by url_for('dashboard'), - is the target of a lot of redirects around the app, but it can - be changed later to point to somewhere else. - ''' - - # grab all the forms this user controls - if current_user.upgraded: - forms = current_user.forms.order_by(Form.id.desc()).all() - else: - forms = [] - - if request_wants_json(): - return jsonify({ - 'ok': True, - 'forms': [{ - 'email': f.email, - 'host': f.host, - 'confirm_sent': f.confirm_sent, - 'confirmed': f.confirmed, - 'is_public': bool(f.hash), - 'url': '{S}/{E}'.format( - S=settings.SERVICE_URL, - E=f.hashid - ) - } for f in forms] - }) - else: - return render_template('forms/list.html', - enabled_forms=[form for form in forms if not form.disabled], - disabled_forms=[form for form in forms if form.disabled] - ) +def serve_dashboard(hashid=None, s=None): + return render_template('forms/dashboard.html') @login_required -def create_form(): - # create a new form - - if not current_user.upgraded: - g.log.info('Failed to create form from dashboard. User is not upgraded.') - return jsonerror(402, {'error': "Please upgrade your account."}) - - if request.get_json(): - email = request.get_json().get('email') - url = request.get_json().get('url') - sitewide = request.get_json().get('sitewide') - else: - email = request.form.get('email') - url = request.form.get('url') - sitewide = request.form.get('sitewide') - - g.log = g.log.bind(email=email, url=url, sitewide=sitewide) - - if not IS_VALID_EMAIL(email): - g.log.info('Failed to create form from dashboard. Invalid address.') - if request_wants_json(): - return jsonerror(400, {'error': "The provided email address is not valid."}) - else: - flash(u'The provided email address is not valid.', 'error') - return redirect(url_for('dashboard')) - - g.log.info('Creating a new form from the dashboard.') - - email = email.lower() # case-insensitive - form = Form(email, owner=current_user) - if url: - url = 'http://' + url if not url.startswith('http') else url - form.host = referrer_to_path(url) - - # sitewide forms, verified with a file at the root of the target domain - if sitewide: - if sitewide_file_check(url, email): - form.host = remove_www(referrer_to_path(urljoin(url, '/'))[:-1]) - form.sitewide = True - else: - return jsonerror(403, { - 'error': u"Couldn't verify the file at {}.".format(url) - }) - - DB.session.add(form) - DB.session.commit() - - if form.host: - # when the email and url are provided, we can automatically confirm the form - # but only if the email is registered for this account - for email in current_user.emails: - if email.address == form.email: - g.log.info('No need for email confirmation.') - form.confirmed = True - DB.session.add(form) - DB.session.commit() - break - else: - # in case the email isn't registered for this user - # we automatically send the email confirmation - form.send_confirmation() - - if request_wants_json(): - return jsonify({ - 'ok': True, - 'hashid': form.hashid, - 'submission_url': settings.API_ROOT + '/' + form.hashid, - 'confirmed': form.confirmed - }) - else: - flash(u'Your new form endpoint was created!', 'success') - return redirect(url_for('dashboard', new=form.hashid) + '#form-' + form.hashid) - - -@login_required -def sitewide_check(): - email = request.args.get('email') - url = request.args.get('url') - - if sitewide_file_check(url, email): - return '', 200 - else: - return '', 404 - - -@login_required -def form_submissions(hashid, format=None): +def export_submissions(hashid, format=None): if not current_user.upgraded: return jsonerror(402, {'error': "Please upgrade your account."}) form = Form.get_with_hashid(hashid) - for cont in form.controllers: if cont.id == current_user.id: break else: - if request_wants_json(): - return jsonerror(403, {'error': "You do not control this form."}) - else: - return redirect(url_for('dashboard')) + return abort(401) - if not format: - # normal request. - if request_wants_json(): - return jsonify({ + submissions, fields = form.submissions_with_fields() + + if format == 'json': + return Response( + json.dumps({ 'host': form.host, 'email': form.email, - 'submissions': [dict(s.data, date=s.submitted_at.isoformat()) for s in form.submissions] - }) - else: - fields = set() - for s in form.submissions: - fields.update(s.data.keys()) - fields -= KEYS_NOT_STORED + 'fields': fields, + 'submissions': submissions + }, sort_keys=True, indent=2), + mimetype='application/json', + headers={ + 'Content-Disposition': 'attachment; filename=form-%s-submissions-%s.json' \ + % (hashid, datetime.datetime.now().isoformat().split('.')[0]) + } + ) + elif format == 'csv': + out = io.BytesIO() + + w = csv.DictWriter(out, fieldnames=fields, encoding='utf-8') + w.writeheader() + for sub in submissions: + w.writerow(sub) - submissions = [] - for sub in form.submissions: - for f in fields: - value = sub.data.get(f, '') - typ = type(value) - sub.data[f] = value if typ is str \ - else pyaml.dump(value, safe=True) - submissions.append(sub) - - return render_template('forms/submissions.html', - form=form, - fields=sorted(fields), - submissions=submissions - ) - elif format: - # an export request, format can be json or csv - if format == 'json': - return Response( - json.dumps({ - 'host': form.host, - 'email': form.email, - 'submissions': [dict(s.data, date=s.submitted_at.isoformat()) for s in form.submissions] - }, sort_keys=True, indent=2), - mimetype='application/json', - headers={ - 'Content-Disposition': 'attachment; filename=form-%s-submissions-%s.json' \ - % (hashid, datetime.datetime.now().isoformat().split('.')[0]) - } - ) - elif format == 'csv': - out = io.BytesIO() - fieldnames = set(field for sub in form.submissions for field in sub.data.keys()) - fieldnames = ['date'] + sorted(fieldnames) - - w = csv.DictWriter(out, fieldnames=fieldnames, encoding='utf-8') - w.writeheader() - for sub in form.submissions: - w.writerow(dict(sub.data, date=sub.submitted_at.isoformat())) - - return Response( - out.getvalue(), - mimetype='text/csv', - headers={ - 'Content-Disposition': 'attachment; filename=form-%s-submissions-%s.csv' \ - % (hashid, datetime.datetime.now().isoformat().split('.')[0]) - } - ) - - -@login_required -def form_recaptcha_toggle(hashid): - form = Form.get_with_hashid(hashid) - valid_check = check_valid_form_settings_request(form) - if valid_check != True: - return valid_check - - checked_status = request.json['checked'] - form.captcha_disabled = not checked_status - DB.session.add(form) - DB.session.commit() - - if form.captcha_disabled: - return jsonify(disabled=True, message='CAPTCHA successfully disabled') - else: - return jsonify(disabled=False, message='CAPTCHA successfully enabled') - -@login_required -def form_email_notification_toggle(hashid): - form = Form.get_with_hashid(hashid) - valid_check = check_valid_form_settings_request(form) - if valid_check != True: - return valid_check - - checked_status = request.json['checked'] - form.disable_email = not checked_status - DB.session.add(form) - DB.session.commit() - - if form.disable_email: - return jsonify(disabled=True, message='Email notifications successfully disabled') - else: - return jsonify(disabled=False, message='Email notifications successfully enabled') - -@login_required -def form_archive_toggle(hashid): - form = Form.get_with_hashid(hashid) - valid_check = check_valid_form_settings_request(form) - if valid_check != True: - return valid_check - - checked_status = request.json['checked'] - form.disable_storage = not checked_status - DB.session.add(form) - DB.session.commit() - - if form.disable_storage: - return jsonify(disabled=True, message='Submission archive successfully disabled') - else: - return jsonify(disabled=False, message='Submission archive successfully enabled') - -@login_required -def form_toggle(hashid): - form = Form.get_with_hashid(hashid) - - # check that this request came from user dashboard to prevent XSS and CSRF - if not valid_domain_request(request): - return render_template('error.html', - title='Improper Request', - text='The request you made is not valid.
Please visit your dashboard and try again.'), 400 - - if form.owner_id != current_user.id: - if form not in current_user.forms: #accounts for bug when form isn't assigned owner_id bc it was not created from dashboard - return render_template('error.html', - title='Wrong user', - text='You aren\'t the owner of that form.
Please log in as the form owner and try again.'), 400 - if not form: - return render_template('error.html', - title='Not a valid form', - text='That form does not exist.
Please check the link and try again.'), 400 - else: - form.disabled = not form.disabled - DB.session.add(form) - DB.session.commit() - if form.disabled: - flash(u'Form successfully disabled', 'success') - else: - flash(u'Form successfully enabled', 'success') - return redirect(url_for('dashboard')) - - -@login_required -def form_deletion(hashid): - form = Form.get_with_hashid(hashid) - - # check that this request came from user dashboard to prevent XSS and CSRF - referrer = referrer_to_baseurl(request.referrer) - service = referrer_to_baseurl(settings.SERVICE_URL) - if referrer != service: - return render_template('error.html', - title='Improper Request', - text='The request you made is not valid.
Please visit your dashboard and try again.'), 400 - - if form.owner_id != current_user.id: - if form not in current_user.forms: #accounts for bug when form isn't assigned owner_id bc it was not created from dashboard - return render_template('error.html', - title='Wrong user', - text='You aren\'t the owner of that form.
Please log in as the form owner and try again.'), 400 - if not form: - return render_template('error.html', - title='Not a valid form', - text='That form does not exist.
Please check the link and try again.'), 400 - else: - for submission in form.submissions: - DB.session.delete(submission) - DB.session.delete(form) - DB.session.commit() - flash(u'Form successfully deleted', 'success') - return redirect(url_for('dashboard')) - - -@login_required -def submission_deletion(hashid, submissionid): - submission = Submission.query.get(submissionid) - form = Form.get_with_hashid(hashid) - - # check that this request came from user dashboard to prevent XSS and CSRF - referrer = referrer_to_baseurl(request.referrer) - service = referrer_to_baseurl(settings.SERVICE_URL) - if referrer != service: - return render_template('error.html', - title='Improper Request', - text='The request you made is not valid.
Please visit your dashboard and try again.'), 400 - - if form.owner_id != current_user.id: - if form not in current_user.forms: #accounts for bug when form isn't assigned owner_id bc it was not created from dashboard - return render_template('error.html', - title='Wrong user', - text='You aren\'t the owner of that form.
Please log in as the form owner and try again.' + str(form.id)), 400 - if not submission: - return render_template('error.html', - title='Not a valid submission', - text='That submission does not exist.
Please check the link and try again.'), 400 - elif submission.form_id != form.id: - return render_template('error.html', - title='Not a valid submissions', - text='That submission does not match the form provided.
Please check the link and try again.'), 400 - else: - DB.session.delete(submission) - form.counter -= 1 - DB.session.add(form) - DB.session.commit() - flash(u'Submission successfully deleted', 'success') - return redirect(url_for('form-submissions', hashid=hashid)) + return Response( + out.getvalue(), + mimetype='text/csv', + headers={ + 'Content-Disposition': 'attachment; filename=form-%s-submissions-%s.csv' \ + % (hashid, datetime.datetime.now().isoformat().split('.')[0]) + } + ) diff --git a/formspree/js/forms/CreateForm.js b/formspree/js/forms/CreateForm.js new file mode 100644 index 0000000..c278aaa --- /dev/null +++ b/formspree/js/forms/CreateForm.js @@ -0,0 +1,262 @@ +/** @format */ + +const url = require('url') +const isValidUrl = require('valid-url').isWebUri +const isValidEmail = require('is-valid-email') +const React = require('react') +const toastr = window.toastr + +const modals = require('../modals') + +module.exports = class CreateForm extends React.Component { + constructor(props) { + super(props) + + this.setEmail = this.setEmail.bind(this) + this.setURL = this.setURL.bind(this) + this.setSitewide = this.setSitewide.bind(this) + this.validate = this.validate.bind(this) + this.create = this.create.bind(this) + this.checkSitewide = this.checkSitewide.bind(this) + + this.state = { + url: '', + email: '', + sitewide: false, + + invalid: null, + verified: false, + disableVerification: false + } + } + + componentDidMount() { + modals() + } + + render() { + if (!this.props.user.upgraded) { + return ( +
+ Please upgrade your account in order to create + forms from the dashboard and manage the forms currently associated + with your emails. +
+ ) + } + + let { + email, + url: urlv, + sitewide, + invalid, + verified, + disableVerification + } = this.state + + return ( +
+
+ + Create a form + + + +
+
+ ) + } + + setEmail(e) { + this.setState({email: e.target.value}, this.validate) + } + + setURL(e) { + this.setState({url: e.target.value}, this.validate) + } + + setSitewide(e) { + this.setState({sitewide: e.target.checked}, this.validate) + } + + validate() { + this.setState(st => { + st.invalid = null + + let {email, url: urlv, sitewide} = st + urlv = /^https?:\/\//.test(urlv) ? urlv : 'http://' + urlv + + if (!isValidEmail(email)) { + st.invalid = 'email' + return + } + + if (sitewide) { + if (urlv && !isValidUrl(urlv)) { + st.invalid = 'urlv' + } + } else { + if (urlv && urlv !== 'http://' && !isValidUrl(urlv)) { + st.invalid = 'urlv' + } + } + + return st + }) + } + + async checkSitewide(e) { + e.preventDefault() + + try { + let r = await (await fetch(`/api/forms/sitewide-check`, { + method: 'POST', + body: JSON.stringify({email: this.state.email, url: this.state.url}), + credentials: 'same-origin', + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json' + } + })).json() + + if (!r.ok) { + toastr.warning("The verification file wasn't found.") + this.setState({verified: false, disableVerification: true}) + + setTimeout(() => { + this.setState({disableVerification: false}) + }, 5000) + return + } + + toastr.success('The file exists! you can create your site-wide form now.') + this.setState({verified: true}) + } catch (e) { + console.error(e) + toastr.error(e.message) + } + } + + async create(e) { + e.preventDefault() + + try { + let r = await (await fetch('/api/forms', { + method: 'POST', + body: JSON.stringify({ + email: this.state.email, + url: this.state.url, + sitewide: this.state.sitewide + }), + credentials: 'same-origin', + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json' + } + })).json() + + toastr.success('Form created!') + this.props.history.push(`/forms/${r.hashid}`) + } catch (e) { + console.error(e) + toastr.error(e.message) + } + } +} diff --git a/formspree/js/forms/FormList.js b/formspree/js/forms/FormList.js new file mode 100644 index 0000000..fba7c7e --- /dev/null +++ b/formspree/js/forms/FormList.js @@ -0,0 +1,200 @@ +/** @format */ + +const React = require('react') +const cs = require('class-set') +const {Link} = require('react-router-dom') +const createPortal = require('react-dom').createPortal + +const CreateForm = require('./CreateForm') +const HeaderPortal = require('./HeaderPortal') + +module.exports = class FormList extends React.Component { + constructor(props) { + super(props) + + this.state = { + loading: true, + user: {}, + enabled_forms: [], + disabled_forms: [], + error: null + } + } + + async componentDidMount() { + try { + let r = await (await fetch('/api/forms', { + credentials: 'same-origin', + headers: {Accept: 'application/json'} + })).json() + + this.setState({ + user: r.user, + enabled_forms: r.forms.filter(f => !f.disabled), + disabled_forms: r.forms.filter(f => f.disabled), + loading: false + }) + } catch (e) { + console.error(e) + this.setState({error: e.message}) + } + } + + render() { + if (this.state.loading) { + return ( +
+

loading...

+
+ ) + } + + if (this.state.error) { + return ( +
+

+ An error has ocurred while we were trying to fetch your forms, + please try again or contact us at support@formspree.io. +

+
+ ) + } + + return ( + <> + +

Your Forms

+
+
+

Active Forms

+ {this.state.enabled_forms.length ? ( + + + {this.state.enabled_forms.map(form => ( + + ))} + +
+ ) : ( +

+ No active forms found. Forms can be enabled by clicking the unlock + icon below. +

+ )} + + {this.state.disabled_forms.length ? ( + <> +

Disabled Forms

+ + + {this.state.disabled_forms.map(form => ( + + ))} + +
+ + ) : null} + + {this.state.enabled_forms.length === 0 && + this.state.disabled_forms.length === 0 && + this.user.upgraded ? ( +
+ You don't have any forms associated with this account, maybe you + should verify your email. +
+ ) : null} +
+ + + + ) + } +} + +class FormItem extends React.Component { + render() { + let form = this.props + + return ( + + + + {form.host ? ( + form.confirmed ? ( + + + + ) : form.confirm_sent ? ( + + + + ) : null + ) : ( + + + + )} + + + + + {form.host ? ( +
+ {form.host} + {form.sitewide ? ( + + / * + + ) : null} +
+ ) : ( + 'Waiting for a submission' + )} + + + + + + {form.email} + + + + + + {form.counter == 0 ? ( + never submitted + ) : ( + `${form.counter} submissions` + )} + + + + ) + } +} diff --git a/formspree/js/forms/FormPage.js b/formspree/js/forms/FormPage.js new file mode 100644 index 0000000..cc0d684 --- /dev/null +++ b/formspree/js/forms/FormPage.js @@ -0,0 +1,476 @@ +/** @format */ + +const toastr = window.toastr +const React = require('react') +const {Route, NavLink, Redirect} = require('react-router-dom') +const CodeMirror = require('react-codemirror2') +require('codemirror/mode/xml/xml') + +const HeaderPortal = require('./HeaderPortal') + +module.exports = class FormPage extends React.Component { + constructor(props) { + super(props) + + this.state = { + form: null + } + + this.fetchForm = this.fetchForm.bind(this) + } + + async componentDidMount() { + this.fetchForm() + } + + render() { + let hashid = this.props.match.params.hashid + + return ( + <> + +

{hashid}

+

+ + Submission History + + + Form Settings + +

+
+ } + /> + {this.state.form && ( + <> + ( + + )} + /> + ( + + )} + /> + + )} + + ) + } + + async fetchForm() { + let hashid = this.props.match.params.hashid + + try { + let r = await (await fetch(`/api/forms/${hashid}`, { + credentials: 'same-origin', + headers: {Accept: 'application/json'} + })).json() + + this.setState({form: r}) + } catch (e) { + console.error(e) + toastr.error(`Failed to fetch form, see the console for more details.`) + } + } +} + +class FormSubmissions extends React.Component { + constructor(props) { + super(props) + + this.deleteSubmission = this.deleteSubmission.bind(this) + } + + render() { + let {form} = this.props + + return ( +
+

+ Submissions for + {!form.hash ? ( + /{form.hashid} + ) : ( + /{form.email} + )} + on {form.host} + {form.sitewide ? 'and all its subpaths.' : null} + {form.hash ? ( + <> +
+ + you can now replace the email in the URL with{' '} + {`/${form.hashid}`} + + + ) : ( + <> +
+ + targeting {form.email} + + + )} +

+ {form.submissions.length ? ( + + + + + {form.fields.slice(1 /* the first field is 'date' */).map(f => ( + + ))} + + + + {form.submissions.map(s => ( + + + {form.fields + .slice(1 /* the first field is 'date' */) + .map(f => ( + + ))} + + + ))} + +
Submitted at{f} +
+ {new Date(Date.parse(s.date)) + .toString() + .split(' ') + .slice(0, 5) + .join(' ')} + +
{s[f]}
+
+ +
+ ) : ( +

No submissions archived yet.

+ )} +
+ ) + } + + async deleteSubmission(e) { + e.preventDefault() + + let subid = e.currentTarget.dataset.sub + + try { + let r = await (await fetch( + `/api/forms/${this.props.form.hashid}/submissions/${subid}`, + { + method: 'DELETE', + credentials: 'same-origin', + headers: {Accept: 'application/json'} + } + )).json() + + if (r.error) { + toastr.warning(`Failed to delete submission: ${r.error}`) + return + } + + toastr.success('Submission deleted.') + this.props.onUpdate() + } catch (e) { + console.error(e) + toastr.error( + 'Failed to delete submission, see the console for more details.' + ) + } + } +} + +class FormSettings extends React.Component { + constructor(props) { + super(props) + + this.update = this.update.bind(this) + this.deleteForm = this.deleteForm.bind(this) + this.cancelDelete = this.cancelDelete.bind(this) + + this.state = { + deleting: false + } + } + + render() { + let {form} = this.props + + return ( + <> +
+

Sample HTML

+
+
+
+

+ Use this code in your HTML, modifying it according to your + needs: +

+ + + + + + + +`} + options={{ + theme: 'oceanic-next', + mode: 'xml', + viewportMargin: Infinity + }} + /> +
+
+
+
+
+

Form Settings

+
+
+
+

Form Enabled

+

+ You can disable this form to cause it to stop receiving new + submissions temporarily or permanently. +

+
+
+ +
+
+
+
+
+

reCAPTCHA

+
+

+ reCAPTCHA provides vital spam protection, but you can turn it + off if you need. +

+
+
+
+ +
+
+
+
+
+

Email Notifications

+

+ You can disable the emails Formspree sends if you just want to + download the submissions from the dashboard. +

+
+
+ +
+
+
+
+

Submission Archive

+

+ You can disable the submission archive if you don't want + Formspree to store your submissions. +

+
+
+ +
+
+
+
+

+ {this.state.deleting + ? 'Are you sure you want to delete?' + : 'Delete Form'} +

+

+ {this.state.deleting ? ( + + This will delete the form on {form.host} targeting{' '} + {form.email} and all its submissions? This action{' '} + cannot be undone. + + ) : ( + + Deleting the form will erase all traces of this form on + our databases, including all the submissions. + + )} +

+
+
+ {this.state.deleting ? ( + <> + + + + ) : ( + + + + )} +
+
+
+
+ + ) + } + + async update(e) { + try { + let res = await (await fetch(`/api/forms/${this.props.form.hashid}`, { + method: 'PATCH', + body: JSON.stringify({ + [e.currentTarget.name]: !e.currentTarget.checked + }), + credentials: 'same-origin', + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json' + } + })).json() + + if (res.error) { + toastr.warning(`Failed to save settings: ${res.error}`) + return + } + + toastr.success('Settings saved.') + this.props.onUpdate() + } catch (e) { + console.error(e) + toastr.error('Failed to update form. See the console for more details.') + } + } + + cancelDelete(e) { + e.preventDefault() + this.setState({deleting: false}) + } + + async deleteForm(e) { + e.preventDefault() + + if (this.props.form.counter > 0 && !this.state.deleting) { + // double-check the user intentions to delete, + // but only if the form has been used already. + this.setState({deleting: true}) + return + } + + this.setState({deleting: false}) + try { + let res = await (await fetch(`/api/forms/${this.props.form.hashid}`, { + method: 'DELETE', + credentials: 'same-origin', + headers: { + Accept: 'application/json' + } + })).json() + + if (res.error) { + toastr.warning(`Failed to delete form: ${res.error}`) + return + } + + toastr.success('Form successfully deleted.') + this.props.history.push('/forms') + } catch (e) { + console.error(e) + toastr.error('Failed to delete form. See the console for more details.') + } + } +} diff --git a/formspree/js/forms/HeaderPortal.js b/formspree/js/forms/HeaderPortal.js new file mode 100644 index 0000000..7642c45 --- /dev/null +++ b/formspree/js/forms/HeaderPortal.js @@ -0,0 +1,7 @@ +/** @format */ + +const createPortal = require('react-dom').createPortal + +module.exports = function TitlePortal(props) { + return createPortal(props.children, document.querySelector('#header .center')) +} diff --git a/formspree/js/forms/dashboard.js b/formspree/js/forms/dashboard.js new file mode 100644 index 0000000..185e367 --- /dev/null +++ b/formspree/js/forms/dashboard.js @@ -0,0 +1,24 @@ +/** @format */ + +const React = require('react') +const render = require('react-dom').render +const {BrowserRouter: Router, Route} = require('react-router-dom') + +const FormList = require('./FormList') +const FormPage = require('./FormPage') + +class Dashboard extends React.Component { + render() { + return ( + + <> + + + + + + ) + } +} + +render(, document.querySelector('.container.block')) diff --git a/formspree/js/main.js b/formspree/js/main.js new file mode 100644 index 0000000..c8463b9 --- /dev/null +++ b/formspree/js/main.js @@ -0,0 +1,99 @@ +/** + * @format + */ + +const $ = window.$ +const StripeCheckout = window.StripeCheckout +const toastr = window.toastr + +toastr.options = {positionClass: 'toast-top-center'} + +/* top navbar */ +var nav = $('body > nav') +nav.addClass('js') +nav.find('.menu').slicknav() +nav + .find('h4') + .clone() + .prependTo('.slicknav_menu') + +/* adding a shadow at the bottom of the menu bar only when not at the top */ +var w = $(window) +w.scroll(function() { + var scrollPos = w.scrollTop() + if (scrollPos && !nav.hasClass('scrolled')) { + nav.addClass('scrolled') + } else if (!scrollPos) { + nav.removeClass('scrolled') + } +}) + +/* background-color should inherit, but CSS's "inherit" breaks z-index */ +var bgcolor = $(document.body).css('background-color') +if (bgcolor.split(',').length === 4 || bgcolor === 'transparent') { + bgcolor = 'white' +} +nav.css('background-color', bgcolor) + +/* modals -- working with or without JS */ +require('./modals')() + +/* turning flask flash messages into js popup notifications */ +window.popupMessages.forEach(function(m, i) { + var category = m[0] || 'info' + var text = m[1] + setTimeout(function() { + toastr[category](text) + }, (1 + i) * 1500) +}) + +/* stripe checkout */ +var stripebutton = $('#stripe-upgrade') +if (stripebutton.length) { + var handler = StripeCheckout.configure(stripebutton.data()) + stripebutton.on('click', function(e) { + handler.open({ + token: function(token) { + stripebutton + .closest('form') + .append( + `` + ) + .append( + `` + ) + .submit() + } + }) + e.preventDefault() + }) +} + +/* quick script for showing the resend confirmation form */ +$('a.resend').on('click', function() { + $(this).hide() + $('form.resend').show() + return false +}) + +/* scripts at other files */ +require('./forms/dashboard.js') + +/* toggle the card management menu */ +$(function() { + $('#card-list tr:even').addClass('even') + $('#card-list tr:not(.even)').hide() + $('#card-list tr:first-child').show() + + $('#card-list tr.even').click(function() { + $(this) + .next('tr') + .toggle() + $(this) + .find('.arrow') + .toggleClass('up') + $(this) + .find('.fa-chevron-right') + .toggleClass('fa-rotate-90') + }) +}) diff --git a/formspree/js/modals.js b/formspree/js/modals.js new file mode 100644 index 0000000..d6c85c3 --- /dev/null +++ b/formspree/js/modals.js @@ -0,0 +1,53 @@ +/** @format */ + +const $ = window.$ + +module.exports = function modals() { + $('.modal').each(function() { + let modal = $(this) + modal.addClass('js') + let id = modal.attr('id') + + $(`[href="#${id}"]`).click(function(e) { + // open the modal + e.preventDefault() + modal.toggleClass('target') + }) + + modal.click(function(e) { + // close the modal + if (e.target === modal[0]) { + cleanHash() + modal.toggleClass('target') + e.preventDefault() + } + }) + modal.find('.x a').click(function(e) { + // close the modal + cleanHash() + e.preventDefault() + modal.toggleClass('target') + }) + }) + + function cleanHash() { + if (!window.location.hash) return + if (window.history && window.history.replaceState) { + window.history.replaceState('', document.title, window.location.pathname) + } else { + let pos = $(window).scrollTop() + window.location.hash = '' + $(window).scrollTop(pos) + } + } + + // activate modals from url hash # + setTimeout(() => { + // setTimeout is needed because :target elements only appear after + // the page is loaded or something like that. + let activatedModal = $('*:target') + if (activatedModal.length && !activatedModal.is('.target')) { + activatedModal.toggleClass('target') + } + }, 0) +} diff --git a/formspree/static/js/sitewide.js b/formspree/js/sitewide.js similarity index 62% rename from formspree/static/js/sitewide.js rename to formspree/js/sitewide.js index d34adf8..03224e6 100644 --- a/formspree/static/js/sitewide.js +++ b/formspree/js/sitewide.js @@ -1,3 +1,5 @@ +/** @format */ + const url = require('url') const isValidUrl = require('valid-url').isWebUri const isValidEmail = require('is-valid-email') @@ -11,7 +13,7 @@ const $ = window.$ const toastr = window.toastr /* create-form validation for site-wide forms */ -module.exports = function sitewide () { +module.exports = function sitewide() { var parentNode = $('#create-form .container') if (!parentNode.length) return @@ -37,20 +39,29 @@ module.exports = function sitewide () { parentNode.on('input', 'input[name="url"], input[name="email"]', run) parentNode.on('click', '.verify button', check) - function run () { + function run() { let checkbox = parentNode.find('input[name="sitewide"]') - let email = parentNode.find('input[name="email"]').val().trim() - let urlv = parentNode.find('input[name="url"]').val().trim() + let email = parentNode + .find('input[name="email"]') + .val() + .trim() + let urlv = parentNode + .find('input[name="url"]') + .val() + .trim() urlv = /^https?:\/\//.test(urlv) ? urlv : 'http://' + urlv let sitewide = checkbox.is(':checked') // wrong input - if (!isValidEmail(email)) { // invalid email + if (!isValidEmail(email)) { + // invalid email data.invalid = 'email' - } else if (sitewide && !isValidUrl(urlv)) { // invalid url with sitewide + } else if (sitewide && !isValidUrl(urlv)) { + // invalid url with sitewide data.invalid = 'url' - } else if (!sitewide && urlv && urlv !== 'http://' && !isValidUrl(urlv)) { // invalid url without sitewide + } else if (!sitewide && urlv && urlv !== 'http://' && !isValidUrl(urlv)) { + // invalid url without sitewide data.invalid = 'url' } else { data.invalid = null @@ -63,15 +74,17 @@ module.exports = function sitewide () { apply(render(data)) } - function check () { + function check() { $.ajax({ url: '/forms/sitewide-check?' + parentNode.find('form').serialize(), - success: function () { - toastr.success('The file exists! you can create your site-wide form now.') + success: function() { + toastr.success( + 'The file exists! you can create your site-wide form now.' + ) data.verified = true apply(render(data)) }, - error: function () { + error: function() { toastr.warning("The verification file wasn't found.") data.verified = false data.disableVerification = true @@ -87,17 +100,29 @@ module.exports = function sitewide () { return false } - function apply (vtree) { + function apply(vtree) { let patches = diff(tree, vtree) rootNode = patch(rootNode, patches) tree = vtree } - function render ({invalid, sitewide, verified, urlv, email, disableVerification}) { + function render({ + invalid, + sitewide, + verified, + urlv, + email, + disableVerification + }) { return h('form', {method: 'post', action: formActionURL}, [ h('.col-1-1', [ h('h4', 'Send email to:'), - h('input', {type: 'email', name: 'email', placeholder: emailPlaceholder, value: email}) + h('input', { + type: 'email', + name: 'email', + placeholder: emailPlaceholder, + value: email + }) ]), h('.col-1-1', [ h('h4', 'From URL:'), @@ -112,35 +137,47 @@ module.exports = function sitewide () { ]), h('.col-3-4.info', [ invalid - ? h('div.red', invalid === 'email' - ? 'Please input a valid email address.' - : [ - 'Please input a valid URL. For example: ', - h('span.code', url.resolve('http://www.mywebsite.com', sitewide ? '' : '/contact.html')) - ]) - : sitewide && verified || !sitewide + ? h( + 'div.red', + invalid === 'email' + ? 'Please input a valid email address.' + : [ + 'Please input a valid URL. For example: ', + h( + 'span.code', + url.resolve( + 'http://www.mywebsite.com', + sitewide ? '' : '/contact.html' + ) + ) + ] + ) + : (sitewide && verified) || !sitewide ? h('div', {innerHTML: '​'}) : h('span', [ - 'Please ensure ', - h('span.code', url.resolve(urlv, '/formspree-verify.txt')), - ' exists and contains a line with ', - h('span.code', email) - ]) + 'Please ensure ', + h('span.code', url.resolve(urlv, '/formspree-verify.txt')), + ' exists and contains a line with ', + h('span.code', email) + ]) ]), h('.col-1-3', [ h('.verify', [ - h('button', sitewide && !invalid && !disableVerification - ? {} - : sitewide - ? {disabled: true} - : {style: {visibility: 'hidden'}, disabled: true}, - 'Verify') + h( + 'button', + sitewide && !invalid && !disableVerification + ? {} + : sitewide + ? {disabled: true} + : {style: {visibility: 'hidden'}, disabled: true}, + 'Verify' + ) ]) ]), h('.col-1-3', {innerHTML: '​'}), h('.col-1-3', [ h('.create', [ - sitewide && verified || !sitewide && !invalid + (sitewide && verified) || (!sitewide && !invalid) ? h('button', {type: 'submit'}, 'Create form') : h('button', {disabled: true}, 'Create form') ]) diff --git a/formspree/routes.py b/formspree/routes.py index 559b5db..3cfd102 100644 --- a/formspree/routes.py +++ b/formspree/routes.py @@ -1,4 +1,5 @@ import formspree.forms.views as fv +import formspree.forms.api as fa import formspree.users.views as uv import formspree.static_pages.views as sv @@ -37,18 +38,18 @@ def configure_routes(app): app.add_url_rule('/logout', 'logout', view_func=uv.logout, methods=['GET']) # Users' forms - app.add_url_rule('/dashboard', 'dashboard', view_func=fv.forms, methods=['GET']) - app.add_url_rule('/forms', 'forms', view_func=fv.forms, methods=['GET']) - app.add_url_rule('/forms', 'create-form', view_func=fv.create_form, methods=['POST']) - app.add_url_rule('/forms/sitewide-check', view_func=fv.sitewide_check, methods=['GET']) - app.add_url_rule('/forms//', 'form-submissions', view_func=fv.form_submissions, methods=['GET']) - app.add_url_rule('/forms/.', 'form-submissions', view_func=fv.form_submissions, methods=['GET']) - app.add_url_rule('/forms//toggle-recaptcha', 'toggle-recaptcha', view_func=fv.form_recaptcha_toggle, methods=['POST']) - app.add_url_rule('/forms//toggle-emails', 'toggle-emails', view_func=fv.form_email_notification_toggle, methods=['POST']) - app.add_url_rule('/forms//toggle-storage', 'toggle-storage', view_func=fv.form_archive_toggle, methods=['POST']) - app.add_url_rule('/forms//toggle', 'form-toggle', view_func=fv.form_toggle, methods=['POST']) - app.add_url_rule('/forms//delete', 'form-deletion', view_func=fv.form_deletion, methods=['POST']) - app.add_url_rule('/forms//delete/', 'submission-deletion', view_func=fv.submission_deletion, methods=['POST']) + app.add_url_rule('/dashboard', 'dashboard', view_func=fv.serve_dashboard, methods=['GET']) + app.add_url_rule('/forms', 'dashboard', view_func=fv.serve_dashboard, methods=['GET']) + app.add_url_rule('/forms/', view_func=fv.serve_dashboard, methods=['GET']) + app.add_url_rule('/forms//', view_func=fv.serve_dashboard, methods=['GET']) + app.add_url_rule('/forms/.', view_func=fv.export_submissions, methods=['GET']) + app.add_url_rule('/api/forms', view_func=fa.list, methods=['GET']) + app.add_url_rule('/api/forms', view_func=fa.create, methods=['POST']) + app.add_url_rule('/api/forms/', view_func=fa.get, methods=['GET']) + app.add_url_rule('/api/forms/', view_func=fa.update, methods=['PATCH']) + app.add_url_rule('/api/forms/', view_func=fa.delete, methods=['DELETE']) + app.add_url_rule('/api/forms/sitewide-check', view_func=fa.sitewide_check, methods=['POST']) + app.add_url_rule('/api/forms//submissions/', view_func=fa.submission_delete, methods=['DELETE']) # Webhooks app.add_url_rule('/webhooks/stripe', view_func=uv.stripe_webhook, methods=['POST']) diff --git a/formspree/static/scss/alertbox.scss b/formspree/scss/alertbox.scss similarity index 100% rename from formspree/static/scss/alertbox.scss rename to formspree/scss/alertbox.scss diff --git a/formspree/static/scss/dashboard.scss b/formspree/scss/dashboard.scss similarity index 95% rename from formspree/static/scss/dashboard.scss rename to formspree/scss/dashboard.scss index 39bdbb1..841c0fa 100644 --- a/formspree/static/scss/dashboard.scss +++ b/formspree/scss/dashboard.scss @@ -111,6 +111,14 @@ } .dashboard { + #header { + h3 { + a { + margin: 0 10px; + } + } + } + .row:after { content: ""; display: none; @@ -444,38 +452,16 @@ } } -.html-highlight { - clear: both; - font-size: 14px; - font-family: monospace; - padding: 5px; - border: 2px dashed #696969; - border-radius: 5px; - - .bracket { - color: #a65700 - } - .tagname { - color: #800000; - font-weight: bold; - } - .attrkey { - color: #074726 - } - .equal { - color: #808030 - } - .attrvalue { - color: #0000e6 - } - .comment { - color: #696969 - } -} - a.button.export { width: 11em; text-align: center; display: inline-block; margin: 0 0 20px 20px; } + +.CodeMirror { + border: 1px solid #eee; + padding: 10px; + height: auto; + font-size: 90%; +} diff --git a/formspree/static/scss/formspree.scss b/formspree/scss/formspree.scss similarity index 100% rename from formspree/static/scss/formspree.scss rename to formspree/scss/formspree.scss diff --git a/formspree/static/scss/grid.scss b/formspree/scss/grid.scss similarity index 100% rename from formspree/static/scss/grid.scss rename to formspree/scss/grid.scss diff --git a/formspree/static/scss/hint/hint-always.scss b/formspree/scss/hint/hint-always.scss similarity index 100% rename from formspree/static/scss/hint/hint-always.scss rename to formspree/scss/hint/hint-always.scss diff --git a/formspree/static/scss/hint/hint-color-types.scss b/formspree/scss/hint/hint-color-types.scss similarity index 100% rename from formspree/static/scss/hint/hint-color-types.scss rename to formspree/scss/hint/hint-color-types.scss diff --git a/formspree/static/scss/hint/hint-core.scss b/formspree/scss/hint/hint-core.scss similarity index 100% rename from formspree/static/scss/hint/hint-core.scss rename to formspree/scss/hint/hint-core.scss diff --git a/formspree/static/scss/hint/hint-effects.scss b/formspree/scss/hint/hint-effects.scss similarity index 100% rename from formspree/static/scss/hint/hint-effects.scss rename to formspree/scss/hint/hint-effects.scss diff --git a/formspree/static/scss/hint/hint-mixins.scss b/formspree/scss/hint/hint-mixins.scss similarity index 100% rename from formspree/static/scss/hint/hint-mixins.scss rename to formspree/scss/hint/hint-mixins.scss diff --git a/formspree/static/scss/hint/hint-position.scss b/formspree/scss/hint/hint-position.scss similarity index 100% rename from formspree/static/scss/hint/hint-position.scss rename to formspree/scss/hint/hint-position.scss diff --git a/formspree/static/scss/hint/hint-rounded.scss b/formspree/scss/hint/hint-rounded.scss similarity index 100% rename from formspree/static/scss/hint/hint-rounded.scss rename to formspree/scss/hint/hint-rounded.scss diff --git a/formspree/static/scss/hint/hint-variables.scss b/formspree/scss/hint/hint-variables.scss similarity index 100% rename from formspree/static/scss/hint/hint-variables.scss rename to formspree/scss/hint/hint-variables.scss diff --git a/formspree/static/scss/hint/hint.scss b/formspree/scss/hint/hint.scss similarity index 100% rename from formspree/static/scss/hint/hint.scss rename to formspree/scss/hint/hint.scss diff --git a/formspree/static/scss/ionicons/_ionicons-font.scss b/formspree/scss/ionicons/_ionicons-font.scss similarity index 100% rename from formspree/static/scss/ionicons/_ionicons-font.scss rename to formspree/scss/ionicons/_ionicons-font.scss diff --git a/formspree/static/scss/ionicons/_ionicons-icons.scss b/formspree/scss/ionicons/_ionicons-icons.scss similarity index 100% rename from formspree/static/scss/ionicons/_ionicons-icons.scss rename to formspree/scss/ionicons/_ionicons-icons.scss diff --git a/formspree/static/scss/ionicons/_ionicons-variables.scss b/formspree/scss/ionicons/_ionicons-variables.scss similarity index 99% rename from formspree/static/scss/ionicons/_ionicons-variables.scss rename to formspree/scss/ionicons/_ionicons-variables.scss index 034a14a..bdeafdf 100644 --- a/formspree/static/scss/ionicons/_ionicons-variables.scss +++ b/formspree/scss/ionicons/_ionicons-variables.scss @@ -1,7 +1,7 @@ // Ionicons Variables // -------------------------- -$ionicons-font-path: "../fonts" !default; +$ionicons-font-path: "fonts" !default; $ionicons-font-family: "Ionicons" !default; $ionicons-version: "2.0.1" !default; $ionicons-prefix: ion- !default; @@ -738,4 +738,4 @@ $ionicon-var-wifi: "\f25c"; $ionicon-var-wineglass: "\f2b9"; $ionicon-var-woman: "\f25d"; $ionicon-var-wrench: "\f2ba"; -$ionicon-var-xbox: "\f30c"; \ No newline at end of file +$ionicon-var-xbox: "\f30c"; diff --git a/formspree/static/scss/ionicons/ionicons.scss b/formspree/scss/ionicons/ionicons.scss similarity index 100% rename from formspree/static/scss/ionicons/ionicons.scss rename to formspree/scss/ionicons/ionicons.scss diff --git a/formspree/static/scss/main.scss b/formspree/scss/main.scss similarity index 99% rename from formspree/static/scss/main.scss rename to formspree/scss/main.scss index 0459491..94526b4 100644 --- a/formspree/static/scss/main.scss +++ b/formspree/scss/main.scss @@ -22,7 +22,7 @@ $error-red: #CC3F36; @import 'dashboard.scss'; @import 'nav.scss'; @import 'toastr.scss'; -@import 'submissions.scss'; +@import 'settings.scss'; @import 'ionicons/ionicons.scss'; html { diff --git a/formspree/static/scss/nav.scss b/formspree/scss/nav.scss similarity index 100% rename from formspree/static/scss/nav.scss rename to formspree/scss/nav.scss diff --git a/formspree/static/scss/normalize.scss b/formspree/scss/normalize.scss similarity index 100% rename from formspree/static/scss/normalize.scss rename to formspree/scss/normalize.scss diff --git a/formspree/static/scss/reset.scss b/formspree/scss/reset.scss similarity index 100% rename from formspree/static/scss/reset.scss rename to formspree/scss/reset.scss diff --git a/formspree/scss/settings.scss b/formspree/scss/settings.scss new file mode 100644 index 0000000..b283b4e --- /dev/null +++ b/formspree/scss/settings.scss @@ -0,0 +1,89 @@ +/** @format */ + +#settings { + p#status { + float: right; + color: $dark-blue; + font-size: 0.7em; + margin-right: 2%; + + &.error { + color: $red; + } + } + + h4 { + margin: 14px 0 4px 0 !important; + } + + p.description { + line-height: 1em; + display: inline-block; + font-size: 0.8em; + margin: 0; + margin-top: 0.2em; + color: #999999; + } + + .switch-row { + margin: auto; + position: relative; + text-align: right; + .switch { + position: absolute; + display: inline-block; + width: 60px; + height: 26px; + right: 5%; + input { + display: none; + } + } + } + + .slider { + position: absolute; + cursor: pointer; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color: #ccc; + -webkit-transition: 0.4s; + transition: 0.4s; + + &:before { + position: absolute; + content: ''; + height: 18px; + width: 26px; + left: 4px; + bottom: 4px; + background-color: white; + -webkit-transition: 0.4s; + transition: 0.4s; + } + } + + input:checked + .slider { + background-color: $dark-green; + } + + input:focus + .slider { + box-shadow: 0 0 1px $dark-green; + } + + input:checked + .slider:before { + -webkit-transform: translateX(26px); + -ms-transform: translateX(26px); + transform: translateX(26px); + } + + .row { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -ms-flex-wrap: wrap; + flex-wrap: wrap; + } +} diff --git a/formspree/static/scss/slicknav/core.scss b/formspree/scss/slicknav/core.scss similarity index 100% rename from formspree/static/scss/slicknav/core.scss rename to formspree/scss/slicknav/core.scss diff --git a/formspree/static/scss/slicknav/theme.scss b/formspree/scss/slicknav/theme.scss similarity index 100% rename from formspree/static/scss/slicknav/theme.scss rename to formspree/scss/slicknav/theme.scss diff --git a/formspree/static/scss/toastr.scss b/formspree/scss/toastr.scss similarity index 100% rename from formspree/static/scss/toastr.scss rename to formspree/scss/toastr.scss diff --git a/formspree/static/scss/typography.scss b/formspree/scss/typography.scss similarity index 100% rename from formspree/static/scss/typography.scss rename to formspree/scss/typography.scss diff --git a/formspree/static/css/main.css b/formspree/static/css/main.css deleted file mode 100644 index 798499f..0000000 --- a/formspree/static/css/main.css +++ /dev/null @@ -1,5913 +0,0 @@ -@charset "UTF-8"; -article, -aside, -details, -figcaption, -figure, -footer, -header, -hgroup, -nav, -section, -summary { - display: block; -} - -audio, -canvas, -video { - display: inline-block; -} - -audio:not([controls]) { - display: none; - height: 0; -} - -[hidden], template { - display: none; -} - -html { - background: #fff; - color: #000; - -webkit-text-size-adjust: 100%; - -ms-text-size-adjust: 100%; -} - -html, -button, -input, -select, -textarea { - font-family: sans-serif; -} - -body { - margin: 0; -} - -a { - background: transparent; -} -a:focus { - outline: thin dotted; -} -a:hover, a:active { - outline: 0; -} - -h1 { - font-size: 2em; - margin: 0.67em 0; -} - -h2 { - font-size: 1.5em; - margin: 0.83em 0; -} - -h3 { - font-size: 1.17em; - margin: 1em 0; -} - -h4 { - font-size: 1em; - margin: 1.33em 0; -} - -h5 { - font-size: 0.83em; - margin: 1.67em 0; -} - -h6 { - font-size: 0.75em; - margin: 2.33em 0; -} - -abbr[title] { - border-bottom: 1px dotted; -} - -b, -strong { - font-weight: bold; -} - -dfn { - font-style: italic; -} - -mark { - background: #ff0; - color: #000; -} - -code, -kbd, -pre, -samp { - font-family: monospace, serif; - font-size: 1em; -} - -pre { - white-space: pre; - white-space: pre-wrap; - word-wrap: break-word; -} - -q { - quotes: "“" "”" "‘" "’"; -} - -q:before, -q:after { - content: ""; - content: none; -} - -small { - font-size: 80%; -} - -sub, -sup { - font-size: 75%; - line-height: 0; - position: relative; - vertical-align: baseline; -} - -sup { - top: -0.5em; -} - -sub { - bottom: -0.25em; -} - -img { - border: 0; -} - -svg:not(:root) { - overflow: hidden; -} - -figure { - margin: 0; -} - -fieldset { - border: 1px solid #c0c0c0; - margin: 0 2px; - padding: 0.35em 0.625em 0.75em; -} - -legend { - border: 0; - padding: 0; - white-space: normal; -} - -button, -input, -select, -textarea { - font-family: inherit; - font-size: 100%; - margin: 0; - vertical-align: baseline; -} - -button, -input { - line-height: normal; -} - -button, -select { - text-transform: none; -} - -button, -html input[type=button], -input[type=reset], -input[type=submit] { - -webkit-appearance: button; - cursor: pointer; -} - -button[disabled], -input[disabled] { - cursor: default; -} - -input[type=checkbox], -input[type=radio] { - box-sizing: border-box; - padding: 0; -} - -input[type=search] { - -webkit-appearance: textfield; - -moz-box-sizing: content-box; - -webkit-box-sizing: content-box; - box-sizing: content-box; -} - -input[type=search]::-webkit-search-cancel-button, -input[type=search]::-webkit-search-decoration { - -webkit-appearance: none; -} - -button::-moz-focus-inner, input::-moz-focus-inner { - border: 0; - padding: 0; -} - -textarea { - overflow: auto; - vertical-align: top; -} - -table { - border-collapse: collapse; - border-spacing: 0; -} - -* { - box-sizing: border-box; - -moz-box-sizing: border-box; - -webkit-box-sizing: border-box; -} - -.row { - width: 100%; -} -.row:after { - content: "."; - display: block; - clear: both; - visibility: hidden; - line-height: 0; - height: 0; -} - -.container { - max-width: 950px; - margin: 0 auto; -} -.container:after { - content: "."; - display: block; - clear: both; - visibility: hidden; - line-height: 0; - height: 0; -} -@media (min-width: 760px) { - .container.narrow { - max-width: 600px; - } -} -@media (max-width: 760px) { - .container { - max-width: 100% !important; - } -} - -.col-1-1 { - float: left; - padding: 0 20px; - width: 100%; -} -@media (max-width: 760px) { - .col-1-1 { - width: 100% !important; - margin-bottom: 20px !important; - } -} - -.col-1-2 { - float: left; - padding: 0 20px; - width: 50%; -} -@media (max-width: 760px) { - .col-1-2 { - width: 100% !important; - margin-bottom: 20px !important; - } -} - -.col-1-3 { - float: left; - padding: 0 20px; - width: 33.33%; -} -@media (max-width: 760px) { - .col-1-3 { - width: 100% !important; - margin-bottom: 20px !important; - } -} - -.col-2-3 { - float: left; - padding: 0 20px; - width: 66.66%; -} -@media (max-width: 760px) { - .col-2-3 { - width: 100% !important; - margin-bottom: 20px !important; - } -} - -.col-1-4 { - float: left; - padding: 0 20px; - width: 25%; -} -@media (max-width: 760px) { - .col-1-4 { - width: 100% !important; - margin-bottom: 20px !important; - } -} - -.col-3-4 { - float: left; - padding: 0 20px; - width: 75%; -} -@media (max-width: 760px) { - .col-3-4 { - width: 100% !important; - margin-bottom: 20px !important; - } -} - -.col-2-5 { - float: left; - padding: 0 20px; - width: 40%; -} -@media (max-width: 760px) { - .col-2-5 { - width: 100% !important; - margin-bottom: 20px !important; - } -} - -.col-3-5 { - float: left; - padding: 0 20px; - width: 60%; -} -@media (max-width: 760px) { - .col-3-5 { - width: 100% !important; - margin-bottom: 20px !important; - } -} - -.col-5-12 { - float: left; - padding: 0 20px; - width: 41.67%; -} -@media (max-width: 760px) { - .col-5-12 { - width: 100% !important; - margin-bottom: 20px !important; - } -} - -.col-5-6 { - float: left; - padding: 0 20px; - width: 83.33%; -} -@media (max-width: 760px) { - .col-5-6 { - width: 100% !important; - margin-bottom: 20px !important; - } -} - -.col-1-6 { - float: left; - padding: 0 20px; - width: 16.67%; -} -@media (max-width: 760px) { - .col-1-6 { - width: 100% !important; - margin-bottom: 20px !important; - } -} - -@media print { - .col-1-1 { - width: 100% !important; - } - - .col-1-2 { - width: 50% !important; - } - - .col-1-4 { - width: 25% !important; - } - - .col-1-3 { - width: 33.33% !important; - } - - .col-2-3 { - width: 66.66% !important; - } - - .col-5-12 { - width: 41.67% !important; - } -} -body { - font-size: 18px; - line-height: 1.5em; - font-family: "proxima-nova-soft", "Proxima Nova Soft", sans-serif; -} - -h1, h2, h3, h4, h5, h6, p { - font-family: "proxima-nova-soft", "Proxima Nova Soft", sans-serif; - -webkit-font-smoothing: antialiased; -} -h1:first-child, h2:first-child, h3:first-child, h4:first-child, h5:first-child, h6:first-child, p:first-child { - margin-top: 0; -} -h1:last-child, h2:last-child, h3:last-child, h4:last-child, h5:last-child, h6:last-child, p:last-child { - margin-bottom: 0; -} -h1 > small, h2 > small, h3 > small, h4 > small, h5 > small, h6 > small, p > small { - font-size: 0.65em; - color: #aaa; -} - -h1, h2, h3, h4, h5, h6 { - font-weight: 600; - line-height: 1.3em; - color: #1b3544; -} -h1.light, h2.light, h3.light, h4.light, h5.light, h6.light { - font-weight: 400; - color: #444; -} - -p { - line-height: 1.5em; - color: #444; -} - -a { - color: #359173; - text-decoration: none; - transition: color 0.3s ease-in-out; -} -a:hover { - color: #2A735B; -} - -.center { - text-align: center; -} - -.right { - text-align: right; -} - -.caps { - text-transform: uppercase; -} - -/*-------------------------------------*\ - HINT.css - A CSS tooltip library -\*-------------------------------------*/ -/** - * HINT.css is a tooltip library made in pure CSS. - * - * Source: https://github.com/chinchang/hint.css - * Demo: http://kushagragour.in/lab/hint/ - * - * Release under The MIT License - * - */ -/** - * source: hint-core.scss - * - * Defines the basic styling for the tooltip. - * Each tooltip is made of 2 parts: - * 1) body (:after) - * 2) arrow (:before) - * - * Classes added: - * 1) hint - */ -.hint, [data-hint] { - position: relative; - display: inline-block; - /** - * tooltip arrow - */ - /** - * tooltip body - */ -} -.hint:before, .hint:after, [data-hint]:before, [data-hint]:after { - position: absolute; - -webkit-transform: translate3d(0, 0, 0); - -moz-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - visibility: hidden; - opacity: 0; - z-index: 1000000; - pointer-events: none; - -webkit-transition: 0.3s ease; - -moz-transition: 0.3s ease; - transition: 0.3s ease; -} -.hint:hover:before, .hint:hover:after, .hint:focus:before, .hint:focus:after, [data-hint]:hover:before, [data-hint]:hover:after, [data-hint]:focus:before, [data-hint]:focus:after { - visibility: visible; - opacity: 1; -} -.hint:before, [data-hint]:before { - content: ""; - position: absolute; - background: transparent; - border: 6px solid transparent; - z-index: 1000001; -} -.hint:after, [data-hint]:after { - font-family: "myriad-pro", sans-serif; - font-weight: 400; - content: attr(data-hint); - background: #1b3544; - color: white; - padding: 12px 15px; - font-size: 16px; - line-height: 16px; - white-space: nowrap; -} - -/** - * source: hint-position.scss - * - * Defines the positoning logic for the tooltips. - * - * Classes added: - * 1) hint--top - * 2) hint--bottom - * 3) hint--left - * 4) hint--right - */ -/** - * set default color for tooltip arrows - */ -.hint--top:before { - border-top-color: #1b3544; -} - -.hint--bottom:before { - border-bottom-color: #1b3544; -} - -.hint--left:before { - border-left-color: #1b3544; -} - -.hint--right:before { - border-right-color: #1b3544; -} - -/** - * top tooltip - */ -.hint--top:before { - margin-bottom: -12px; -} -.hint--top:after { - margin-left: -18px; -} -.hint--top:before, .hint--top:after { - bottom: 100%; - left: 18px; -} -.hint--top:hover:after, .hint--top:hover:before, .hint--top:focus:after, .hint--top:focus:before { - -webkit-transform: translateY(-8px); - -moz-transform: translateY(-8px); - transform: translateY(-8px); -} - -/** - * bottom tooltip - */ -.hint--bottom:before { - margin-top: -12px; -} -.hint--bottom:after { - margin-left: -18px; -} -.hint--bottom:before, .hint--bottom:after { - top: 100%; - left: 18px; -} -.hint--bottom:hover:after, .hint--bottom:hover:before, .hint--bottom:focus:after, .hint--bottom:focus:before { - -webkit-transform: translateY(8px); - -moz-transform: translateY(8px); - transform: translateY(8px); -} - -/** - * right tooltip - */ -.hint--right:before { - margin-left: -12px; - margin-bottom: -6px; -} -.hint--right:after { - margin-bottom: -20px; -} -.hint--right:before, .hint--right:after { - left: 100%; - bottom: 50%; -} -.hint--right:hover:after, .hint--right:hover:before, .hint--right:focus:after, .hint--right:focus:before { - -webkit-transform: translateX(8px); - -moz-transform: translateX(8px); - transform: translateX(8px); -} - -/** - * left tooltip - */ -.hint--left:before { - margin-right: -12px; - margin-bottom: -6px; -} -.hint--left:after { - margin-bottom: -20px; -} -.hint--left:before, .hint--left:after { - right: 100%; - bottom: 50%; -} -.hint--left:hover:after, .hint--left:hover:before, .hint--left:focus:after, .hint--left:focus:before { - -webkit-transform: translateX(-8px); - -moz-transform: translateX(-8px); - transform: translateX(-8px); -} - -/** - * source: hint-color-types.scss - * - * Contains tooltips of various types based on color differences. - * - * Classes added: - * 1) hint--error - * 2) hint--warning - * 3) hint--info - * 4) hint--success - * - */ -/** - * Error - */ -.hint--error:after { - background-color: #b34e4d; -} -.hint--error.hint--top:before { - border-top-color: #b34e4d; -} -.hint--error.hint--bottom:before { - border-bottom-color: #b34e4d; -} -.hint--error.hint--left:before { - border-left-color: #b34e4d; -} -.hint--error.hint--right:before { - border-right-color: #b34e4d; -} - -/** - * Warning - */ -.hint--warning:after { - background-color: #c09854; -} -.hint--warning.hint--top:before { - border-top-color: #c09854; -} -.hint--warning.hint--bottom:before { - border-bottom-color: #c09854; -} -.hint--warning.hint--left:before { - border-left-color: #c09854; -} -.hint--warning.hint--right:before { - border-right-color: #c09854; -} - -/** - * Info - */ -.hint--info:after { - background-color: #3986ac; -} -.hint--info.hint--top:before { - border-top-color: #3986ac; -} -.hint--info.hint--bottom:before { - border-bottom-color: #3986ac; -} -.hint--info.hint--left:before { - border-left-color: #3986ac; -} -.hint--info.hint--right:before { - border-right-color: #3986ac; -} - -/** - * Success - */ -.hint--success:after { - background-color: #458746; -} -.hint--success.hint--top:before { - border-top-color: #458746; -} -.hint--success.hint--bottom:before { - border-bottom-color: #458746; -} -.hint--success.hint--left:before { - border-left-color: #458746; -} -.hint--success.hint--right:before { - border-right-color: #458746; -} - -/** - * source: hint-always.scss - * - * Defines a persisted tooltip which shows always. - * - * Classes added: - * 1) hint--always - * - */ -.hint--always:after, .hint--always:before { - opacity: 1; - visibility: visible; -} -.hint--always.hint--top:after, .hint--always.hint--top:before { - -webkit-transform: translateY(-8px); - -moz-transform: translateY(-8px); - transform: translateY(-8px); -} -.hint--always.hint--bottom:after, .hint--always.hint--bottom:before { - -webkit-transform: translateY(8px); - -moz-transform: translateY(8px); - transform: translateY(8px); -} -.hint--always.hint--left:after, .hint--always.hint--left:before { - -webkit-transform: translateX(-8px); - -moz-transform: translateX(-8px); - transform: translateX(-8px); -} -.hint--always.hint--right:after, .hint--always.hint--right:before { - -webkit-transform: translateX(8px); - -moz-transform: translateX(8px); - transform: translateX(8px); -} - -/** - * source: hint-rounded.scss - * - * Defines rounded corner tooltips. - * - * Classes added: - * 1) hint--rounded - * - */ -.hint--rounded:after { - border-radius: 4px; -} - -/** - * source: hint-effects.scss - * - * Defines various transition effects for the tooltips. - * - * Classes added: - * 1) hint--bounce - * - */ -.hint--bounce:before, .hint--bounce:after { - -webkit-transition: opacity 0.3s ease, visibility 0.3s ease, -webkit-transform 0.3s cubic-bezier(0.71, 1.7, 0.77, 1.24); - -moz-transition: opacity 0.3s ease, visibility 0.3s ease, -moz-transform 0.3s cubic-bezier(0.71, 1.7, 0.77, 1.24); - transition: opacity 0.3s ease, visibility 0.3s ease, transform 0.3s cubic-bezier(0.71, 1.7, 0.77, 1.24); -} - -.alert-box { - padding: 15px; - font-size: 1em; - line-height: 1.5em; - display: block; - border: 2px solid #359173; - background-color: transparent; - color: #359173; -} -.alert-box.error { - border-color: #D9534F; - background-color: transparent; - color: #D9534F; -} -.alert-box.success { - border-color: #359173; - background-color: transparent; - color: #359173; -} -.alert-box.banner { - text-align: center; - margin-bottom: 0; -} -@media (max-width: 760px) { - .alert-box.banner { - position: absolute; - left: 0; - width: 100%; - border: 0; - border-bottom: 2px solid #359173; - } -} -.alert-box.banner a { - opacity: 0.75; - text-decoration: underline; -} - -a.alert-box:hover { - color: #1b3544; - border-color: #f1f1fa; -} - -a.alert-box.error:hover { - color: #D9534F; - border-color: #D9534F; -} - -a.alert-box.success:hover { - color: #359173; - border-color: #359173; -} - -.highlight { - padding: 2px 6px; - font-weight: bold; - font-size: 20px; - color: white; - background-color: #35918D; - border-radius: 3px; - margin: 3px; -} - -.login .row { - padding: 2.2em 0; -} -.login input, .login button { - font-size: 1.2em; - margin: 2px 0 1em 0; -} - -.no-underline { - border-bottom: none !important; -} - -.no-border { - border: none !important; - padding: 0 !important; - margin: 0 !important; -} - -.invoice { - font-size: 9pt; - line-height: 1.2em; -} -.invoice .middle > * { - vertical-align: middle; -} -.invoice strong { - color: #1b3544; -} -.invoice img { - display: inline; - height: 50px; - margin-right: 10px; -} -.invoice h1 { - display: inline; -} -.invoice .row { - padding-top: 40px; -} -.invoice .row p { - -webkit-margin-before: 0; -} -.invoice h3 { - margin-bottom: 0; -} -.invoice #invoice-table h3 { - margin-bottom: 10px; -} -.invoice #invoice-table table, .invoice #invoice-table tbody td { - border: 0.25px solid #DFDFDF; -} -.invoice #invoice-table thead { - background-color: #359173; - color: white; - text-align: center; - border-color: #000000; -} -.invoice #invoice-table tbody { - vertical-align: top; -} -.invoice #invoice-table th, .invoice #invoice-table td { - padding: 10px; -} -.invoice .invoice-unpaid:after { - content: "UNPAID"; - position: absolute; - top: 120px; - right: 15%; - z-index: 1; - font-family: "Special Elite", Arial, sans-serif; - transform: rotate(-45deg); - font-size: 40px; - color: #c00; - border: solid 4px #c00; - padding: 15px 5px 5px; - border-radius: 5px; - opacity: 0.7; - text-shadow: 0 0 2px #c00; - box-shadow: 0 0 2px #c00; -} - -.dashboard { - /* icon morphing */ -} -.dashboard .row:after { - content: ""; - display: none; -} -.dashboard .card { - border-width: 0; -} -.dashboard span[class^=ion-] { - display: inline-block; - font-size: 20px; - text-align: center; - width: 32px; -} -.dashboard .delete { - color: #D9534F; - border-color: #D9534F; -} -.dashboard .delete:hover { - transition: color 0.3s ease-in-out; - color: #D87431; -} -.dashboard div.submissions-col { - overflow-x: auto; -} -.dashboard table { - text-align: left; - width: 100%; -} -@media screen and (max-width: 600px) { - .dashboard table.responsive { - border: 0; - } - .dashboard table.responsive thead { - display: none; - } - .dashboard table.responsive tr { - margin-bottom: 10px; - display: block; - border-bottom: 5px solid #ddd; - } - .dashboard table.responsive tr td { - display: block; - font-size: 13px; - border-bottom: 1px dotted #ccc; - margin: 10px auto; - max-width: 100%; - } - .dashboard table.responsive tr td:last-child { - border-bottom: 0; - } - .dashboard table.responsive tr td:before { - content: attr(data-label); - display: block; - text-transform: uppercase; - font-weight: bold; - } -} -.dashboard table.submissions { - padding: 2px; - background: #fff; -} -.dashboard table.submissions th { - padding: 7px 0; -} -.dashboard table.submissions tr:first-child td { - padding-top: 10px; -} -.dashboard table.submissions td { - padding: 3px 1px; -} -.dashboard table.submissions pre { - font-family: inherit; - margin: 0; - max-width: 300px; -} -.dashboard table.submissions tr pre.full { - display: none; -} -.dashboard table.submissions tr:target pre { - display: none; -} -.dashboard table.submissions tr:target pre + pre.full { - display: block; -} -.dashboard table.forms td.target-email, .dashboard table.emails td.target-email { - max-width: 250px; - word-break: break-word; -} -.dashboard table.forms td.n-submissions, .dashboard table.emails td.n-submissions { - min-width: 150px; -} -.dashboard table.forms tr.new span[class^=ion-], .dashboard table.emails tr.new span[class^=ion-] { - color: #D9534F; -} -.dashboard table.forms tr.waiting_confirmation span[class^=ion-], .dashboard table.emails tr.waiting_confirmation span[class^=ion-] { - color: #D87431; -} -.dashboard table.forms tr.verified span[class^=ion-], .dashboard table.emails tr.verified span[class^=ion-] { - color: #2A735B; -} -.dashboard table.forms tr.new a:not(*:hover), .dashboard table.emails tr.new a:not(*:hover) { - border-bottom: 1px dotted; - margin-bottom: -1px; - line-height: 1em; -} -.dashboard table.forms tr.new .never, .dashboard table.emails tr.new .never { - font-size: 15px; -} -.dashboard table.forms tr:not(.new) *:not(.n-submissions) a:not(*:hover), .dashboard table.emails tr:not(.new) *:not(.n-submissions) a:not(*:hover) { - color: inherit; -} -.dashboard table.emails tr:nth-child(2) td { - padding-top: 10px; -} -.dashboard table.emails td:last-child { - text-align: center; -} -.dashboard .pad-top { - padding-top: 0.9em; -} -.dashboard #card-list { - border-collapse: collapse; -} -.dashboard #card-list tr { - border: solid 2px #359173; - border-radius: 3px; -} -.dashboard #card-list td { - background: #FFF; - color: #000; - padding: 7px 15px; -} -.dashboard .fa-chevron-right { - transition: transform 0.25s ease-in-out; -} -.dashboard #card-list tr.even td { - cursor: pointer; -} -.dashboard .create-form { - margin: 3em 0; -} -.dashboard .create-form form { - clear: both; -} -.dashboard .create-form form input:not([type=checkbox]):not([type=radio]) { - margin-top: 0; - clear: both; - width: 100%; - vertical-align: top; -} -.dashboard .create-form form button { - padding: 0.63em 32px; - text-align: center; -} -.dashboard .create-form .info { - font-size: 13px; - margin-bottom: 10px; - text-align: right; -} -.dashboard .create-form .modal:not(.js):target > *, -.dashboard .create-form .modal.target > * { - top: 20%; -} -.dashboard .modal[id^=form-] textarea { - font-size: 15px; -} -.dashboard .modal > * { - background: #fefefe; - border: #333333 solid 1px; - border-radius: 5px; - margin-left: -385px; - position: fixed; - left: 50%; - top: -100%; - z-index: 11; - width: 770px; - -webkit-transform: translate(0, -500%); - -ms-transform: translate(0, -500%); - transform: translate(0, -500%); - -webkit-transition: -webkit-transform 0.3s ease-out; - -moz-transition: -moz-transform 0.3s ease-out; - -o-transition: -o-transform 0.3s ease-out; - transition: transform 0.3s ease-out; - padding: 0.3em 1.3em 1.3em 1.3em; -} -.dashboard .modal > * .x a { - float: right; - padding: 10px; - font-size: 1.7em; -} -.dashboard .modal > * h4 { - margin: 0; - padding: 0; - margin-top: 13px; - float: left; -} -.dashboard .modal.narrow > * { - width: 500px; - margin-left: -290px; -} -.dashboard .modal .small { - font-size: 0.75em; -} -.dashboard .modal .identified { - background-size: 12% auto; - background-repeat: no-repeat; - background-position: right 10% center; - transition: none; - background-image: url("/static/img/cards/card.png"); -} -.dashboard .modal .identified.visa { - background-image: url("/static/img/cards/visa.png"); -} -.dashboard .modal .identified.mastercard { - background-image: url("/static/img/cards/mastercard.png"); -} -.dashboard .modal .identified.amex { - background-image: url("/static/img/cards/amex.png"); -} -.dashboard .modal .identified.dinersclub { - background-image: url("/static/img/cards/dinersclub.png"); -} -.dashboard .modal .identified.discover { - background-image: url("/static/img/cards/discover.png"); -} -.dashboard .modal .identified.jcb { - background-image: url("/static/img/cards/jcb.png"); -} -.dashboard .modal .identified.visaelectron { - background-image: url("/static/img/cards/visaelectron.png"); -} -.dashboard .modal .identified.maestro { - background-image: url("/static/img/cards/maestro.png"); -} -.dashboard .modal .card { - font-size: 1em; - text-transform: uppercase; - font-weight: 600; - border: 2px solid #359173; - color: #359173; - background: transparent; - line-height: 1em; - padding: 0.6em 0.9em; - transition: all 0.3s ease-in-out; -} -.dashboard .modal .card:hover { - border-color: #2A735B; - color: #2A735B; -} -.dashboard .modal:not(.js):target > *, .dashboard .modal.target > * { - -webkit-transform: translate(0, 0); - -ms-transform: translate(0, 0); - transform: translate(0, 0); - top: 10%; -} -.dashboard .modal:before { - content: ""; - display: none; - background: rgba(0, 0, 0, 0.6); - position: fixed; - top: 0; - left: 0; - right: 0; - bottom: 0; - z-index: 10; -} -.dashboard .modal:not(.js):target:before, .dashboard .modal.target:before { - display: block; -} -.dashboard .modal .red { - color: #D9534F; -} -.dashboard .fa-unlock:hover::before { - content: ""; -} -.dashboard .fa-lock:hover::before { - content: ""; -} - -.html-highlight { - clear: both; - font-size: 14px; - font-family: monospace; - padding: 5px; - border: 2px dashed #696969; - border-radius: 5px; -} -.html-highlight .bracket { - color: #a65700; -} -.html-highlight .tagname { - color: #800000; - font-weight: bold; -} -.html-highlight .attrkey { - color: #074726; -} -.html-highlight .equal { - color: #808030; -} -.html-highlight .attrvalue { - color: #0000e6; -} -.html-highlight .comment { - color: #696969; -} - -a.button.export { - width: 11em; - text-align: center; - display: inline-block; - margin: 0 0 20px 20px; -} - -.slicknav_btn { - position: relative; - display: block; - vertical-align: middle; - float: right; - padding: 0.438em 0.625em 0.438em 0.625em; - line-height: 1.125em; - cursor: pointer; -} -.slicknav_btn .slicknav_icon-bar + .slicknav_icon-bar { - margin-top: 0.188em; -} - -.slicknav_menu { - *zoom: 1; -} -.slicknav_menu .slicknav_menutxt { - display: block; - line-height: 1.188em; - float: left; -} -.slicknav_menu .slicknav_icon { - float: left; - margin: 0.188em 0 0 0.438em; -} -.slicknav_menu .slicknav_no-text { - margin: 0; -} -.slicknav_menu .slicknav_icon-bar { - display: block; - width: 1.125em; - height: 0.125em; - -webkit-border-radius: 1px; - -moz-border-radius: 1px; - border-radius: 1px; - -webkit-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); - -moz-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); - box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); -} -.slicknav_menu:before { - content: " "; - display: table; -} -.slicknav_menu:after { - content: " "; - display: table; - clear: both; -} - -.slicknav_nav { - clear: both; -} -.slicknav_nav ul { - display: block; -} -.slicknav_nav li { - display: block; -} -.slicknav_nav .slicknav_arrow { - font-size: 0.8em; - margin: 0 0 0 0.4em; -} -.slicknav_nav .slicknav_item { - cursor: pointer; -} -.slicknav_nav .slicknav_item a { - display: inline; -} -.slicknav_nav .slicknav_row { - display: block; -} -.slicknav_nav a { - display: block; -} -.slicknav_nav .slicknav_parent-link a { - display: inline; -} - -.slicknav_brand { - float: left; -} - -.slicknav_menu { - font-size: 16px; - box-sizing: border-box; - background: #4c4c4c; - padding: 5px; -} -.slicknav_menu * { - box-sizing: border-box; -} -.slicknav_menu .slicknav_menutxt { - color: #fff; - font-weight: bold; - text-shadow: 0 1px 3px #000; -} -.slicknav_menu .slicknav_icon-bar { - background-color: #fff; -} - -.slicknav_btn { - margin: 5px 5px 6px; - text-decoration: none; - text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75); - -webkit-border-radius: 4px; - -moz-border-radius: 4px; - border-radius: 4px; - background-color: #222; -} - -.slicknav_nav { - color: #fff; - margin: 0; - padding: 0; - font-size: 0.875em; - list-style: none; - overflow: hidden; -} -.slicknav_nav ul { - list-style: none; - overflow: hidden; - padding: 0; - margin: 0 0 0 20px; -} -.slicknav_nav .slicknav_row { - padding: 5px 10px; - margin: 2px 5px; -} -.slicknav_nav .slicknav_row:hover { - -webkit-border-radius: 6px; - -moz-border-radius: 6px; - border-radius: 6px; - background: #ccc; - color: #fff; -} -.slicknav_nav a { - padding: 5px 10px; - margin: 2px 5px; - text-decoration: none; - color: #fff; -} -.slicknav_nav a:hover { - -webkit-border-radius: 6px; - -moz-border-radius: 6px; - border-radius: 6px; - background: #ccc; - color: #222; -} -.slicknav_nav .slicknav_txtnode { - margin-left: 15px; -} -.slicknav_nav .slicknav_item a { - padding: 0; - margin: 0; -} -.slicknav_nav .slicknav_parent-link a { - padding: 0; - margin: 0; -} - -.slicknav_brand { - color: #fff; - font-size: 18px; - line-height: 30px; - padding: 7px 12px; - height: 44px; -} - -.slicknav_menu { - display: none; -} - -body > nav { - position: fixed; - top: 0; - left: 0; - right: 0; - background: inherit; - z-index: 9; - padding: 7px 10px; - height: 41px; -} -body > nav + * { - margin-top: 41px; -} -body > nav.scrolled { - box-shadow: 0 0 0.6em rgba(17, 17, 17, 0.3); -} -body > nav > .greetings { - float: left; -} -body > nav > .menu { - float: right; -} -body > nav .item { - margin-left: 0.5em; -} - -@media screen and (max-width: 40em) { - body > nav.js { - display: none; - } - - .slicknav_menu { - display: block; - } -} -.slicknav_menu { - background: #4CD1A7; - /* our transcluded menu header ("Welcome...") */ -} -.slicknav_menu a { - color: white; -} -.slicknav_menu > a { - float: right; -} -.slicknav_menu h4 { - padding: 0; - margin: 0; - line-height: 33px; - margin-top: 5px; - float: left; -} -.slicknav_menu .slicknav_btn { - background-color: #2A735B; -} -.slicknav_menu .slicknav_menutxt { - text-shadow: 0 1px 3px #2A735B; -} - -.toast-title { - font-weight: bold; -} - -.toast-message { - -ms-word-wrap: break-word; - word-wrap: break-word; -} - -.toast-message a, -.toast-message label { - color: #ffffff; -} - -.toast-message a:hover { - color: #cccccc; - text-decoration: none; -} - -.toast-close-button { - position: relative; - right: -0.3em; - top: -0.3em; - float: right; - font-size: 20px; - font-weight: bold; - color: #ffffff; - -webkit-text-shadow: 0 1px 0 #ffffff; - text-shadow: 0 1px 0 #ffffff; - opacity: 0.8; - -ms-filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=80); - filter: alpha(opacity=80); -} - -.toast-close-button:hover, -.toast-close-button:focus { - color: #000000; - text-decoration: none; - cursor: pointer; - opacity: 0.4; - -ms-filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=40); - filter: alpha(opacity=40); -} - -/*Additional properties for button version - iOS requires the button element instead of an anchor tag. - If you want the anchor version, it requires `href="#"`.*/ -button.toast-close-button { - padding: 0; - cursor: pointer; - background: transparent; - border: 0; - -webkit-appearance: none; -} - -.toast-top-center { - top: 0; - right: 0; - width: 100%; -} - -.toast-bottom-center { - bottom: 0; - right: 0; - width: 100%; -} - -.toast-top-full-width { - top: 0; - right: 0; - width: 100%; -} - -.toast-bottom-full-width { - bottom: 0; - right: 0; - width: 100%; -} - -.toast-top-left { - top: 12px; - left: 12px; -} - -.toast-top-right { - top: 12px; - right: 12px; -} - -.toast-bottom-right { - right: 12px; - bottom: 12px; -} - -.toast-bottom-left { - bottom: 12px; - left: 12px; -} - -#toast-container { - position: fixed; - z-index: 999999; - /*overrides*/ -} - -#toast-container * { - -moz-box-sizing: border-box; - -webkit-box-sizing: border-box; - box-sizing: border-box; -} - -#toast-container > div { - position: relative; - overflow: hidden; - margin: 0 0 6px; - padding: 15px 15px 15px 50px; - width: 300px; - -moz-border-radius: 3px 3px 3px 3px; - -webkit-border-radius: 3px 3px 3px 3px; - border-radius: 3px 3px 3px 3px; - background-position: 15px center; - background-repeat: no-repeat; - -moz-box-shadow: 0 0 12px #999999; - -webkit-box-shadow: 0 0 12px #999999; - box-shadow: 0 0 12px #999999; - color: #ffffff; - opacity: 0.8; - -ms-filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=80); - filter: alpha(opacity=80); -} - -#toast-container > :hover { - -moz-box-shadow: 0 0 12px #000000; - -webkit-box-shadow: 0 0 12px #000000; - box-shadow: 0 0 12px #000000; - opacity: 1; - -ms-filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=100); - filter: alpha(opacity=100); - cursor: pointer; -} - -#toast-container > .toast-info { - background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGwSURBVEhLtZa9SgNBEMc9sUxxRcoUKSzSWIhXpFMhhYWFhaBg4yPYiWCXZxBLERsLRS3EQkEfwCKdjWJAwSKCgoKCcudv4O5YLrt7EzgXhiU3/4+b2ckmwVjJSpKkQ6wAi4gwhT+z3wRBcEz0yjSseUTrcRyfsHsXmD0AmbHOC9Ii8VImnuXBPglHpQ5wwSVM7sNnTG7Za4JwDdCjxyAiH3nyA2mtaTJufiDZ5dCaqlItILh1NHatfN5skvjx9Z38m69CgzuXmZgVrPIGE763Jx9qKsRozWYw6xOHdER+nn2KkO+Bb+UV5CBN6WC6QtBgbRVozrahAbmm6HtUsgtPC19tFdxXZYBOfkbmFJ1VaHA1VAHjd0pp70oTZzvR+EVrx2Ygfdsq6eu55BHYR8hlcki+n+kERUFG8BrA0BwjeAv2M8WLQBtcy+SD6fNsmnB3AlBLrgTtVW1c2QN4bVWLATaIS60J2Du5y1TiJgjSBvFVZgTmwCU+dAZFoPxGEEs8nyHC9Bwe2GvEJv2WXZb0vjdyFT4Cxk3e/kIqlOGoVLwwPevpYHT+00T+hWwXDf4AJAOUqWcDhbwAAAAASUVORK5CYII=") !important; -} - -#toast-container > .toast-error { - background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAHOSURBVEhLrZa/SgNBEMZzh0WKCClSCKaIYOED+AAKeQQLG8HWztLCImBrYadgIdY+gIKNYkBFSwu7CAoqCgkkoGBI/E28PdbLZmeDLgzZzcx83/zZ2SSXC1j9fr+I1Hq93g2yxH4iwM1vkoBWAdxCmpzTxfkN2RcyZNaHFIkSo10+8kgxkXIURV5HGxTmFuc75B2RfQkpxHG8aAgaAFa0tAHqYFfQ7Iwe2yhODk8+J4C7yAoRTWI3w/4klGRgR4lO7Rpn9+gvMyWp+uxFh8+H+ARlgN1nJuJuQAYvNkEnwGFck18Er4q3egEc/oO+mhLdKgRyhdNFiacC0rlOCbhNVz4H9FnAYgDBvU3QIioZlJFLJtsoHYRDfiZoUyIxqCtRpVlANq0EU4dApjrtgezPFad5S19Wgjkc0hNVnuF4HjVA6C7QrSIbylB+oZe3aHgBsqlNqKYH48jXyJKMuAbiyVJ8KzaB3eRc0pg9VwQ4niFryI68qiOi3AbjwdsfnAtk0bCjTLJKr6mrD9g8iq/S/B81hguOMlQTnVyG40wAcjnmgsCNESDrjme7wfftP4P7SP4N3CJZdvzoNyGq2c/HWOXJGsvVg+RA/k2MC/wN6I2YA2Pt8GkAAAAASUVORK5CYII=") !important; -} - -#toast-container > .toast-success { - background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAADsSURBVEhLY2AYBfQMgf///3P8+/evAIgvA/FsIF+BavYDDWMBGroaSMMBiE8VC7AZDrIFaMFnii3AZTjUgsUUWUDA8OdAH6iQbQEhw4HyGsPEcKBXBIC4ARhex4G4BsjmweU1soIFaGg/WtoFZRIZdEvIMhxkCCjXIVsATV6gFGACs4Rsw0EGgIIH3QJYJgHSARQZDrWAB+jawzgs+Q2UO49D7jnRSRGoEFRILcdmEMWGI0cm0JJ2QpYA1RDvcmzJEWhABhD/pqrL0S0CWuABKgnRki9lLseS7g2AlqwHWQSKH4oKLrILpRGhEQCw2LiRUIa4lwAAAABJRU5ErkJggg==") !important; -} - -#toast-container > .toast-warning { - background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGYSURBVEhL5ZSvTsNQFMbXZGICMYGYmJhAQIJAICYQPAACiSDB8AiICQQJT4CqQEwgJvYASAQCiZiYmJhAIBATCARJy+9rTsldd8sKu1M0+dLb057v6/lbq/2rK0mS/TRNj9cWNAKPYIJII7gIxCcQ51cvqID+GIEX8ASG4B1bK5gIZFeQfoJdEXOfgX4QAQg7kH2A65yQ87lyxb27sggkAzAuFhbbg1K2kgCkB1bVwyIR9m2L7PRPIhDUIXgGtyKw575yz3lTNs6X4JXnjV+LKM/m3MydnTbtOKIjtz6VhCBq4vSm3ncdrD2lk0VgUXSVKjVDJXJzijW1RQdsU7F77He8u68koNZTz8Oz5yGa6J3H3lZ0xYgXBK2QymlWWA+RWnYhskLBv2vmE+hBMCtbA7KX5drWyRT/2JsqZ2IvfB9Y4bWDNMFbJRFmC9E74SoS0CqulwjkC0+5bpcV1CZ8NMej4pjy0U+doDQsGyo1hzVJttIjhQ7GnBtRFN1UarUlH8F3xict+HY07rEzoUGPlWcjRFRr4/gChZgc3ZL2d8oAAAAASUVORK5CYII=") !important; -} - -#toast-container.toast-top-center > div, -#toast-container.toast-bottom-center > div { - width: 300px; - margin: auto; -} - -#toast-container.toast-top-full-width > div, -#toast-container.toast-bottom-full-width > div { - width: 96%; - margin: auto; -} - -.toast { - background-color: #030303; -} - -.toast-success { - background-color: #359173; -} - -.toast-error { - background-color: #CC3F36; -} - -.toast-info { - background-color: #4ca1a7; -} - -.toast-warning { - background-color: #D87431; -} - -.toast-progress { - position: absolute; - left: 0; - bottom: 0; - height: 4px; - background-color: #000000; - opacity: 0.4; - -ms-filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=40); - filter: alpha(opacity=40); -} - -/*Responsive Design*/ -@media all and (max-width: 240px) { - #toast-container > div { - padding: 8px 8px 8px 50px; - width: 11em; - } - - #toast-container .toast-close-button { - right: -0.2em; - top: -0.2em; - } -} -@media all and (min-width: 241px) and (max-width: 480px) { - #toast-container > div { - padding: 8px 8px 8px 50px; - width: 18em; - } - - #toast-container .toast-close-button { - right: -0.2em; - top: -0.2em; - } -} -@media all and (min-width: 481px) and (max-width: 768px) { - #toast-container > div { - padding: 15px 15px 15px 50px; - width: 25em; - } -} -.dropdown { - position: relative; - display: inline-block; - cursor: pointer; -} - -.dropdown-content { - display: none; - position: absolute; - background-color: #f1f1f1; - min-width: 160px; - overflow: auto; - box-shadow: 0 8px 16px 0 rgba(0, 0, 0, 0.2); - z-index: 1; -} - -.dropdown-content a { - color: black; - padding: 12px 16px; - text-decoration: none; - display: block; -} - -.show { - display: block; -} - -#settings-button { - display: block; -} - -.modal .float-left { - float: left; -} -.modal p#status { - float: right; - color: #1b3544; - font-size: 0.7em; - margin-right: 2%; -} -.modal p#status.error { - color: #D9534F; -} -.modal h4.large { - font-size: 1.2em; -} -.modal p.description { - line-height: 1em; - display: inline-block; - font-size: 0.8em; - margin: 0; - margin-top: 0.2em; - color: #999999; -} -.modal .col-1-6.switch-row { - margin: auto; -} -.modal .switch { - position: absolute; - display: inline-block; - width: 60px; - height: 26px; - right: 5%; -} -.modal .switch input { - display: none; -} -.modal .slider { - position: absolute; - cursor: pointer; - top: 0; - left: 0; - right: 0; - bottom: 0; - background-color: #ccc; - -webkit-transition: 0.4s; - transition: 0.4s; -} -.modal .slider:before { - position: absolute; - content: ""; - height: 18px; - width: 26px; - left: 4px; - bottom: 4px; - background-color: white; - -webkit-transition: 0.4s; - transition: 0.4s; -} -.modal input:checked + .slider { - background-color: #2A735B; -} -.modal input:focus + .slider { - box-shadow: 0 0 1px #2A735B; -} -.modal input:checked + .slider:before { - -webkit-transform: translateX(26px); - -ms-transform: translateX(26px); - transform: translateX(26px); -} -.modal .row { - display: -webkit-box; - display: -ms-flexbox; - display: flex; - -ms-flex-wrap: wrap; - flex-wrap: wrap; - margin-right: -15px; - margin-left: -15px; -} - -/*! - Ionicons, v2.0.1 - Created by Ben Sperry for the Ionic Framework, http://ionicons.com/ - https://twitter.com/benjsperry https://twitter.com/ionicframework - MIT License: https://github.com/driftyco/ionicons - - Android-style icons originally built by Google’s - Material Design Icons: https://github.com/google/material-design-icons - used under CC BY http://creativecommons.org/licenses/by/4.0/ - Modified icons to fit ionicon’s grid from original. -*/ -@font-face { - font-family: "Ionicons"; - src: url("../fonts/ionicons.eot?v=2.0.1"); - src: url("../fonts/ionicons.eot?v=2.0.1#iefix") format("embedded-opentype"), url("../fonts/ionicons.ttf?v=2.0.1") format("truetype"), url("../fonts/ionicons.woff?v=2.0.1") format("woff"), url("../fonts/ionicons.svg?v=2.0.1#Ionicons") format("svg"); - font-weight: normal; - font-style: normal; -} -.ion, .ionicons, -.ion-alert:before, -.ion-alert-circled:before, -.ion-android-add:before, -.ion-android-add-circle:before, -.ion-android-alarm-clock:before, -.ion-android-alert:before, -.ion-android-apps:before, -.ion-android-archive:before, -.ion-android-arrow-back:before, -.ion-android-arrow-down:before, -.ion-android-arrow-dropdown:before, -.ion-android-arrow-dropdown-circle:before, -.ion-android-arrow-dropleft:before, -.ion-android-arrow-dropleft-circle:before, -.ion-android-arrow-dropright:before, -.ion-android-arrow-dropright-circle:before, -.ion-android-arrow-dropup:before, -.ion-android-arrow-dropup-circle:before, -.ion-android-arrow-forward:before, -.ion-android-arrow-up:before, -.ion-android-attach:before, -.ion-android-bar:before, -.ion-android-bicycle:before, -.ion-android-boat:before, -.ion-android-bookmark:before, -.ion-android-bulb:before, -.ion-android-bus:before, -.ion-android-calendar:before, -.ion-android-call:before, -.ion-android-camera:before, -.ion-android-cancel:before, -.ion-android-car:before, -.ion-android-cart:before, -.ion-android-chat:before, -.ion-android-checkbox:before, -.ion-android-checkbox-blank:before, -.ion-android-checkbox-outline:before, -.ion-android-checkbox-outline-blank:before, -.ion-android-checkmark-circle:before, -.ion-android-clipboard:before, -.ion-android-close:before, -.ion-android-cloud:before, -.ion-android-cloud-circle:before, -.ion-android-cloud-done:before, -.ion-android-cloud-outline:before, -.ion-android-color-palette:before, -.ion-android-compass:before, -.ion-android-contact:before, -.ion-android-contacts:before, -.ion-android-contract:before, -.ion-android-create:before, -.ion-android-delete:before, -.ion-android-desktop:before, -.ion-android-document:before, -.ion-android-done:before, -.ion-android-done-all:before, -.ion-android-download:before, -.ion-android-drafts:before, -.ion-android-exit:before, -.ion-android-expand:before, -.ion-android-favorite:before, -.ion-android-favorite-outline:before, -.ion-android-film:before, -.ion-android-folder:before, -.ion-android-folder-open:before, -.ion-android-funnel:before, -.ion-android-globe:before, -.ion-android-hand:before, -.ion-android-hangout:before, -.ion-android-happy:before, -.ion-android-home:before, -.ion-android-image:before, -.ion-android-laptop:before, -.ion-android-list:before, -.ion-android-locate:before, -.ion-android-lock:before, -.ion-android-mail:before, -.ion-android-map:before, -.ion-android-menu:before, -.ion-android-microphone:before, -.ion-android-microphone-off:before, -.ion-android-more-horizontal:before, -.ion-android-more-vertical:before, -.ion-android-navigate:before, -.ion-android-notifications:before, -.ion-android-notifications-none:before, -.ion-android-notifications-off:before, -.ion-android-open:before, -.ion-android-options:before, -.ion-android-people:before, -.ion-android-person:before, -.ion-android-person-add:before, -.ion-android-phone-landscape:before, -.ion-android-phone-portrait:before, -.ion-android-pin:before, -.ion-android-plane:before, -.ion-android-playstore:before, -.ion-android-print:before, -.ion-android-radio-button-off:before, -.ion-android-radio-button-on:before, -.ion-android-refresh:before, -.ion-android-remove:before, -.ion-android-remove-circle:before, -.ion-android-restaurant:before, -.ion-android-sad:before, -.ion-android-search:before, -.ion-android-send:before, -.ion-android-settings:before, -.ion-android-share:before, -.ion-android-share-alt:before, -.ion-android-star:before, -.ion-android-star-half:before, -.ion-android-star-outline:before, -.ion-android-stopwatch:before, -.ion-android-subway:before, -.ion-android-sunny:before, -.ion-android-sync:before, -.ion-android-textsms:before, -.ion-android-time:before, -.ion-android-train:before, -.ion-android-unlock:before, -.ion-android-upload:before, -.ion-android-volume-down:before, -.ion-android-volume-mute:before, -.ion-android-volume-off:before, -.ion-android-volume-up:before, -.ion-android-walk:before, -.ion-android-warning:before, -.ion-android-watch:before, -.ion-android-wifi:before, -.ion-aperture:before, -.ion-archive:before, -.ion-arrow-down-a:before, -.ion-arrow-down-b:before, -.ion-arrow-down-c:before, -.ion-arrow-expand:before, -.ion-arrow-graph-down-left:before, -.ion-arrow-graph-down-right:before, -.ion-arrow-graph-up-left:before, -.ion-arrow-graph-up-right:before, -.ion-arrow-left-a:before, -.ion-arrow-left-b:before, -.ion-arrow-left-c:before, -.ion-arrow-move:before, -.ion-arrow-resize:before, -.ion-arrow-return-left:before, -.ion-arrow-return-right:before, -.ion-arrow-right-a:before, -.ion-arrow-right-b:before, -.ion-arrow-right-c:before, -.ion-arrow-shrink:before, -.ion-arrow-swap:before, -.ion-arrow-up-a:before, -.ion-arrow-up-b:before, -.ion-arrow-up-c:before, -.ion-asterisk:before, -.ion-at:before, -.ion-backspace:before, -.ion-backspace-outline:before, -.ion-bag:before, -.ion-battery-charging:before, -.ion-battery-empty:before, -.ion-battery-full:before, -.ion-battery-half:before, -.ion-battery-low:before, -.ion-beaker:before, -.ion-beer:before, -.ion-bluetooth:before, -.ion-bonfire:before, -.ion-bookmark:before, -.ion-bowtie:before, -.ion-briefcase:before, -.ion-bug:before, -.ion-calculator:before, -.ion-calendar:before, -.ion-camera:before, -.ion-card:before, -.ion-cash:before, -.ion-chatbox:before, -.ion-chatbox-working:before, -.ion-chatboxes:before, -.ion-chatbubble:before, -.ion-chatbubble-working:before, -.ion-chatbubbles:before, -.ion-checkmark:before, -.ion-checkmark-circled:before, -.ion-checkmark-round:before, -.ion-chevron-down:before, -.ion-chevron-left:before, -.ion-chevron-right:before, -.ion-chevron-up:before, -.ion-clipboard:before, -.ion-clock:before, -.ion-close:before, -.ion-close-circled:before, -.ion-close-round:before, -.ion-closed-captioning:before, -.ion-cloud:before, -.ion-code:before, -.ion-code-download:before, -.ion-code-working:before, -.ion-coffee:before, -.ion-compass:before, -.ion-compose:before, -.ion-connection-bars:before, -.ion-contrast:before, -.ion-crop:before, -.ion-cube:before, -.ion-disc:before, -.ion-document:before, -.ion-document-text:before, -.ion-drag:before, -.ion-earth:before, -.ion-easel:before, -.ion-edit:before, -.ion-egg:before, -.ion-eject:before, -.ion-email:before, -.ion-email-unread:before, -.ion-erlenmeyer-flask:before, -.ion-erlenmeyer-flask-bubbles:before, -.ion-eye:before, -.ion-eye-disabled:before, -.ion-female:before, -.ion-filing:before, -.ion-film-marker:before, -.ion-fireball:before, -.ion-flag:before, -.ion-flame:before, -.ion-flash:before, -.ion-flash-off:before, -.ion-folder:before, -.ion-fork:before, -.ion-fork-repo:before, -.ion-forward:before, -.ion-funnel:before, -.ion-gear-a:before, -.ion-gear-b:before, -.ion-grid:before, -.ion-hammer:before, -.ion-happy:before, -.ion-happy-outline:before, -.ion-headphone:before, -.ion-heart:before, -.ion-heart-broken:before, -.ion-help:before, -.ion-help-buoy:before, -.ion-help-circled:before, -.ion-home:before, -.ion-icecream:before, -.ion-image:before, -.ion-images:before, -.ion-information:before, -.ion-information-circled:before, -.ion-ionic:before, -.ion-ios-alarm:before, -.ion-ios-alarm-outline:before, -.ion-ios-albums:before, -.ion-ios-albums-outline:before, -.ion-ios-americanfootball:before, -.ion-ios-americanfootball-outline:before, -.ion-ios-analytics:before, -.ion-ios-analytics-outline:before, -.ion-ios-arrow-back:before, -.ion-ios-arrow-down:before, -.ion-ios-arrow-forward:before, -.ion-ios-arrow-left:before, -.ion-ios-arrow-right:before, -.ion-ios-arrow-thin-down:before, -.ion-ios-arrow-thin-left:before, -.ion-ios-arrow-thin-right:before, -.ion-ios-arrow-thin-up:before, -.ion-ios-arrow-up:before, -.ion-ios-at:before, -.ion-ios-at-outline:before, -.ion-ios-barcode:before, -.ion-ios-barcode-outline:before, -.ion-ios-baseball:before, -.ion-ios-baseball-outline:before, -.ion-ios-basketball:before, -.ion-ios-basketball-outline:before, -.ion-ios-bell:before, -.ion-ios-bell-outline:before, -.ion-ios-body:before, -.ion-ios-body-outline:before, -.ion-ios-bolt:before, -.ion-ios-bolt-outline:before, -.ion-ios-book:before, -.ion-ios-book-outline:before, -.ion-ios-bookmarks:before, -.ion-ios-bookmarks-outline:before, -.ion-ios-box:before, -.ion-ios-box-outline:before, -.ion-ios-briefcase:before, -.ion-ios-briefcase-outline:before, -.ion-ios-browsers:before, -.ion-ios-browsers-outline:before, -.ion-ios-calculator:before, -.ion-ios-calculator-outline:before, -.ion-ios-calendar:before, -.ion-ios-calendar-outline:before, -.ion-ios-camera:before, -.ion-ios-camera-outline:before, -.ion-ios-cart:before, -.ion-ios-cart-outline:before, -.ion-ios-chatboxes:before, -.ion-ios-chatboxes-outline:before, -.ion-ios-chatbubble:before, -.ion-ios-chatbubble-outline:before, -.ion-ios-checkmark:before, -.ion-ios-checkmark-empty:before, -.ion-ios-checkmark-outline:before, -.ion-ios-circle-filled:before, -.ion-ios-circle-outline:before, -.ion-ios-clock:before, -.ion-ios-clock-outline:before, -.ion-ios-close:before, -.ion-ios-close-empty:before, -.ion-ios-close-outline:before, -.ion-ios-cloud:before, -.ion-ios-cloud-download:before, -.ion-ios-cloud-download-outline:before, -.ion-ios-cloud-outline:before, -.ion-ios-cloud-upload:before, -.ion-ios-cloud-upload-outline:before, -.ion-ios-cloudy:before, -.ion-ios-cloudy-night:before, -.ion-ios-cloudy-night-outline:before, -.ion-ios-cloudy-outline:before, -.ion-ios-cog:before, -.ion-ios-cog-outline:before, -.ion-ios-color-filter:before, -.ion-ios-color-filter-outline:before, -.ion-ios-color-wand:before, -.ion-ios-color-wand-outline:before, -.ion-ios-compose:before, -.ion-ios-compose-outline:before, -.ion-ios-contact:before, -.ion-ios-contact-outline:before, -.ion-ios-copy:before, -.ion-ios-copy-outline:before, -.ion-ios-crop:before, -.ion-ios-crop-strong:before, -.ion-ios-download:before, -.ion-ios-download-outline:before, -.ion-ios-drag:before, -.ion-ios-email:before, -.ion-ios-email-outline:before, -.ion-ios-eye:before, -.ion-ios-eye-outline:before, -.ion-ios-fastforward:before, -.ion-ios-fastforward-outline:before, -.ion-ios-filing:before, -.ion-ios-filing-outline:before, -.ion-ios-film:before, -.ion-ios-film-outline:before, -.ion-ios-flag:before, -.ion-ios-flag-outline:before, -.ion-ios-flame:before, -.ion-ios-flame-outline:before, -.ion-ios-flask:before, -.ion-ios-flask-outline:before, -.ion-ios-flower:before, -.ion-ios-flower-outline:before, -.ion-ios-folder:before, -.ion-ios-folder-outline:before, -.ion-ios-football:before, -.ion-ios-football-outline:before, -.ion-ios-game-controller-a:before, -.ion-ios-game-controller-a-outline:before, -.ion-ios-game-controller-b:before, -.ion-ios-game-controller-b-outline:before, -.ion-ios-gear:before, -.ion-ios-gear-outline:before, -.ion-ios-glasses:before, -.ion-ios-glasses-outline:before, -.ion-ios-grid-view:before, -.ion-ios-grid-view-outline:before, -.ion-ios-heart:before, -.ion-ios-heart-outline:before, -.ion-ios-help:before, -.ion-ios-help-empty:before, -.ion-ios-help-outline:before, -.ion-ios-home:before, -.ion-ios-home-outline:before, -.ion-ios-infinite:before, -.ion-ios-infinite-outline:before, -.ion-ios-information:before, -.ion-ios-information-empty:before, -.ion-ios-information-outline:before, -.ion-ios-ionic-outline:before, -.ion-ios-keypad:before, -.ion-ios-keypad-outline:before, -.ion-ios-lightbulb:before, -.ion-ios-lightbulb-outline:before, -.ion-ios-list:before, -.ion-ios-list-outline:before, -.ion-ios-location:before, -.ion-ios-location-outline:before, -.ion-ios-locked:before, -.ion-ios-locked-outline:before, -.ion-ios-loop:before, -.ion-ios-loop-strong:before, -.ion-ios-medical:before, -.ion-ios-medical-outline:before, -.ion-ios-medkit:before, -.ion-ios-medkit-outline:before, -.ion-ios-mic:before, -.ion-ios-mic-off:before, -.ion-ios-mic-outline:before, -.ion-ios-minus:before, -.ion-ios-minus-empty:before, -.ion-ios-minus-outline:before, -.ion-ios-monitor:before, -.ion-ios-monitor-outline:before, -.ion-ios-moon:before, -.ion-ios-moon-outline:before, -.ion-ios-more:before, -.ion-ios-more-outline:before, -.ion-ios-musical-note:before, -.ion-ios-musical-notes:before, -.ion-ios-navigate:before, -.ion-ios-navigate-outline:before, -.ion-ios-nutrition:before, -.ion-ios-nutrition-outline:before, -.ion-ios-paper:before, -.ion-ios-paper-outline:before, -.ion-ios-paperplane:before, -.ion-ios-paperplane-outline:before, -.ion-ios-partlysunny:before, -.ion-ios-partlysunny-outline:before, -.ion-ios-pause:before, -.ion-ios-pause-outline:before, -.ion-ios-paw:before, -.ion-ios-paw-outline:before, -.ion-ios-people:before, -.ion-ios-people-outline:before, -.ion-ios-person:before, -.ion-ios-person-outline:before, -.ion-ios-personadd:before, -.ion-ios-personadd-outline:before, -.ion-ios-photos:before, -.ion-ios-photos-outline:before, -.ion-ios-pie:before, -.ion-ios-pie-outline:before, -.ion-ios-pint:before, -.ion-ios-pint-outline:before, -.ion-ios-play:before, -.ion-ios-play-outline:before, -.ion-ios-plus:before, -.ion-ios-plus-empty:before, -.ion-ios-plus-outline:before, -.ion-ios-pricetag:before, -.ion-ios-pricetag-outline:before, -.ion-ios-pricetags:before, -.ion-ios-pricetags-outline:before, -.ion-ios-printer:before, -.ion-ios-printer-outline:before, -.ion-ios-pulse:before, -.ion-ios-pulse-strong:before, -.ion-ios-rainy:before, -.ion-ios-rainy-outline:before, -.ion-ios-recording:before, -.ion-ios-recording-outline:before, -.ion-ios-redo:before, -.ion-ios-redo-outline:before, -.ion-ios-refresh:before, -.ion-ios-refresh-empty:before, -.ion-ios-refresh-outline:before, -.ion-ios-reload:before, -.ion-ios-reverse-camera:before, -.ion-ios-reverse-camera-outline:before, -.ion-ios-rewind:before, -.ion-ios-rewind-outline:before, -.ion-ios-rose:before, -.ion-ios-rose-outline:before, -.ion-ios-search:before, -.ion-ios-search-strong:before, -.ion-ios-settings:before, -.ion-ios-settings-strong:before, -.ion-ios-shuffle:before, -.ion-ios-shuffle-strong:before, -.ion-ios-skipbackward:before, -.ion-ios-skipbackward-outline:before, -.ion-ios-skipforward:before, -.ion-ios-skipforward-outline:before, -.ion-ios-snowy:before, -.ion-ios-speedometer:before, -.ion-ios-speedometer-outline:before, -.ion-ios-star:before, -.ion-ios-star-half:before, -.ion-ios-star-outline:before, -.ion-ios-stopwatch:before, -.ion-ios-stopwatch-outline:before, -.ion-ios-sunny:before, -.ion-ios-sunny-outline:before, -.ion-ios-telephone:before, -.ion-ios-telephone-outline:before, -.ion-ios-tennisball:before, -.ion-ios-tennisball-outline:before, -.ion-ios-thunderstorm:before, -.ion-ios-thunderstorm-outline:before, -.ion-ios-time:before, -.ion-ios-time-outline:before, -.ion-ios-timer:before, -.ion-ios-timer-outline:before, -.ion-ios-toggle:before, -.ion-ios-toggle-outline:before, -.ion-ios-trash:before, -.ion-ios-trash-outline:before, -.ion-ios-undo:before, -.ion-ios-undo-outline:before, -.ion-ios-unlocked:before, -.ion-ios-unlocked-outline:before, -.ion-ios-upload:before, -.ion-ios-upload-outline:before, -.ion-ios-videocam:before, -.ion-ios-videocam-outline:before, -.ion-ios-volume-high:before, -.ion-ios-volume-low:before, -.ion-ios-wineglass:before, -.ion-ios-wineglass-outline:before, -.ion-ios-world:before, -.ion-ios-world-outline:before, -.ion-ipad:before, -.ion-iphone:before, -.ion-ipod:before, -.ion-jet:before, -.ion-key:before, -.ion-knife:before, -.ion-laptop:before, -.ion-leaf:before, -.ion-levels:before, -.ion-lightbulb:before, -.ion-link:before, -.ion-load-a:before, -.ion-load-b:before, -.ion-load-c:before, -.ion-load-d:before, -.ion-location:before, -.ion-lock-combination:before, -.ion-locked:before, -.ion-log-in:before, -.ion-log-out:before, -.ion-loop:before, -.ion-magnet:before, -.ion-male:before, -.ion-man:before, -.ion-map:before, -.ion-medkit:before, -.ion-merge:before, -.ion-mic-a:before, -.ion-mic-b:before, -.ion-mic-c:before, -.ion-minus:before, -.ion-minus-circled:before, -.ion-minus-round:before, -.ion-model-s:before, -.ion-monitor:before, -.ion-more:before, -.ion-mouse:before, -.ion-music-note:before, -.ion-navicon:before, -.ion-navicon-round:before, -.ion-navigate:before, -.ion-network:before, -.ion-no-smoking:before, -.ion-nuclear:before, -.ion-outlet:before, -.ion-paintbrush:before, -.ion-paintbucket:before, -.ion-paper-airplane:before, -.ion-paperclip:before, -.ion-pause:before, -.ion-person:before, -.ion-person-add:before, -.ion-person-stalker:before, -.ion-pie-graph:before, -.ion-pin:before, -.ion-pinpoint:before, -.ion-pizza:before, -.ion-plane:before, -.ion-planet:before, -.ion-play:before, -.ion-playstation:before, -.ion-plus:before, -.ion-plus-circled:before, -.ion-plus-round:before, -.ion-podium:before, -.ion-pound:before, -.ion-power:before, -.ion-pricetag:before, -.ion-pricetags:before, -.ion-printer:before, -.ion-pull-request:before, -.ion-qr-scanner:before, -.ion-quote:before, -.ion-radio-waves:before, -.ion-record:before, -.ion-refresh:before, -.ion-reply:before, -.ion-reply-all:before, -.ion-ribbon-a:before, -.ion-ribbon-b:before, -.ion-sad:before, -.ion-sad-outline:before, -.ion-scissors:before, -.ion-search:before, -.ion-settings:before, -.ion-share:before, -.ion-shuffle:before, -.ion-skip-backward:before, -.ion-skip-forward:before, -.ion-social-android:before, -.ion-social-android-outline:before, -.ion-social-angular:before, -.ion-social-angular-outline:before, -.ion-social-apple:before, -.ion-social-apple-outline:before, -.ion-social-bitcoin:before, -.ion-social-bitcoin-outline:before, -.ion-social-buffer:before, -.ion-social-buffer-outline:before, -.ion-social-chrome:before, -.ion-social-chrome-outline:before, -.ion-social-codepen:before, -.ion-social-codepen-outline:before, -.ion-social-css3:before, -.ion-social-css3-outline:before, -.ion-social-designernews:before, -.ion-social-designernews-outline:before, -.ion-social-dribbble:before, -.ion-social-dribbble-outline:before, -.ion-social-dropbox:before, -.ion-social-dropbox-outline:before, -.ion-social-euro:before, -.ion-social-euro-outline:before, -.ion-social-facebook:before, -.ion-social-facebook-outline:before, -.ion-social-foursquare:before, -.ion-social-foursquare-outline:before, -.ion-social-freebsd-devil:before, -.ion-social-github:before, -.ion-social-github-outline:before, -.ion-social-google:before, -.ion-social-google-outline:before, -.ion-social-googleplus:before, -.ion-social-googleplus-outline:before, -.ion-social-hackernews:before, -.ion-social-hackernews-outline:before, -.ion-social-html5:before, -.ion-social-html5-outline:before, -.ion-social-instagram:before, -.ion-social-instagram-outline:before, -.ion-social-javascript:before, -.ion-social-javascript-outline:before, -.ion-social-linkedin:before, -.ion-social-linkedin-outline:before, -.ion-social-markdown:before, -.ion-social-nodejs:before, -.ion-social-octocat:before, -.ion-social-pinterest:before, -.ion-social-pinterest-outline:before, -.ion-social-python:before, -.ion-social-reddit:before, -.ion-social-reddit-outline:before, -.ion-social-rss:before, -.ion-social-rss-outline:before, -.ion-social-sass:before, -.ion-social-skype:before, -.ion-social-skype-outline:before, -.ion-social-snapchat:before, -.ion-social-snapchat-outline:before, -.ion-social-tumblr:before, -.ion-social-tumblr-outline:before, -.ion-social-tux:before, -.ion-social-twitch:before, -.ion-social-twitch-outline:before, -.ion-social-twitter:before, -.ion-social-twitter-outline:before, -.ion-social-usd:before, -.ion-social-usd-outline:before, -.ion-social-vimeo:before, -.ion-social-vimeo-outline:before, -.ion-social-whatsapp:before, -.ion-social-whatsapp-outline:before, -.ion-social-windows:before, -.ion-social-windows-outline:before, -.ion-social-wordpress:before, -.ion-social-wordpress-outline:before, -.ion-social-yahoo:before, -.ion-social-yahoo-outline:before, -.ion-social-yen:before, -.ion-social-yen-outline:before, -.ion-social-youtube:before, -.ion-social-youtube-outline:before, -.ion-soup-can:before, -.ion-soup-can-outline:before, -.ion-speakerphone:before, -.ion-speedometer:before, -.ion-spoon:before, -.ion-star:before, -.ion-stats-bars:before, -.ion-steam:before, -.ion-stop:before, -.ion-thermometer:before, -.ion-thumbsdown:before, -.ion-thumbsup:before, -.ion-toggle:before, -.ion-toggle-filled:before, -.ion-transgender:before, -.ion-trash-a:before, -.ion-trash-b:before, -.ion-trophy:before, -.ion-tshirt:before, -.ion-tshirt-outline:before, -.ion-umbrella:before, -.ion-university:before, -.ion-unlocked:before, -.ion-upload:before, -.ion-usb:before, -.ion-videocamera:before, -.ion-volume-high:before, -.ion-volume-low:before, -.ion-volume-medium:before, -.ion-volume-mute:before, -.ion-wand:before, -.ion-waterdrop:before, -.ion-wifi:before, -.ion-wineglass:before, -.ion-woman:before, -.ion-wrench:before, -.ion-xbox:before { - display: inline-block; - font-family: "Ionicons"; - speak: none; - font-style: normal; - font-weight: normal; - font-variant: normal; - text-transform: none; - text-rendering: auto; - line-height: 1; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} - -.ion-alert:before { - content: ""; -} - -.ion-alert-circled:before { - content: ""; -} - -.ion-android-add:before { - content: ""; -} - -.ion-android-add-circle:before { - content: ""; -} - -.ion-android-alarm-clock:before { - content: ""; -} - -.ion-android-alert:before { - content: ""; -} - -.ion-android-apps:before { - content: ""; -} - -.ion-android-archive:before { - content: ""; -} - -.ion-android-arrow-back:before { - content: ""; -} - -.ion-android-arrow-down:before { - content: ""; -} - -.ion-android-arrow-dropdown:before { - content: ""; -} - -.ion-android-arrow-dropdown-circle:before { - content: ""; -} - -.ion-android-arrow-dropleft:before { - content: ""; -} - -.ion-android-arrow-dropleft-circle:before { - content: ""; -} - -.ion-android-arrow-dropright:before { - content: ""; -} - -.ion-android-arrow-dropright-circle:before { - content: ""; -} - -.ion-android-arrow-dropup:before { - content: ""; -} - -.ion-android-arrow-dropup-circle:before { - content: ""; -} - -.ion-android-arrow-forward:before { - content: ""; -} - -.ion-android-arrow-up:before { - content: ""; -} - -.ion-android-attach:before { - content: ""; -} - -.ion-android-bar:before { - content: ""; -} - -.ion-android-bicycle:before { - content: ""; -} - -.ion-android-boat:before { - content: ""; -} - -.ion-android-bookmark:before { - content: ""; -} - -.ion-android-bulb:before { - content: ""; -} - -.ion-android-bus:before { - content: ""; -} - -.ion-android-calendar:before { - content: ""; -} - -.ion-android-call:before { - content: ""; -} - -.ion-android-camera:before { - content: ""; -} - -.ion-android-cancel:before { - content: ""; -} - -.ion-android-car:before { - content: ""; -} - -.ion-android-cart:before { - content: ""; -} - -.ion-android-chat:before { - content: ""; -} - -.ion-android-checkbox:before { - content: ""; -} - -.ion-android-checkbox-blank:before { - content: ""; -} - -.ion-android-checkbox-outline:before { - content: ""; -} - -.ion-android-checkbox-outline-blank:before { - content: ""; -} - -.ion-android-checkmark-circle:before { - content: ""; -} - -.ion-android-clipboard:before { - content: ""; -} - -.ion-android-close:before { - content: ""; -} - -.ion-android-cloud:before { - content: ""; -} - -.ion-android-cloud-circle:before { - content: ""; -} - -.ion-android-cloud-done:before { - content: ""; -} - -.ion-android-cloud-outline:before { - content: ""; -} - -.ion-android-color-palette:before { - content: ""; -} - -.ion-android-compass:before { - content: ""; -} - -.ion-android-contact:before { - content: ""; -} - -.ion-android-contacts:before { - content: ""; -} - -.ion-android-contract:before { - content: ""; -} - -.ion-android-create:before { - content: ""; -} - -.ion-android-delete:before { - content: ""; -} - -.ion-android-desktop:before { - content: ""; -} - -.ion-android-document:before { - content: ""; -} - -.ion-android-done:before { - content: ""; -} - -.ion-android-done-all:before { - content: ""; -} - -.ion-android-download:before { - content: ""; -} - -.ion-android-drafts:before { - content: ""; -} - -.ion-android-exit:before { - content: ""; -} - -.ion-android-expand:before { - content: ""; -} - -.ion-android-favorite:before { - content: ""; -} - -.ion-android-favorite-outline:before { - content: ""; -} - -.ion-android-film:before { - content: ""; -} - -.ion-android-folder:before { - content: ""; -} - -.ion-android-folder-open:before { - content: ""; -} - -.ion-android-funnel:before { - content: ""; -} - -.ion-android-globe:before { - content: ""; -} - -.ion-android-hand:before { - content: ""; -} - -.ion-android-hangout:before { - content: ""; -} - -.ion-android-happy:before { - content: ""; -} - -.ion-android-home:before { - content: ""; -} - -.ion-android-image:before { - content: ""; -} - -.ion-android-laptop:before { - content: ""; -} - -.ion-android-list:before { - content: ""; -} - -.ion-android-locate:before { - content: ""; -} - -.ion-android-lock:before { - content: ""; -} - -.ion-android-mail:before { - content: ""; -} - -.ion-android-map:before { - content: ""; -} - -.ion-android-menu:before { - content: ""; -} - -.ion-android-microphone:before { - content: ""; -} - -.ion-android-microphone-off:before { - content: ""; -} - -.ion-android-more-horizontal:before { - content: ""; -} - -.ion-android-more-vertical:before { - content: ""; -} - -.ion-android-navigate:before { - content: ""; -} - -.ion-android-notifications:before { - content: ""; -} - -.ion-android-notifications-none:before { - content: ""; -} - -.ion-android-notifications-off:before { - content: ""; -} - -.ion-android-open:before { - content: ""; -} - -.ion-android-options:before { - content: ""; -} - -.ion-android-people:before { - content: ""; -} - -.ion-android-person:before { - content: ""; -} - -.ion-android-person-add:before { - content: ""; -} - -.ion-android-phone-landscape:before { - content: ""; -} - -.ion-android-phone-portrait:before { - content: ""; -} - -.ion-android-pin:before { - content: ""; -} - -.ion-android-plane:before { - content: ""; -} - -.ion-android-playstore:before { - content: ""; -} - -.ion-android-print:before { - content: ""; -} - -.ion-android-radio-button-off:before { - content: ""; -} - -.ion-android-radio-button-on:before { - content: ""; -} - -.ion-android-refresh:before { - content: ""; -} - -.ion-android-remove:before { - content: ""; -} - -.ion-android-remove-circle:before { - content: ""; -} - -.ion-android-restaurant:before { - content: ""; -} - -.ion-android-sad:before { - content: ""; -} - -.ion-android-search:before { - content: ""; -} - -.ion-android-send:before { - content: ""; -} - -.ion-android-settings:before { - content: ""; -} - -.ion-android-share:before { - content: ""; -} - -.ion-android-share-alt:before { - content: ""; -} - -.ion-android-star:before { - content: ""; -} - -.ion-android-star-half:before { - content: ""; -} - -.ion-android-star-outline:before { - content: ""; -} - -.ion-android-stopwatch:before { - content: ""; -} - -.ion-android-subway:before { - content: ""; -} - -.ion-android-sunny:before { - content: ""; -} - -.ion-android-sync:before { - content: ""; -} - -.ion-android-textsms:before { - content: ""; -} - -.ion-android-time:before { - content: ""; -} - -.ion-android-train:before { - content: ""; -} - -.ion-android-unlock:before { - content: ""; -} - -.ion-android-upload:before { - content: ""; -} - -.ion-android-volume-down:before { - content: ""; -} - -.ion-android-volume-mute:before { - content: ""; -} - -.ion-android-volume-off:before { - content: ""; -} - -.ion-android-volume-up:before { - content: ""; -} - -.ion-android-walk:before { - content: ""; -} - -.ion-android-warning:before { - content: ""; -} - -.ion-android-watch:before { - content: ""; -} - -.ion-android-wifi:before { - content: ""; -} - -.ion-aperture:before { - content: ""; -} - -.ion-archive:before { - content: ""; -} - -.ion-arrow-down-a:before { - content: ""; -} - -.ion-arrow-down-b:before { - content: ""; -} - -.ion-arrow-down-c:before { - content: ""; -} - -.ion-arrow-expand:before { - content: ""; -} - -.ion-arrow-graph-down-left:before { - content: ""; -} - -.ion-arrow-graph-down-right:before { - content: ""; -} - -.ion-arrow-graph-up-left:before { - content: ""; -} - -.ion-arrow-graph-up-right:before { - content: ""; -} - -.ion-arrow-left-a:before { - content: ""; -} - -.ion-arrow-left-b:before { - content: ""; -} - -.ion-arrow-left-c:before { - content: ""; -} - -.ion-arrow-move:before { - content: ""; -} - -.ion-arrow-resize:before { - content: ""; -} - -.ion-arrow-return-left:before { - content: ""; -} - -.ion-arrow-return-right:before { - content: ""; -} - -.ion-arrow-right-a:before { - content: ""; -} - -.ion-arrow-right-b:before { - content: ""; -} - -.ion-arrow-right-c:before { - content: ""; -} - -.ion-arrow-shrink:before { - content: ""; -} - -.ion-arrow-swap:before { - content: ""; -} - -.ion-arrow-up-a:before { - content: ""; -} - -.ion-arrow-up-b:before { - content: ""; -} - -.ion-arrow-up-c:before { - content: ""; -} - -.ion-asterisk:before { - content: ""; -} - -.ion-at:before { - content: ""; -} - -.ion-backspace:before { - content: ""; -} - -.ion-backspace-outline:before { - content: ""; -} - -.ion-bag:before { - content: ""; -} - -.ion-battery-charging:before { - content: ""; -} - -.ion-battery-empty:before { - content: ""; -} - -.ion-battery-full:before { - content: ""; -} - -.ion-battery-half:before { - content: ""; -} - -.ion-battery-low:before { - content: ""; -} - -.ion-beaker:before { - content: ""; -} - -.ion-beer:before { - content: ""; -} - -.ion-bluetooth:before { - content: ""; -} - -.ion-bonfire:before { - content: ""; -} - -.ion-bookmark:before { - content: ""; -} - -.ion-bowtie:before { - content: ""; -} - -.ion-briefcase:before { - content: ""; -} - -.ion-bug:before { - content: ""; -} - -.ion-calculator:before { - content: ""; -} - -.ion-calendar:before { - content: ""; -} - -.ion-camera:before { - content: ""; -} - -.ion-card:before { - content: ""; -} - -.ion-cash:before { - content: ""; -} - -.ion-chatbox:before { - content: ""; -} - -.ion-chatbox-working:before { - content: ""; -} - -.ion-chatboxes:before { - content: ""; -} - -.ion-chatbubble:before { - content: ""; -} - -.ion-chatbubble-working:before { - content: ""; -} - -.ion-chatbubbles:before { - content: ""; -} - -.ion-checkmark:before { - content: ""; -} - -.ion-checkmark-circled:before { - content: ""; -} - -.ion-checkmark-round:before { - content: ""; -} - -.ion-chevron-down:before { - content: ""; -} - -.ion-chevron-left:before { - content: ""; -} - -.ion-chevron-right:before { - content: ""; -} - -.ion-chevron-up:before { - content: ""; -} - -.ion-clipboard:before { - content: ""; -} - -.ion-clock:before { - content: ""; -} - -.ion-close:before { - content: ""; -} - -.ion-close-circled:before { - content: ""; -} - -.ion-close-round:before { - content: ""; -} - -.ion-closed-captioning:before { - content: ""; -} - -.ion-cloud:before { - content: ""; -} - -.ion-code:before { - content: ""; -} - -.ion-code-download:before { - content: ""; -} - -.ion-code-working:before { - content: ""; -} - -.ion-coffee:before { - content: ""; -} - -.ion-compass:before { - content: ""; -} - -.ion-compose:before { - content: ""; -} - -.ion-connection-bars:before { - content: ""; -} - -.ion-contrast:before { - content: ""; -} - -.ion-crop:before { - content: ""; -} - -.ion-cube:before { - content: ""; -} - -.ion-disc:before { - content: ""; -} - -.ion-document:before { - content: ""; -} - -.ion-document-text:before { - content: ""; -} - -.ion-drag:before { - content: ""; -} - -.ion-earth:before { - content: ""; -} - -.ion-easel:before { - content: ""; -} - -.ion-edit:before { - content: ""; -} - -.ion-egg:before { - content: ""; -} - -.ion-eject:before { - content: ""; -} - -.ion-email:before { - content: ""; -} - -.ion-email-unread:before { - content: ""; -} - -.ion-erlenmeyer-flask:before { - content: ""; -} - -.ion-erlenmeyer-flask-bubbles:before { - content: ""; -} - -.ion-eye:before { - content: ""; -} - -.ion-eye-disabled:before { - content: ""; -} - -.ion-female:before { - content: ""; -} - -.ion-filing:before { - content: ""; -} - -.ion-film-marker:before { - content: ""; -} - -.ion-fireball:before { - content: ""; -} - -.ion-flag:before { - content: ""; -} - -.ion-flame:before { - content: ""; -} - -.ion-flash:before { - content: ""; -} - -.ion-flash-off:before { - content: ""; -} - -.ion-folder:before { - content: ""; -} - -.ion-fork:before { - content: ""; -} - -.ion-fork-repo:before { - content: ""; -} - -.ion-forward:before { - content: ""; -} - -.ion-funnel:before { - content: ""; -} - -.ion-gear-a:before { - content: ""; -} - -.ion-gear-b:before { - content: ""; -} - -.ion-grid:before { - content: ""; -} - -.ion-hammer:before { - content: ""; -} - -.ion-happy:before { - content: ""; -} - -.ion-happy-outline:before { - content: ""; -} - -.ion-headphone:before { - content: ""; -} - -.ion-heart:before { - content: ""; -} - -.ion-heart-broken:before { - content: ""; -} - -.ion-help:before { - content: ""; -} - -.ion-help-buoy:before { - content: ""; -} - -.ion-help-circled:before { - content: ""; -} - -.ion-home:before { - content: ""; -} - -.ion-icecream:before { - content: ""; -} - -.ion-image:before { - content: ""; -} - -.ion-images:before { - content: ""; -} - -.ion-information:before { - content: ""; -} - -.ion-information-circled:before { - content: ""; -} - -.ion-ionic:before { - content: ""; -} - -.ion-ios-alarm:before { - content: ""; -} - -.ion-ios-alarm-outline:before { - content: ""; -} - -.ion-ios-albums:before { - content: ""; -} - -.ion-ios-albums-outline:before { - content: ""; -} - -.ion-ios-americanfootball:before { - content: ""; -} - -.ion-ios-americanfootball-outline:before { - content: ""; -} - -.ion-ios-analytics:before { - content: ""; -} - -.ion-ios-analytics-outline:before { - content: ""; -} - -.ion-ios-arrow-back:before { - content: ""; -} - -.ion-ios-arrow-down:before { - content: ""; -} - -.ion-ios-arrow-forward:before { - content: ""; -} - -.ion-ios-arrow-left:before { - content: ""; -} - -.ion-ios-arrow-right:before { - content: ""; -} - -.ion-ios-arrow-thin-down:before { - content: ""; -} - -.ion-ios-arrow-thin-left:before { - content: ""; -} - -.ion-ios-arrow-thin-right:before { - content: ""; -} - -.ion-ios-arrow-thin-up:before { - content: ""; -} - -.ion-ios-arrow-up:before { - content: ""; -} - -.ion-ios-at:before { - content: ""; -} - -.ion-ios-at-outline:before { - content: ""; -} - -.ion-ios-barcode:before { - content: ""; -} - -.ion-ios-barcode-outline:before { - content: ""; -} - -.ion-ios-baseball:before { - content: ""; -} - -.ion-ios-baseball-outline:before { - content: ""; -} - -.ion-ios-basketball:before { - content: ""; -} - -.ion-ios-basketball-outline:before { - content: ""; -} - -.ion-ios-bell:before { - content: ""; -} - -.ion-ios-bell-outline:before { - content: ""; -} - -.ion-ios-body:before { - content: ""; -} - -.ion-ios-body-outline:before { - content: ""; -} - -.ion-ios-bolt:before { - content: ""; -} - -.ion-ios-bolt-outline:before { - content: ""; -} - -.ion-ios-book:before { - content: ""; -} - -.ion-ios-book-outline:before { - content: ""; -} - -.ion-ios-bookmarks:before { - content: ""; -} - -.ion-ios-bookmarks-outline:before { - content: ""; -} - -.ion-ios-box:before { - content: ""; -} - -.ion-ios-box-outline:before { - content: ""; -} - -.ion-ios-briefcase:before { - content: ""; -} - -.ion-ios-briefcase-outline:before { - content: ""; -} - -.ion-ios-browsers:before { - content: ""; -} - -.ion-ios-browsers-outline:before { - content: ""; -} - -.ion-ios-calculator:before { - content: ""; -} - -.ion-ios-calculator-outline:before { - content: ""; -} - -.ion-ios-calendar:before { - content: ""; -} - -.ion-ios-calendar-outline:before { - content: ""; -} - -.ion-ios-camera:before { - content: ""; -} - -.ion-ios-camera-outline:before { - content: ""; -} - -.ion-ios-cart:before { - content: ""; -} - -.ion-ios-cart-outline:before { - content: ""; -} - -.ion-ios-chatboxes:before { - content: ""; -} - -.ion-ios-chatboxes-outline:before { - content: ""; -} - -.ion-ios-chatbubble:before { - content: ""; -} - -.ion-ios-chatbubble-outline:before { - content: ""; -} - -.ion-ios-checkmark:before { - content: ""; -} - -.ion-ios-checkmark-empty:before { - content: ""; -} - -.ion-ios-checkmark-outline:before { - content: ""; -} - -.ion-ios-circle-filled:before { - content: ""; -} - -.ion-ios-circle-outline:before { - content: ""; -} - -.ion-ios-clock:before { - content: ""; -} - -.ion-ios-clock-outline:before { - content: ""; -} - -.ion-ios-close:before { - content: ""; -} - -.ion-ios-close-empty:before { - content: ""; -} - -.ion-ios-close-outline:before { - content: ""; -} - -.ion-ios-cloud:before { - content: ""; -} - -.ion-ios-cloud-download:before { - content: ""; -} - -.ion-ios-cloud-download-outline:before { - content: ""; -} - -.ion-ios-cloud-outline:before { - content: ""; -} - -.ion-ios-cloud-upload:before { - content: ""; -} - -.ion-ios-cloud-upload-outline:before { - content: ""; -} - -.ion-ios-cloudy:before { - content: ""; -} - -.ion-ios-cloudy-night:before { - content: ""; -} - -.ion-ios-cloudy-night-outline:before { - content: ""; -} - -.ion-ios-cloudy-outline:before { - content: ""; -} - -.ion-ios-cog:before { - content: ""; -} - -.ion-ios-cog-outline:before { - content: ""; -} - -.ion-ios-color-filter:before { - content: ""; -} - -.ion-ios-color-filter-outline:before { - content: ""; -} - -.ion-ios-color-wand:before { - content: ""; -} - -.ion-ios-color-wand-outline:before { - content: ""; -} - -.ion-ios-compose:before { - content: ""; -} - -.ion-ios-compose-outline:before { - content: ""; -} - -.ion-ios-contact:before { - content: ""; -} - -.ion-ios-contact-outline:before { - content: ""; -} - -.ion-ios-copy:before { - content: ""; -} - -.ion-ios-copy-outline:before { - content: ""; -} - -.ion-ios-crop:before { - content: ""; -} - -.ion-ios-crop-strong:before { - content: ""; -} - -.ion-ios-download:before { - content: ""; -} - -.ion-ios-download-outline:before { - content: ""; -} - -.ion-ios-drag:before { - content: ""; -} - -.ion-ios-email:before { - content: ""; -} - -.ion-ios-email-outline:before { - content: ""; -} - -.ion-ios-eye:before { - content: ""; -} - -.ion-ios-eye-outline:before { - content: ""; -} - -.ion-ios-fastforward:before { - content: ""; -} - -.ion-ios-fastforward-outline:before { - content: ""; -} - -.ion-ios-filing:before { - content: ""; -} - -.ion-ios-filing-outline:before { - content: ""; -} - -.ion-ios-film:before { - content: ""; -} - -.ion-ios-film-outline:before { - content: ""; -} - -.ion-ios-flag:before { - content: ""; -} - -.ion-ios-flag-outline:before { - content: ""; -} - -.ion-ios-flame:before { - content: ""; -} - -.ion-ios-flame-outline:before { - content: ""; -} - -.ion-ios-flask:before { - content: ""; -} - -.ion-ios-flask-outline:before { - content: ""; -} - -.ion-ios-flower:before { - content: ""; -} - -.ion-ios-flower-outline:before { - content: ""; -} - -.ion-ios-folder:before { - content: ""; -} - -.ion-ios-folder-outline:before { - content: ""; -} - -.ion-ios-football:before { - content: ""; -} - -.ion-ios-football-outline:before { - content: ""; -} - -.ion-ios-game-controller-a:before { - content: ""; -} - -.ion-ios-game-controller-a-outline:before { - content: ""; -} - -.ion-ios-game-controller-b:before { - content: ""; -} - -.ion-ios-game-controller-b-outline:before { - content: ""; -} - -.ion-ios-gear:before { - content: ""; -} - -.ion-ios-gear-outline:before { - content: ""; -} - -.ion-ios-glasses:before { - content: ""; -} - -.ion-ios-glasses-outline:before { - content: ""; -} - -.ion-ios-grid-view:before { - content: ""; -} - -.ion-ios-grid-view-outline:before { - content: ""; -} - -.ion-ios-heart:before { - content: ""; -} - -.ion-ios-heart-outline:before { - content: ""; -} - -.ion-ios-help:before { - content: ""; -} - -.ion-ios-help-empty:before { - content: ""; -} - -.ion-ios-help-outline:before { - content: ""; -} - -.ion-ios-home:before { - content: ""; -} - -.ion-ios-home-outline:before { - content: ""; -} - -.ion-ios-infinite:before { - content: ""; -} - -.ion-ios-infinite-outline:before { - content: ""; -} - -.ion-ios-information:before { - content: ""; -} - -.ion-ios-information-empty:before { - content: ""; -} - -.ion-ios-information-outline:before { - content: ""; -} - -.ion-ios-ionic-outline:before { - content: ""; -} - -.ion-ios-keypad:before { - content: ""; -} - -.ion-ios-keypad-outline:before { - content: ""; -} - -.ion-ios-lightbulb:before { - content: ""; -} - -.ion-ios-lightbulb-outline:before { - content: ""; -} - -.ion-ios-list:before { - content: ""; -} - -.ion-ios-list-outline:before { - content: ""; -} - -.ion-ios-location:before { - content: ""; -} - -.ion-ios-location-outline:before { - content: ""; -} - -.ion-ios-locked:before { - content: ""; -} - -.ion-ios-locked-outline:before { - content: ""; -} - -.ion-ios-loop:before { - content: ""; -} - -.ion-ios-loop-strong:before { - content: ""; -} - -.ion-ios-medical:before { - content: ""; -} - -.ion-ios-medical-outline:before { - content: ""; -} - -.ion-ios-medkit:before { - content: ""; -} - -.ion-ios-medkit-outline:before { - content: ""; -} - -.ion-ios-mic:before { - content: ""; -} - -.ion-ios-mic-off:before { - content: ""; -} - -.ion-ios-mic-outline:before { - content: ""; -} - -.ion-ios-minus:before { - content: ""; -} - -.ion-ios-minus-empty:before { - content: ""; -} - -.ion-ios-minus-outline:before { - content: ""; -} - -.ion-ios-monitor:before { - content: ""; -} - -.ion-ios-monitor-outline:before { - content: ""; -} - -.ion-ios-moon:before { - content: ""; -} - -.ion-ios-moon-outline:before { - content: ""; -} - -.ion-ios-more:before { - content: ""; -} - -.ion-ios-more-outline:before { - content: ""; -} - -.ion-ios-musical-note:before { - content: ""; -} - -.ion-ios-musical-notes:before { - content: ""; -} - -.ion-ios-navigate:before { - content: ""; -} - -.ion-ios-navigate-outline:before { - content: ""; -} - -.ion-ios-nutrition:before { - content: ""; -} - -.ion-ios-nutrition-outline:before { - content: ""; -} - -.ion-ios-paper:before { - content: ""; -} - -.ion-ios-paper-outline:before { - content: ""; -} - -.ion-ios-paperplane:before { - content: ""; -} - -.ion-ios-paperplane-outline:before { - content: ""; -} - -.ion-ios-partlysunny:before { - content: ""; -} - -.ion-ios-partlysunny-outline:before { - content: ""; -} - -.ion-ios-pause:before { - content: ""; -} - -.ion-ios-pause-outline:before { - content: ""; -} - -.ion-ios-paw:before { - content: ""; -} - -.ion-ios-paw-outline:before { - content: ""; -} - -.ion-ios-people:before { - content: ""; -} - -.ion-ios-people-outline:before { - content: ""; -} - -.ion-ios-person:before { - content: ""; -} - -.ion-ios-person-outline:before { - content: ""; -} - -.ion-ios-personadd:before { - content: ""; -} - -.ion-ios-personadd-outline:before { - content: ""; -} - -.ion-ios-photos:before { - content: ""; -} - -.ion-ios-photos-outline:before { - content: ""; -} - -.ion-ios-pie:before { - content: ""; -} - -.ion-ios-pie-outline:before { - content: ""; -} - -.ion-ios-pint:before { - content: ""; -} - -.ion-ios-pint-outline:before { - content: ""; -} - -.ion-ios-play:before { - content: ""; -} - -.ion-ios-play-outline:before { - content: ""; -} - -.ion-ios-plus:before { - content: ""; -} - -.ion-ios-plus-empty:before { - content: ""; -} - -.ion-ios-plus-outline:before { - content: ""; -} - -.ion-ios-pricetag:before { - content: ""; -} - -.ion-ios-pricetag-outline:before { - content: ""; -} - -.ion-ios-pricetags:before { - content: ""; -} - -.ion-ios-pricetags-outline:before { - content: ""; -} - -.ion-ios-printer:before { - content: ""; -} - -.ion-ios-printer-outline:before { - content: ""; -} - -.ion-ios-pulse:before { - content: ""; -} - -.ion-ios-pulse-strong:before { - content: ""; -} - -.ion-ios-rainy:before { - content: ""; -} - -.ion-ios-rainy-outline:before { - content: ""; -} - -.ion-ios-recording:before { - content: ""; -} - -.ion-ios-recording-outline:before { - content: ""; -} - -.ion-ios-redo:before { - content: ""; -} - -.ion-ios-redo-outline:before { - content: ""; -} - -.ion-ios-refresh:before { - content: ""; -} - -.ion-ios-refresh-empty:before { - content: ""; -} - -.ion-ios-refresh-outline:before { - content: ""; -} - -.ion-ios-reload:before { - content: ""; -} - -.ion-ios-reverse-camera:before { - content: ""; -} - -.ion-ios-reverse-camera-outline:before { - content: ""; -} - -.ion-ios-rewind:before { - content: ""; -} - -.ion-ios-rewind-outline:before { - content: ""; -} - -.ion-ios-rose:before { - content: ""; -} - -.ion-ios-rose-outline:before { - content: ""; -} - -.ion-ios-search:before { - content: ""; -} - -.ion-ios-search-strong:before { - content: ""; -} - -.ion-ios-settings:before { - content: ""; -} - -.ion-ios-settings-strong:before { - content: ""; -} - -.ion-ios-shuffle:before { - content: ""; -} - -.ion-ios-shuffle-strong:before { - content: ""; -} - -.ion-ios-skipbackward:before { - content: ""; -} - -.ion-ios-skipbackward-outline:before { - content: ""; -} - -.ion-ios-skipforward:before { - content: ""; -} - -.ion-ios-skipforward-outline:before { - content: ""; -} - -.ion-ios-snowy:before { - content: ""; -} - -.ion-ios-speedometer:before { - content: ""; -} - -.ion-ios-speedometer-outline:before { - content: ""; -} - -.ion-ios-star:before { - content: ""; -} - -.ion-ios-star-half:before { - content: ""; -} - -.ion-ios-star-outline:before { - content: ""; -} - -.ion-ios-stopwatch:before { - content: ""; -} - -.ion-ios-stopwatch-outline:before { - content: ""; -} - -.ion-ios-sunny:before { - content: ""; -} - -.ion-ios-sunny-outline:before { - content: ""; -} - -.ion-ios-telephone:before { - content: ""; -} - -.ion-ios-telephone-outline:before { - content: ""; -} - -.ion-ios-tennisball:before { - content: ""; -} - -.ion-ios-tennisball-outline:before { - content: ""; -} - -.ion-ios-thunderstorm:before { - content: ""; -} - -.ion-ios-thunderstorm-outline:before { - content: ""; -} - -.ion-ios-time:before { - content: ""; -} - -.ion-ios-time-outline:before { - content: ""; -} - -.ion-ios-timer:before { - content: ""; -} - -.ion-ios-timer-outline:before { - content: ""; -} - -.ion-ios-toggle:before { - content: ""; -} - -.ion-ios-toggle-outline:before { - content: ""; -} - -.ion-ios-trash:before { - content: ""; -} - -.ion-ios-trash-outline:before { - content: ""; -} - -.ion-ios-undo:before { - content: ""; -} - -.ion-ios-undo-outline:before { - content: ""; -} - -.ion-ios-unlocked:before { - content: ""; -} - -.ion-ios-unlocked-outline:before { - content: ""; -} - -.ion-ios-upload:before { - content: ""; -} - -.ion-ios-upload-outline:before { - content: ""; -} - -.ion-ios-videocam:before { - content: ""; -} - -.ion-ios-videocam-outline:before { - content: ""; -} - -.ion-ios-volume-high:before { - content: ""; -} - -.ion-ios-volume-low:before { - content: ""; -} - -.ion-ios-wineglass:before { - content: ""; -} - -.ion-ios-wineglass-outline:before { - content: ""; -} - -.ion-ios-world:before { - content: ""; -} - -.ion-ios-world-outline:before { - content: ""; -} - -.ion-ipad:before { - content: ""; -} - -.ion-iphone:before { - content: ""; -} - -.ion-ipod:before { - content: ""; -} - -.ion-jet:before { - content: ""; -} - -.ion-key:before { - content: ""; -} - -.ion-knife:before { - content: ""; -} - -.ion-laptop:before { - content: ""; -} - -.ion-leaf:before { - content: ""; -} - -.ion-levels:before { - content: ""; -} - -.ion-lightbulb:before { - content: ""; -} - -.ion-link:before { - content: ""; -} - -.ion-load-a:before { - content: ""; -} - -.ion-load-b:before { - content: ""; -} - -.ion-load-c:before { - content: ""; -} - -.ion-load-d:before { - content: ""; -} - -.ion-location:before { - content: ""; -} - -.ion-lock-combination:before { - content: ""; -} - -.ion-locked:before { - content: ""; -} - -.ion-log-in:before { - content: ""; -} - -.ion-log-out:before { - content: ""; -} - -.ion-loop:before { - content: ""; -} - -.ion-magnet:before { - content: ""; -} - -.ion-male:before { - content: ""; -} - -.ion-man:before { - content: ""; -} - -.ion-map:before { - content: ""; -} - -.ion-medkit:before { - content: ""; -} - -.ion-merge:before { - content: ""; -} - -.ion-mic-a:before { - content: ""; -} - -.ion-mic-b:before { - content: ""; -} - -.ion-mic-c:before { - content: ""; -} - -.ion-minus:before { - content: ""; -} - -.ion-minus-circled:before { - content: ""; -} - -.ion-minus-round:before { - content: ""; -} - -.ion-model-s:before { - content: ""; -} - -.ion-monitor:before { - content: ""; -} - -.ion-more:before { - content: ""; -} - -.ion-mouse:before { - content: ""; -} - -.ion-music-note:before { - content: ""; -} - -.ion-navicon:before { - content: ""; -} - -.ion-navicon-round:before { - content: ""; -} - -.ion-navigate:before { - content: ""; -} - -.ion-network:before { - content: ""; -} - -.ion-no-smoking:before { - content: ""; -} - -.ion-nuclear:before { - content: ""; -} - -.ion-outlet:before { - content: ""; -} - -.ion-paintbrush:before { - content: ""; -} - -.ion-paintbucket:before { - content: ""; -} - -.ion-paper-airplane:before { - content: ""; -} - -.ion-paperclip:before { - content: ""; -} - -.ion-pause:before { - content: ""; -} - -.ion-person:before { - content: ""; -} - -.ion-person-add:before { - content: ""; -} - -.ion-person-stalker:before { - content: ""; -} - -.ion-pie-graph:before { - content: ""; -} - -.ion-pin:before { - content: ""; -} - -.ion-pinpoint:before { - content: ""; -} - -.ion-pizza:before { - content: ""; -} - -.ion-plane:before { - content: ""; -} - -.ion-planet:before { - content: ""; -} - -.ion-play:before { - content: ""; -} - -.ion-playstation:before { - content: ""; -} - -.ion-plus:before { - content: ""; -} - -.ion-plus-circled:before { - content: ""; -} - -.ion-plus-round:before { - content: ""; -} - -.ion-podium:before { - content: ""; -} - -.ion-pound:before { - content: ""; -} - -.ion-power:before { - content: ""; -} - -.ion-pricetag:before { - content: ""; -} - -.ion-pricetags:before { - content: ""; -} - -.ion-printer:before { - content: ""; -} - -.ion-pull-request:before { - content: ""; -} - -.ion-qr-scanner:before { - content: ""; -} - -.ion-quote:before { - content: ""; -} - -.ion-radio-waves:before { - content: ""; -} - -.ion-record:before { - content: ""; -} - -.ion-refresh:before { - content: ""; -} - -.ion-reply:before { - content: ""; -} - -.ion-reply-all:before { - content: ""; -} - -.ion-ribbon-a:before { - content: ""; -} - -.ion-ribbon-b:before { - content: ""; -} - -.ion-sad:before { - content: ""; -} - -.ion-sad-outline:before { - content: ""; -} - -.ion-scissors:before { - content: ""; -} - -.ion-search:before { - content: ""; -} - -.ion-settings:before { - content: ""; -} - -.ion-share:before { - content: ""; -} - -.ion-shuffle:before { - content: ""; -} - -.ion-skip-backward:before { - content: ""; -} - -.ion-skip-forward:before { - content: ""; -} - -.ion-social-android:before { - content: ""; -} - -.ion-social-android-outline:before { - content: ""; -} - -.ion-social-angular:before { - content: ""; -} - -.ion-social-angular-outline:before { - content: ""; -} - -.ion-social-apple:before { - content: ""; -} - -.ion-social-apple-outline:before { - content: ""; -} - -.ion-social-bitcoin:before { - content: ""; -} - -.ion-social-bitcoin-outline:before { - content: ""; -} - -.ion-social-buffer:before { - content: ""; -} - -.ion-social-buffer-outline:before { - content: ""; -} - -.ion-social-chrome:before { - content: ""; -} - -.ion-social-chrome-outline:before { - content: ""; -} - -.ion-social-codepen:before { - content: ""; -} - -.ion-social-codepen-outline:before { - content: ""; -} - -.ion-social-css3:before { - content: ""; -} - -.ion-social-css3-outline:before { - content: ""; -} - -.ion-social-designernews:before { - content: ""; -} - -.ion-social-designernews-outline:before { - content: ""; -} - -.ion-social-dribbble:before { - content: ""; -} - -.ion-social-dribbble-outline:before { - content: ""; -} - -.ion-social-dropbox:before { - content: ""; -} - -.ion-social-dropbox-outline:before { - content: ""; -} - -.ion-social-euro:before { - content: ""; -} - -.ion-social-euro-outline:before { - content: ""; -} - -.ion-social-facebook:before { - content: ""; -} - -.ion-social-facebook-outline:before { - content: ""; -} - -.ion-social-foursquare:before { - content: ""; -} - -.ion-social-foursquare-outline:before { - content: ""; -} - -.ion-social-freebsd-devil:before { - content: ""; -} - -.ion-social-github:before { - content: ""; -} - -.ion-social-github-outline:before { - content: ""; -} - -.ion-social-google:before { - content: ""; -} - -.ion-social-google-outline:before { - content: ""; -} - -.ion-social-googleplus:before { - content: ""; -} - -.ion-social-googleplus-outline:before { - content: ""; -} - -.ion-social-hackernews:before { - content: ""; -} - -.ion-social-hackernews-outline:before { - content: ""; -} - -.ion-social-html5:before { - content: ""; -} - -.ion-social-html5-outline:before { - content: ""; -} - -.ion-social-instagram:before { - content: ""; -} - -.ion-social-instagram-outline:before { - content: ""; -} - -.ion-social-javascript:before { - content: ""; -} - -.ion-social-javascript-outline:before { - content: ""; -} - -.ion-social-linkedin:before { - content: ""; -} - -.ion-social-linkedin-outline:before { - content: ""; -} - -.ion-social-markdown:before { - content: ""; -} - -.ion-social-nodejs:before { - content: ""; -} - -.ion-social-octocat:before { - content: ""; -} - -.ion-social-pinterest:before { - content: ""; -} - -.ion-social-pinterest-outline:before { - content: ""; -} - -.ion-social-python:before { - content: ""; -} - -.ion-social-reddit:before { - content: ""; -} - -.ion-social-reddit-outline:before { - content: ""; -} - -.ion-social-rss:before { - content: ""; -} - -.ion-social-rss-outline:before { - content: ""; -} - -.ion-social-sass:before { - content: ""; -} - -.ion-social-skype:before { - content: ""; -} - -.ion-social-skype-outline:before { - content: ""; -} - -.ion-social-snapchat:before { - content: ""; -} - -.ion-social-snapchat-outline:before { - content: ""; -} - -.ion-social-tumblr:before { - content: ""; -} - -.ion-social-tumblr-outline:before { - content: ""; -} - -.ion-social-tux:before { - content: ""; -} - -.ion-social-twitch:before { - content: ""; -} - -.ion-social-twitch-outline:before { - content: ""; -} - -.ion-social-twitter:before { - content: ""; -} - -.ion-social-twitter-outline:before { - content: ""; -} - -.ion-social-usd:before { - content: ""; -} - -.ion-social-usd-outline:before { - content: ""; -} - -.ion-social-vimeo:before { - content: ""; -} - -.ion-social-vimeo-outline:before { - content: ""; -} - -.ion-social-whatsapp:before { - content: ""; -} - -.ion-social-whatsapp-outline:before { - content: ""; -} - -.ion-social-windows:before { - content: ""; -} - -.ion-social-windows-outline:before { - content: ""; -} - -.ion-social-wordpress:before { - content: ""; -} - -.ion-social-wordpress-outline:before { - content: ""; -} - -.ion-social-yahoo:before { - content: ""; -} - -.ion-social-yahoo-outline:before { - content: ""; -} - -.ion-social-yen:before { - content: ""; -} - -.ion-social-yen-outline:before { - content: ""; -} - -.ion-social-youtube:before { - content: ""; -} - -.ion-social-youtube-outline:before { - content: ""; -} - -.ion-soup-can:before { - content: ""; -} - -.ion-soup-can-outline:before { - content: ""; -} - -.ion-speakerphone:before { - content: ""; -} - -.ion-speedometer:before { - content: ""; -} - -.ion-spoon:before { - content: ""; -} - -.ion-star:before { - content: ""; -} - -.ion-stats-bars:before { - content: ""; -} - -.ion-steam:before { - content: ""; -} - -.ion-stop:before { - content: ""; -} - -.ion-thermometer:before { - content: ""; -} - -.ion-thumbsdown:before { - content: ""; -} - -.ion-thumbsup:before { - content: ""; -} - -.ion-toggle:before { - content: ""; -} - -.ion-toggle-filled:before { - content: ""; -} - -.ion-transgender:before { - content: ""; -} - -.ion-trash-a:before { - content: ""; -} - -.ion-trash-b:before { - content: ""; -} - -.ion-trophy:before { - content: ""; -} - -.ion-tshirt:before { - content: ""; -} - -.ion-tshirt-outline:before { - content: ""; -} - -.ion-umbrella:before { - content: ""; -} - -.ion-university:before { - content: ""; -} - -.ion-unlocked:before { - content: ""; -} - -.ion-upload:before { - content: ""; -} - -.ion-usb:before { - content: ""; -} - -.ion-videocamera:before { - content: ""; -} - -.ion-volume-high:before { - content: ""; -} - -.ion-volume-low:before { - content: ""; -} - -.ion-volume-medium:before { - content: ""; -} - -.ion-volume-mute:before { - content: ""; -} - -.ion-wand:before { - content: ""; -} - -.ion-waterdrop:before { - content: ""; -} - -.ion-wifi:before { - content: ""; -} - -.ion-wineglass:before { - content: ""; -} - -.ion-woman:before { - content: ""; -} - -.ion-wrench:before { - content: ""; -} - -.ion-xbox:before { - content: ""; -} - -html { - height: 100%; -} - -body { - min-height: 100%; -} - -body#card { - background: #f1f1fa; - padding-top: 4em; - font-size: 0.9em; - text-align: center; -} -body#card.dashboard { - padding-top: 0; -} - -.tooltip { - font-weight: 600; - cursor: help; -} - -#title { - text-align: center; - margin-bottom: 3em; -} -#title h1 { - font-size: 1.2em; -} -#title img { - max-width: 70px; -} - -.row.section { - padding-top: 5em; - padding-bottom: 5em; - border-bottom: 1px solid #ddd; -} -.row.section#header { - border-color: #359173; -} - -#header { - border-bottom: 1px solid #ddd; -} -#header i { - font-size: 4em; - color: #1b3544; -} -#header .next { - opacity: 0.5; -} -#header .success i { - color: #359173; -} -#header .error i { - color: #D9534F; -} -#header .done { - opacity: 0.3; -} -#header .done p { - text-decoration: line-through; -} -#header .done i, #header .current i { - color: #359173; -} - -.container { - padding-top: 1em; - padding-bottom: 1em; -} -@media (max-width: 760px) { - .container { - padding-bottom: 0 !important; - } -} -.container.block { - padding-bottom: 1.5em; - padding-top: 1.5em; -} -@media (max-width: 760px) { - .container.block { - padding-bottom: 0 !important; - } -} -.container.block:first-child { - padding-top: 0; -} -.container.block:last-child { - padding-bottom: 0; -} -@media (min-width: 760px) { - .container.card { - max-width: 500px; - } -} -@media (max-width: 760px) { - .container.card { - margin-right: 20px; - margin-left: 20px; - } -} -.container.index-card { - max-width: 950px; -} - -.card, -.index-card { - padding: 0.9em; - background: #fff; - border: 1px solid #ddd; -} -.card h1, -.index-card h1 { - font-size: 1.8em; -} - -.row.grey { - background: #f1f1fa; -} - -p { - line-height: 1.5em; -} - -p.code { - font-size: 0.8em; - font-family: "source-code-pro", monospace; - border: 1px solid #ddd; - background: #fff; -} -@media (max-width: 760px) { - p.code { - overflow: auto; - } -} - -span.code { - font-family: "source-code-pro", monospace; - display: inline-block; - padding: 0 0.2em; - border: 1px solid #ddd; - background: #fff; - font-size: 0.9em; -} - -input, textarea { - font-size: 0.8em; - font-family: "proxima-nova-soft", sans-serif; - border: 1px solid #ddd; - background: #fff; - padding: 0.9em; - transition: all 0.3s ease-in-out; - width: 100%; -} -input.code, textarea.code { - font-family: "source-code-pro", monospace; -} -input:focus, textarea:focus { - border-color: #2A735B; - outline: none; - box-shadow: 0 0 5px 1px #359173; -} - -input[type=checkbox], -input[type=radio] { - width: auto; - margin-right: 6px; -} - -form input, form textarea { - margin-bottom: 0.5em; -} - -table#invoices { - line-height: 3em; - overflow-x: auto; -} -@media screen and (max-width: 736px) { - table#invoices { - border: 0; - } - table#invoices thead { - display: none; - } - table#invoices tr { - margin-bottom: 10px; - display: block; - border-bottom: 5px solid #ddd; - } - table#invoices tr td { - display: block; - font-size: 13px; - border-bottom: 1px dotted #ccc; - margin: 10px auto; - max-width: 100%; - } - table#invoices tr td:last-child { - border-bottom: 0; - } - table#invoices tr td:before { - content: attr(data-label); - display: block; - text-transform: uppercase; - font-weight: bold; - } -} - -button, a.button { - font-size: 1em; - text-transform: uppercase; - font-weight: 600; - border: 2px solid #359173; - color: #359173; - background: transparent; - line-height: 1em; - padding: 0.6em 0.9em; - transition: all 0.3s ease-in-out; -} -button.no-uppercase, a.button.no-uppercase { - text-transform: none !important; -} -button:hover, a.button:hover { - border-color: #2A735B; - color: #2A735B; -} -button:hover.emphasis, a.button:hover.emphasis { - color: white; - background-color: #2A735B; -} -button:focus, a.button:focus { - outline: 0; -} -button.destructive, a.button.destructive { - color: #D9534F; - border-color: #D9534F; -} -button.disabled, a.button.disabled { - color: #707070; - border-color: #707070; -} -button[disabled], button[disabled]:hover, a.button[disabled], a.button[disabled]:hover { - color: #b0e2d2; - border-color: #b0e2d2; -} - -.animate { - -moz-animation-iteration-count: once; - -moz-animation-timing-function: cubic-bezier(0.895, 0.03, 0.685, 0.22); - -moz-animation-duration: 0.4s; - -webkit-animation-iteration-count: once; - -webkit-animation-timing-function: cubic-bezier(0.895, 0.03, 0.685, 0.22); - -webkit-animation-duration: 0.4s; -} -.animate.dropIn { - -moz-animation-name: dropIn; - -webkit-animation-name: dropIn; -} - -@-webkit-keyframes fadeIn { - 0% { - -webkit-transform: translate3d(0, 0, 0); - -moz-transform: translate3d(0, 0, 0); - opacity: 0; - } - 100% { - -webkit-transform: translate3d(0, 0, 0); - -moz-transform: translate3d(0, 0, 0); - opacity: 1; - } -} -@-webkit-keyframes dropIn { - 0% { - opacity: 0; - -webkit-transform: translate3d(0, -150px, 0); - -moz-transform: translate3d(0, -150px, 0); - } - 100% { - opacity: 1; - -webkit-transform: translate3d(0, 0, 0); - -moz-transform: translate3d(0, 0, 0); - } -} -@-webkit-keyframes dropInLong { - 0% { - opacity: 0; - -webkit-transform: translate3d(0, -450px, 0); - -moz-transform: translate3d(0, -450px, 0); - } - 100% { - opacity: 1; - -webkit-transform: translate3d(0, 0, 0); - -moz-transform: translate3d(0, 0, 0); - } -} -@-webkit-keyframes rotate { - 100% { - -webkit-transform: rotate(45deg); - -moz-transform: rotate(45deg); - } -} -@-webkit-keyframes rotateBack { - 100% { - -webkit-transform: rotate(0deg); - -moz-transform: rotate(0deg); - } -} -.overlay { - position: fixed; - width: 100%; - height: 100%; - top: -10000px; - left: -10000px; - opacity: 0; - transition: opacity 0.4s linear; - background: rgba(255, 255, 255, 0.96); -} - -body.showOverlay { - overflow: hidden; -} -body.showOverlay .overlay { - top: 0; - left: 0; - opacity: 1; -} -body.showOverlay .overlay iframe { - -webkit-animation-iteration-count: once; - -webkit-animation-timing-function: cubic-bezier(0.895, 0.03, 0.685, 0.22); - -webkit-animation-duration: 0.4s; - -moz-animation-name: dropInLong; - -webkit-animation-name: dropInLong; -} - -.toggleOverlay { - cursor: pointer; - position: fixed; - top: 20px; - left: 20px; - font-size: 2.2em; - font-weight: 600; - -moz-animation-iteration-count: once; - -moz-animation-fill-mode: forwards; - -moz-animation-timing-function: linear; - -moz-animation-duration: 0.2s; - -webkit-animation-iteration-count: once; - -webkit-animation-fill-mode: forwards; - -webkit-animation-timing-function: linear; - -webkit-animation-duration: 0.2s; -} - -body.showOverlay .toggleOverlay { - -moz-animation-name: rotate; - -webkit-animation-name: rotate; -} - -#toast-container { - right: 30%; - left: 30%; - width: 40%; -} diff --git a/formspree/static/js/bundle.js b/formspree/static/js/bundle.js deleted file mode 100644 index ef89404..0000000 --- a/formspree/static/js/bundle.js +++ /dev/null @@ -1,3531 +0,0 @@ -(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o nav'); -nav.addClass('js'); -nav.find('.menu').slicknav(); -nav.find('h4').clone().prependTo('.slicknav_menu'); - -/* adding a shadow at the bottom of the menu bar only when not at the top */ -var w = $(window); -w.scroll(function () { - var scrollPos = w.scrollTop(); - if (scrollPos && !nav.hasClass('scrolled')) { - nav.addClass('scrolled'); - } else if (!scrollPos) { - nav.removeClass('scrolled'); - } -}); - -/* background-color should inherit, but CSS's "inherit" breaks z-index */ -var bgcolor = $(document.body).css('background-color'); -if (bgcolor.split(',').length === 4 || bgcolor === 'transparent') { - bgcolor = 'white'; -} -nav.css('background-color', bgcolor); - -/* modals -- working with or without JS */ -function modals() { - $('.modal').each(function () { - var modal = $(this); - modal.addClass('js'); - var id = modal.attr('id'); - - $('[href="#' + id + '"]').click(function (e) { - // open the modal - e.preventDefault(); - modal.toggleClass('target'); - }); - - modal.click(function (e) { - // close the modal - if (e.target === modal[0]) { - cleanHash(); - modal.toggleClass('target'); - e.preventDefault(); - } - }); - modal.find('.x a').click(function (e) { - // close the modal - cleanHash(); - e.preventDefault(); - modal.toggleClass('target'); - }); - }); - - function cleanHash() { - if (!window.location.hash) return; - if (window.history && window.history.replaceState) { - window.history.replaceState('', document.title, window.location.pathname); - } else { - var pos = $(window).scrollTop(); - window.location.hash = ''; - $(window).scrollTop(pos); - } - } - - // activate modals from url hash # - setTimeout(function () { - // setTimeout is needed because :target elements only appear after - // the page is loaded or something like that. - var activatedModal = $('*:target'); - if (activatedModal.length && !activatedModal.is('.target')) { - activatedModal.toggleClass('target'); - } - }, 0); -} -modals(); - -/* turning flask flash messages into js popup notifications */ -window.popupMessages.forEach(function (m, i) { - var category = m[0] || 'info'; - var text = m[1]; - setTimeout(function () { - toastr[category](text); - }, (1 + i) * 1500); -}); - -/* stripe checkout */ -var stripebutton = $('#stripe-upgrade'); -if (stripebutton.length) { - var handler = StripeCheckout.configure(stripebutton.data()); - stripebutton.on('click', function (e) { - handler.open({ - token: function token(_token) { - stripebutton.closest('form').append('').append('').submit(); - } - }); - e.preventDefault(); - }); -} - -/* quick script for showing the resend confirmation form */ -$('a.resend').on('click', function () { - $(this).hide(); - $('form.resend').show(); - return false; -}); - -/* scripts at other files */ -require('./sitewide')(); - -/* toggle the card management menu */ -$(function () { - $("#card-list tr:even").addClass("even"); - $("#card-list tr:not(.even)").hide(); - $("#card-list tr:first-child").show(); - - $("#card-list tr.even").click(function () { - $(this).next("tr").toggle(); - $(this).find(".arrow").toggleClass("up"); - $(this).find(".fa-chevron-right").toggleClass("fa-rotate-90"); - }); -}); - -},{"./sitewide":2}],2:[function(require,module,exports){ -'use strict'; - -var url = require('url'); -var isValidUrl = require('valid-url').isWebUri; -var isValidEmail = require('is-valid-email'); - -var h = require('virtual-dom/h'); -var diff = require('virtual-dom/diff'); -var patch = require('virtual-dom/patch'); -var createElement = require('virtual-dom/create-element'); - -var $ = window.$; -var toastr = window.toastr; - -/* create-form validation for site-wide forms */ -module.exports = function sitewide() { - var parentNode = $('#create-form .container'); - if (!parentNode.length) return; - - var formActionURL = parentNode.find('form').attr('action'); - var currentUserEmail = parentNode.find('[name="email"]').val(); - var emailPlaceholder = parentNode.find('[name="email"]').attr('placeholder'); - var urlPlaceholder = parentNode.find('[name="url"]').attr('placeholder'); - var sitewideHint = parentNode.find('label[data-hint]').data('hint'); - - // since we have javascript, let's trash this HTML and recreate with virtual-dom - - var data = { - invalid: null, - sitewide: false, - verified: false, - email: currentUserEmail - }; - var tree = render(data); - var rootNode = createElement(tree); - parentNode[0].replaceChild(rootNode, parentNode.find('form')[0]); - - parentNode.on('change', 'input[name="sitewide"]', run); - parentNode.on('input', 'input[name="url"], input[name="email"]', run); - parentNode.on('click', '.verify button', check); - - function run() { - var checkbox = parentNode.find('input[name="sitewide"]'); - - var email = parentNode.find('input[name="email"]').val().trim(); - var urlv = parentNode.find('input[name="url"]').val().trim(); - urlv = /^https?:\/\//.test(urlv) ? urlv : 'http://' + urlv; - var sitewide = checkbox.is(':checked'); - - // wrong input - if (!isValidEmail(email)) { - // invalid email - data.invalid = 'email'; - } else if (sitewide && !isValidUrl(urlv)) { - // invalid url with sitewide - data.invalid = 'url'; - } else if (!sitewide && urlv && urlv !== 'http://' && !isValidUrl(urlv)) { - // invalid url without sitewide - data.invalid = 'url'; - } else { - data.invalid = null; - } - - data.sitewide = sitewide; - data.urlv = urlv; - data.email = email; - - apply(render(data)); - } - - function check() { - $.ajax({ - url: '/forms/sitewide-check?' + parentNode.find('form').serialize(), - success: function success() { - toastr.success('The file exists! you can create your site-wide form now.'); - data.verified = true; - apply(render(data)); - }, - error: function error() { - toastr.warning("The verification file wasn't found."); - data.verified = false; - data.disableVerification = true; - apply(render(data)); - - setTimeout(function () { - data.disableVerification = false; - apply(render(data)); - }, 5000); - } - }); - - return false; - } - - function apply(vtree) { - var patches = diff(tree, vtree); - rootNode = patch(rootNode, patches); - tree = vtree; - } - - function render(_ref) { - var invalid = _ref.invalid; - var sitewide = _ref.sitewide; - var verified = _ref.verified; - var urlv = _ref.urlv; - var email = _ref.email; - var disableVerification = _ref.disableVerification; - - return h('form', { method: 'post', action: formActionURL }, [h('.col-1-1', [h('h4', 'Send email to:'), h('input', { type: 'email', name: 'email', placeholder: emailPlaceholder, value: email })]), h('.col-1-1', [h('h4', 'From URL:'), h('input', { type: 'text', name: 'url', placeholder: urlPlaceholder })]), h('.container', [h('.col-1-4', [h('label.hint--bottom', { dataset: { hint: sitewideHint } }, [h('input', { type: 'checkbox', name: 'sitewide', value: 'true' }), ' site-wide'])]), h('.col-3-4.info', [invalid ? h('div.red', invalid === 'email' ? 'Please input a valid email address.' : ['Please input a valid URL. For example: ', h('span.code', url.resolve('http://www.mywebsite.com', sitewide ? '' : '/contact.html'))]) : sitewide && verified || !sitewide ? h('div', { innerHTML: '​' }) : h('span', ['Please ensure ', h('span.code', url.resolve(urlv, '/formspree-verify.txt')), ' exists and contains a line with ', h('span.code', email)])]), h('.col-1-3', [h('.verify', [h('button', sitewide && !invalid && !disableVerification ? {} : sitewide ? { disabled: true } : { style: { visibility: 'hidden' }, disabled: true }, 'Verify')])]), h('.col-1-3', { innerHTML: '​' }), h('.col-1-3', [h('.create', [sitewide && verified || !sitewide && !invalid ? h('button', { type: 'submit' }, 'Create form') : h('button', { disabled: true }, 'Create form')])])])]); - } -}; - -},{"is-valid-email":10,"url":15,"valid-url":17,"virtual-dom/create-element":18,"virtual-dom/diff":19,"virtual-dom/h":20,"virtual-dom/patch":21}],3:[function(require,module,exports){ - -},{}],4:[function(require,module,exports){ -/*! - * Cross-Browser Split 1.1.1 - * Copyright 2007-2012 Steven Levithan - * Available under the MIT License - * ECMAScript compliant, uniform cross-browser split method - */ - -/** - * Splits a string into an array of strings using a regex or string separator. Matches of the - * separator are not included in the result array. However, if `separator` is a regex that contains - * capturing groups, backreferences are spliced into the result each time `separator` is matched. - * Fixes browser bugs compared to the native `String.prototype.split` and can be used reliably - * cross-browser. - * @param {String} str String to split. - * @param {RegExp|String} separator Regex or string to use for separating the string. - * @param {Number} [limit] Maximum number of items to include in the result array. - * @returns {Array} Array of substrings. - * @example - * - * // Basic use - * split('a b c d', ' '); - * // -> ['a', 'b', 'c', 'd'] - * - * // With limit - * split('a b c d', ' ', 2); - * // -> ['a', 'b'] - * - * // Backreferences in result array - * split('..word1 word2..', /([a-z]+)(\d+)/i); - * // -> ['..', 'word', '1', ' ', 'word', '2', '..'] - */ -module.exports = (function split(undef) { - - var nativeSplit = String.prototype.split, - compliantExecNpcg = /()??/.exec("")[1] === undef, - // NPCG: nonparticipating capturing group - self; - - self = function(str, separator, limit) { - // If `separator` is not a regex, use `nativeSplit` - if (Object.prototype.toString.call(separator) !== "[object RegExp]") { - return nativeSplit.call(str, separator, limit); - } - var output = [], - flags = (separator.ignoreCase ? "i" : "") + (separator.multiline ? "m" : "") + (separator.extended ? "x" : "") + // Proposed for ES6 - (separator.sticky ? "y" : ""), - // Firefox 3+ - lastLastIndex = 0, - // Make `global` and avoid `lastIndex` issues by working with a copy - separator = new RegExp(separator.source, flags + "g"), - separator2, match, lastIndex, lastLength; - str += ""; // Type-convert - if (!compliantExecNpcg) { - // Doesn't need flags gy, but they don't hurt - separator2 = new RegExp("^" + separator.source + "$(?!\\s)", flags); - } - /* Values for `limit`, per the spec: - * If undefined: 4294967295 // Math.pow(2, 32) - 1 - * If 0, Infinity, or NaN: 0 - * If positive number: limit = Math.floor(limit); if (limit > 4294967295) limit -= 4294967296; - * If negative number: 4294967296 - Math.floor(Math.abs(limit)) - * If other: Type-convert, then use the above rules - */ - limit = limit === undef ? -1 >>> 0 : // Math.pow(2, 32) - 1 - limit >>> 0; // ToUint32(limit) - while (match = separator.exec(str)) { - // `separator.lastIndex` is not reliable cross-browser - lastIndex = match.index + match[0].length; - if (lastIndex > lastLastIndex) { - output.push(str.slice(lastLastIndex, match.index)); - // Fix browsers whose `exec` methods don't consistently return `undefined` for - // nonparticipating capturing groups - if (!compliantExecNpcg && match.length > 1) { - match[0].replace(separator2, function() { - for (var i = 1; i < arguments.length - 2; i++) { - if (arguments[i] === undef) { - match[i] = undef; - } - } - }); - } - if (match.length > 1 && match.index < str.length) { - Array.prototype.push.apply(output, match.slice(1)); - } - lastLength = match[0].length; - lastLastIndex = lastIndex; - if (output.length >= limit) { - break; - } - } - if (separator.lastIndex === match.index) { - separator.lastIndex++; // Avoid an infinite loop - } - } - if (lastLastIndex === str.length) { - if (lastLength || !separator.test("")) { - output.push(""); - } - } else { - output.push(str.slice(lastLastIndex)); - } - return output.length > limit ? output.slice(0, limit) : output; - }; - - return self; -})(); - -},{}],5:[function(require,module,exports){ -'use strict'; - -var OneVersionConstraint = require('individual/one-version'); - -var MY_VERSION = '7'; -OneVersionConstraint('ev-store', MY_VERSION); - -var hashKey = '__EV_STORE_KEY@' + MY_VERSION; - -module.exports = EvStore; - -function EvStore(elem) { - var hash = elem[hashKey]; - - if (!hash) { - hash = elem[hashKey] = {}; - } - - return hash; -} - -},{"individual/one-version":8}],6:[function(require,module,exports){ -(function (global){ -var topLevel = typeof global !== 'undefined' ? global : - typeof window !== 'undefined' ? window : {} -var minDoc = require('min-document'); - -if (typeof document !== 'undefined') { - module.exports = document; -} else { - var doccy = topLevel['__GLOBAL_DOCUMENT_CACHE@4']; - - if (!doccy) { - doccy = topLevel['__GLOBAL_DOCUMENT_CACHE@4'] = minDoc; - } - - module.exports = doccy; -} - -}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"min-document":3}],7:[function(require,module,exports){ -(function (global){ -'use strict'; - -/*global window, global*/ - -var root = typeof window !== 'undefined' ? - window : typeof global !== 'undefined' ? - global : {}; - -module.exports = Individual; - -function Individual(key, value) { - if (key in root) { - return root[key]; - } - - root[key] = value; - - return value; -} - -}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{}],8:[function(require,module,exports){ -'use strict'; - -var Individual = require('./index.js'); - -module.exports = OneVersion; - -function OneVersion(moduleName, version, defaultValue) { - var key = '__INDIVIDUAL_ONE_VERSION_' + moduleName; - var enforceKey = key + '_ENFORCE_SINGLETON'; - - var versionValue = Individual(enforceKey, version); - - if (versionValue !== version) { - throw new Error('Can only have one copy of ' + - moduleName + '.\n' + - 'You already have version ' + versionValue + - ' installed.\n' + - 'This means you cannot install version ' + version); - } - - return Individual(key, defaultValue); -} - -},{"./index.js":7}],9:[function(require,module,exports){ -"use strict"; - -module.exports = function isObject(x) { - return typeof x === "object" && x !== null; -}; - -},{}],10:[function(require,module,exports){ -(function(){ - - function isValidEmail(v) { - if (!v) return false; - var re = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; - return re.test(v); - } - - if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') { - module.exports = isValidEmail; - } else { - window.isValidEmail = isValidEmail; - } - -})(); - -},{}],11:[function(require,module,exports){ -(function (global){ -/*! https://mths.be/punycode v1.3.2 by @mathias */ -;(function(root) { - - /** Detect free variables */ - var freeExports = typeof exports == 'object' && exports && - !exports.nodeType && exports; - var freeModule = typeof module == 'object' && module && - !module.nodeType && module; - var freeGlobal = typeof global == 'object' && global; - if ( - freeGlobal.global === freeGlobal || - freeGlobal.window === freeGlobal || - freeGlobal.self === freeGlobal - ) { - root = freeGlobal; - } - - /** - * The `punycode` object. - * @name punycode - * @type Object - */ - var punycode, - - /** Highest positive signed 32-bit float value */ - maxInt = 2147483647, // aka. 0x7FFFFFFF or 2^31-1 - - /** Bootstring parameters */ - base = 36, - tMin = 1, - tMax = 26, - skew = 38, - damp = 700, - initialBias = 72, - initialN = 128, // 0x80 - delimiter = '-', // '\x2D' - - /** Regular expressions */ - regexPunycode = /^xn--/, - regexNonASCII = /[^\x20-\x7E]/, // unprintable ASCII chars + non-ASCII chars - regexSeparators = /[\x2E\u3002\uFF0E\uFF61]/g, // RFC 3490 separators - - /** Error messages */ - errors = { - 'overflow': 'Overflow: input needs wider integers to process', - 'not-basic': 'Illegal input >= 0x80 (not a basic code point)', - 'invalid-input': 'Invalid input' - }, - - /** Convenience shortcuts */ - baseMinusTMin = base - tMin, - floor = Math.floor, - stringFromCharCode = String.fromCharCode, - - /** Temporary variable */ - key; - - /*--------------------------------------------------------------------------*/ - - /** - * A generic error utility function. - * @private - * @param {String} type The error type. - * @returns {Error} Throws a `RangeError` with the applicable error message. - */ - function error(type) { - throw RangeError(errors[type]); - } - - /** - * A generic `Array#map` utility function. - * @private - * @param {Array} array The array to iterate over. - * @param {Function} callback The function that gets called for every array - * item. - * @returns {Array} A new array of values returned by the callback function. - */ - function map(array, fn) { - var length = array.length; - var result = []; - while (length--) { - result[length] = fn(array[length]); - } - return result; - } - - /** - * A simple `Array#map`-like wrapper to work with domain name strings or email - * addresses. - * @private - * @param {String} domain The domain name or email address. - * @param {Function} callback The function that gets called for every - * character. - * @returns {Array} A new string of characters returned by the callback - * function. - */ - function mapDomain(string, fn) { - var parts = string.split('@'); - var result = ''; - if (parts.length > 1) { - // In email addresses, only the domain name should be punycoded. Leave - // the local part (i.e. everything up to `@`) intact. - result = parts[0] + '@'; - string = parts[1]; - } - // Avoid `split(regex)` for IE8 compatibility. See #17. - string = string.replace(regexSeparators, '\x2E'); - var labels = string.split('.'); - var encoded = map(labels, fn).join('.'); - return result + encoded; - } - - /** - * Creates an array containing the numeric code points of each Unicode - * character in the string. While JavaScript uses UCS-2 internally, - * this function will convert a pair of surrogate halves (each of which - * UCS-2 exposes as separate characters) into a single code point, - * matching UTF-16. - * @see `punycode.ucs2.encode` - * @see - * @memberOf punycode.ucs2 - * @name decode - * @param {String} string The Unicode input string (UCS-2). - * @returns {Array} The new array of code points. - */ - function ucs2decode(string) { - var output = [], - counter = 0, - length = string.length, - value, - extra; - while (counter < length) { - value = string.charCodeAt(counter++); - if (value >= 0xD800 && value <= 0xDBFF && counter < length) { - // high surrogate, and there is a next character - extra = string.charCodeAt(counter++); - if ((extra & 0xFC00) == 0xDC00) { // low surrogate - output.push(((value & 0x3FF) << 10) + (extra & 0x3FF) + 0x10000); - } else { - // unmatched surrogate; only append this code unit, in case the next - // code unit is the high surrogate of a surrogate pair - output.push(value); - counter--; - } - } else { - output.push(value); - } - } - return output; - } - - /** - * Creates a string based on an array of numeric code points. - * @see `punycode.ucs2.decode` - * @memberOf punycode.ucs2 - * @name encode - * @param {Array} codePoints The array of numeric code points. - * @returns {String} The new Unicode string (UCS-2). - */ - function ucs2encode(array) { - return map(array, function(value) { - var output = ''; - if (value > 0xFFFF) { - value -= 0x10000; - output += stringFromCharCode(value >>> 10 & 0x3FF | 0xD800); - value = 0xDC00 | value & 0x3FF; - } - output += stringFromCharCode(value); - return output; - }).join(''); - } - - /** - * Converts a basic code point into a digit/integer. - * @see `digitToBasic()` - * @private - * @param {Number} codePoint The basic numeric code point value. - * @returns {Number} The numeric value of a basic code point (for use in - * representing integers) in the range `0` to `base - 1`, or `base` if - * the code point does not represent a value. - */ - function basicToDigit(codePoint) { - if (codePoint - 48 < 10) { - return codePoint - 22; - } - if (codePoint - 65 < 26) { - return codePoint - 65; - } - if (codePoint - 97 < 26) { - return codePoint - 97; - } - return base; - } - - /** - * Converts a digit/integer into a basic code point. - * @see `basicToDigit()` - * @private - * @param {Number} digit The numeric value of a basic code point. - * @returns {Number} The basic code point whose value (when used for - * representing integers) is `digit`, which needs to be in the range - * `0` to `base - 1`. If `flag` is non-zero, the uppercase form is - * used; else, the lowercase form is used. The behavior is undefined - * if `flag` is non-zero and `digit` has no uppercase form. - */ - function digitToBasic(digit, flag) { - // 0..25 map to ASCII a..z or A..Z - // 26..35 map to ASCII 0..9 - return digit + 22 + 75 * (digit < 26) - ((flag != 0) << 5); - } - - /** - * Bias adaptation function as per section 3.4 of RFC 3492. - * http://tools.ietf.org/html/rfc3492#section-3.4 - * @private - */ - function adapt(delta, numPoints, firstTime) { - var k = 0; - delta = firstTime ? floor(delta / damp) : delta >> 1; - delta += floor(delta / numPoints); - for (/* no initialization */; delta > baseMinusTMin * tMax >> 1; k += base) { - delta = floor(delta / baseMinusTMin); - } - return floor(k + (baseMinusTMin + 1) * delta / (delta + skew)); - } - - /** - * Converts a Punycode string of ASCII-only symbols to a string of Unicode - * symbols. - * @memberOf punycode - * @param {String} input The Punycode string of ASCII-only symbols. - * @returns {String} The resulting string of Unicode symbols. - */ - function decode(input) { - // Don't use UCS-2 - var output = [], - inputLength = input.length, - out, - i = 0, - n = initialN, - bias = initialBias, - basic, - j, - index, - oldi, - w, - k, - digit, - t, - /** Cached calculation results */ - baseMinusT; - - // Handle the basic code points: let `basic` be the number of input code - // points before the last delimiter, or `0` if there is none, then copy - // the first basic code points to the output. - - basic = input.lastIndexOf(delimiter); - if (basic < 0) { - basic = 0; - } - - for (j = 0; j < basic; ++j) { - // if it's not a basic code point - if (input.charCodeAt(j) >= 0x80) { - error('not-basic'); - } - output.push(input.charCodeAt(j)); - } - - // Main decoding loop: start just after the last delimiter if any basic code - // points were copied; start at the beginning otherwise. - - for (index = basic > 0 ? basic + 1 : 0; index < inputLength; /* no final expression */) { - - // `index` is the index of the next character to be consumed. - // Decode a generalized variable-length integer into `delta`, - // which gets added to `i`. The overflow checking is easier - // if we increase `i` as we go, then subtract off its starting - // value at the end to obtain `delta`. - for (oldi = i, w = 1, k = base; /* no condition */; k += base) { - - if (index >= inputLength) { - error('invalid-input'); - } - - digit = basicToDigit(input.charCodeAt(index++)); - - if (digit >= base || digit > floor((maxInt - i) / w)) { - error('overflow'); - } - - i += digit * w; - t = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias); - - if (digit < t) { - break; - } - - baseMinusT = base - t; - if (w > floor(maxInt / baseMinusT)) { - error('overflow'); - } - - w *= baseMinusT; - - } - - out = output.length + 1; - bias = adapt(i - oldi, out, oldi == 0); - - // `i` was supposed to wrap around from `out` to `0`, - // incrementing `n` each time, so we'll fix that now: - if (floor(i / out) > maxInt - n) { - error('overflow'); - } - - n += floor(i / out); - i %= out; - - // Insert `n` at position `i` of the output - output.splice(i++, 0, n); - - } - - return ucs2encode(output); - } - - /** - * Converts a string of Unicode symbols (e.g. a domain name label) to a - * Punycode string of ASCII-only symbols. - * @memberOf punycode - * @param {String} input The string of Unicode symbols. - * @returns {String} The resulting Punycode string of ASCII-only symbols. - */ - function encode(input) { - var n, - delta, - handledCPCount, - basicLength, - bias, - j, - m, - q, - k, - t, - currentValue, - output = [], - /** `inputLength` will hold the number of code points in `input`. */ - inputLength, - /** Cached calculation results */ - handledCPCountPlusOne, - baseMinusT, - qMinusT; - - // Convert the input in UCS-2 to Unicode - input = ucs2decode(input); - - // Cache the length - inputLength = input.length; - - // Initialize the state - n = initialN; - delta = 0; - bias = initialBias; - - // Handle the basic code points - for (j = 0; j < inputLength; ++j) { - currentValue = input[j]; - if (currentValue < 0x80) { - output.push(stringFromCharCode(currentValue)); - } - } - - handledCPCount = basicLength = output.length; - - // `handledCPCount` is the number of code points that have been handled; - // `basicLength` is the number of basic code points. - - // Finish the basic string - if it is not empty - with a delimiter - if (basicLength) { - output.push(delimiter); - } - - // Main encoding loop: - while (handledCPCount < inputLength) { - - // All non-basic code points < n have been handled already. Find the next - // larger one: - for (m = maxInt, j = 0; j < inputLength; ++j) { - currentValue = input[j]; - if (currentValue >= n && currentValue < m) { - m = currentValue; - } - } - - // Increase `delta` enough to advance the decoder's state to , - // but guard against overflow - handledCPCountPlusOne = handledCPCount + 1; - if (m - n > floor((maxInt - delta) / handledCPCountPlusOne)) { - error('overflow'); - } - - delta += (m - n) * handledCPCountPlusOne; - n = m; - - for (j = 0; j < inputLength; ++j) { - currentValue = input[j]; - - if (currentValue < n && ++delta > maxInt) { - error('overflow'); - } - - if (currentValue == n) { - // Represent delta as a generalized variable-length integer - for (q = delta, k = base; /* no condition */; k += base) { - t = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias); - if (q < t) { - break; - } - qMinusT = q - t; - baseMinusT = base - t; - output.push( - stringFromCharCode(digitToBasic(t + qMinusT % baseMinusT, 0)) - ); - q = floor(qMinusT / baseMinusT); - } - - output.push(stringFromCharCode(digitToBasic(q, 0))); - bias = adapt(delta, handledCPCountPlusOne, handledCPCount == basicLength); - delta = 0; - ++handledCPCount; - } - } - - ++delta; - ++n; - - } - return output.join(''); - } - - /** - * Converts a Punycode string representing a domain name or an email address - * to Unicode. Only the Punycoded parts of the input will be converted, i.e. - * it doesn't matter if you call it on a string that has already been - * converted to Unicode. - * @memberOf punycode - * @param {String} input The Punycoded domain name or email address to - * convert to Unicode. - * @returns {String} The Unicode representation of the given Punycode - * string. - */ - function toUnicode(input) { - return mapDomain(input, function(string) { - return regexPunycode.test(string) - ? decode(string.slice(4).toLowerCase()) - : string; - }); - } - - /** - * Converts a Unicode string representing a domain name or an email address to - * Punycode. Only the non-ASCII parts of the domain name will be converted, - * i.e. it doesn't matter if you call it with a domain that's already in - * ASCII. - * @memberOf punycode - * @param {String} input The domain name or email address to convert, as a - * Unicode string. - * @returns {String} The Punycode representation of the given domain name or - * email address. - */ - function toASCII(input) { - return mapDomain(input, function(string) { - return regexNonASCII.test(string) - ? 'xn--' + encode(string) - : string; - }); - } - - /*--------------------------------------------------------------------------*/ - - /** Define the public API */ - punycode = { - /** - * A string representing the current Punycode.js version number. - * @memberOf punycode - * @type String - */ - 'version': '1.3.2', - /** - * An object of methods to convert from JavaScript's internal character - * representation (UCS-2) to Unicode code points, and back. - * @see - * @memberOf punycode - * @type Object - */ - 'ucs2': { - 'decode': ucs2decode, - 'encode': ucs2encode - }, - 'decode': decode, - 'encode': encode, - 'toASCII': toASCII, - 'toUnicode': toUnicode - }; - - /** Expose `punycode` */ - // Some AMD build optimizers, like r.js, check for specific condition patterns - // like the following: - if ( - typeof define == 'function' && - typeof define.amd == 'object' && - define.amd - ) { - define('punycode', function() { - return punycode; - }); - } else if (freeExports && freeModule) { - if (module.exports == freeExports) { // in Node.js or RingoJS v0.8.0+ - freeModule.exports = punycode; - } else { // in Narwhal or RingoJS v0.7.0- - for (key in punycode) { - punycode.hasOwnProperty(key) && (freeExports[key] = punycode[key]); - } - } - } else { // in Rhino or a web browser - root.punycode = punycode; - } - -}(this)); - -}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{}],12:[function(require,module,exports){ -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -'use strict'; - -// If obj.hasOwnProperty has been overridden, then calling -// obj.hasOwnProperty(prop) will break. -// See: https://github.com/joyent/node/issues/1707 -function hasOwnProperty(obj, prop) { - return Object.prototype.hasOwnProperty.call(obj, prop); -} - -module.exports = function(qs, sep, eq, options) { - sep = sep || '&'; - eq = eq || '='; - var obj = {}; - - if (typeof qs !== 'string' || qs.length === 0) { - return obj; - } - - var regexp = /\+/g; - qs = qs.split(sep); - - var maxKeys = 1000; - if (options && typeof options.maxKeys === 'number') { - maxKeys = options.maxKeys; - } - - var len = qs.length; - // maxKeys <= 0 means that we should not limit keys count - if (maxKeys > 0 && len > maxKeys) { - len = maxKeys; - } - - for (var i = 0; i < len; ++i) { - var x = qs[i].replace(regexp, '%20'), - idx = x.indexOf(eq), - kstr, vstr, k, v; - - if (idx >= 0) { - kstr = x.substr(0, idx); - vstr = x.substr(idx + 1); - } else { - kstr = x; - vstr = ''; - } - - k = decodeURIComponent(kstr); - v = decodeURIComponent(vstr); - - if (!hasOwnProperty(obj, k)) { - obj[k] = v; - } else if (isArray(obj[k])) { - obj[k].push(v); - } else { - obj[k] = [obj[k], v]; - } - } - - return obj; -}; - -var isArray = Array.isArray || function (xs) { - return Object.prototype.toString.call(xs) === '[object Array]'; -}; - -},{}],13:[function(require,module,exports){ -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -'use strict'; - -var stringifyPrimitive = function(v) { - switch (typeof v) { - case 'string': - return v; - - case 'boolean': - return v ? 'true' : 'false'; - - case 'number': - return isFinite(v) ? v : ''; - - default: - return ''; - } -}; - -module.exports = function(obj, sep, eq, name) { - sep = sep || '&'; - eq = eq || '='; - if (obj === null) { - obj = undefined; - } - - if (typeof obj === 'object') { - return map(objectKeys(obj), function(k) { - var ks = encodeURIComponent(stringifyPrimitive(k)) + eq; - if (isArray(obj[k])) { - return map(obj[k], function(v) { - return ks + encodeURIComponent(stringifyPrimitive(v)); - }).join(sep); - } else { - return ks + encodeURIComponent(stringifyPrimitive(obj[k])); - } - }).join(sep); - - } - - if (!name) return ''; - return encodeURIComponent(stringifyPrimitive(name)) + eq + - encodeURIComponent(stringifyPrimitive(obj)); -}; - -var isArray = Array.isArray || function (xs) { - return Object.prototype.toString.call(xs) === '[object Array]'; -}; - -function map (xs, f) { - if (xs.map) return xs.map(f); - var res = []; - for (var i = 0; i < xs.length; i++) { - res.push(f(xs[i], i)); - } - return res; -} - -var objectKeys = Object.keys || function (obj) { - var res = []; - for (var key in obj) { - if (Object.prototype.hasOwnProperty.call(obj, key)) res.push(key); - } - return res; -}; - -},{}],14:[function(require,module,exports){ -'use strict'; - -exports.decode = exports.parse = require('./decode'); -exports.encode = exports.stringify = require('./encode'); - -},{"./decode":12,"./encode":13}],15:[function(require,module,exports){ -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -'use strict'; - -var punycode = require('punycode'); -var util = require('./util'); - -exports.parse = urlParse; -exports.resolve = urlResolve; -exports.resolveObject = urlResolveObject; -exports.format = urlFormat; - -exports.Url = Url; - -function Url() { - this.protocol = null; - this.slashes = null; - this.auth = null; - this.host = null; - this.port = null; - this.hostname = null; - this.hash = null; - this.search = null; - this.query = null; - this.pathname = null; - this.path = null; - this.href = null; -} - -// Reference: RFC 3986, RFC 1808, RFC 2396 - -// define these here so at least they only have to be -// compiled once on the first module load. -var protocolPattern = /^([a-z0-9.+-]+:)/i, - portPattern = /:[0-9]*$/, - - // Special case for a simple path URL - simplePathPattern = /^(\/\/?(?!\/)[^\?\s]*)(\?[^\s]*)?$/, - - // RFC 2396: characters reserved for delimiting URLs. - // We actually just auto-escape these. - delims = ['<', '>', '"', '`', ' ', '\r', '\n', '\t'], - - // RFC 2396: characters not allowed for various reasons. - unwise = ['{', '}', '|', '\\', '^', '`'].concat(delims), - - // Allowed by RFCs, but cause of XSS attacks. Always escape these. - autoEscape = ['\''].concat(unwise), - // Characters that are never ever allowed in a hostname. - // Note that any invalid chars are also handled, but these - // are the ones that are *expected* to be seen, so we fast-path - // them. - nonHostChars = ['%', '/', '?', ';', '#'].concat(autoEscape), - hostEndingChars = ['/', '?', '#'], - hostnameMaxLen = 255, - hostnamePartPattern = /^[+a-z0-9A-Z_-]{0,63}$/, - hostnamePartStart = /^([+a-z0-9A-Z_-]{0,63})(.*)$/, - // protocols that can allow "unsafe" and "unwise" chars. - unsafeProtocol = { - 'javascript': true, - 'javascript:': true - }, - // protocols that never have a hostname. - hostlessProtocol = { - 'javascript': true, - 'javascript:': true - }, - // protocols that always contain a // bit. - slashedProtocol = { - 'http': true, - 'https': true, - 'ftp': true, - 'gopher': true, - 'file': true, - 'http:': true, - 'https:': true, - 'ftp:': true, - 'gopher:': true, - 'file:': true - }, - querystring = require('querystring'); - -function urlParse(url, parseQueryString, slashesDenoteHost) { - if (url && util.isObject(url) && url instanceof Url) return url; - - var u = new Url; - u.parse(url, parseQueryString, slashesDenoteHost); - return u; -} - -Url.prototype.parse = function(url, parseQueryString, slashesDenoteHost) { - if (!util.isString(url)) { - throw new TypeError("Parameter 'url' must be a string, not " + typeof url); - } - - // Copy chrome, IE, opera backslash-handling behavior. - // Back slashes before the query string get converted to forward slashes - // See: https://code.google.com/p/chromium/issues/detail?id=25916 - var queryIndex = url.indexOf('?'), - splitter = - (queryIndex !== -1 && queryIndex < url.indexOf('#')) ? '?' : '#', - uSplit = url.split(splitter), - slashRegex = /\\/g; - uSplit[0] = uSplit[0].replace(slashRegex, '/'); - url = uSplit.join(splitter); - - var rest = url; - - // trim before proceeding. - // This is to support parse stuff like " http://foo.com \n" - rest = rest.trim(); - - if (!slashesDenoteHost && url.split('#').length === 1) { - // Try fast path regexp - var simplePath = simplePathPattern.exec(rest); - if (simplePath) { - this.path = rest; - this.href = rest; - this.pathname = simplePath[1]; - if (simplePath[2]) { - this.search = simplePath[2]; - if (parseQueryString) { - this.query = querystring.parse(this.search.substr(1)); - } else { - this.query = this.search.substr(1); - } - } else if (parseQueryString) { - this.search = ''; - this.query = {}; - } - return this; - } - } - - var proto = protocolPattern.exec(rest); - if (proto) { - proto = proto[0]; - var lowerProto = proto.toLowerCase(); - this.protocol = lowerProto; - rest = rest.substr(proto.length); - } - - // figure out if it's got a host - // user@server is *always* interpreted as a hostname, and url - // resolution will treat //foo/bar as host=foo,path=bar because that's - // how the browser resolves relative URLs. - if (slashesDenoteHost || proto || rest.match(/^\/\/[^@\/]+@[^@\/]+/)) { - var slashes = rest.substr(0, 2) === '//'; - if (slashes && !(proto && hostlessProtocol[proto])) { - rest = rest.substr(2); - this.slashes = true; - } - } - - if (!hostlessProtocol[proto] && - (slashes || (proto && !slashedProtocol[proto]))) { - - // there's a hostname. - // the first instance of /, ?, ;, or # ends the host. - // - // If there is an @ in the hostname, then non-host chars *are* allowed - // to the left of the last @ sign, unless some host-ending character - // comes *before* the @-sign. - // URLs are obnoxious. - // - // ex: - // http://a@b@c/ => user:a@b host:c - // http://a@b?@c => user:a host:c path:/?@c - - // v0.12 TODO(isaacs): This is not quite how Chrome does things. - // Review our test case against browsers more comprehensively. - - // find the first instance of any hostEndingChars - var hostEnd = -1; - for (var i = 0; i < hostEndingChars.length; i++) { - var hec = rest.indexOf(hostEndingChars[i]); - if (hec !== -1 && (hostEnd === -1 || hec < hostEnd)) - hostEnd = hec; - } - - // at this point, either we have an explicit point where the - // auth portion cannot go past, or the last @ char is the decider. - var auth, atSign; - if (hostEnd === -1) { - // atSign can be anywhere. - atSign = rest.lastIndexOf('@'); - } else { - // atSign must be in auth portion. - // http://a@b/c@d => host:b auth:a path:/c@d - atSign = rest.lastIndexOf('@', hostEnd); - } - - // Now we have a portion which is definitely the auth. - // Pull that off. - if (atSign !== -1) { - auth = rest.slice(0, atSign); - rest = rest.slice(atSign + 1); - this.auth = decodeURIComponent(auth); - } - - // the host is the remaining to the left of the first non-host char - hostEnd = -1; - for (var i = 0; i < nonHostChars.length; i++) { - var hec = rest.indexOf(nonHostChars[i]); - if (hec !== -1 && (hostEnd === -1 || hec < hostEnd)) - hostEnd = hec; - } - // if we still have not hit it, then the entire thing is a host. - if (hostEnd === -1) - hostEnd = rest.length; - - this.host = rest.slice(0, hostEnd); - rest = rest.slice(hostEnd); - - // pull out port. - this.parseHost(); - - // we've indicated that there is a hostname, - // so even if it's empty, it has to be present. - this.hostname = this.hostname || ''; - - // if hostname begins with [ and ends with ] - // assume that it's an IPv6 address. - var ipv6Hostname = this.hostname[0] === '[' && - this.hostname[this.hostname.length - 1] === ']'; - - // validate a little. - if (!ipv6Hostname) { - var hostparts = this.hostname.split(/\./); - for (var i = 0, l = hostparts.length; i < l; i++) { - var part = hostparts[i]; - if (!part) continue; - if (!part.match(hostnamePartPattern)) { - var newpart = ''; - for (var j = 0, k = part.length; j < k; j++) { - if (part.charCodeAt(j) > 127) { - // we replace non-ASCII char with a temporary placeholder - // we need this to make sure size of hostname is not - // broken by replacing non-ASCII by nothing - newpart += 'x'; - } else { - newpart += part[j]; - } - } - // we test again with ASCII char only - if (!newpart.match(hostnamePartPattern)) { - var validParts = hostparts.slice(0, i); - var notHost = hostparts.slice(i + 1); - var bit = part.match(hostnamePartStart); - if (bit) { - validParts.push(bit[1]); - notHost.unshift(bit[2]); - } - if (notHost.length) { - rest = '/' + notHost.join('.') + rest; - } - this.hostname = validParts.join('.'); - break; - } - } - } - } - - if (this.hostname.length > hostnameMaxLen) { - this.hostname = ''; - } else { - // hostnames are always lower case. - this.hostname = this.hostname.toLowerCase(); - } - - if (!ipv6Hostname) { - // IDNA Support: Returns a punycoded representation of "domain". - // It only converts parts of the domain name that - // have non-ASCII characters, i.e. it doesn't matter if - // you call it with a domain that already is ASCII-only. - this.hostname = punycode.toASCII(this.hostname); - } - - var p = this.port ? ':' + this.port : ''; - var h = this.hostname || ''; - this.host = h + p; - this.href += this.host; - - // strip [ and ] from the hostname - // the host field still retains them, though - if (ipv6Hostname) { - this.hostname = this.hostname.substr(1, this.hostname.length - 2); - if (rest[0] !== '/') { - rest = '/' + rest; - } - } - } - - // now rest is set to the post-host stuff. - // chop off any delim chars. - if (!unsafeProtocol[lowerProto]) { - - // First, make 100% sure that any "autoEscape" chars get - // escaped, even if encodeURIComponent doesn't think they - // need to be. - for (var i = 0, l = autoEscape.length; i < l; i++) { - var ae = autoEscape[i]; - if (rest.indexOf(ae) === -1) - continue; - var esc = encodeURIComponent(ae); - if (esc === ae) { - esc = escape(ae); - } - rest = rest.split(ae).join(esc); - } - } - - - // chop off from the tail first. - var hash = rest.indexOf('#'); - if (hash !== -1) { - // got a fragment string. - this.hash = rest.substr(hash); - rest = rest.slice(0, hash); - } - var qm = rest.indexOf('?'); - if (qm !== -1) { - this.search = rest.substr(qm); - this.query = rest.substr(qm + 1); - if (parseQueryString) { - this.query = querystring.parse(this.query); - } - rest = rest.slice(0, qm); - } else if (parseQueryString) { - // no query string, but parseQueryString still requested - this.search = ''; - this.query = {}; - } - if (rest) this.pathname = rest; - if (slashedProtocol[lowerProto] && - this.hostname && !this.pathname) { - this.pathname = '/'; - } - - //to support http.request - if (this.pathname || this.search) { - var p = this.pathname || ''; - var s = this.search || ''; - this.path = p + s; - } - - // finally, reconstruct the href based on what has been validated. - this.href = this.format(); - return this; -}; - -// format a parsed object into a url string -function urlFormat(obj) { - // ensure it's an object, and not a string url. - // If it's an obj, this is a no-op. - // this way, you can call url_format() on strings - // to clean up potentially wonky urls. - if (util.isString(obj)) obj = urlParse(obj); - if (!(obj instanceof Url)) return Url.prototype.format.call(obj); - return obj.format(); -} - -Url.prototype.format = function() { - var auth = this.auth || ''; - if (auth) { - auth = encodeURIComponent(auth); - auth = auth.replace(/%3A/i, ':'); - auth += '@'; - } - - var protocol = this.protocol || '', - pathname = this.pathname || '', - hash = this.hash || '', - host = false, - query = ''; - - if (this.host) { - host = auth + this.host; - } else if (this.hostname) { - host = auth + (this.hostname.indexOf(':') === -1 ? - this.hostname : - '[' + this.hostname + ']'); - if (this.port) { - host += ':' + this.port; - } - } - - if (this.query && - util.isObject(this.query) && - Object.keys(this.query).length) { - query = querystring.stringify(this.query); - } - - var search = this.search || (query && ('?' + query)) || ''; - - if (protocol && protocol.substr(-1) !== ':') protocol += ':'; - - // only the slashedProtocols get the //. Not mailto:, xmpp:, etc. - // unless they had them to begin with. - if (this.slashes || - (!protocol || slashedProtocol[protocol]) && host !== false) { - host = '//' + (host || ''); - if (pathname && pathname.charAt(0) !== '/') pathname = '/' + pathname; - } else if (!host) { - host = ''; - } - - if (hash && hash.charAt(0) !== '#') hash = '#' + hash; - if (search && search.charAt(0) !== '?') search = '?' + search; - - pathname = pathname.replace(/[?#]/g, function(match) { - return encodeURIComponent(match); - }); - search = search.replace('#', '%23'); - - return protocol + host + pathname + search + hash; -}; - -function urlResolve(source, relative) { - return urlParse(source, false, true).resolve(relative); -} - -Url.prototype.resolve = function(relative) { - return this.resolveObject(urlParse(relative, false, true)).format(); -}; - -function urlResolveObject(source, relative) { - if (!source) return relative; - return urlParse(source, false, true).resolveObject(relative); -} - -Url.prototype.resolveObject = function(relative) { - if (util.isString(relative)) { - var rel = new Url(); - rel.parse(relative, false, true); - relative = rel; - } - - var result = new Url(); - var tkeys = Object.keys(this); - for (var tk = 0; tk < tkeys.length; tk++) { - var tkey = tkeys[tk]; - result[tkey] = this[tkey]; - } - - // hash is always overridden, no matter what. - // even href="" will remove it. - result.hash = relative.hash; - - // if the relative url is empty, then there's nothing left to do here. - if (relative.href === '') { - result.href = result.format(); - return result; - } - - // hrefs like //foo/bar always cut to the protocol. - if (relative.slashes && !relative.protocol) { - // take everything except the protocol from relative - var rkeys = Object.keys(relative); - for (var rk = 0; rk < rkeys.length; rk++) { - var rkey = rkeys[rk]; - if (rkey !== 'protocol') - result[rkey] = relative[rkey]; - } - - //urlParse appends trailing / to urls like http://www.example.com - if (slashedProtocol[result.protocol] && - result.hostname && !result.pathname) { - result.path = result.pathname = '/'; - } - - result.href = result.format(); - return result; - } - - if (relative.protocol && relative.protocol !== result.protocol) { - // if it's a known url protocol, then changing - // the protocol does weird things - // first, if it's not file:, then we MUST have a host, - // and if there was a path - // to begin with, then we MUST have a path. - // if it is file:, then the host is dropped, - // because that's known to be hostless. - // anything else is assumed to be absolute. - if (!slashedProtocol[relative.protocol]) { - var keys = Object.keys(relative); - for (var v = 0; v < keys.length; v++) { - var k = keys[v]; - result[k] = relative[k]; - } - result.href = result.format(); - return result; - } - - result.protocol = relative.protocol; - if (!relative.host && !hostlessProtocol[relative.protocol]) { - var relPath = (relative.pathname || '').split('/'); - while (relPath.length && !(relative.host = relPath.shift())); - if (!relative.host) relative.host = ''; - if (!relative.hostname) relative.hostname = ''; - if (relPath[0] !== '') relPath.unshift(''); - if (relPath.length < 2) relPath.unshift(''); - result.pathname = relPath.join('/'); - } else { - result.pathname = relative.pathname; - } - result.search = relative.search; - result.query = relative.query; - result.host = relative.host || ''; - result.auth = relative.auth; - result.hostname = relative.hostname || relative.host; - result.port = relative.port; - // to support http.request - if (result.pathname || result.search) { - var p = result.pathname || ''; - var s = result.search || ''; - result.path = p + s; - } - result.slashes = result.slashes || relative.slashes; - result.href = result.format(); - return result; - } - - var isSourceAbs = (result.pathname && result.pathname.charAt(0) === '/'), - isRelAbs = ( - relative.host || - relative.pathname && relative.pathname.charAt(0) === '/' - ), - mustEndAbs = (isRelAbs || isSourceAbs || - (result.host && relative.pathname)), - removeAllDots = mustEndAbs, - srcPath = result.pathname && result.pathname.split('/') || [], - relPath = relative.pathname && relative.pathname.split('/') || [], - psychotic = result.protocol && !slashedProtocol[result.protocol]; - - // if the url is a non-slashed url, then relative - // links like ../.. should be able - // to crawl up to the hostname, as well. This is strange. - // result.protocol has already been set by now. - // Later on, put the first path part into the host field. - if (psychotic) { - result.hostname = ''; - result.port = null; - if (result.host) { - if (srcPath[0] === '') srcPath[0] = result.host; - else srcPath.unshift(result.host); - } - result.host = ''; - if (relative.protocol) { - relative.hostname = null; - relative.port = null; - if (relative.host) { - if (relPath[0] === '') relPath[0] = relative.host; - else relPath.unshift(relative.host); - } - relative.host = null; - } - mustEndAbs = mustEndAbs && (relPath[0] === '' || srcPath[0] === ''); - } - - if (isRelAbs) { - // it's absolute. - result.host = (relative.host || relative.host === '') ? - relative.host : result.host; - result.hostname = (relative.hostname || relative.hostname === '') ? - relative.hostname : result.hostname; - result.search = relative.search; - result.query = relative.query; - srcPath = relPath; - // fall through to the dot-handling below. - } else if (relPath.length) { - // it's relative - // throw away the existing file, and take the new path instead. - if (!srcPath) srcPath = []; - srcPath.pop(); - srcPath = srcPath.concat(relPath); - result.search = relative.search; - result.query = relative.query; - } else if (!util.isNullOrUndefined(relative.search)) { - // just pull out the search. - // like href='?foo'. - // Put this after the other two cases because it simplifies the booleans - if (psychotic) { - result.hostname = result.host = srcPath.shift(); - //occationaly the auth can get stuck only in host - //this especially happens in cases like - //url.resolveObject('mailto:local1@domain1', 'local2@domain2') - var authInHost = result.host && result.host.indexOf('@') > 0 ? - result.host.split('@') : false; - if (authInHost) { - result.auth = authInHost.shift(); - result.host = result.hostname = authInHost.shift(); - } - } - result.search = relative.search; - result.query = relative.query; - //to support http.request - if (!util.isNull(result.pathname) || !util.isNull(result.search)) { - result.path = (result.pathname ? result.pathname : '') + - (result.search ? result.search : ''); - } - result.href = result.format(); - return result; - } - - if (!srcPath.length) { - // no path at all. easy. - // we've already handled the other stuff above. - result.pathname = null; - //to support http.request - if (result.search) { - result.path = '/' + result.search; - } else { - result.path = null; - } - result.href = result.format(); - return result; - } - - // if a url ENDs in . or .., then it must get a trailing slash. - // however, if it ends in anything else non-slashy, - // then it must NOT get a trailing slash. - var last = srcPath.slice(-1)[0]; - var hasTrailingSlash = ( - (result.host || relative.host || srcPath.length > 1) && - (last === '.' || last === '..') || last === ''); - - // strip single dots, resolve double dots to parent dir - // if the path tries to go above the root, `up` ends up > 0 - var up = 0; - for (var i = srcPath.length; i >= 0; i--) { - last = srcPath[i]; - if (last === '.') { - srcPath.splice(i, 1); - } else if (last === '..') { - srcPath.splice(i, 1); - up++; - } else if (up) { - srcPath.splice(i, 1); - up--; - } - } - - // if the path is allowed to go above the root, restore leading ..s - if (!mustEndAbs && !removeAllDots) { - for (; up--; up) { - srcPath.unshift('..'); - } - } - - if (mustEndAbs && srcPath[0] !== '' && - (!srcPath[0] || srcPath[0].charAt(0) !== '/')) { - srcPath.unshift(''); - } - - if (hasTrailingSlash && (srcPath.join('/').substr(-1) !== '/')) { - srcPath.push(''); - } - - var isAbsolute = srcPath[0] === '' || - (srcPath[0] && srcPath[0].charAt(0) === '/'); - - // put the host back - if (psychotic) { - result.hostname = result.host = isAbsolute ? '' : - srcPath.length ? srcPath.shift() : ''; - //occationaly the auth can get stuck only in host - //this especially happens in cases like - //url.resolveObject('mailto:local1@domain1', 'local2@domain2') - var authInHost = result.host && result.host.indexOf('@') > 0 ? - result.host.split('@') : false; - if (authInHost) { - result.auth = authInHost.shift(); - result.host = result.hostname = authInHost.shift(); - } - } - - mustEndAbs = mustEndAbs || (result.host && srcPath.length); - - if (mustEndAbs && !isAbsolute) { - srcPath.unshift(''); - } - - if (!srcPath.length) { - result.pathname = null; - result.path = null; - } else { - result.pathname = srcPath.join('/'); - } - - //to support request.http - if (!util.isNull(result.pathname) || !util.isNull(result.search)) { - result.path = (result.pathname ? result.pathname : '') + - (result.search ? result.search : ''); - } - result.auth = relative.auth || result.auth; - result.slashes = result.slashes || relative.slashes; - result.href = result.format(); - return result; -}; - -Url.prototype.parseHost = function() { - var host = this.host; - var port = portPattern.exec(host); - if (port) { - port = port[0]; - if (port !== ':') { - this.port = port.substr(1); - } - host = host.substr(0, host.length - port.length); - } - if (host) this.hostname = host; -}; - -},{"./util":16,"punycode":11,"querystring":14}],16:[function(require,module,exports){ -'use strict'; - -module.exports = { - isString: function(arg) { - return typeof(arg) === 'string'; - }, - isObject: function(arg) { - return typeof(arg) === 'object' && arg !== null; - }, - isNull: function(arg) { - return arg === null; - }, - isNullOrUndefined: function(arg) { - return arg == null; - } -}; - -},{}],17:[function(require,module,exports){ -(function(module) { - 'use strict'; - - module.exports.is_uri = is_iri; - module.exports.is_http_uri = is_http_iri; - module.exports.is_https_uri = is_https_iri; - module.exports.is_web_uri = is_web_iri; - // Create aliases - module.exports.isUri = is_iri; - module.exports.isHttpUri = is_http_iri; - module.exports.isHttpsUri = is_https_iri; - module.exports.isWebUri = is_web_iri; - - - // private function - // internal URI spitter method - direct from RFC 3986 - var splitUri = function(uri) { - var splitted = uri.match(/(?:([^:\/?#]+):)?(?:\/\/([^\/?#]*))?([^?#]*)(?:\?([^#]*))?(?:#(.*))?/); - return splitted; - }; - - function is_iri(value) { - if (!value) { - return; - } - - // check for illegal characters - if (/[^a-z0-9\:\/\?\#\[\]\@\!\$\&\'\(\)\*\+\,\;\=\.\-\_\~\%]/i.test(value)) return; - - // check for hex escapes that aren't complete - if (/%[^0-9a-f]/i.test(value)) return; - if (/%[0-9a-f](:?[^0-9a-f]|$)/i.test(value)) return; - - var splitted = []; - var scheme = ''; - var authority = ''; - var path = ''; - var query = ''; - var fragment = ''; - var out = ''; - - // from RFC 3986 - splitted = splitUri(value); - scheme = splitted[1]; - authority = splitted[2]; - path = splitted[3]; - query = splitted[4]; - fragment = splitted[5]; - - // scheme and path are required, though the path can be empty - if (!(scheme && scheme.length && path.length >= 0)) return; - - // if authority is present, the path must be empty or begin with a / - if (authority && authority.length) { - if (!(path.length === 0 || /^\//.test(path))) return; - } else { - // if authority is not present, the path must not start with // - if (/^\/\//.test(path)) return; - } - - // scheme must begin with a letter, then consist of letters, digits, +, ., or - - if (!/^[a-z][a-z0-9\+\-\.]*$/.test(scheme.toLowerCase())) return; - - // re-assemble the URL per section 5.3 in RFC 3986 - out += scheme + ':'; - if (authority && authority.length) { - out += '//' + authority; - } - - out += path; - - if (query && query.length) { - out += '?' + query; - } - - if (fragment && fragment.length) { - out += '#' + fragment; - } - - return out; - } - - function is_http_iri(value, allowHttps) { - if (!is_iri(value)) { - return; - } - - var splitted = []; - var scheme = ''; - var authority = ''; - var path = ''; - var port = ''; - var query = ''; - var fragment = ''; - var out = ''; - - // from RFC 3986 - splitted = splitUri(value); - scheme = splitted[1]; - authority = splitted[2]; - path = splitted[3]; - query = splitted[4]; - fragment = splitted[5]; - - if (!scheme) return; - - if(allowHttps) { - if (scheme.toLowerCase() != 'https') return; - } else { - if (scheme.toLowerCase() != 'http') return; - } - - // fully-qualified URIs must have an authority section that is - // a valid host - if (!authority) { - return; - } - - // enable port component - if (/:(\d+)$/.test(authority)) { - port = authority.match(/:(\d+)$/)[0]; - authority = authority.replace(/:\d+$/, ''); - } - - out += scheme + ':'; - out += '//' + authority; - - if (port) { - out += port; - } - - out += path; - - if(query && query.length){ - out += '?' + query; - } - - if(fragment && fragment.length){ - out += '#' + fragment; - } - - return out; - } - - function is_https_iri(value) { - return is_http_iri(value, true); - } - - function is_web_iri(value) { - return (is_http_iri(value) || is_https_iri(value)); - } - -})(module); - -},{}],18:[function(require,module,exports){ -var createElement = require("./vdom/create-element.js") - -module.exports = createElement - -},{"./vdom/create-element.js":23}],19:[function(require,module,exports){ -var diff = require("./vtree/diff.js") - -module.exports = diff - -},{"./vtree/diff.js":43}],20:[function(require,module,exports){ -var h = require("./virtual-hyperscript/index.js") - -module.exports = h - -},{"./virtual-hyperscript/index.js":30}],21:[function(require,module,exports){ -var patch = require("./vdom/patch.js") - -module.exports = patch - -},{"./vdom/patch.js":26}],22:[function(require,module,exports){ -var isObject = require("is-object") -var isHook = require("../vnode/is-vhook.js") - -module.exports = applyProperties - -function applyProperties(node, props, previous) { - for (var propName in props) { - var propValue = props[propName] - - if (propValue === undefined) { - removeProperty(node, propName, propValue, previous); - } else if (isHook(propValue)) { - removeProperty(node, propName, propValue, previous) - if (propValue.hook) { - propValue.hook(node, - propName, - previous ? previous[propName] : undefined) - } - } else { - if (isObject(propValue)) { - patchObject(node, props, previous, propName, propValue); - } else { - node[propName] = propValue - } - } - } -} - -function removeProperty(node, propName, propValue, previous) { - if (previous) { - var previousValue = previous[propName] - - if (!isHook(previousValue)) { - if (propName === "attributes") { - for (var attrName in previousValue) { - node.removeAttribute(attrName) - } - } else if (propName === "style") { - for (var i in previousValue) { - node.style[i] = "" - } - } else if (typeof previousValue === "string") { - node[propName] = "" - } else { - node[propName] = null - } - } else if (previousValue.unhook) { - previousValue.unhook(node, propName, propValue) - } - } -} - -function patchObject(node, props, previous, propName, propValue) { - var previousValue = previous ? previous[propName] : undefined - - // Set attributes - if (propName === "attributes") { - for (var attrName in propValue) { - var attrValue = propValue[attrName] - - if (attrValue === undefined) { - node.removeAttribute(attrName) - } else { - node.setAttribute(attrName, attrValue) - } - } - - return - } - - if(previousValue && isObject(previousValue) && - getPrototype(previousValue) !== getPrototype(propValue)) { - node[propName] = propValue - return - } - - if (!isObject(node[propName])) { - node[propName] = {} - } - - var replacer = propName === "style" ? "" : undefined - - for (var k in propValue) { - var value = propValue[k] - node[propName][k] = (value === undefined) ? replacer : value - } -} - -function getPrototype(value) { - if (Object.getPrototypeOf) { - return Object.getPrototypeOf(value) - } else if (value.__proto__) { - return value.__proto__ - } else if (value.constructor) { - return value.constructor.prototype - } -} - -},{"../vnode/is-vhook.js":34,"is-object":9}],23:[function(require,module,exports){ -var document = require("global/document") - -var applyProperties = require("./apply-properties") - -var isVNode = require("../vnode/is-vnode.js") -var isVText = require("../vnode/is-vtext.js") -var isWidget = require("../vnode/is-widget.js") -var handleThunk = require("../vnode/handle-thunk.js") - -module.exports = createElement - -function createElement(vnode, opts) { - var doc = opts ? opts.document || document : document - var warn = opts ? opts.warn : null - - vnode = handleThunk(vnode).a - - if (isWidget(vnode)) { - return vnode.init() - } else if (isVText(vnode)) { - return doc.createTextNode(vnode.text) - } else if (!isVNode(vnode)) { - if (warn) { - warn("Item is not a valid virtual dom node", vnode) - } - return null - } - - var node = (vnode.namespace === null) ? - doc.createElement(vnode.tagName) : - doc.createElementNS(vnode.namespace, vnode.tagName) - - var props = vnode.properties - applyProperties(node, props) - - var children = vnode.children - - for (var i = 0; i < children.length; i++) { - var childNode = createElement(children[i], opts) - if (childNode) { - node.appendChild(childNode) - } - } - - return node -} - -},{"../vnode/handle-thunk.js":32,"../vnode/is-vnode.js":35,"../vnode/is-vtext.js":36,"../vnode/is-widget.js":37,"./apply-properties":22,"global/document":6}],24:[function(require,module,exports){ -// Maps a virtual DOM tree onto a real DOM tree in an efficient manner. -// We don't want to read all of the DOM nodes in the tree so we use -// the in-order tree indexing to eliminate recursion down certain branches. -// We only recurse into a DOM node if we know that it contains a child of -// interest. - -var noChild = {} - -module.exports = domIndex - -function domIndex(rootNode, tree, indices, nodes) { - if (!indices || indices.length === 0) { - return {} - } else { - indices.sort(ascending) - return recurse(rootNode, tree, indices, nodes, 0) - } -} - -function recurse(rootNode, tree, indices, nodes, rootIndex) { - nodes = nodes || {} - - - if (rootNode) { - if (indexInRange(indices, rootIndex, rootIndex)) { - nodes[rootIndex] = rootNode - } - - var vChildren = tree.children - - if (vChildren) { - - var childNodes = rootNode.childNodes - - for (var i = 0; i < tree.children.length; i++) { - rootIndex += 1 - - var vChild = vChildren[i] || noChild - var nextIndex = rootIndex + (vChild.count || 0) - - // skip recursion down the tree if there are no nodes down here - if (indexInRange(indices, rootIndex, nextIndex)) { - recurse(childNodes[i], vChild, indices, nodes, rootIndex) - } - - rootIndex = nextIndex - } - } - } - - return nodes -} - -// Binary search for an index in the interval [left, right] -function indexInRange(indices, left, right) { - if (indices.length === 0) { - return false - } - - var minIndex = 0 - var maxIndex = indices.length - 1 - var currentIndex - var currentItem - - while (minIndex <= maxIndex) { - currentIndex = ((maxIndex + minIndex) / 2) >> 0 - currentItem = indices[currentIndex] - - if (minIndex === maxIndex) { - return currentItem >= left && currentItem <= right - } else if (currentItem < left) { - minIndex = currentIndex + 1 - } else if (currentItem > right) { - maxIndex = currentIndex - 1 - } else { - return true - } - } - - return false; -} - -function ascending(a, b) { - return a > b ? 1 : -1 -} - -},{}],25:[function(require,module,exports){ -var applyProperties = require("./apply-properties") - -var isWidget = require("../vnode/is-widget.js") -var VPatch = require("../vnode/vpatch.js") - -var updateWidget = require("./update-widget") - -module.exports = applyPatch - -function applyPatch(vpatch, domNode, renderOptions) { - var type = vpatch.type - var vNode = vpatch.vNode - var patch = vpatch.patch - - switch (type) { - case VPatch.REMOVE: - return removeNode(domNode, vNode) - case VPatch.INSERT: - return insertNode(domNode, patch, renderOptions) - case VPatch.VTEXT: - return stringPatch(domNode, vNode, patch, renderOptions) - case VPatch.WIDGET: - return widgetPatch(domNode, vNode, patch, renderOptions) - case VPatch.VNODE: - return vNodePatch(domNode, vNode, patch, renderOptions) - case VPatch.ORDER: - reorderChildren(domNode, patch) - return domNode - case VPatch.PROPS: - applyProperties(domNode, patch, vNode.properties) - return domNode - case VPatch.THUNK: - return replaceRoot(domNode, - renderOptions.patch(domNode, patch, renderOptions)) - default: - return domNode - } -} - -function removeNode(domNode, vNode) { - var parentNode = domNode.parentNode - - if (parentNode) { - parentNode.removeChild(domNode) - } - - destroyWidget(domNode, vNode); - - return null -} - -function insertNode(parentNode, vNode, renderOptions) { - var newNode = renderOptions.render(vNode, renderOptions) - - if (parentNode) { - parentNode.appendChild(newNode) - } - - return parentNode -} - -function stringPatch(domNode, leftVNode, vText, renderOptions) { - var newNode - - if (domNode.nodeType === 3) { - domNode.replaceData(0, domNode.length, vText.text) - newNode = domNode - } else { - var parentNode = domNode.parentNode - newNode = renderOptions.render(vText, renderOptions) - - if (parentNode && newNode !== domNode) { - parentNode.replaceChild(newNode, domNode) - } - } - - return newNode -} - -function widgetPatch(domNode, leftVNode, widget, renderOptions) { - var updating = updateWidget(leftVNode, widget) - var newNode - - if (updating) { - newNode = widget.update(leftVNode, domNode) || domNode - } else { - newNode = renderOptions.render(widget, renderOptions) - } - - var parentNode = domNode.parentNode - - if (parentNode && newNode !== domNode) { - parentNode.replaceChild(newNode, domNode) - } - - if (!updating) { - destroyWidget(domNode, leftVNode) - } - - return newNode -} - -function vNodePatch(domNode, leftVNode, vNode, renderOptions) { - var parentNode = domNode.parentNode - var newNode = renderOptions.render(vNode, renderOptions) - - if (parentNode && newNode !== domNode) { - parentNode.replaceChild(newNode, domNode) - } - - return newNode -} - -function destroyWidget(domNode, w) { - if (typeof w.destroy === "function" && isWidget(w)) { - w.destroy(domNode) - } -} - -function reorderChildren(domNode, moves) { - var childNodes = domNode.childNodes - var keyMap = {} - var node - var remove - var insert - - for (var i = 0; i < moves.removes.length; i++) { - remove = moves.removes[i] - node = childNodes[remove.from] - if (remove.key) { - keyMap[remove.key] = node - } - domNode.removeChild(node) - } - - var length = childNodes.length - for (var j = 0; j < moves.inserts.length; j++) { - insert = moves.inserts[j] - node = keyMap[insert.key] - // this is the weirdest bug i've ever seen in webkit - domNode.insertBefore(node, insert.to >= length++ ? null : childNodes[insert.to]) - } -} - -function replaceRoot(oldRoot, newRoot) { - if (oldRoot && newRoot && oldRoot !== newRoot && oldRoot.parentNode) { - oldRoot.parentNode.replaceChild(newRoot, oldRoot) - } - - return newRoot; -} - -},{"../vnode/is-widget.js":37,"../vnode/vpatch.js":40,"./apply-properties":22,"./update-widget":27}],26:[function(require,module,exports){ -var document = require("global/document") -var isArray = require("x-is-array") - -var render = require("./create-element") -var domIndex = require("./dom-index") -var patchOp = require("./patch-op") -module.exports = patch - -function patch(rootNode, patches, renderOptions) { - renderOptions = renderOptions || {} - renderOptions.patch = renderOptions.patch && renderOptions.patch !== patch - ? renderOptions.patch - : patchRecursive - renderOptions.render = renderOptions.render || render - - return renderOptions.patch(rootNode, patches, renderOptions) -} - -function patchRecursive(rootNode, patches, renderOptions) { - var indices = patchIndices(patches) - - if (indices.length === 0) { - return rootNode - } - - var index = domIndex(rootNode, patches.a, indices) - var ownerDocument = rootNode.ownerDocument - - if (!renderOptions.document && ownerDocument !== document) { - renderOptions.document = ownerDocument - } - - for (var i = 0; i < indices.length; i++) { - var nodeIndex = indices[i] - rootNode = applyPatch(rootNode, - index[nodeIndex], - patches[nodeIndex], - renderOptions) - } - - return rootNode -} - -function applyPatch(rootNode, domNode, patchList, renderOptions) { - if (!domNode) { - return rootNode - } - - var newNode - - if (isArray(patchList)) { - for (var i = 0; i < patchList.length; i++) { - newNode = patchOp(patchList[i], domNode, renderOptions) - - if (domNode === rootNode) { - rootNode = newNode - } - } - } else { - newNode = patchOp(patchList, domNode, renderOptions) - - if (domNode === rootNode) { - rootNode = newNode - } - } - - return rootNode -} - -function patchIndices(patches) { - var indices = [] - - for (var key in patches) { - if (key !== "a") { - indices.push(Number(key)) - } - } - - return indices -} - -},{"./create-element":23,"./dom-index":24,"./patch-op":25,"global/document":6,"x-is-array":44}],27:[function(require,module,exports){ -var isWidget = require("../vnode/is-widget.js") - -module.exports = updateWidget - -function updateWidget(a, b) { - if (isWidget(a) && isWidget(b)) { - if ("name" in a && "name" in b) { - return a.id === b.id - } else { - return a.init === b.init - } - } - - return false -} - -},{"../vnode/is-widget.js":37}],28:[function(require,module,exports){ -'use strict'; - -var EvStore = require('ev-store'); - -module.exports = EvHook; - -function EvHook(value) { - if (!(this instanceof EvHook)) { - return new EvHook(value); - } - - this.value = value; -} - -EvHook.prototype.hook = function (node, propertyName) { - var es = EvStore(node); - var propName = propertyName.substr(3); - - es[propName] = this.value; -}; - -EvHook.prototype.unhook = function(node, propertyName) { - var es = EvStore(node); - var propName = propertyName.substr(3); - - es[propName] = undefined; -}; - -},{"ev-store":5}],29:[function(require,module,exports){ -'use strict'; - -module.exports = SoftSetHook; - -function SoftSetHook(value) { - if (!(this instanceof SoftSetHook)) { - return new SoftSetHook(value); - } - - this.value = value; -} - -SoftSetHook.prototype.hook = function (node, propertyName) { - if (node[propertyName] !== this.value) { - node[propertyName] = this.value; - } -}; - -},{}],30:[function(require,module,exports){ -'use strict'; - -var isArray = require('x-is-array'); - -var VNode = require('../vnode/vnode.js'); -var VText = require('../vnode/vtext.js'); -var isVNode = require('../vnode/is-vnode'); -var isVText = require('../vnode/is-vtext'); -var isWidget = require('../vnode/is-widget'); -var isHook = require('../vnode/is-vhook'); -var isVThunk = require('../vnode/is-thunk'); - -var parseTag = require('./parse-tag.js'); -var softSetHook = require('./hooks/soft-set-hook.js'); -var evHook = require('./hooks/ev-hook.js'); - -module.exports = h; - -function h(tagName, properties, children) { - var childNodes = []; - var tag, props, key, namespace; - - if (!children && isChildren(properties)) { - children = properties; - props = {}; - } - - props = props || properties || {}; - tag = parseTag(tagName, props); - - // support keys - if (props.hasOwnProperty('key')) { - key = props.key; - props.key = undefined; - } - - // support namespace - if (props.hasOwnProperty('namespace')) { - namespace = props.namespace; - props.namespace = undefined; - } - - // fix cursor bug - if (tag === 'INPUT' && - !namespace && - props.hasOwnProperty('value') && - props.value !== undefined && - !isHook(props.value) - ) { - props.value = softSetHook(props.value); - } - - transformProperties(props); - - if (children !== undefined && children !== null) { - addChild(children, childNodes, tag, props); - } - - - return new VNode(tag, props, childNodes, key, namespace); -} - -function addChild(c, childNodes, tag, props) { - if (typeof c === 'string') { - childNodes.push(new VText(c)); - } else if (typeof c === 'number') { - childNodes.push(new VText(String(c))); - } else if (isChild(c)) { - childNodes.push(c); - } else if (isArray(c)) { - for (var i = 0; i < c.length; i++) { - addChild(c[i], childNodes, tag, props); - } - } else if (c === null || c === undefined) { - return; - } else { - throw UnexpectedVirtualElement({ - foreignObject: c, - parentVnode: { - tagName: tag, - properties: props - } - }); - } -} - -function transformProperties(props) { - for (var propName in props) { - if (props.hasOwnProperty(propName)) { - var value = props[propName]; - - if (isHook(value)) { - continue; - } - - if (propName.substr(0, 3) === 'ev-') { - // add ev-foo support - props[propName] = evHook(value); - } - } - } -} - -function isChild(x) { - return isVNode(x) || isVText(x) || isWidget(x) || isVThunk(x); -} - -function isChildren(x) { - return typeof x === 'string' || isArray(x) || isChild(x); -} - -function UnexpectedVirtualElement(data) { - var err = new Error(); - - err.type = 'virtual-hyperscript.unexpected.virtual-element'; - err.message = 'Unexpected virtual child passed to h().\n' + - 'Expected a VNode / Vthunk / VWidget / string but:\n' + - 'got:\n' + - errorString(data.foreignObject) + - '.\n' + - 'The parent vnode is:\n' + - errorString(data.parentVnode) - '\n' + - 'Suggested fix: change your `h(..., [ ... ])` callsite.'; - err.foreignObject = data.foreignObject; - err.parentVnode = data.parentVnode; - - return err; -} - -function errorString(obj) { - try { - return JSON.stringify(obj, null, ' '); - } catch (e) { - return String(obj); - } -} - -},{"../vnode/is-thunk":33,"../vnode/is-vhook":34,"../vnode/is-vnode":35,"../vnode/is-vtext":36,"../vnode/is-widget":37,"../vnode/vnode.js":39,"../vnode/vtext.js":41,"./hooks/ev-hook.js":28,"./hooks/soft-set-hook.js":29,"./parse-tag.js":31,"x-is-array":44}],31:[function(require,module,exports){ -'use strict'; - -var split = require('browser-split'); - -var classIdSplit = /([\.#]?[a-zA-Z0-9\u007F-\uFFFF_:-]+)/; -var notClassId = /^\.|#/; - -module.exports = parseTag; - -function parseTag(tag, props) { - if (!tag) { - return 'DIV'; - } - - var noId = !(props.hasOwnProperty('id')); - - var tagParts = split(tag, classIdSplit); - var tagName = null; - - if (notClassId.test(tagParts[1])) { - tagName = 'DIV'; - } - - var classes, part, type, i; - - for (i = 0; i < tagParts.length; i++) { - part = tagParts[i]; - - if (!part) { - continue; - } - - type = part.charAt(0); - - if (!tagName) { - tagName = part; - } else if (type === '.') { - classes = classes || []; - classes.push(part.substring(1, part.length)); - } else if (type === '#' && noId) { - props.id = part.substring(1, part.length); - } - } - - if (classes) { - if (props.className) { - classes.push(props.className); - } - - props.className = classes.join(' '); - } - - return props.namespace ? tagName : tagName.toUpperCase(); -} - -},{"browser-split":4}],32:[function(require,module,exports){ -var isVNode = require("./is-vnode") -var isVText = require("./is-vtext") -var isWidget = require("./is-widget") -var isThunk = require("./is-thunk") - -module.exports = handleThunk - -function handleThunk(a, b) { - var renderedA = a - var renderedB = b - - if (isThunk(b)) { - renderedB = renderThunk(b, a) - } - - if (isThunk(a)) { - renderedA = renderThunk(a, null) - } - - return { - a: renderedA, - b: renderedB - } -} - -function renderThunk(thunk, previous) { - var renderedThunk = thunk.vnode - - if (!renderedThunk) { - renderedThunk = thunk.vnode = thunk.render(previous) - } - - if (!(isVNode(renderedThunk) || - isVText(renderedThunk) || - isWidget(renderedThunk))) { - throw new Error("thunk did not return a valid node"); - } - - return renderedThunk -} - -},{"./is-thunk":33,"./is-vnode":35,"./is-vtext":36,"./is-widget":37}],33:[function(require,module,exports){ -module.exports = isThunk - -function isThunk(t) { - return t && t.type === "Thunk" -} - -},{}],34:[function(require,module,exports){ -module.exports = isHook - -function isHook(hook) { - return hook && - (typeof hook.hook === "function" && !hook.hasOwnProperty("hook") || - typeof hook.unhook === "function" && !hook.hasOwnProperty("unhook")) -} - -},{}],35:[function(require,module,exports){ -var version = require("./version") - -module.exports = isVirtualNode - -function isVirtualNode(x) { - return x && x.type === "VirtualNode" && x.version === version -} - -},{"./version":38}],36:[function(require,module,exports){ -var version = require("./version") - -module.exports = isVirtualText - -function isVirtualText(x) { - return x && x.type === "VirtualText" && x.version === version -} - -},{"./version":38}],37:[function(require,module,exports){ -module.exports = isWidget - -function isWidget(w) { - return w && w.type === "Widget" -} - -},{}],38:[function(require,module,exports){ -module.exports = "2" - -},{}],39:[function(require,module,exports){ -var version = require("./version") -var isVNode = require("./is-vnode") -var isWidget = require("./is-widget") -var isThunk = require("./is-thunk") -var isVHook = require("./is-vhook") - -module.exports = VirtualNode - -var noProperties = {} -var noChildren = [] - -function VirtualNode(tagName, properties, children, key, namespace) { - this.tagName = tagName - this.properties = properties || noProperties - this.children = children || noChildren - this.key = key != null ? String(key) : undefined - this.namespace = (typeof namespace === "string") ? namespace : null - - var count = (children && children.length) || 0 - var descendants = 0 - var hasWidgets = false - var hasThunks = false - var descendantHooks = false - var hooks - - for (var propName in properties) { - if (properties.hasOwnProperty(propName)) { - var property = properties[propName] - if (isVHook(property) && property.unhook) { - if (!hooks) { - hooks = {} - } - - hooks[propName] = property - } - } - } - - for (var i = 0; i < count; i++) { - var child = children[i] - if (isVNode(child)) { - descendants += child.count || 0 - - if (!hasWidgets && child.hasWidgets) { - hasWidgets = true - } - - if (!hasThunks && child.hasThunks) { - hasThunks = true - } - - if (!descendantHooks && (child.hooks || child.descendantHooks)) { - descendantHooks = true - } - } else if (!hasWidgets && isWidget(child)) { - if (typeof child.destroy === "function") { - hasWidgets = true - } - } else if (!hasThunks && isThunk(child)) { - hasThunks = true; - } - } - - this.count = count + descendants - this.hasWidgets = hasWidgets - this.hasThunks = hasThunks - this.hooks = hooks - this.descendantHooks = descendantHooks -} - -VirtualNode.prototype.version = version -VirtualNode.prototype.type = "VirtualNode" - -},{"./is-thunk":33,"./is-vhook":34,"./is-vnode":35,"./is-widget":37,"./version":38}],40:[function(require,module,exports){ -var version = require("./version") - -VirtualPatch.NONE = 0 -VirtualPatch.VTEXT = 1 -VirtualPatch.VNODE = 2 -VirtualPatch.WIDGET = 3 -VirtualPatch.PROPS = 4 -VirtualPatch.ORDER = 5 -VirtualPatch.INSERT = 6 -VirtualPatch.REMOVE = 7 -VirtualPatch.THUNK = 8 - -module.exports = VirtualPatch - -function VirtualPatch(type, vNode, patch) { - this.type = Number(type) - this.vNode = vNode - this.patch = patch -} - -VirtualPatch.prototype.version = version -VirtualPatch.prototype.type = "VirtualPatch" - -},{"./version":38}],41:[function(require,module,exports){ -var version = require("./version") - -module.exports = VirtualText - -function VirtualText(text) { - this.text = String(text) -} - -VirtualText.prototype.version = version -VirtualText.prototype.type = "VirtualText" - -},{"./version":38}],42:[function(require,module,exports){ -var isObject = require("is-object") -var isHook = require("../vnode/is-vhook") - -module.exports = diffProps - -function diffProps(a, b) { - var diff - - for (var aKey in a) { - if (!(aKey in b)) { - diff = diff || {} - diff[aKey] = undefined - } - - var aValue = a[aKey] - var bValue = b[aKey] - - if (aValue === bValue) { - continue - } else if (isObject(aValue) && isObject(bValue)) { - if (getPrototype(bValue) !== getPrototype(aValue)) { - diff = diff || {} - diff[aKey] = bValue - } else if (isHook(bValue)) { - diff = diff || {} - diff[aKey] = bValue - } else { - var objectDiff = diffProps(aValue, bValue) - if (objectDiff) { - diff = diff || {} - diff[aKey] = objectDiff - } - } - } else { - diff = diff || {} - diff[aKey] = bValue - } - } - - for (var bKey in b) { - if (!(bKey in a)) { - diff = diff || {} - diff[bKey] = b[bKey] - } - } - - return diff -} - -function getPrototype(value) { - if (Object.getPrototypeOf) { - return Object.getPrototypeOf(value) - } else if (value.__proto__) { - return value.__proto__ - } else if (value.constructor) { - return value.constructor.prototype - } -} - -},{"../vnode/is-vhook":34,"is-object":9}],43:[function(require,module,exports){ -var isArray = require("x-is-array") - -var VPatch = require("../vnode/vpatch") -var isVNode = require("../vnode/is-vnode") -var isVText = require("../vnode/is-vtext") -var isWidget = require("../vnode/is-widget") -var isThunk = require("../vnode/is-thunk") -var handleThunk = require("../vnode/handle-thunk") - -var diffProps = require("./diff-props") - -module.exports = diff - -function diff(a, b) { - var patch = { a: a } - walk(a, b, patch, 0) - return patch -} - -function walk(a, b, patch, index) { - if (a === b) { - return - } - - var apply = patch[index] - var applyClear = false - - if (isThunk(a) || isThunk(b)) { - thunks(a, b, patch, index) - } else if (b == null) { - - // If a is a widget we will add a remove patch for it - // Otherwise any child widgets/hooks must be destroyed. - // This prevents adding two remove patches for a widget. - if (!isWidget(a)) { - clearState(a, patch, index) - apply = patch[index] - } - - apply = appendPatch(apply, new VPatch(VPatch.REMOVE, a, b)) - } else if (isVNode(b)) { - if (isVNode(a)) { - if (a.tagName === b.tagName && - a.namespace === b.namespace && - a.key === b.key) { - var propsPatch = diffProps(a.properties, b.properties) - if (propsPatch) { - apply = appendPatch(apply, - new VPatch(VPatch.PROPS, a, propsPatch)) - } - apply = diffChildren(a, b, patch, apply, index) - } else { - apply = appendPatch(apply, new VPatch(VPatch.VNODE, a, b)) - applyClear = true - } - } else { - apply = appendPatch(apply, new VPatch(VPatch.VNODE, a, b)) - applyClear = true - } - } else if (isVText(b)) { - if (!isVText(a)) { - apply = appendPatch(apply, new VPatch(VPatch.VTEXT, a, b)) - applyClear = true - } else if (a.text !== b.text) { - apply = appendPatch(apply, new VPatch(VPatch.VTEXT, a, b)) - } - } else if (isWidget(b)) { - if (!isWidget(a)) { - applyClear = true - } - - apply = appendPatch(apply, new VPatch(VPatch.WIDGET, a, b)) - } - - if (apply) { - patch[index] = apply - } - - if (applyClear) { - clearState(a, patch, index) - } -} - -function diffChildren(a, b, patch, apply, index) { - var aChildren = a.children - var orderedSet = reorder(aChildren, b.children) - var bChildren = orderedSet.children - - var aLen = aChildren.length - var bLen = bChildren.length - var len = aLen > bLen ? aLen : bLen - - for (var i = 0; i < len; i++) { - var leftNode = aChildren[i] - var rightNode = bChildren[i] - index += 1 - - if (!leftNode) { - if (rightNode) { - // Excess nodes in b need to be added - apply = appendPatch(apply, - new VPatch(VPatch.INSERT, null, rightNode)) - } - } else { - walk(leftNode, rightNode, patch, index) - } - - if (isVNode(leftNode) && leftNode.count) { - index += leftNode.count - } - } - - if (orderedSet.moves) { - // Reorder nodes last - apply = appendPatch(apply, new VPatch( - VPatch.ORDER, - a, - orderedSet.moves - )) - } - - return apply -} - -function clearState(vNode, patch, index) { - // TODO: Make this a single walk, not two - unhook(vNode, patch, index) - destroyWidgets(vNode, patch, index) -} - -// Patch records for all destroyed widgets must be added because we need -// a DOM node reference for the destroy function -function destroyWidgets(vNode, patch, index) { - if (isWidget(vNode)) { - if (typeof vNode.destroy === "function") { - patch[index] = appendPatch( - patch[index], - new VPatch(VPatch.REMOVE, vNode, null) - ) - } - } else if (isVNode(vNode) && (vNode.hasWidgets || vNode.hasThunks)) { - var children = vNode.children - var len = children.length - for (var i = 0; i < len; i++) { - var child = children[i] - index += 1 - - destroyWidgets(child, patch, index) - - if (isVNode(child) && child.count) { - index += child.count - } - } - } else if (isThunk(vNode)) { - thunks(vNode, null, patch, index) - } -} - -// Create a sub-patch for thunks -function thunks(a, b, patch, index) { - var nodes = handleThunk(a, b) - var thunkPatch = diff(nodes.a, nodes.b) - if (hasPatches(thunkPatch)) { - patch[index] = new VPatch(VPatch.THUNK, null, thunkPatch) - } -} - -function hasPatches(patch) { - for (var index in patch) { - if (index !== "a") { - return true - } - } - - return false -} - -// Execute hooks when two nodes are identical -function unhook(vNode, patch, index) { - if (isVNode(vNode)) { - if (vNode.hooks) { - patch[index] = appendPatch( - patch[index], - new VPatch( - VPatch.PROPS, - vNode, - undefinedKeys(vNode.hooks) - ) - ) - } - - if (vNode.descendantHooks || vNode.hasThunks) { - var children = vNode.children - var len = children.length - for (var i = 0; i < len; i++) { - var child = children[i] - index += 1 - - unhook(child, patch, index) - - if (isVNode(child) && child.count) { - index += child.count - } - } - } - } else if (isThunk(vNode)) { - thunks(vNode, null, patch, index) - } -} - -function undefinedKeys(obj) { - var result = {} - - for (var key in obj) { - result[key] = undefined - } - - return result -} - -// List diff, naive left to right reordering -function reorder(aChildren, bChildren) { - // O(M) time, O(M) memory - var bChildIndex = keyIndex(bChildren) - var bKeys = bChildIndex.keys - var bFree = bChildIndex.free - - if (bFree.length === bChildren.length) { - return { - children: bChildren, - moves: null - } - } - - // O(N) time, O(N) memory - var aChildIndex = keyIndex(aChildren) - var aKeys = aChildIndex.keys - var aFree = aChildIndex.free - - if (aFree.length === aChildren.length) { - return { - children: bChildren, - moves: null - } - } - - // O(MAX(N, M)) memory - var newChildren = [] - - var freeIndex = 0 - var freeCount = bFree.length - var deletedItems = 0 - - // Iterate through a and match a node in b - // O(N) time, - for (var i = 0 ; i < aChildren.length; i++) { - var aItem = aChildren[i] - var itemIndex - - if (aItem.key) { - if (bKeys.hasOwnProperty(aItem.key)) { - // Match up the old keys - itemIndex = bKeys[aItem.key] - newChildren.push(bChildren[itemIndex]) - - } else { - // Remove old keyed items - itemIndex = i - deletedItems++ - newChildren.push(null) - } - } else { - // Match the item in a with the next free item in b - if (freeIndex < freeCount) { - itemIndex = bFree[freeIndex++] - newChildren.push(bChildren[itemIndex]) - } else { - // There are no free items in b to match with - // the free items in a, so the extra free nodes - // are deleted. - itemIndex = i - deletedItems++ - newChildren.push(null) - } - } - } - - var lastFreeIndex = freeIndex >= bFree.length ? - bChildren.length : - bFree[freeIndex] - - // Iterate through b and append any new keys - // O(M) time - for (var j = 0; j < bChildren.length; j++) { - var newItem = bChildren[j] - - if (newItem.key) { - if (!aKeys.hasOwnProperty(newItem.key)) { - // Add any new keyed items - // We are adding new items to the end and then sorting them - // in place. In future we should insert new items in place. - newChildren.push(newItem) - } - } else if (j >= lastFreeIndex) { - // Add any leftover non-keyed items - newChildren.push(newItem) - } - } - - var simulate = newChildren.slice() - var simulateIndex = 0 - var removes = [] - var inserts = [] - var simulateItem - - for (var k = 0; k < bChildren.length;) { - var wantedItem = bChildren[k] - simulateItem = simulate[simulateIndex] - - // remove items - while (simulateItem === null && simulate.length) { - removes.push(remove(simulate, simulateIndex, null)) - simulateItem = simulate[simulateIndex] - } - - if (!simulateItem || simulateItem.key !== wantedItem.key) { - // if we need a key in this position... - if (wantedItem.key) { - if (simulateItem && simulateItem.key) { - // if an insert doesn't put this key in place, it needs to move - if (bKeys[simulateItem.key] !== k + 1) { - removes.push(remove(simulate, simulateIndex, simulateItem.key)) - simulateItem = simulate[simulateIndex] - // if the remove didn't put the wanted item in place, we need to insert it - if (!simulateItem || simulateItem.key !== wantedItem.key) { - inserts.push({key: wantedItem.key, to: k}) - } - // items are matching, so skip ahead - else { - simulateIndex++ - } - } - else { - inserts.push({key: wantedItem.key, to: k}) - } - } - else { - inserts.push({key: wantedItem.key, to: k}) - } - k++ - } - // a key in simulate has no matching wanted key, remove it - else if (simulateItem && simulateItem.key) { - removes.push(remove(simulate, simulateIndex, simulateItem.key)) - } - } - else { - simulateIndex++ - k++ - } - } - - // remove all the remaining nodes from simulate - while(simulateIndex < simulate.length) { - simulateItem = simulate[simulateIndex] - removes.push(remove(simulate, simulateIndex, simulateItem && simulateItem.key)) - } - - // If the only moves we have are deletes then we can just - // let the delete patch remove these items. - if (removes.length === deletedItems && !inserts.length) { - return { - children: newChildren, - moves: null - } - } - - return { - children: newChildren, - moves: { - removes: removes, - inserts: inserts - } - } -} - -function remove(arr, index, key) { - arr.splice(index, 1) - - return { - from: index, - key: key - } -} - -function keyIndex(children) { - var keys = {} - var free = [] - var length = children.length - - for (var i = 0; i < length; i++) { - var child = children[i] - - if (child.key) { - keys[child.key] = i - } else { - free.push(i) - } - } - - return { - keys: keys, // A hash of key name to index - free: free // An array of unkeyed item indices - } -} - -function appendPatch(apply, patch) { - if (apply) { - if (isArray(apply)) { - apply.push(patch) - } else { - apply = [apply, patch] - } - - return apply - } else { - return patch - } -} - -},{"../vnode/handle-thunk":32,"../vnode/is-thunk":33,"../vnode/is-vnode":35,"../vnode/is-vtext":36,"../vnode/is-widget":37,"../vnode/vpatch":40,"./diff-props":42,"x-is-array":44}],44:[function(require,module,exports){ -var nativeIsArray = Array.isArray -var toString = Object.prototype.toString - -module.exports = nativeIsArray || isArray - -function isArray(obj) { - return toString.call(obj) === "[object Array]" -} - -},{}]},{},[1]); diff --git a/formspree/static/js/main.js b/formspree/static/js/main.js deleted file mode 100644 index 94af907..0000000 --- a/formspree/static/js/main.js +++ /dev/null @@ -1,128 +0,0 @@ -const $ = window.$ -const StripeCheckout = window.StripeCheckout -const toastr = window.toastr - -toastr.options = { positionClass: 'toast-top-center' } - -/* top navbar */ -var nav = $('body > nav') -nav.addClass('js') -nav.find('.menu').slicknav() -nav.find('h4').clone().prependTo('.slicknav_menu') - -/* adding a shadow at the bottom of the menu bar only when not at the top */ -var w = $(window) -w.scroll(function () { - var scrollPos = w.scrollTop() - if (scrollPos && !nav.hasClass('scrolled')) { - nav.addClass('scrolled') - } else if (!scrollPos) { - nav.removeClass('scrolled') - } -}) - -/* background-color should inherit, but CSS's "inherit" breaks z-index */ -var bgcolor = $(document.body).css('background-color') -if (bgcolor.split(',').length === 4 || bgcolor === 'transparent') { - bgcolor = 'white' -} -nav.css('background-color', bgcolor) - -/* modals -- working with or without JS */ -function modals () { - $('.modal').each(function () { - let modal = $(this) - modal.addClass('js') - let id = modal.attr('id') - - $(`[href="#${id}"]`).click(function (e) { - // open the modal - e.preventDefault() - modal.toggleClass('target') - }) - - modal.click(function (e) { - // close the modal - if (e.target === modal[0]) { - cleanHash() - modal.toggleClass('target') - e.preventDefault() - } - }) - modal.find('.x a').click(function (e) { - // close the modal - cleanHash() - e.preventDefault() - modal.toggleClass('target') - }) - }) - - function cleanHash () { - if (!window.location.hash) return - if (window.history && window.history.replaceState) { - window.history.replaceState('', document.title, window.location.pathname) - } else { - let pos = $(window).scrollTop() - window.location.hash = '' - $(window).scrollTop(pos) - } - } - - // activate modals from url hash # - setTimeout(() => { - // setTimeout is needed because :target elements only appear after - // the page is loaded or something like that. - let activatedModal = $('*:target') - if (activatedModal.length && !activatedModal.is('.target')) { - activatedModal.toggleClass('target') - } - }, 0) -} -modals() - -/* turning flask flash messages into js popup notifications */ -window.popupMessages.forEach(function (m, i) { - var category = m[0] || 'info' - var text = m[1] - setTimeout(function () { toastr[category](text) }, (1 + i) * 1500) -}) - -/* stripe checkout */ -var stripebutton = $('#stripe-upgrade') -if (stripebutton.length) { - var handler = StripeCheckout.configure(stripebutton.data()) - stripebutton.on('click', function (e) { - handler.open({ - token: function (token) { - stripebutton.closest('form') - .append(``) - .append(``) - .submit() - } - }) - e.preventDefault() - }) -} - -/* quick script for showing the resend confirmation form */ -$('a.resend').on('click', function () { - $(this).hide() - $('form.resend').show() - return false -}) - -/* scripts at other files */ -require('./sitewide')() - -/* toggle the card management menu */ - $(function () { - $("#card-list tr:even").addClass("even"); - $("#card-list tr:not(.even)").hide(); - $("#card-list tr:first-child").show(); - - $("#card-list tr.even").click(function () { - $(this).next("tr").toggle(); - $(this).find(".arrow").toggleClass("up"); - $(this).find(".fa-chevron-right").toggleClass("fa-rotate-90"); - }); - }); diff --git a/formspree/static/js/submissions.js b/formspree/static/js/submissions.js deleted file mode 100644 index e6382a6..0000000 --- a/formspree/static/js/submissions.js +++ /dev/null @@ -1,57 +0,0 @@ -var settingsDropDownContent = $("#settings-dropdown-content")[0]; - -$(window).click(function(e) { - if(!e.target.matches('#settings-button') && e.target.nodeName != 'path' && e.target.nodeName != 'svg') { - - if (settingsDropDownContent.classList.contains("show")) { - settingsDropDownContent.classList.remove("show"); - } - } -}); - -$(document).ready(function() { - $("#settings-button").click(function() { - settingsDropDownContent.classList.toggle("show"); - }); -}); - -$(document).ready(function() { - $(':checkbox').change(function() { - targetAttributeBox = this; - var target; - var checkedStatus = this.checked; - var status = $("#status"); - - if (this.id == 'recaptcha') { - target = '/forms/' + hashid + '/toggle-recaptcha'; - } else if (this.id == 'email-notifications') { - target = '/forms/' + hashid + '/toggle-emails'; - } else if (this.id == 'submission-storage') { - target = '/forms/' + hashid + '/toggle-storage'; - } - - $.ajax({ - url: target, - method: 'POST', - contentType: 'application/json', - data: JSON.stringify({ - checked: checkedStatus - }), - dataType: 'json', - beforeSend: function() { - status.removeClass("error"); - status.html('Saving... '); - }, - success: function (data) { - status.html('Saved '); - console.log(data); - }, - error: function (data) { - status.html('Error saving '); - status.addClass("error"); - targetAttributeBox.checked = !checkedStatus; - console.log(data); - } - }); - }) -}); diff --git a/formspree/static/js/vendor/jquery.min.js b/formspree/static/js/vendor/jquery.min.js deleted file mode 100644 index 18bdbed..0000000 --- a/formspree/static/js/vendor/jquery.min.js +++ /dev/null @@ -1,5 +0,0 @@ -/*! jQuery v2.1.3 | (c) 2005, 2014 jQuery Foundation, Inc. | jquery.org/license */ -!function(a,b){"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){var c=[],d=c.slice,e=c.concat,f=c.push,g=c.indexOf,h={},i=h.toString,j=h.hasOwnProperty,k={},l=a.document,m="2.1.3",n=function(a,b){return new n.fn.init(a,b)},o=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,p=/^-ms-/,q=/-([\da-z])/gi,r=function(a,b){return b.toUpperCase()};n.fn=n.prototype={jquery:m,constructor:n,selector:"",length:0,toArray:function(){return d.call(this)},get:function(a){return null!=a?0>a?this[a+this.length]:this[a]:d.call(this)},pushStack:function(a){var b=n.merge(this.constructor(),a);return b.prevObject=this,b.context=this.context,b},each:function(a,b){return n.each(this,a,b)},map:function(a){return this.pushStack(n.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(d.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(0>a?b:0);return this.pushStack(c>=0&&b>c?[this[c]]:[])},end:function(){return this.prevObject||this.constructor(null)},push:f,sort:c.sort,splice:c.splice},n.extend=n.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for("boolean"==typeof g&&(j=g,g=arguments[h]||{},h++),"object"==typeof g||n.isFunction(g)||(g={}),h===i&&(g=this,h--);i>h;h++)if(null!=(a=arguments[h]))for(b in a)c=g[b],d=a[b],g!==d&&(j&&d&&(n.isPlainObject(d)||(e=n.isArray(d)))?(e?(e=!1,f=c&&n.isArray(c)?c:[]):f=c&&n.isPlainObject(c)?c:{},g[b]=n.extend(j,f,d)):void 0!==d&&(g[b]=d));return g},n.extend({expando:"jQuery"+(m+Math.random()).replace(/\D/g,""),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return"function"===n.type(a)},isArray:Array.isArray,isWindow:function(a){return null!=a&&a===a.window},isNumeric:function(a){return!n.isArray(a)&&a-parseFloat(a)+1>=0},isPlainObject:function(a){return"object"!==n.type(a)||a.nodeType||n.isWindow(a)?!1:a.constructor&&!j.call(a.constructor.prototype,"isPrototypeOf")?!1:!0},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},type:function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?h[i.call(a)]||"object":typeof a},globalEval:function(a){var b,c=eval;a=n.trim(a),a&&(1===a.indexOf("use strict")?(b=l.createElement("script"),b.text=a,l.head.appendChild(b).parentNode.removeChild(b)):c(a))},camelCase:function(a){return a.replace(p,"ms-").replace(q,r)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,b,c){var d,e=0,f=a.length,g=s(a);if(c){if(g){for(;f>e;e++)if(d=b.apply(a[e],c),d===!1)break}else for(e in a)if(d=b.apply(a[e],c),d===!1)break}else if(g){for(;f>e;e++)if(d=b.call(a[e],e,a[e]),d===!1)break}else for(e in a)if(d=b.call(a[e],e,a[e]),d===!1)break;return a},trim:function(a){return null==a?"":(a+"").replace(o,"")},makeArray:function(a,b){var c=b||[];return null!=a&&(s(Object(a))?n.merge(c,"string"==typeof a?[a]:a):f.call(c,a)),c},inArray:function(a,b,c){return null==b?-1:g.call(b,a,c)},merge:function(a,b){for(var c=+b.length,d=0,e=a.length;c>d;d++)a[e++]=b[d];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;g>f;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,f=0,g=a.length,h=s(a),i=[];if(h)for(;g>f;f++)d=b(a[f],f,c),null!=d&&i.push(d);else for(f in a)d=b(a[f],f,c),null!=d&&i.push(d);return e.apply([],i)},guid:1,proxy:function(a,b){var c,e,f;return"string"==typeof b&&(c=a[b],b=a,a=c),n.isFunction(a)?(e=d.call(arguments,2),f=function(){return a.apply(b||this,e.concat(d.call(arguments)))},f.guid=a.guid=a.guid||n.guid++,f):void 0},now:Date.now,support:k}),n.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(a,b){h["[object "+b+"]"]=b.toLowerCase()});function s(a){var b=a.length,c=n.type(a);return"function"===c||n.isWindow(a)?!1:1===a.nodeType&&b?!0:"array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a}var t=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u="sizzle"+1*new Date,v=a.document,w=0,x=0,y=hb(),z=hb(),A=hb(),B=function(a,b){return a===b&&(l=!0),0},C=1<<31,D={}.hasOwnProperty,E=[],F=E.pop,G=E.push,H=E.push,I=E.slice,J=function(a,b){for(var c=0,d=a.length;d>c;c++)if(a[c]===b)return c;return-1},K="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",L="[\\x20\\t\\r\\n\\f]",M="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",N=M.replace("w","w#"),O="\\["+L+"*("+M+")(?:"+L+"*([*^$|!~]?=)"+L+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+N+"))|)"+L+"*\\]",P=":("+M+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+O+")*)|.*)\\)|)",Q=new RegExp(L+"+","g"),R=new RegExp("^"+L+"+|((?:^|[^\\\\])(?:\\\\.)*)"+L+"+$","g"),S=new RegExp("^"+L+"*,"+L+"*"),T=new RegExp("^"+L+"*([>+~]|"+L+")"+L+"*"),U=new RegExp("="+L+"*([^\\]'\"]*?)"+L+"*\\]","g"),V=new RegExp(P),W=new RegExp("^"+N+"$"),X={ID:new RegExp("^#("+M+")"),CLASS:new RegExp("^\\.("+M+")"),TAG:new RegExp("^("+M.replace("w","w*")+")"),ATTR:new RegExp("^"+O),PSEUDO:new RegExp("^"+P),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+L+"*(even|odd|(([+-]|)(\\d*)n|)"+L+"*(?:([+-]|)"+L+"*(\\d+)|))"+L+"*\\)|)","i"),bool:new RegExp("^(?:"+K+")$","i"),needsContext:new RegExp("^"+L+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+L+"*((?:-\\d)?\\d*)"+L+"*\\)|)(?=[^-]|$)","i")},Y=/^(?:input|select|textarea|button)$/i,Z=/^h\d$/i,$=/^[^{]+\{\s*\[native \w/,_=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ab=/[+~]/,bb=/'|\\/g,cb=new RegExp("\\\\([\\da-f]{1,6}"+L+"?|("+L+")|.)","ig"),db=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:0>d?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)},eb=function(){m()};try{H.apply(E=I.call(v.childNodes),v.childNodes),E[v.childNodes.length].nodeType}catch(fb){H={apply:E.length?function(a,b){G.apply(a,I.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function gb(a,b,d,e){var f,h,j,k,l,o,r,s,w,x;if((b?b.ownerDocument||b:v)!==n&&m(b),b=b||n,d=d||[],k=b.nodeType,"string"!=typeof a||!a||1!==k&&9!==k&&11!==k)return d;if(!e&&p){if(11!==k&&(f=_.exec(a)))if(j=f[1]){if(9===k){if(h=b.getElementById(j),!h||!h.parentNode)return d;if(h.id===j)return d.push(h),d}else if(b.ownerDocument&&(h=b.ownerDocument.getElementById(j))&&t(b,h)&&h.id===j)return d.push(h),d}else{if(f[2])return H.apply(d,b.getElementsByTagName(a)),d;if((j=f[3])&&c.getElementsByClassName)return H.apply(d,b.getElementsByClassName(j)),d}if(c.qsa&&(!q||!q.test(a))){if(s=r=u,w=b,x=1!==k&&a,1===k&&"object"!==b.nodeName.toLowerCase()){o=g(a),(r=b.getAttribute("id"))?s=r.replace(bb,"\\$&"):b.setAttribute("id",s),s="[id='"+s+"'] ",l=o.length;while(l--)o[l]=s+rb(o[l]);w=ab.test(a)&&pb(b.parentNode)||b,x=o.join(",")}if(x)try{return H.apply(d,w.querySelectorAll(x)),d}catch(y){}finally{r||b.removeAttribute("id")}}}return i(a.replace(R,"$1"),b,d,e)}function hb(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function ib(a){return a[u]=!0,a}function jb(a){var b=n.createElement("div");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function kb(a,b){var c=a.split("|"),e=a.length;while(e--)d.attrHandle[c[e]]=b}function lb(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&(~b.sourceIndex||C)-(~a.sourceIndex||C);if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function mb(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function nb(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function ob(a){return ib(function(b){return b=+b,ib(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function pb(a){return a&&"undefined"!=typeof a.getElementsByTagName&&a}c=gb.support={},f=gb.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?"HTML"!==b.nodeName:!1},m=gb.setDocument=function(a){var b,e,g=a?a.ownerDocument||a:v;return g!==n&&9===g.nodeType&&g.documentElement?(n=g,o=g.documentElement,e=g.defaultView,e&&e!==e.top&&(e.addEventListener?e.addEventListener("unload",eb,!1):e.attachEvent&&e.attachEvent("onunload",eb)),p=!f(g),c.attributes=jb(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=jb(function(a){return a.appendChild(g.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=$.test(g.getElementsByClassName),c.getById=jb(function(a){return o.appendChild(a).id=u,!g.getElementsByName||!g.getElementsByName(u).length}),c.getById?(d.find.ID=function(a,b){if("undefined"!=typeof b.getElementById&&p){var c=b.getElementById(a);return c&&c.parentNode?[c]:[]}},d.filter.ID=function(a){var b=a.replace(cb,db);return function(a){return a.getAttribute("id")===b}}):(delete d.find.ID,d.filter.ID=function(a){var b=a.replace(cb,db);return function(a){var c="undefined"!=typeof a.getAttributeNode&&a.getAttributeNode("id");return c&&c.value===b}}),d.find.TAG=c.getElementsByTagName?function(a,b){return"undefined"!=typeof b.getElementsByTagName?b.getElementsByTagName(a):c.qsa?b.querySelectorAll(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){return p?b.getElementsByClassName(a):void 0},r=[],q=[],(c.qsa=$.test(g.querySelectorAll))&&(jb(function(a){o.appendChild(a).innerHTML="",a.querySelectorAll("[msallowcapture^='']").length&&q.push("[*^$]="+L+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||q.push("\\["+L+"*(?:value|"+K+")"),a.querySelectorAll("[id~="+u+"-]").length||q.push("~="),a.querySelectorAll(":checked").length||q.push(":checked"),a.querySelectorAll("a#"+u+"+*").length||q.push(".#.+[+~]")}),jb(function(a){var b=g.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&q.push("name"+L+"*[*^$|!~]?="),a.querySelectorAll(":enabled").length||q.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),q.push(",.*:")})),(c.matchesSelector=$.test(s=o.matches||o.webkitMatchesSelector||o.mozMatchesSelector||o.oMatchesSelector||o.msMatchesSelector))&&jb(function(a){c.disconnectedMatch=s.call(a,"div"),s.call(a,"[s!='']:x"),r.push("!=",P)}),q=q.length&&new RegExp(q.join("|")),r=r.length&&new RegExp(r.join("|")),b=$.test(o.compareDocumentPosition),t=b||$.test(o.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},B=b?function(a,b){if(a===b)return l=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===g||a.ownerDocument===v&&t(v,a)?-1:b===g||b.ownerDocument===v&&t(v,b)?1:k?J(k,a)-J(k,b):0:4&d?-1:1)}:function(a,b){if(a===b)return l=!0,0;var c,d=0,e=a.parentNode,f=b.parentNode,h=[a],i=[b];if(!e||!f)return a===g?-1:b===g?1:e?-1:f?1:k?J(k,a)-J(k,b):0;if(e===f)return lb(a,b);c=a;while(c=c.parentNode)h.unshift(c);c=b;while(c=c.parentNode)i.unshift(c);while(h[d]===i[d])d++;return d?lb(h[d],i[d]):h[d]===v?-1:i[d]===v?1:0},g):n},gb.matches=function(a,b){return gb(a,null,null,b)},gb.matchesSelector=function(a,b){if((a.ownerDocument||a)!==n&&m(a),b=b.replace(U,"='$1']"),!(!c.matchesSelector||!p||r&&r.test(b)||q&&q.test(b)))try{var d=s.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return gb(b,n,null,[a]).length>0},gb.contains=function(a,b){return(a.ownerDocument||a)!==n&&m(a),t(a,b)},gb.attr=function(a,b){(a.ownerDocument||a)!==n&&m(a);var e=d.attrHandle[b.toLowerCase()],f=e&&D.call(d.attrHandle,b.toLowerCase())?e(a,b,!p):void 0;return void 0!==f?f:c.attributes||!p?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},gb.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},gb.uniqueSort=function(a){var b,d=[],e=0,f=0;if(l=!c.detectDuplicates,k=!c.sortStable&&a.slice(0),a.sort(B),l){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return k=null,a},e=gb.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=gb.selectors={cacheLength:50,createPseudo:ib,match:X,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(cb,db),a[3]=(a[3]||a[4]||a[5]||"").replace(cb,db),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||gb.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&gb.error(a[0]),a},PSEUDO:function(a){var b,c=!a[6]&&a[2];return X.CHILD.test(a[0])?null:(a[3]?a[2]=a[4]||a[5]||"":c&&V.test(c)&&(b=g(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(cb,db).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=y[a+" "];return b||(b=new RegExp("(^|"+L+")"+a+"("+L+"|$)"))&&y(a,function(a){return b.test("string"==typeof a.className&&a.className||"undefined"!=typeof a.getAttribute&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=gb.attr(d,a);return null==e?"!="===b:b?(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e.replace(Q," ")+" ").indexOf(c)>-1:"|="===b?e===c||e.slice(0,c.length+1)===c+"-":!1):!0}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),s=!i&&!h;if(q){if(f){while(p){l=b;while(l=l[p])if(h?l.nodeName.toLowerCase()===r:1===l.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&s){k=q[u]||(q[u]={}),j=k[a]||[],n=j[0]===w&&j[1],m=j[0]===w&&j[2],l=n&&q.childNodes[n];while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if(1===l.nodeType&&++m&&l===b){k[a]=[w,n,m];break}}else if(s&&(j=(b[u]||(b[u]={}))[a])&&j[0]===w)m=j[1];else while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if((h?l.nodeName.toLowerCase()===r:1===l.nodeType)&&++m&&(s&&((l[u]||(l[u]={}))[a]=[w,m]),l===b))break;return m-=e,m===d||m%d===0&&m/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||gb.error("unsupported pseudo: "+a);return e[u]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?ib(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=J(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:ib(function(a){var b=[],c=[],d=h(a.replace(R,"$1"));return d[u]?ib(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),b[0]=null,!c.pop()}}),has:ib(function(a){return function(b){return gb(a,b).length>0}}),contains:ib(function(a){return a=a.replace(cb,db),function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:ib(function(a){return W.test(a||"")||gb.error("unsupported lang: "+a),a=a.replace(cb,db).toLowerCase(),function(b){var c;do if(c=p?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===o},focus:function(a){return a===n.activeElement&&(!n.hasFocus||n.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return Z.test(a.nodeName)},input:function(a){return Y.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:ob(function(){return[0]}),last:ob(function(a,b){return[b-1]}),eq:ob(function(a,b,c){return[0>c?c+b:c]}),even:ob(function(a,b){for(var c=0;b>c;c+=2)a.push(c);return a}),odd:ob(function(a,b){for(var c=1;b>c;c+=2)a.push(c);return a}),lt:ob(function(a,b,c){for(var d=0>c?c+b:c;--d>=0;)a.push(d);return a}),gt:ob(function(a,b,c){for(var d=0>c?c+b:c;++db;b++)d+=a[b].value;return d}function sb(a,b,c){var d=b.dir,e=c&&"parentNode"===d,f=x++;return b.first?function(b,c,f){while(b=b[d])if(1===b.nodeType||e)return a(b,c,f)}:function(b,c,g){var h,i,j=[w,f];if(g){while(b=b[d])if((1===b.nodeType||e)&&a(b,c,g))return!0}else while(b=b[d])if(1===b.nodeType||e){if(i=b[u]||(b[u]={}),(h=i[d])&&h[0]===w&&h[1]===f)return j[2]=h[2];if(i[d]=j,j[2]=a(b,c,g))return!0}}}function tb(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function ub(a,b,c){for(var d=0,e=b.length;e>d;d++)gb(a,b[d],c);return c}function vb(a,b,c,d,e){for(var f,g=[],h=0,i=a.length,j=null!=b;i>h;h++)(f=a[h])&&(!c||c(f,d,e))&&(g.push(f),j&&b.push(h));return g}function wb(a,b,c,d,e,f){return d&&!d[u]&&(d=wb(d)),e&&!e[u]&&(e=wb(e,f)),ib(function(f,g,h,i){var j,k,l,m=[],n=[],o=g.length,p=f||ub(b||"*",h.nodeType?[h]:h,[]),q=!a||!f&&b?p:vb(p,m,a,h,i),r=c?e||(f?a:o||d)?[]:g:q;if(c&&c(q,r,h,i),d){j=vb(r,n),d(j,[],h,i),k=j.length;while(k--)(l=j[k])&&(r[n[k]]=!(q[n[k]]=l))}if(f){if(e||a){if(e){j=[],k=r.length;while(k--)(l=r[k])&&j.push(q[k]=l);e(null,r=[],j,i)}k=r.length;while(k--)(l=r[k])&&(j=e?J(f,l):m[k])>-1&&(f[j]=!(g[j]=l))}}else r=vb(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):H.apply(g,r)})}function xb(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],h=g||d.relative[" "],i=g?1:0,k=sb(function(a){return a===b},h,!0),l=sb(function(a){return J(b,a)>-1},h,!0),m=[function(a,c,d){var e=!g&&(d||c!==j)||((b=c).nodeType?k(a,c,d):l(a,c,d));return b=null,e}];f>i;i++)if(c=d.relative[a[i].type])m=[sb(tb(m),c)];else{if(c=d.filter[a[i].type].apply(null,a[i].matches),c[u]){for(e=++i;f>e;e++)if(d.relative[a[e].type])break;return wb(i>1&&tb(m),i>1&&rb(a.slice(0,i-1).concat({value:" "===a[i-2].type?"*":""})).replace(R,"$1"),c,e>i&&xb(a.slice(i,e)),f>e&&xb(a=a.slice(e)),f>e&&rb(a))}m.push(c)}return tb(m)}function yb(a,b){var c=b.length>0,e=a.length>0,f=function(f,g,h,i,k){var l,m,o,p=0,q="0",r=f&&[],s=[],t=j,u=f||e&&d.find.TAG("*",k),v=w+=null==t?1:Math.random()||.1,x=u.length;for(k&&(j=g!==n&&g);q!==x&&null!=(l=u[q]);q++){if(e&&l){m=0;while(o=a[m++])if(o(l,g,h)){i.push(l);break}k&&(w=v)}c&&((l=!o&&l)&&p--,f&&r.push(l))}if(p+=q,c&&q!==p){m=0;while(o=b[m++])o(r,s,g,h);if(f){if(p>0)while(q--)r[q]||s[q]||(s[q]=F.call(i));s=vb(s)}H.apply(i,s),k&&!f&&s.length>0&&p+b.length>1&&gb.uniqueSort(i)}return k&&(w=v,j=t),r};return c?ib(f):f}return h=gb.compile=function(a,b){var c,d=[],e=[],f=A[a+" "];if(!f){b||(b=g(a)),c=b.length;while(c--)f=xb(b[c]),f[u]?d.push(f):e.push(f);f=A(a,yb(e,d)),f.selector=a}return f},i=gb.select=function(a,b,e,f){var i,j,k,l,m,n="function"==typeof a&&a,o=!f&&g(a=n.selector||a);if(e=e||[],1===o.length){if(j=o[0]=o[0].slice(0),j.length>2&&"ID"===(k=j[0]).type&&c.getById&&9===b.nodeType&&p&&d.relative[j[1].type]){if(b=(d.find.ID(k.matches[0].replace(cb,db),b)||[])[0],!b)return e;n&&(b=b.parentNode),a=a.slice(j.shift().value.length)}i=X.needsContext.test(a)?0:j.length;while(i--){if(k=j[i],d.relative[l=k.type])break;if((m=d.find[l])&&(f=m(k.matches[0].replace(cb,db),ab.test(j[0].type)&&pb(b.parentNode)||b))){if(j.splice(i,1),a=f.length&&rb(j),!a)return H.apply(e,f),e;break}}}return(n||h(a,o))(f,b,!p,e,ab.test(a)&&pb(b.parentNode)||b),e},c.sortStable=u.split("").sort(B).join("")===u,c.detectDuplicates=!!l,m(),c.sortDetached=jb(function(a){return 1&a.compareDocumentPosition(n.createElement("div"))}),jb(function(a){return a.innerHTML="","#"===a.firstChild.getAttribute("href")})||kb("type|href|height|width",function(a,b,c){return c?void 0:a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&jb(function(a){return a.innerHTML="",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||kb("value",function(a,b,c){return c||"input"!==a.nodeName.toLowerCase()?void 0:a.defaultValue}),jb(function(a){return null==a.getAttribute("disabled")})||kb(K,function(a,b,c){var d;return c?void 0:a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),gb}(a);n.find=t,n.expr=t.selectors,n.expr[":"]=n.expr.pseudos,n.unique=t.uniqueSort,n.text=t.getText,n.isXMLDoc=t.isXML,n.contains=t.contains;var u=n.expr.match.needsContext,v=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,w=/^.[^:#\[\.,]*$/;function x(a,b,c){if(n.isFunction(b))return n.grep(a,function(a,d){return!!b.call(a,d,a)!==c});if(b.nodeType)return n.grep(a,function(a){return a===b!==c});if("string"==typeof b){if(w.test(b))return n.filter(b,a,c);b=n.filter(b,a)}return n.grep(a,function(a){return g.call(b,a)>=0!==c})}n.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?n.find.matchesSelector(d,a)?[d]:[]:n.find.matches(a,n.grep(b,function(a){return 1===a.nodeType}))},n.fn.extend({find:function(a){var b,c=this.length,d=[],e=this;if("string"!=typeof a)return this.pushStack(n(a).filter(function(){for(b=0;c>b;b++)if(n.contains(e[b],this))return!0}));for(b=0;c>b;b++)n.find(a,e[b],d);return d=this.pushStack(c>1?n.unique(d):d),d.selector=this.selector?this.selector+" "+a:a,d},filter:function(a){return this.pushStack(x(this,a||[],!1))},not:function(a){return this.pushStack(x(this,a||[],!0))},is:function(a){return!!x(this,"string"==typeof a&&u.test(a)?n(a):a||[],!1).length}});var y,z=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,A=n.fn.init=function(a,b){var c,d;if(!a)return this;if("string"==typeof a){if(c="<"===a[0]&&">"===a[a.length-1]&&a.length>=3?[null,a,null]:z.exec(a),!c||!c[1]&&b)return!b||b.jquery?(b||y).find(a):this.constructor(b).find(a);if(c[1]){if(b=b instanceof n?b[0]:b,n.merge(this,n.parseHTML(c[1],b&&b.nodeType?b.ownerDocument||b:l,!0)),v.test(c[1])&&n.isPlainObject(b))for(c in b)n.isFunction(this[c])?this[c](b[c]):this.attr(c,b[c]);return this}return d=l.getElementById(c[2]),d&&d.parentNode&&(this.length=1,this[0]=d),this.context=l,this.selector=a,this}return a.nodeType?(this.context=this[0]=a,this.length=1,this):n.isFunction(a)?"undefined"!=typeof y.ready?y.ready(a):a(n):(void 0!==a.selector&&(this.selector=a.selector,this.context=a.context),n.makeArray(a,this))};A.prototype=n.fn,y=n(l);var B=/^(?:parents|prev(?:Until|All))/,C={children:!0,contents:!0,next:!0,prev:!0};n.extend({dir:function(a,b,c){var d=[],e=void 0!==c;while((a=a[b])&&9!==a.nodeType)if(1===a.nodeType){if(e&&n(a).is(c))break;d.push(a)}return d},sibling:function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c}}),n.fn.extend({has:function(a){var b=n(a,this),c=b.length;return this.filter(function(){for(var a=0;c>a;a++)if(n.contains(this,b[a]))return!0})},closest:function(a,b){for(var c,d=0,e=this.length,f=[],g=u.test(a)||"string"!=typeof a?n(a,b||this.context):0;e>d;d++)for(c=this[d];c&&c!==b;c=c.parentNode)if(c.nodeType<11&&(g?g.index(c)>-1:1===c.nodeType&&n.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?n.unique(f):f)},index:function(a){return a?"string"==typeof a?g.call(n(a),this[0]):g.call(this,a.jquery?a[0]:a):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(n.unique(n.merge(this.get(),n(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function D(a,b){while((a=a[b])&&1!==a.nodeType);return a}n.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return n.dir(a,"parentNode")},parentsUntil:function(a,b,c){return n.dir(a,"parentNode",c)},next:function(a){return D(a,"nextSibling")},prev:function(a){return D(a,"previousSibling")},nextAll:function(a){return n.dir(a,"nextSibling")},prevAll:function(a){return n.dir(a,"previousSibling")},nextUntil:function(a,b,c){return n.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return n.dir(a,"previousSibling",c)},siblings:function(a){return n.sibling((a.parentNode||{}).firstChild,a)},children:function(a){return n.sibling(a.firstChild)},contents:function(a){return a.contentDocument||n.merge([],a.childNodes)}},function(a,b){n.fn[a]=function(c,d){var e=n.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=n.filter(d,e)),this.length>1&&(C[a]||n.unique(e),B.test(a)&&e.reverse()),this.pushStack(e)}});var E=/\S+/g,F={};function G(a){var b=F[a]={};return n.each(a.match(E)||[],function(a,c){b[c]=!0}),b}n.Callbacks=function(a){a="string"==typeof a?F[a]||G(a):n.extend({},a);var b,c,d,e,f,g,h=[],i=!a.once&&[],j=function(l){for(b=a.memory&&l,c=!0,g=e||0,e=0,f=h.length,d=!0;h&&f>g;g++)if(h[g].apply(l[0],l[1])===!1&&a.stopOnFalse){b=!1;break}d=!1,h&&(i?i.length&&j(i.shift()):b?h=[]:k.disable())},k={add:function(){if(h){var c=h.length;!function g(b){n.each(b,function(b,c){var d=n.type(c);"function"===d?a.unique&&k.has(c)||h.push(c):c&&c.length&&"string"!==d&&g(c)})}(arguments),d?f=h.length:b&&(e=c,j(b))}return this},remove:function(){return h&&n.each(arguments,function(a,b){var c;while((c=n.inArray(b,h,c))>-1)h.splice(c,1),d&&(f>=c&&f--,g>=c&&g--)}),this},has:function(a){return a?n.inArray(a,h)>-1:!(!h||!h.length)},empty:function(){return h=[],f=0,this},disable:function(){return h=i=b=void 0,this},disabled:function(){return!h},lock:function(){return i=void 0,b||k.disable(),this},locked:function(){return!i},fireWith:function(a,b){return!h||c&&!i||(b=b||[],b=[a,b.slice?b.slice():b],d?i.push(b):j(b)),this},fire:function(){return k.fireWith(this,arguments),this},fired:function(){return!!c}};return k},n.extend({Deferred:function(a){var b=[["resolve","done",n.Callbacks("once memory"),"resolved"],["reject","fail",n.Callbacks("once memory"),"rejected"],["notify","progress",n.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return n.Deferred(function(c){n.each(b,function(b,f){var g=n.isFunction(a[b])&&a[b];e[f[1]](function(){var a=g&&g.apply(this,arguments);a&&n.isFunction(a.promise)?a.promise().done(c.resolve).fail(c.reject).progress(c.notify):c[f[0]+"With"](this===d?c.promise():this,g?[a]:arguments)})}),a=null}).promise()},promise:function(a){return null!=a?n.extend(a,d):d}},e={};return d.pipe=d.then,n.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[1^a][2].disable,b[2][2].lock),e[f[0]]=function(){return e[f[0]+"With"](this===e?d:this,arguments),this},e[f[0]+"With"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b=0,c=d.call(arguments),e=c.length,f=1!==e||a&&n.isFunction(a.promise)?e:0,g=1===f?a:n.Deferred(),h=function(a,b,c){return function(e){b[a]=this,c[a]=arguments.length>1?d.call(arguments):e,c===i?g.notifyWith(b,c):--f||g.resolveWith(b,c)}},i,j,k;if(e>1)for(i=new Array(e),j=new Array(e),k=new Array(e);e>b;b++)c[b]&&n.isFunction(c[b].promise)?c[b].promise().done(h(b,k,c)).fail(g.reject).progress(h(b,j,i)):--f;return f||g.resolveWith(k,c),g.promise()}});var H;n.fn.ready=function(a){return n.ready.promise().done(a),this},n.extend({isReady:!1,readyWait:1,holdReady:function(a){a?n.readyWait++:n.ready(!0)},ready:function(a){(a===!0?--n.readyWait:n.isReady)||(n.isReady=!0,a!==!0&&--n.readyWait>0||(H.resolveWith(l,[n]),n.fn.triggerHandler&&(n(l).triggerHandler("ready"),n(l).off("ready"))))}});function I(){l.removeEventListener("DOMContentLoaded",I,!1),a.removeEventListener("load",I,!1),n.ready()}n.ready.promise=function(b){return H||(H=n.Deferred(),"complete"===l.readyState?setTimeout(n.ready):(l.addEventListener("DOMContentLoaded",I,!1),a.addEventListener("load",I,!1))),H.promise(b)},n.ready.promise();var J=n.access=function(a,b,c,d,e,f,g){var h=0,i=a.length,j=null==c;if("object"===n.type(c)){e=!0;for(h in c)n.access(a,b,h,c[h],!0,f,g)}else if(void 0!==d&&(e=!0,n.isFunction(d)||(g=!0),j&&(g?(b.call(a,d),b=null):(j=b,b=function(a,b,c){return j.call(n(a),c)})),b))for(;i>h;h++)b(a[h],c,g?d:d.call(a[h],h,b(a[h],c)));return e?a:j?b.call(a):i?b(a[0],c):f};n.acceptData=function(a){return 1===a.nodeType||9===a.nodeType||!+a.nodeType};function K(){Object.defineProperty(this.cache={},0,{get:function(){return{}}}),this.expando=n.expando+K.uid++}K.uid=1,K.accepts=n.acceptData,K.prototype={key:function(a){if(!K.accepts(a))return 0;var b={},c=a[this.expando];if(!c){c=K.uid++;try{b[this.expando]={value:c},Object.defineProperties(a,b)}catch(d){b[this.expando]=c,n.extend(a,b)}}return this.cache[c]||(this.cache[c]={}),c},set:function(a,b,c){var d,e=this.key(a),f=this.cache[e];if("string"==typeof b)f[b]=c;else if(n.isEmptyObject(f))n.extend(this.cache[e],b);else for(d in b)f[d]=b[d];return f},get:function(a,b){var c=this.cache[this.key(a)];return void 0===b?c:c[b]},access:function(a,b,c){var d;return void 0===b||b&&"string"==typeof b&&void 0===c?(d=this.get(a,b),void 0!==d?d:this.get(a,n.camelCase(b))):(this.set(a,b,c),void 0!==c?c:b)},remove:function(a,b){var c,d,e,f=this.key(a),g=this.cache[f];if(void 0===b)this.cache[f]={};else{n.isArray(b)?d=b.concat(b.map(n.camelCase)):(e=n.camelCase(b),b in g?d=[b,e]:(d=e,d=d in g?[d]:d.match(E)||[])),c=d.length;while(c--)delete g[d[c]]}},hasData:function(a){return!n.isEmptyObject(this.cache[a[this.expando]]||{})},discard:function(a){a[this.expando]&&delete this.cache[a[this.expando]]}};var L=new K,M=new K,N=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,O=/([A-Z])/g;function P(a,b,c){var d;if(void 0===c&&1===a.nodeType)if(d="data-"+b.replace(O,"-$1").toLowerCase(),c=a.getAttribute(d),"string"==typeof c){try{c="true"===c?!0:"false"===c?!1:"null"===c?null:+c+""===c?+c:N.test(c)?n.parseJSON(c):c}catch(e){}M.set(a,b,c)}else c=void 0;return c}n.extend({hasData:function(a){return M.hasData(a)||L.hasData(a)},data:function(a,b,c){return M.access(a,b,c) -},removeData:function(a,b){M.remove(a,b)},_data:function(a,b,c){return L.access(a,b,c)},_removeData:function(a,b){L.remove(a,b)}}),n.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=M.get(f),1===f.nodeType&&!L.get(f,"hasDataAttrs"))){c=g.length;while(c--)g[c]&&(d=g[c].name,0===d.indexOf("data-")&&(d=n.camelCase(d.slice(5)),P(f,d,e[d])));L.set(f,"hasDataAttrs",!0)}return e}return"object"==typeof a?this.each(function(){M.set(this,a)}):J(this,function(b){var c,d=n.camelCase(a);if(f&&void 0===b){if(c=M.get(f,a),void 0!==c)return c;if(c=M.get(f,d),void 0!==c)return c;if(c=P(f,d,void 0),void 0!==c)return c}else this.each(function(){var c=M.get(this,d);M.set(this,d,b),-1!==a.indexOf("-")&&void 0!==c&&M.set(this,a,b)})},null,b,arguments.length>1,null,!0)},removeData:function(a){return this.each(function(){M.remove(this,a)})}}),n.extend({queue:function(a,b,c){var d;return a?(b=(b||"fx")+"queue",d=L.get(a,b),c&&(!d||n.isArray(c)?d=L.access(a,b,n.makeArray(c)):d.push(c)),d||[]):void 0},dequeue:function(a,b){b=b||"fx";var c=n.queue(a,b),d=c.length,e=c.shift(),f=n._queueHooks(a,b),g=function(){n.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return L.get(a,c)||L.access(a,c,{empty:n.Callbacks("once memory").add(function(){L.remove(a,[b+"queue",c])})})}}),n.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.lengthx",k.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue}();var U="undefined";k.focusinBubbles="onfocusin"in a;var V=/^key/,W=/^(?:mouse|pointer|contextmenu)|click/,X=/^(?:focusinfocus|focusoutblur)$/,Y=/^([^.]*)(?:\.(.+)|)$/;function Z(){return!0}function $(){return!1}function _(){try{return l.activeElement}catch(a){}}n.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=L.get(a);if(r){c.handler&&(f=c,c=f.handler,e=f.selector),c.guid||(c.guid=n.guid++),(i=r.events)||(i=r.events={}),(g=r.handle)||(g=r.handle=function(b){return typeof n!==U&&n.event.triggered!==b.type?n.event.dispatch.apply(a,arguments):void 0}),b=(b||"").match(E)||[""],j=b.length;while(j--)h=Y.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o&&(l=n.event.special[o]||{},o=(e?l.delegateType:l.bindType)||o,l=n.event.special[o]||{},k=n.extend({type:o,origType:q,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&n.expr.match.needsContext.test(e),namespace:p.join(".")},f),(m=i[o])||(m=i[o]=[],m.delegateCount=0,l.setup&&l.setup.call(a,d,p,g)!==!1||a.addEventListener&&a.addEventListener(o,g,!1)),l.add&&(l.add.call(a,k),k.handler.guid||(k.handler.guid=c.guid)),e?m.splice(m.delegateCount++,0,k):m.push(k),n.event.global[o]=!0)}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=L.hasData(a)&&L.get(a);if(r&&(i=r.events)){b=(b||"").match(E)||[""],j=b.length;while(j--)if(h=Y.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o){l=n.event.special[o]||{},o=(d?l.delegateType:l.bindType)||o,m=i[o]||[],h=h[2]&&new RegExp("(^|\\.)"+p.join("\\.(?:.*\\.|)")+"(\\.|$)"),g=f=m.length;while(f--)k=m[f],!e&&q!==k.origType||c&&c.guid!==k.guid||h&&!h.test(k.namespace)||d&&d!==k.selector&&("**"!==d||!k.selector)||(m.splice(f,1),k.selector&&m.delegateCount--,l.remove&&l.remove.call(a,k));g&&!m.length&&(l.teardown&&l.teardown.call(a,p,r.handle)!==!1||n.removeEvent(a,o,r.handle),delete i[o])}else for(o in i)n.event.remove(a,o+b[j],c,d,!0);n.isEmptyObject(i)&&(delete r.handle,L.remove(a,"events"))}},trigger:function(b,c,d,e){var f,g,h,i,k,m,o,p=[d||l],q=j.call(b,"type")?b.type:b,r=j.call(b,"namespace")?b.namespace.split("."):[];if(g=h=d=d||l,3!==d.nodeType&&8!==d.nodeType&&!X.test(q+n.event.triggered)&&(q.indexOf(".")>=0&&(r=q.split("."),q=r.shift(),r.sort()),k=q.indexOf(":")<0&&"on"+q,b=b[n.expando]?b:new n.Event(q,"object"==typeof b&&b),b.isTrigger=e?2:3,b.namespace=r.join("."),b.namespace_re=b.namespace?new RegExp("(^|\\.)"+r.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,b.result=void 0,b.target||(b.target=d),c=null==c?[b]:n.makeArray(c,[b]),o=n.event.special[q]||{},e||!o.trigger||o.trigger.apply(d,c)!==!1)){if(!e&&!o.noBubble&&!n.isWindow(d)){for(i=o.delegateType||q,X.test(i+q)||(g=g.parentNode);g;g=g.parentNode)p.push(g),h=g;h===(d.ownerDocument||l)&&p.push(h.defaultView||h.parentWindow||a)}f=0;while((g=p[f++])&&!b.isPropagationStopped())b.type=f>1?i:o.bindType||q,m=(L.get(g,"events")||{})[b.type]&&L.get(g,"handle"),m&&m.apply(g,c),m=k&&g[k],m&&m.apply&&n.acceptData(g)&&(b.result=m.apply(g,c),b.result===!1&&b.preventDefault());return b.type=q,e||b.isDefaultPrevented()||o._default&&o._default.apply(p.pop(),c)!==!1||!n.acceptData(d)||k&&n.isFunction(d[q])&&!n.isWindow(d)&&(h=d[k],h&&(d[k]=null),n.event.triggered=q,d[q](),n.event.triggered=void 0,h&&(d[k]=h)),b.result}},dispatch:function(a){a=n.event.fix(a);var b,c,e,f,g,h=[],i=d.call(arguments),j=(L.get(this,"events")||{})[a.type]||[],k=n.event.special[a.type]||{};if(i[0]=a,a.delegateTarget=this,!k.preDispatch||k.preDispatch.call(this,a)!==!1){h=n.event.handlers.call(this,a,j),b=0;while((f=h[b++])&&!a.isPropagationStopped()){a.currentTarget=f.elem,c=0;while((g=f.handlers[c++])&&!a.isImmediatePropagationStopped())(!a.namespace_re||a.namespace_re.test(g.namespace))&&(a.handleObj=g,a.data=g.data,e=((n.event.special[g.origType]||{}).handle||g.handler).apply(f.elem,i),void 0!==e&&(a.result=e)===!1&&(a.preventDefault(),a.stopPropagation()))}return k.postDispatch&&k.postDispatch.call(this,a),a.result}},handlers:function(a,b){var c,d,e,f,g=[],h=b.delegateCount,i=a.target;if(h&&i.nodeType&&(!a.button||"click"!==a.type))for(;i!==this;i=i.parentNode||this)if(i.disabled!==!0||"click"!==a.type){for(d=[],c=0;h>c;c++)f=b[c],e=f.selector+" ",void 0===d[e]&&(d[e]=f.needsContext?n(e,this).index(i)>=0:n.find(e,this,null,[i]).length),d[e]&&d.push(f);d.length&&g.push({elem:i,handlers:d})}return h]*)\/>/gi,bb=/<([\w:]+)/,cb=/<|&#?\w+;/,db=/<(?:script|style|link)/i,eb=/checked\s*(?:[^=]|=\s*.checked.)/i,fb=/^$|\/(?:java|ecma)script/i,gb=/^true\/(.*)/,hb=/^\s*\s*$/g,ib={option:[1,""],thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};ib.optgroup=ib.option,ib.tbody=ib.tfoot=ib.colgroup=ib.caption=ib.thead,ib.th=ib.td;function jb(a,b){return n.nodeName(a,"table")&&n.nodeName(11!==b.nodeType?b:b.firstChild,"tr")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function kb(a){return a.type=(null!==a.getAttribute("type"))+"/"+a.type,a}function lb(a){var b=gb.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function mb(a,b){for(var c=0,d=a.length;d>c;c++)L.set(a[c],"globalEval",!b||L.get(b[c],"globalEval"))}function nb(a,b){var c,d,e,f,g,h,i,j;if(1===b.nodeType){if(L.hasData(a)&&(f=L.access(a),g=L.set(b,f),j=f.events)){delete g.handle,g.events={};for(e in j)for(c=0,d=j[e].length;d>c;c++)n.event.add(b,e,j[e][c])}M.hasData(a)&&(h=M.access(a),i=n.extend({},h),M.set(b,i))}}function ob(a,b){var c=a.getElementsByTagName?a.getElementsByTagName(b||"*"):a.querySelectorAll?a.querySelectorAll(b||"*"):[];return void 0===b||b&&n.nodeName(a,b)?n.merge([a],c):c}function pb(a,b){var c=b.nodeName.toLowerCase();"input"===c&&T.test(a.type)?b.checked=a.checked:("input"===c||"textarea"===c)&&(b.defaultValue=a.defaultValue)}n.extend({clone:function(a,b,c){var d,e,f,g,h=a.cloneNode(!0),i=n.contains(a.ownerDocument,a);if(!(k.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||n.isXMLDoc(a)))for(g=ob(h),f=ob(a),d=0,e=f.length;e>d;d++)pb(f[d],g[d]);if(b)if(c)for(f=f||ob(a),g=g||ob(h),d=0,e=f.length;e>d;d++)nb(f[d],g[d]);else nb(a,h);return g=ob(h,"script"),g.length>0&&mb(g,!i&&ob(a,"script")),h},buildFragment:function(a,b,c,d){for(var e,f,g,h,i,j,k=b.createDocumentFragment(),l=[],m=0,o=a.length;o>m;m++)if(e=a[m],e||0===e)if("object"===n.type(e))n.merge(l,e.nodeType?[e]:e);else if(cb.test(e)){f=f||k.appendChild(b.createElement("div")),g=(bb.exec(e)||["",""])[1].toLowerCase(),h=ib[g]||ib._default,f.innerHTML=h[1]+e.replace(ab,"<$1>")+h[2],j=h[0];while(j--)f=f.lastChild;n.merge(l,f.childNodes),f=k.firstChild,f.textContent=""}else l.push(b.createTextNode(e));k.textContent="",m=0;while(e=l[m++])if((!d||-1===n.inArray(e,d))&&(i=n.contains(e.ownerDocument,e),f=ob(k.appendChild(e),"script"),i&&mb(f),c)){j=0;while(e=f[j++])fb.test(e.type||"")&&c.push(e)}return k},cleanData:function(a){for(var b,c,d,e,f=n.event.special,g=0;void 0!==(c=a[g]);g++){if(n.acceptData(c)&&(e=c[L.expando],e&&(b=L.cache[e]))){if(b.events)for(d in b.events)f[d]?n.event.remove(c,d):n.removeEvent(c,d,b.handle);L.cache[e]&&delete L.cache[e]}delete M.cache[c[M.expando]]}}}),n.fn.extend({text:function(a){return J(this,function(a){return void 0===a?n.text(this):this.empty().each(function(){(1===this.nodeType||11===this.nodeType||9===this.nodeType)&&(this.textContent=a)})},null,a,arguments.length)},append:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=jb(this,a);b.appendChild(a)}})},prepend:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=jb(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},remove:function(a,b){for(var c,d=a?n.filter(a,this):this,e=0;null!=(c=d[e]);e++)b||1!==c.nodeType||n.cleanData(ob(c)),c.parentNode&&(b&&n.contains(c.ownerDocument,c)&&mb(ob(c,"script")),c.parentNode.removeChild(c));return this},empty:function(){for(var a,b=0;null!=(a=this[b]);b++)1===a.nodeType&&(n.cleanData(ob(a,!1)),a.textContent="");return this},clone:function(a,b){return a=null==a?!1:a,b=null==b?a:b,this.map(function(){return n.clone(this,a,b)})},html:function(a){return J(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a&&1===b.nodeType)return b.innerHTML;if("string"==typeof a&&!db.test(a)&&!ib[(bb.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(ab,"<$1>");try{for(;d>c;c++)b=this[c]||{},1===b.nodeType&&(n.cleanData(ob(b,!1)),b.innerHTML=a);b=0}catch(e){}}b&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(){var a=arguments[0];return this.domManip(arguments,function(b){a=this.parentNode,n.cleanData(ob(this)),a&&a.replaceChild(b,this)}),a&&(a.length||a.nodeType)?this:this.remove()},detach:function(a){return this.remove(a,!0)},domManip:function(a,b){a=e.apply([],a);var c,d,f,g,h,i,j=0,l=this.length,m=this,o=l-1,p=a[0],q=n.isFunction(p);if(q||l>1&&"string"==typeof p&&!k.checkClone&&eb.test(p))return this.each(function(c){var d=m.eq(c);q&&(a[0]=p.call(this,c,d.html())),d.domManip(a,b)});if(l&&(c=n.buildFragment(a,this[0].ownerDocument,!1,this),d=c.firstChild,1===c.childNodes.length&&(c=d),d)){for(f=n.map(ob(c,"script"),kb),g=f.length;l>j;j++)h=c,j!==o&&(h=n.clone(h,!0,!0),g&&n.merge(f,ob(h,"script"))),b.call(this[j],h,j);if(g)for(i=f[f.length-1].ownerDocument,n.map(f,lb),j=0;g>j;j++)h=f[j],fb.test(h.type||"")&&!L.access(h,"globalEval")&&n.contains(i,h)&&(h.src?n._evalUrl&&n._evalUrl(h.src):n.globalEval(h.textContent.replace(hb,"")))}return this}}),n.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){n.fn[a]=function(a){for(var c,d=[],e=n(a),g=e.length-1,h=0;g>=h;h++)c=h===g?this:this.clone(!0),n(e[h])[b](c),f.apply(d,c.get());return this.pushStack(d)}});var qb,rb={};function sb(b,c){var d,e=n(c.createElement(b)).appendTo(c.body),f=a.getDefaultComputedStyle&&(d=a.getDefaultComputedStyle(e[0]))?d.display:n.css(e[0],"display");return e.detach(),f}function tb(a){var b=l,c=rb[a];return c||(c=sb(a,b),"none"!==c&&c||(qb=(qb||n("