diff --git a/app/assets/main.html b/app/assets/main.html index 702718c76..69cf297d1 100644 --- a/app/assets/main.html +++ b/app/assets/main.html @@ -76,7 +76,7 @@ <script src="/lib/ace/ace.js" defer></script> <script src="/javascripts/vendor.js" defer></script> <script src="/javascripts/aether.js" defer></script> - <script src="/javascripts/app.js" defer></script> <!-- it's all Backbone! --> + <script src="/javascripts/app.js" defer></script> <![endif]> <script> diff --git a/app/lib/LevelLoader.coffee b/app/lib/LevelLoader.coffee index 5b932bb80..0307de8cf 100644 --- a/app/lib/LevelLoader.coffee +++ b/app/lib/LevelLoader.coffee @@ -72,10 +72,12 @@ module.exports = class LevelLoader extends CocoClass url += "?team=#{@team}" if @team session = new LevelSession().setURL url + session.project = ['creator', 'team', 'heroConfig', 'codeLanguage', 'submittedCodeLanguage', 'state'] if @headless @sessionResource = @supermodel.loadModel(session, 'level_session', {cache: false}) @session = @sessionResource.model if @opponentSessionID opponentSession = new LevelSession().setURL "/db/level.session/#{@opponentSessionID}" + opponentSession.project = session.project if @headless @opponentSessionResource = @supermodel.loadModel(opponentSession, 'opponent_session', {cache: false}) @opponentSession = @opponentSessionResource.model diff --git a/app/locale/en.coffee b/app/locale/en.coffee index d86116776..933f20ebb 100644 --- a/app/locale/en.coffee +++ b/app/locale/en.coffee @@ -94,14 +94,12 @@ campaign_classic_algorithms_description: "... in which you learn the most popular algorithms in Computer Science." share_progress_modal: - blurb: "You’re making great progress! Tell someone how much you've learned with CodeCombat." + blurb: "You’re making great progress! Tell your parent how much you've learned with CodeCombat." #{change} email_invalid: "Email address invalid." - form_blurb: "Enter their email below and we’ll show them!" + form_blurb: "Enter your parent's email below and we’ll show them!" form_label: "Email Address" placeholder: "email address" title: "Excellent Work, Apprentice" - tell_friend: "Tell your Friend" - tell_parent: "Tell your Parent" login: sign_up: "Create Account" @@ -263,6 +261,7 @@ victory_hour_of_code_done_yes: "Yes, I'm finished with my Hour of Code™!" victory_experience_gained: "XP Gained" victory_gems_gained: "Gems Gained" + victory_become_a_viking: "Become a Viking" guide_title: "Guide" tome_minion_spells: "Your Minions' Spells" # Only in old-style levels. tome_read_only_spells: "Read-Only Spells" # Only in old-style levels. @@ -398,9 +397,9 @@ subscribe: comparison_blurb: "Sharpen your skills with a CodeCombat subscription!" - feature1: "60+ basic levels across 4 worlds" + feature1: "80+ basic levels across 4 worlds" # {change} feature2: "7 powerful <strong>new heroes</strong> with unique skills!" - feature3: "30+ bonus levels" + feature3: "50+ bonus levels" # {change} feature4: "<strong>3500 bonus gems</strong> every month!" feature5: "Video tutorials" feature6: "Premium email support" @@ -428,6 +427,10 @@ parents_blurb1: "With CodeCombat, your child learns by writing real code. They start by learning simple commands, and progress to more advanced topics." parents_blurb2: "For $9.99 USD/mo, they get new challenges every week and personal email support from professional programmers." parents_blurb3: "No Risk: 100% money back guarantee, easy 1-click unsubscribe." + payment_methods: "Payment Methods" + payment_methods_title: "Accepted Payment Methods" + payment_methods_blurb1: "We currently accept credit cards, Alipay, and bitcoins." + payment_methods_blurb2: "If you require an alternate form of payment, please contact" stripe_description: "Monthly Subscription" subscription_required_to_play: "You'll need a subscription to play this level." unlock_help_videos: "Subscribe to unlock all video tutorials." @@ -442,6 +445,7 @@ managed_subs: "Managed Subscriptions" managed_subs_desc: "Add subscriptions for other players (students, children, etc.)" group_discounts: "Group discounts" + group_discounts_1: "We also offer group discounts for bulk subscriptions." group_discounts_1st: "1st subscription" group_discounts_full: "Full price" group_discounts_2nd: "Subscriptions 2-11" @@ -588,8 +592,8 @@ teacher_subs_1: "Please contact" teacher_subs_2: "to set up a free monthly subscription." sub_includes_title: "What is included in the subscription?" - sub_includes_1: "In additional to the 70+ basic levels, students with a monthly subscription get access to these additional features:" - sub_includes_2: "40+ practice levels" + sub_includes_1: "In addition to the 80+ basic levels, students with a monthly subscription get access to these additional features:" # {change} + sub_includes_2: "50+ practice levels" # {change} sub_includes_3: "Video tutorials" sub_includes_4: "Premium email support" sub_includes_5: "7 new heroes with unique skills to master" @@ -606,7 +610,6 @@ how_much_2: "monthly subscription" how_much_3: "costs $9.99, and can be cancelled anytime." how_much_4: "Additionally, we provide discounts for larger groups:" - group_discounts_1: "We also offer group discounts for bulk subscriptions." sys_requirements_title: "System Requirements" sys_requirements_1: "A modern web browser. Newer versions of Chrome, Firefox, or Safari. Internet Explorer 9 or later." sys_requirements_2: "CodeCombat is not supported on iPad yet." diff --git a/app/locale/pt-PT.coffee b/app/locale/pt-PT.coffee index dfc46c0c6..be3269f39 100644 --- a/app/locale/pt-PT.coffee +++ b/app/locale/pt-PT.coffee @@ -577,8 +577,8 @@ module.exports = nativeDescription: "Português (Portugal)", englishDescription: teachers: title: "CodeCombat: Informações para Professores" -# intro_1: "CodeCombat is an online game that teaches programming. Students write code in real programming languages." -# intro_2: "No experience required!" + intro_1: "O CodeCombat é um jogo 'online' que ensina programação. Os estudantes escrevem código em linguagens de programação reais." + intro_2: "Não é necessário ter experiência!" free_title: "Quanto custa?" # cost_china: "CodeCombat in China is free for the first five levels, after which it costs $9.99 per month for access to our other 120+ levels on our exclusive China servers." # free_1: "CodeCombat Basic is FREE! There are 70+ free levels which cover every concept." @@ -604,8 +604,8 @@ module.exports = nativeDescription: "Português (Portugal)", englishDescription: how_much_1: "Uma" how_much_2: "subscrição mensal" how_much_3: "custa $9.99 e pode ser cancelada a qualquer momento." -# how_much_4: "Additionally, we provide discounts for larger groups:" -# group_discounts_1: "We also offer group discounts for bulk subscriptions." + how_much_4: "Adicionalmente, oferecemos descontos para grupos maiores:" + group_discounts_1: "Também oferecemos descontos de grupo para subscrições em massa." sys_requirements_title: "Requisitos do Sistema" sys_requirements_1: "Um navegador moderno. As versões mais recentes do Chrome, Firefox ou Safari. Internet Explorer 9 ou mais recente." sys_requirements_2: "O CodeCombat ainda não é suportado em iPad's." @@ -867,26 +867,26 @@ module.exports = nativeDescription: "Português (Portugal)", englishDescription: # scribe_introduction_pref: "CodeCombat isn't just going to be a bunch of levels. It will also include a resource for knowledge, a wiki of programming concepts that levels can hook into. That way rather than each Artisan having to describe in detail what a comparison operator is, they can simply link their level to the Article describing them that is already written for the player's edification. Something along the lines of what the " # scribe_introduction_url_mozilla: "Mozilla Developer Network" # scribe_introduction_suf: " has built. If your idea of fun is articulating the concepts of programming in Markdown form, then this class might be for you." - scribe_attribute_1: "Habilidade com palavras é basicamente do que precisas. Não apenas gramática e ortografia, mas seres capaz de explicar ideias complicadas a outros." + scribe_attribute_1: "Habilidade com palavras é basicamente o que precisas. Não apenas gramática e ortografia, mas seres capaz de explicar ideias complicadas a outros." contact_us_url: "Contacta-nos" - scribe_join_description: "fala-nos um bocado de ti, a tua experiência com a programação e o tipo de coisas sobre o qual gostavas de escrever. Começamos a partir daí!" + scribe_join_description: "fala-nos um bocado de ti, da tua experiência com a programação e do tipo de coisas sobre as quais gostarias de escrever. Começamos a partir daí!" scribe_subscribe_desc: "Receber e-mails sobre anúncios relativos à escrita de artigos." diplomat_introduction_pref: "Portanto, se há uma coisa que aprendemos com o nosso " diplomat_launch_url: "lançamento em Outubro" - diplomat_introduction_suf: "é que há um interesse considerável no CodeCombat noutros países! Estamos a construir um exército de tradutores dispostos a transformar um conjunto de palavras noutro conjuto de palavras, para conseguir que o CodeCombat fique o mais acessível quanto posível em todo o mundo. Se gostas de dar espreitadelas a conteúdos futuros e disponibilizar estes níveis para os teus colegas nacionais o mais depressa possível, então esta classe talvez seja para ti." + diplomat_introduction_suf: "é que há um interesse considerável no CodeCombat noutros países! Estamos a construir um exército de tradutores dispostos a transformar um conjunto de palavras num outro conjuto de palavras, para conseguir que o CodeCombat fique o mais acessível quanto posível em todo o mundo. Se gostas de dar espreitadelas a conteúdos futuros e disponibilizar os níveis para os teus colegas nacionais o mais depressa possível, então esta classe talvez seja para ti." diplomat_attribute_1: "Fluência em Inglês e no idioma para o qual gostarias de traduzir. Quando são tentadas passar ideias complicadas, é importante uma excelente compreensão das duas!" diplomat_i18n_page_prefix: "Podes começar a traduzir os nossos níveis se fores à nossa" diplomat_i18n_page: "página de traduções" diplomat_i18n_page_suffix: ", ou a nossa interface e website no GitHub." diplomat_join_pref_github: "Encontra o ficheiro 'locale' do teu idioma " diplomat_github_url: "no GitHub" - diplomat_join_suf_github: ", edita-o online e submete um 'pull request'. Assinala ainda esta caixa abaixo para ficares atualizado em relação a novos desenvolvimentos da internacionalização!" + diplomat_join_suf_github: ", edita-o online e submete um 'pull request'. Assinala ainda a caixa abaixo para ficares atualizado em relação a novos desenvolvimentos da internacionalização!" diplomat_subscribe_desc: "Receber e-mails sobre desenvolvimentos da i18n e níveis para traduzir." # ambassador_introduction: "This is a community we're building, and you are the connections. We've got forums, emails, and social networks with lots of people to talk with and help get acquainted with the game and learn from. If you want to help people get involved and have fun, and get a good feel of the pulse of CodeCombat and where we're going, then this class might be for you." # ambassador_attribute_1: "Communication skills. Be able to identify the problems players are having and help them solve them. Also, keep the rest of us informed about what players are saying, what they like and don't like and want more of!" # ambassador_join_desc: "tell us a little about yourself, what you've done and what you'd be interested in doing. We'll go from there!" ambassador_join_note_strong: "Nota" - ambassador_join_note_desc: "Uma das nossas maiores prioridades é construir níveis multijogador onde os jogadores com dificuldade a passar níveis podem invocar feiticeiros mais experientes para serem ajudados. Esta será uma ótima forma para os embixadores fazerem o que sabem. Vamos manter-te atualizado!" + ambassador_join_note_desc: "Uma das nossas maiores prioridades é construir níveis multijogador onde os jogadores com dificuldade para passar níveis possam invocar feiticeiros mais experientes para os ajudarem. Esta será uma ótima forma de os embaixadores fazerem o que sabem. Vamos manter-te atualizado!" ambassador_subscribe_desc: "Receber e-mails relativos a novidades do suporte e desenvolvimentos do modo multijogador." changes_auto_save: "As alterações são guardadas automaticamente quando clicas nas caixas." diligent_scribes: "Os Nossos Dedicados Escrivões:" diff --git a/app/locale/sk.coffee b/app/locale/sk.coffee index 66e993114..8f535d4cd 100644 --- a/app/locale/sk.coffee +++ b/app/locale/sk.coffee @@ -64,7 +64,7 @@ module.exports = nativeDescription: "slovenčina", englishDescription: "Slovak", achievements: "Úspechy" # Tooltip on achievement list button from /play account: "Účet" # Tooltip on account button from /play settings: "Nastavenia" # Tooltip on settings button from /play -# poll: "Poll" # Tooltip on poll button from /play + poll: "Anketa" # Tooltip on poll button from /play next: "Ďalší" # Go from choose hero to choose inventory before playing a level change_hero: "Zmeniť hrdinu" # Go back from choose inventory to choose hero choose_inventory: "Vyzbrojiť sa s predmetmi" @@ -254,7 +254,7 @@ module.exports = nativeDescription: "slovenčina", englishDescription: "Slovak", victory_sign_up: "Přihlásit se pre uloženie progresu" victory_sign_up_poke: "Chceš uložiť svoj kód? Vytvorte si účet zdarma!" victory_rate_the_level: "Ohodnoťte túto úroveň: " # Only in old-style levels. - victory_return_to_ladder: "Vrátiť sa na Rebríčky" + victory_return_to_ladder: "Rebríčky" victory_play_continue: "Pokračovať" victory_saving_progress: "Stav ukladania" victory_go_home: "Návrat Domov" # Only in old-style levels. @@ -334,7 +334,7 @@ module.exports = nativeDescription: "slovenčina", englishDescription: "Slovak", tip_javascript_java: "Porovnávať Javu a JavaScript je ako porovnávať auto a lietajúci koberec. - Chris Heilmann" tip_move_forward: "Ak nevieš lietať, bež, ak nemôžeš bežať, kráčaj, ak nemôžeš kráčať, choď po štyroch, ale nech už robíš čokoľvek, musíš sa hýbať vpred - Martin Luther King Jr." tip_google: "Máš problém, ktorý nevieš vyriešiť ? Vygoogluj si ho !" - tip_adding_evil: "pridanie špitky zla." + tip_adding_evil: "Pridanie špitky zla." tip_hate_computers: "Ľudia, ktorí si myslia, že nenávidia počítače, v skutočnosti nenávidia mizerných programátorov. - Larry Niven" tip_open_source_contribute: "Aj ty môžeš zlepšiť CodeCombat !" tip_recurse: "Iterácia je ľudská, rekurzia božská.. - L. Peter Deutsch" @@ -484,11 +484,11 @@ module.exports = nativeDescription: "slovenčina", englishDescription: "Slovak", backstab: "Pichnutie do chrbta" # As in "this dagger does this much backstab damage" skills: "Schopnosti" attack_1: "Upravuje na" - attack_2: "hodnotu udávanej" - attack_3: "újmy zbraňou." + attack_2: "hodnotu udávanej újmy zbraňou pre typ" + attack_3: "." health_1: "Upravuje hodnotu zdravia na" - health_2: "hodnoty zaručenej" - health_3: "brnením." + health_2: "hodnoty zaručenej brnením" + health_3: "." speed_1: "Pohybuje sa rýchlosťou" speed_2: "metrov za sekundu." available_for_purchase: "Dostupné na zakúpenie" # Shows up when you have unlocked, but not purchased, a hero in the hero store @@ -542,73 +542,73 @@ module.exports = nativeDescription: "slovenčina", englishDescription: "Slovak", editor_config_behaviors_label: "Chytré správanie" editor_config_behaviors_description: "Automaticky doplňuje hranaté a oblé zátvorky a úvodzovky." -# about: -# why_codecombat: "Why CodeCombat?" -# why_paragraph_1: "If you want to learn to program, you don't need lessons. You need to write a lot of code and have a great time doing it." -# why_paragraph_2_prefix: "That's what programming is about. It's gotta be fun. Not fun like" -# why_paragraph_2_italic: "yay a badge" -# why_paragraph_2_center: "but fun like" -# why_paragraph_2_italic_caps: "NO MOM I HAVE TO FINISH THE LEVEL!" -# why_paragraph_2_suffix: "That's why CodeCombat is a multiplayer game, not a gamified lesson course. We won't stop until you can't stop--but this time, that's a good thing." -# why_paragraph_3: "If you're going to get addicted to some game, get addicted to this one and become one of the wizards of the tech age." -# press_title: "Bloggers/Press" -# press_paragraph_1_prefix: "Want to write about us? Feel free to download and use all of the resources included in our" -# press_paragraph_1_link: "press packet" -# press_paragraph_1_suffix: ". All logos and images may be used without contacting us directly." -# team: "Team" -# george_title: "Cofounder" -# george_blurb: "Businesser" -# scott_title: "Cofounder" -# scott_blurb: "Reasonable One" -# nick_title: "Cofounder" -# nick_blurb: "Motivation Guru" -# michael_title: "Programmer" -# michael_blurb: "Sys Admin" -# matt_title: "Programmer" -# matt_blurb: "Bicyclist" -# cat_title: "Chief Artisan" -# cat_blurb: "Airbender" -# josh_title: "Game Designer" -# josh_blurb: "Floor Is Lava" -# jose_title: "Music" -# jose_blurb: "Taking Off" -# retrostyle_title: "Illustration" -# retrostyle_blurb: "RetroStyle Games" + about: + why_codecombat: "Prečo CodeCombat?" + why_paragraph_1: "Ak sa chceš naučiť programovať, nepotrebuješ lekcie. To, čo potrebuješ je možnosť písať veľa kódu a baviť sa pri tom." + why_paragraph_2_prefix: "O tom je programovanie. Nemá to byť zábava typu" + why_paragraph_2_italic: "jéj, mám ďalší odznak" + why_paragraph_2_center: ",ale nadšenie ako" + why_paragraph_2_italic_caps: "HNEĎ MAMI, LEN DOKONČÍM TÚTO ÚROVEŇ !" + why_paragraph_2_suffix: "CodeCombat je skutočná hra pre viacej hráčov, od ktorej sa dá ťažko odtrhnúť." + why_paragraph_3: "Ak už sa máš byť závislý na nejakej hre, tak nech je to táto, pri ktorej sa staneš čarodejníkom technického veku." + press_title: "Blogeri/Tlač" + press_paragraph_1_prefix: "Chceš o nás písať ? Môžeš si stiahnúť a použiť všetky zdroje zahrnuté v našom" + press_paragraph_1_link: "tlačovom balíčku" + press_paragraph_1_suffix: ". Všetky logá a obrázky môžeš použiť bez toho, aby si nás priamo kontaktoval." + team: "Tím" + george_title: "Spoluzakladateľ" + george_blurb: "Podnikateľ" + scott_title: "Spoluzakladateľ" + scott_blurb: "Ten rozumný" + nick_title: "Spoluzakladateľ" + nick_blurb: "Motivačný Guru" + michael_title: "Programátor" + michael_blurb: "Systémový administrátor" + matt_title: "Programátor" + matt_blurb: "Bicyklista" + cat_title: "Najvyššia remeselníčka" + cat_blurb: "Ohýbačka vzduchu" + josh_title: "Dizajnér hier" + josh_blurb: "Podlaha je láva" + jose_title: "Hudba" + jose_blurb: "Vzlet" + retrostyle_title: "Ilustrácia" + retrostyle_blurb: "Retro hry" -# teachers: -# title: "CodeCombat: Info for Teachers" -# intro_1: "CodeCombat is an online game that teaches programming. Students write code in real programming languages." -# intro_2: "No experience required!" -# free_title: "How much does it cost?" + teachers: + title: "CodeCombat: Informácie pre učiteľov" + intro_1: "CodeCombat je online hra, ktorá učí programovať. Študenti píšu kód v skutočných programovacích jazykoch." + intro_2: "Nie sú nutné žiadne predchádzajúce skúsenosti !" + free_title: "Koľko to stojí ?" # cost_china: "CodeCombat in China is free for the first five levels, after which it costs $9.99 per month for access to our other 120+ levels on our exclusive China servers." -# free_1: "CodeCombat Basic is FREE! There are 70+ free levels which cover every concept." -# free_2: "A monthly subscription provides access to video tutorials and extra practice levels." -# teacher_subs_title: "Teachers get free subscriptions!" -# teacher_subs_1: "Please contact" -# teacher_subs_2: "to set up a free monthly subscription." -# sub_includes_title: "What is included in the subscription?" -# sub_includes_1: "In additional to the 70+ basic levels, students with a monthly subscription get access to these additional features:" -# sub_includes_2: "40+ practice levels" -# sub_includes_3: "Video tutorials" -# sub_includes_4: "Premium email support" -# sub_includes_5: "7 new heroes with unique skills to master" -# sub_includes_6: "3500 bonus gems every month" -# who_for_title: "Who is CodeCombat for?" -# who_for_1: "We recommend CodeCombat for students aged 9 and up. No prior programming experience is needed." -# who_for_2: "We've designed CodeCombat to appeal to both boys and girls." -# material_title: "How much material is there?" + free_1: "CodeCombat Basic is ZDARMA ! K dispozícii je 70+ úrovní pokrývajúcich každý koncept." + free_2: "Mesačné predplatné poskytuje prístup k videonávodom a k úrovniam na precvičenie navyše." + teacher_subs_title: "Pre učiteľov je predplatné zdarma !" + teacher_subs_1: "Napíšte na" + teacher_subs_2: "pre zriadenie mesačného predplatného zdarma." + sub_includes_title: "Čo zahrnuje predplatné ?" + sub_includes_1: "Študenti s mesačným predplatným získajú ku 70+ základným úrovniam aj :" + sub_includes_2: "40+ tréningových úrovní" + sub_includes_3: "Video návody" + sub_includes_4: "Prémiovú emailovú podporu" + sub_includes_5: "7 nových hrdinov s jedinečnými schopnosťami" + sub_includes_6: "3500 bonusových diamantov každý mesiac" + who_for_title: "Pre koho je určený CodeComabt ?" + who_for_1: "CodeCombat odporúčame pre žiakov od 9 rokov. Nie sú nutné žiadne predchádzajúce skúsenosti s programovaním." + who_for_2: "CodeCombat sme navrhli tak, aby oslovil chlapcov aj dievčatá." + material_title: "Aký je objem učebnej látky ?" # material_china: "Approximately 22 hours of gameplay spread over 120+ subscriber-only levels so far, with 5 new levels every week." -# material_1: "Approximately 8 hours of free content and an additional 14 hours of subscriber content, with 5 new levels every week." -# concepts_title: "What concepts are covered?" -# how_much_title: "How much does a monthly subscription cost?" -# how_much_1: "A" -# how_much_2: "monthly subscription" -# how_much_3: "costs $9.99, and can be cancelled anytime." -# how_much_4: "Additionally, we provide discounts for larger groups:" + material_1: "Asi 8 hodín bezplatného obsahu a ďalších 14 hodín pre predplatiteľov. 5 nových úrovní každý týždeň." + concepts_title: "Aké pojmy sú pokryté ?" + how_much_title: "Koľko stojí mesačné predplatné ?" + how_much_1: "" + how_much_2: "Mesačné predplatné" + how_much_3: ", ktoré môže byť kedykoľvek zrušené, stojí 9.99$." + how_much_4: "Zľavy pre väčšie skupiny:" # group_discounts_1: "We also offer group discounts for bulk subscriptions." -# sys_requirements_title: "System Requirements" -# sys_requirements_1: "A modern web browser. Newer versions of Chrome, Firefox, or Safari. Internet Explorer 9 or later." -# sys_requirements_2: "CodeCombat is not supported on iPad yet." + sys_requirements_title: "Systémové požiadavky" + sys_requirements_1: "Moderný webový prehliadač. Nové verzie prehliadačov Chrome, Firefox alebo Safari. Internet Explorer 9 alebo novší." + sys_requirements_2: "CodeCombat nie je zatiaľ podprovaný pre iPad." versions: save_version_title: "Ulož novú verziu" @@ -700,43 +700,43 @@ module.exports = nativeDescription: "slovenčina", englishDescription: "Slovak", # beautify: "Beautify your code by standardizing its formatting." # maximize_editor: "Maximize/minimize code editor." -# community: -# main_title: "CodeCombat Community" -# introduction: "Check out the ways you can get involved below and decide what sounds the most fun. We look forward to working with you!" -# level_editor_prefix: "Use the CodeCombat" -# level_editor_suffix: "to create and edit levels. Users have created levels for their classes, friends, hackathons, students, and siblings. If create a new level sounds intimidating you can start by forking one of ours!" -# thang_editor_prefix: "We call units within the game 'thangs'. Use the" -# thang_editor_suffix: "to modify the CodeCombat source artwork. Allow units to throw projectiles, alter the direction of an animation, change a unit's hit points, or upload your own vector sprites." -# article_editor_prefix: "See a mistake in some of our docs? Want to make some instructions for your own creations? Check out the" -# article_editor_suffix: "and help CodeCombat players get the most out of their playtime." -# find_us: "Find us on these sites" -# social_blog: "Read the CodeCombat blog on Sett" -# social_discource: "Join the discussion on our Discourse forum" -# social_facebook: "Like CodeCombat on Facebook" -# social_twitter: "Follow CodeCombat on Twitter" -# social_gplus: "Join CodeCombat on Google+" -# social_hipchat: "Chat with us in the public CodeCombat HipChat room" -# contribute_to_the_project: "Contribute to the project" + community: + main_title: "CodeCombat Komunita" + introduction: "Pozri si spôsoby ako sa môžeš zapojiť a rozhodni sa, čo ťa najviac láka.Tešime sa na spoluprácu !" + level_editor_prefix: "Použi" + level_editor_suffix: "na vytvorenie a úpravu úrovní. Uživatelia vytvorili úrovne pre svoje triedy, svojích priateľov, žiakov, súrodencov a aj pre deň kódovania. Ak sa bojíš začínať celkom od začiatku, môžeš začať klonovaním a úpravou našich úrovní." + thang_editor_prefix: "Jednotky hry nazývame vecičky - 'thangs'. Použi" + thang_editor_suffix: "na úpravu grafiky. Povoľ jednotkám vrhať strely, zmeň smer animácie, zmeň body zásahu alebo nahraj vlastné vektorové sprity." + article_editor_prefix: "Vidíš chybu v našich dokumentoch ? Chceš pridať inštrukcie k vlastným výtvorom ? Pozri sa na" + article_editor_suffix: "a pomôž hráčom, aby získali, čo najviac z hrania na CodeCombat." + find_us: "Nájdeš nás na týchto stránkach" + social_blog: "Prečítaj si blog na Sette" + social_discource: "Pridaj sa k diskusii na fóre Discourse" + social_facebook: "Daj Like CodeCombatu na Facebooku" + social_twitter: "Sleduj CodeCombat na Twitteri" + social_gplus: "Pripoj sa ku CodeCombatu na Google+" + social_hipchat: "Chatujte s nami vo verejnej HipChat miestnosti" + contribute_to_the_project: "Prispej svojou prácou" -# classes: -# archmage_title: "Archmage" -# archmage_title_description: "(Coder)" -# archmage_summary: "If you are a developer interested in coding educational games, become an archmage to help us build CodeCombat!" -# artisan_title: "Artisan" -# artisan_title_description: "(Level Builder)" -# artisan_summary: "Build and share levels for you and your friends to play. Become an Artisan to learn the art of teaching others to program." -# adventurer_title: "Adventurer" -# adventurer_title_description: "(Level Playtester)" -# adventurer_summary: "Get our new levels (even our subscriber content) for free one week early and help us work out bugs before our public release." -# scribe_title: "Scribe" -# scribe_title_description: "(Article Editor)" -# scribe_summary: "Good code needs good documentation. Write, edit, and improve the docs read by millions of players across the globe." -# diplomat_title: "Diplomat" -# diplomat_title_description: "(Translator)" -# diplomat_summary: "CodeCombat is localized in 45+ languages by our Diplomats. Help us out and contribute translations." -# ambassador_title: "Ambassador" -# ambassador_title_description: "(Support)" -# ambassador_summary: "Tame our forum users and provide direction for those with questions. Our ambassadors represent CodeCombat to the world." + classes: + archmage_title: "Arcimág" + archmage_title_description: "(Programátor)" + archmage_summary: "Ak si vývojár so záujmom o kódovanie vzdelávacíh hier, staň sa Arcimágom a pomôž nám s vývojom CodeCombatu !" + artisan_title: "Remeselník" + artisan_title_description: "(Tvorca úrovní)" + artisan_summary: "Tvor a zdieľaj úrovne, ktoré si môžu zahrať tvoji priatelia. Staň sa Remeselníkom a nauč sa umenie učiť iných programovať." + adventurer_title: "Dobrodruh" + adventurer_title_description: "(Testovač úrovní)" + adventurer_summary: "Dostaň sa k naším novým úrovniam (dokonca aj k tým pre predplatiteľov) zdarma a o týždeň skôr. Pomôž nám odhaliť chyby pred ich zverejnemím." + scribe_title: "Pisár" + scribe_title_description: "(Editor)" + scribe_summary: "Dobrý kód potrebuje dobrú dokumentáciu. Píš, edituj a vylepši dokumenty, ktoré čítajú milióny hráčov na celom svete." + diplomat_title: "Diplomat" + diplomat_title_description: "(Prekladateľ)" + diplomat_summary: "CodeCombat je preložený vďaka naším diplomatom do 45+ jazykov. Pomôž nám s prekladom." + ambassador_title: "Ambasador" + ambassador_title_description: "(Poradca)" + ambassador_summary: "Kroť použivateľov nášho fóra a nasmeruj na správnu cestu tých, čo sa pýtajú. Naši ambasádori reprezentujú CodeCombat na celom svete." # editor: # main_title: "CodeCombat Editors" @@ -828,10 +828,10 @@ module.exports = nativeDescription: "slovenčina", englishDescription: "Slovak", # polls: # priority: "Priority" -# contribute: -# page_title: "Contributing" -# intro_blurb: "CodeCombat is 100% open source! Hundreds of dedicated players have helped us build the game into what it is today. Join us and write the next chapter in CodeCombat's quest to teach the world to code!" -# alert_account_message_intro: "Hey there!" + contribute: + page_title: "Prispenie" + intro_blurb: "CodeCombat je 100% open source! Stovky nadšených hráčov nám pomohli dostať hru na dnešnú úroveň. Pripoj sa k nám a napíš ďalšiu kapitolu CodeCombatu, ktorý učí svet kódovať!" + alert_account_message_intro: "Ahoj!" # alert_account_message: "To subscribe for class emails, you'll need to be logged in first." # archmage_introduction: "One of the best parts about building games is they synthesize so many different things. Graphics, sound, real-time networking, social networking, and of course many of the more common aspects of programming, from low-level database management, and server administration to user facing design and interface building. There's a lot to do, and if you're an experienced programmer with a hankering to really dive into the nitty-gritty of CodeCombat, this class might be for you. We would love to have your help building the best programming game ever." # class_attributes: "Class Attributes" @@ -896,61 +896,61 @@ module.exports = nativeDescription: "slovenčina", englishDescription: "Slovak", # translating_diplomats: "Our Translating Diplomats:" # helpful_ambassadors: "Our Helpful Ambassadors:" -# ladder: -# please_login: "Please log in first before playing a ladder game." -# my_matches: "My Matches" -# simulate: "Simulate" -# simulation_explanation: "By simulating games you can get your game ranked faster!" -# simulate_games: "Simulate Games!" -# simulate_all: "RESET AND SIMULATE GAMES" -# games_simulated_by: "Games simulated by you:" -# games_simulated_for: "Games simulated for you:" -# games_simulated: "Games simulated" -# games_played: "Games played" -# ratio: "Ratio" -# leaderboard: "Leaderboard" -# battle_as: "Battle as " -# summary_your: "Your " -# summary_matches: "Matches - " -# summary_wins: " Wins, " -# summary_losses: " Losses" -# rank_no_code: "No New Code to Rank" -# rank_my_game: "Rank My Game!" -# rank_submitting: "Submitting..." -# rank_submitted: "Submitted for Ranking" -# rank_failed: "Failed to Rank" -# rank_being_ranked: "Game Being Ranked" -# rank_last_submitted: "submitted " -# help_simulate: "Help simulate games?" -# code_being_simulated: "Your new code is being simulated by other players for ranking. This will refresh as new matches come in." -# no_ranked_matches_pre: "No ranked matches for the " -# no_ranked_matches_post: " team! Play against some competitors and then come back here to get your game ranked." -# choose_opponent: "Choose an Opponent" -# select_your_language: "Select your language!" -# tutorial_play: "Play Tutorial" -# tutorial_recommended: "Recommended if you've never played before" -# tutorial_skip: "Skip Tutorial" -# tutorial_not_sure: "Not sure what's going on?" -# tutorial_play_first: "Play the Tutorial first." -# simple_ai: "Simple AI" -# warmup: "Warmup" -# friends_playing: "Friends Playing" -# log_in_for_friends: "Log in to play with your friends!" -# social_connect_blurb: "Connect and play against your friends!" -# invite_friends_to_battle: "Invite your friends to join you in battle!" -# fight: "Fight!" -# watch_victory: "Watch your victory" -# defeat_the: "Defeat the" -# tournament_started: ", started" -# tournament_ends: "Tournament ends" -# tournament_ended: "Tournament ended" -# tournament_rules: "Tournament Rules" -# tournament_blurb: "Write code, collect gold, build armies, crush foes, win prizes, and upgrade your career in our $40,000 Greed tournament! Check out the details" -# tournament_blurb_criss_cross: "Win bids, construct paths, outwit opponents, grab gems, and upgrade your career in our Criss-Cross tournament! Check out the details" -# tournament_blurb_zero_sum: "Unleash your coding creativity in both gold gathering and battle tactics in this alpine mirror match between red sorcerer and blue sorcerer. The tournament began on Friday, March 27 and will run until Monday, April 6 at 5PM PDT. Compete for fun and glory! Check out the details" -# tournament_blurb_blog: "on our blog" -# rules: "Rules" -# winners: "Winners" + ladder: + please_login: "Pred hraním rebríčkovej hry sa musíš najskôr prihlásiť." + my_matches: "Moje súboje" + simulate: "Simuluj" + simulation_explanation: "Simulovaním sa dostane hra rýchlejšie do rebríčka !!" + simulate_games: "Simuluj hry !" + simulate_all: "RESETUJ A SIMULUJ HRY" + games_simulated_by: "Tebou simulované hry:" + games_simulated_for: "Pre teba simulované hry:" + games_simulated: "Simulované hry" + games_played: "Odohrané hry" + ratio: "Pomer" + leaderboard: "Rebríček" + battle_as: "Hraj ako " + summary_your: "Tvoje " + summary_matches: "Súboje - počet výhier " + summary_wins: ", počet prehier " + summary_losses: " " + rank_no_code: "Žiadny nový kód na ocenenie" + rank_my_game: "Oceň moju hru !" + rank_submitting: "Odosielam..." + rank_submitted: "Odoslané na ocenenie" + rank_failed: "Chyba pri oceňovaní" + rank_being_ranked: "Hra je oceňovaná" + rank_last_submitted: "odoslané " + help_simulate: "Pomôžeš so simuláciou hier ?" + code_being_simulated: "Tvoj nový kód je simulovaný iným hráčom. Rebríček sa obnoví po nových súbojoch." + no_ranked_matches_pre: "Žiadne ocenené súboje pre " + no_ranked_matches_post: " tím ! Hraj proti súperom a potom sa sem vráť a uvidíš ocenenie svojej hry." + choose_opponent: "Vyber si súpera" + select_your_language: "Vyber si jazyk !" + tutorial_play: "Hraj tutoriál" + tutorial_recommended: "Odporúčané, pokiaľ si ešte nikdy nehral" + tutorial_skip: "Preskoč tutoriál" + tutorial_not_sure: "Nie si si istý, čo sa deje ?" + tutorial_play_first: "Hraj najskôr tutoriál." + simple_ai: "Jednoduchá umelá inteligencia" + warmup: "Na rozohratie" + friends_playing: "Hra proti priateľom" + log_in_for_friends: "Prihlás sa a hraj s priateľmi !" + social_connect_blurb: "Pripoj sa a hraj proti svojím priateľom !" + invite_friends_to_battle: "Pozvi priateľov a bojuj s nimi !" + fight: "Bojuj !" + watch_victory: "Pozri si svoju výhru" + defeat_the: "Poraz" + tournament_started: ", spustený" + tournament_ends: "Turnaj končí" + tournament_ended: "Turnaj skončil" + tournament_rules: "Pravidlá turnaja" + tournament_blurb: "Píš kód, zbieraj mince, stavaj armády, rozdrv nepriateľov, vyhraj ceny v hodnote 40,000$. Greed tournament! Pozri sa na detaily." + tournament_blurb_criss_cross: "Vyhraj ponuky, buduj cesty, preľsti súperov,zbieraj diamanty grab gems a vylepši svoju kariéru v našom Krížovkárskom turnaji ! Pozri sa na detaily" + tournament_blurb_zero_sum: "Odviaž svoju kódovaciu kreativitu pri zbieraní mincí a bojovej taktike v spravodlivom vysokohorskom súboji medzi medzi červenou a modrou čarodejkou. Turnaj začal v piatok 27. marca 2015 a skončil 6. apríla 2015. Súťaž pre zábavu a slávu ! Pozri sa na detaily" + tournament_blurb_blog: "v našom blogu." + rules: "Pravidlá" + winners: "Víťazi" user: stats: "Stats" diff --git a/app/models/CocoModel.coffee b/app/models/CocoModel.coffee index ca402f865..94cffaea0 100644 --- a/app/models/CocoModel.coffee +++ b/app/models/CocoModel.coffee @@ -1,5 +1,6 @@ storage = require 'core/storage' deltasLib = require 'core/deltas' +locale = require 'locale/locale' class CocoModel extends Backbone.Model idAttribute: '_id' @@ -26,6 +27,7 @@ class CocoModel extends Backbone.Model # if fixed, RevertModal will also need the fix setProjection: (project) -> + # TODO: ends up getting done twice, since the URL is modified and the @project is modified. So don't do this, just set project directly... (?) return if project is @project url = @getURL() url += '&project=' unless /project=/.test url @@ -399,12 +401,19 @@ class CocoModel extends Backbone.Model # use it to determine what properties actually need to be translated props = workingSchema.props or [] props = (prop for prop in props when parentData[prop]) + #unless props.length + # console.log 'props is', props, 'path is', path, 'data is', data, 'parentData is', parentData, 'workingSchema is', workingSchema + # langCodeArrays.push _.without _.keys(locale), 'update' # Every language has covered a path with no properties to be translated. + # return + + return if 'additionalProperties' of i18n # Workaround for #2630: Programmable is weird # get a list of lang codes where its object has keys for every prop to be translated coverage = _.filter(_.keys(i18n), (langCode) -> translations = i18n[langCode] _.all((translations[prop] for prop in props)) ) + #console.log 'got coverage', coverage, 'for', path, props, workingSchema, parentData langCodeArrays.push coverage ) diff --git a/app/schemas/models/level_session.coffee b/app/schemas/models/level_session.coffee index a4fca840e..2ebf83c91 100644 --- a/app/schemas/models/level_session.coffee +++ b/app/schemas/models/level_session.coffee @@ -88,7 +88,7 @@ _.extend LevelSessionSchema.properties, type: 'boolean' # Not tracked any more frame: type: 'number' # Not tracked any more - thangs: + thangs: # ... what is this? Is this used? type: 'object' additionalProperties: title: 'Thang' @@ -241,7 +241,7 @@ _.extend LevelSessionSchema.properties, description: 'The date a match was computed.' playtime: title: 'Playtime so far' - description: 'The total seconds of playtime on this session when the match was computed.' + description: 'The total seconds of playtime on this session when the match was computed. Not currently tracked.' type: 'number' metrics: type: 'object' diff --git a/app/schemas/models/user.coffee b/app/schemas/models/user.coffee index 510827657..111ddab62 100644 --- a/app/schemas/models/user.coffee +++ b/app/schemas/models/user.coffee @@ -274,6 +274,12 @@ _.extend UserSchema.properties, levelSystemMiscPatches: c.int() thangTypeTranslationPatches: c.int() thangTypeMiscPatches: c.int() + achievementTranslationPatches: c.int() + achievementMiscPatches: c.int() + pollTranslationPatches: c.int() + pollMiscPatches: c.int() + campaignTranslationPatches: c.int() + campaignMiscPatches: c.int() earned: c.RewardSchema 'earned by achievements' purchased: c.RewardSchema 'purchased with gems or money' diff --git a/app/styles/admin/analytics-subscriptions.sass b/app/styles/admin/analytics-subscriptions.sass index c182ff9c5..43c0e7543 100644 --- a/app/styles/admin/analytics-subscriptions.sass +++ b/app/styles/admin/analytics-subscriptions.sass @@ -26,9 +26,6 @@ height: 500px width: 100% - // TODO: figure out why this is necessary - margin-bottom: 100px - .x.axis font-size: 9pt path diff --git a/app/styles/editor/poll/poll-edit-view.sass b/app/styles/editor/poll/poll-edit-view.sass index 72f13a11c..c76880a62 100644 --- a/app/styles/editor/poll/poll-edit-view.sass +++ b/app/styles/editor/poll/poll-edit-view.sass @@ -14,4 +14,4 @@ #poll-view min-height: 200px position: relative - + z-index: 0 diff --git a/app/styles/modal/subscribe-modal.sass b/app/styles/modal/subscribe-modal.sass index 0f33abe56..7ea1cfab9 100644 --- a/app/styles/modal/subscribe-modal.sass +++ b/app/styles/modal/subscribe-modal.sass @@ -118,6 +118,20 @@ font-family: $headings-font-family font-size: 18px + //- Payment methods info popover link + + #payment-methods-info + position: absolute + right: 38px + top: 389px + text-decoration: underline + cursor: pointer + font-weight: bold + line-height: 18px + color: black + font-family: $headings-font-family + font-size: 18px + //- Purchase button .purchase-button diff --git a/app/styles/play/campaign-view.sass b/app/styles/play/campaign-view.sass index 486dc038f..caaf52d57 100644 --- a/app/styles/play/campaign-view.sass +++ b/app/styles/play/campaign-view.sass @@ -563,14 +563,20 @@ $gameControlMargin: 30px width: 100% text-align: center - .campaign-name, .levels-completed, .campaign-locked, .campaign-description + .campaign-name, .levels-completed, .campaign-locked margin: 0 color: white text-shadow: black 2px 2px 0, black -2px -2px 0, black 2px -2px 0, black -2px 2px 0, black 2px 0px 0, black 0px -2px 0, black -2px 0px 0, black 0px 2px 0 + .campaign-locked + margin: 32px 0 + .campaign-description margin: 0px 40px - font-size: 22px + background: transparent url(/images/level/popover_border_background.png) no-repeat + background-size: 100% 100% + padding: 12px + color: black .levels-completed font-size: 22px diff --git a/app/styles/play/level/modal/hero-victory-modal.sass b/app/styles/play/level/modal/hero-victory-modal.sass index 8d2cf4c97..e922715b2 100644 --- a/app/styles/play/level/modal/hero-victory-modal.sass +++ b/app/styles/play/level/modal/hero-victory-modal.sass @@ -369,6 +369,11 @@ .text-link color: lighten(#0b63bc, 10%) + .offer + display: none + + p + color: white html.no-borderimage #hero-victory-modal diff --git a/app/styles/play/modal/share-progress-modal.sass b/app/styles/play/modal/share-progress-modal.sass index 4498ba26a..6e2eb771f 100644 --- a/app/styles/play/modal/share-progress-modal.sass +++ b/app/styles/play/modal/share-progress-modal.sass @@ -39,24 +39,8 @@ font-weight: bold color: black - p.parent-blurb, p.friend-blurb - line-height: 16px - display: none - - .tell-parent-btn, .tell-friend-btn - margin: 10px - border-image: url(/images/level/code_toolbar_submit_button_active.png) 14 20 20 20 fill round - color: white - // width: 80px - font-size: 28px - line-height: 28px - text-transform: none - font-variant: small-caps - font-family: "Open Sans Condensed", "Helvetica Neue", Helvetica, Arial, sans-serif - .send-container margin-top: 10px - display: none .email-form .email-input width: 200px @@ -77,7 +61,7 @@ .continue-container margin-top: 10px margin-right: -12px - .back-link, .continue-link + .continue-link color: black font-weight: normal font-size: 11px diff --git a/app/templates/admin/analytics-subscriptions.jade b/app/templates/admin/analytics-subscriptions.jade index 0f98913f4..54d4dfd5e 100644 --- a/app/templates/admin/analytics-subscriptions.jade +++ b/app/templates/admin/analytics-subscriptions.jade @@ -1,12 +1,13 @@ extends /templates/base block content - + if !me.isAdmin() div You must be logged in as an admin to view this page. else + if total === 0 - h1 Fetching subscriptions data... + h4 Fetching dashboard data... else .container-fluid .row @@ -37,15 +38,59 @@ block content div *Stripe APIs do not return information about inactive subs. - br - - table.table.table-condensed.concepts-table + h2 Recent Subscribers + if !subscribers || subscribers.length < 1 + h4 Fetching recent subscribers... + else + table.table.table-condensed + thead + tr + th User Start + th Sub Start + if subscriberCancelled + th Cancelled + else + th + th + //- th Name + th Email + th Hero + th Level + th Last Level + th Age + th Spoken + tbody + each subscriber in subscribers + tr + td= subscriber.user.dateCreated.substring(0, 10) + td= subscriber.start.substring(0, 10) + td + if subscriber.cancel + span= subscriber.cancel.substring(0, 10) + td + if subscriber.user.stripe.sponsorID + span Sponsored + //- td + //- a(href="/user/#{subscriber.user._id}")= subscriber.user.name || 'Anoner' + td= subscriber.user.emailLower + td= subscriber.hero + td= subscriber.level + td= subscriber.user.lastLevel + td= subscriber.user.ageRange + td= subscriber.user.preferredLanguage + + h2 Subscriptions + if !subs || subs.length < 1 + h4 Fetching subscriptions... + else + table.table.table-condensed thead tr th Day th Total th Started th Cancelled + th Net tbody each sub in subs tr @@ -53,3 +98,4 @@ block content td= sub.total td= sub.started td= sub.cancelled + td= sub.started - sub.cancelled diff --git a/app/templates/community-view.jade b/app/templates/community-view.jade index b5a7be488..21511f6bc 100644 --- a/app/templates/community-view.jade +++ b/app/templates/community-view.jade @@ -14,9 +14,9 @@ block content h2 a.spl(href="/editor/level", data-i18n="editor.level_title") p - span(data-i18n="community.level_editor_prefix") Use the CodeCombat - a.spl.spr(href="/editor/level", data-i18n="editor.level_title") - span(data-i18n="community.level_editor_suffix") to create and edit levels. Users have created levels for their classes, friends, hackathons, students, and siblings. If create a new level sounds intimidating you can start by forking one of ours! + span.spr(data-i18n="community.level_editor_prefix") Use the CodeCombat + a(href="/editor/level", data-i18n="editor.level_title") + span.spl(data-i18n="community.level_editor_suffix") to create and edit levels. Users have created levels for their classes, friends, hackathons, students, and siblings. If create a new level sounds intimidating you can start by forking one of ours! .community-columns a(href="/editor/thang") @@ -24,9 +24,9 @@ block content h2 a.spl(href="/editor/thang", data-i18n="editor.thang_title") p - span(data-i18n="community.thang_editor_prefix") We call units within the game 'thangs'. Use the - a.spl.spr(href="/editor/thang", data-i18n="editor.thang_title") - span(data-i18n="community.thang_editor_suffix") to modify the CodeCombat source artwork. Allow units to throw projectiles, alter the direction of an animation, change a unit's hit points, or upload your own vector sprites. + span.spr(data-i18n="community.thang_editor_prefix") We call units within the game 'thangs'. Use the + a(href="/editor/thang", data-i18n="editor.thang_title") + span.spl(data-i18n="community.thang_editor_suffix") to modify the CodeCombat source artwork. Allow units to throw projectiles, alter the direction of an animation, change a unit's hit points, or upload your own vector sprites. .community-columns a(href="/editor/article") @@ -34,9 +34,9 @@ block content h2 a.spl(href="/editor/article", data-i18n="editor.article_title") p - span(data-i18n="community.article_editor_prefix") See a mistake in some of our docs? Want to make some instructions for your own creations? Check out the - a.spl.spr(href="/editor/article", data-i18n="editor.article_title") - span(data-i18n="community.article_editor_suffix") and help CodeCombat players get the most out of their playtime. + span.spr(data-i18n="community.article_editor_prefix") See a mistake in some of our docs? Want to make some instructions for your own creations? Check out the + a(href="/editor/article", data-i18n="editor.article_title") + span.spl(data-i18n="community.article_editor_suffix") and help CodeCombat players get the most out of their playtime. div diff --git a/app/templates/core/auth.jade b/app/templates/core/auth.jade index d68b1e6a7..3f5ff3221 100644 --- a/app/templates/core/auth.jade +++ b/app/templates/core/auth.jade @@ -20,6 +20,9 @@ if showRequiredError .alert.alert-success span(data-i18n="signup.required") You need to log in before you can that way. + else if mode === 'signup' && showSignupRationale + .alert.alert-info + span(data-i18n="play_level.victory_sign_up_poke") Want to save your code? Create a free account! form.form .form-group diff --git a/app/templates/core/contact.jade b/app/templates/core/contact.jade index 167f0a490..d57702fb3 100644 --- a/app/templates/core/contact.jade +++ b/app/templates/core/contact.jade @@ -16,9 +16,9 @@ block modal-body-content p(data-i18n="contact.subscriber_support") Since you're a CodeCombat subscriber, your email will get our priority support. else p - span(data-i18n="contact.subscribe_prefix") If you need help figuring out a level, please - a.spl.spr(data-toggle="coco-modal", data-target="core/SubscribeModal", data-i18n="contact.subscribe") buy a CodeCombat subscription - span(data-i18n="contact.subscribe_suffix") and we'll be happy to help you with your code. + span.spr(data-i18n="contact.subscribe_prefix") If you need help figuring out a level, please + a(data-toggle="coco-modal", data-target="core/SubscribeModal", data-i18n="contact.subscribe") buy a CodeCombat subscription + span.spl(data-i18n="contact.subscribe_suffix") and we'll be happy to help you with your code. .form .form-group label.control-label(for="contact-email", data-i18n="general.email") Email diff --git a/app/templates/core/subscribe-modal.jade b/app/templates/core/subscribe-modal.jade index 99d07ed6c..7fc061285 100644 --- a/app/templates/core/subscribe-modal.jade +++ b/app/templates/core/subscribe-modal.jade @@ -71,6 +71,7 @@ td.center-ok span.glyphicon.glyphicon-ok #parents-info(data-i18n="subscribe.parents") + #payment-methods-info(data-i18n="subscribe.payment_methods") button.btn.btn-lg.btn-illustrated.purchase-button(data-i18n="subscribe.subscribe_title") button.btn.btn-lg.btn-illustrated.parent-button(data-i18n="subscribe.parent_button") diff --git a/app/templates/play/campaign-view.jade b/app/templates/play/campaign-view.jade index 813e622d5..b74e80e90 100644 --- a/app/templates/play/campaign-view.jade +++ b/app/templates/play/campaign-view.jade @@ -15,8 +15,8 @@ if campaign if level.unlocksHero && (!level.purchasedHero || editorMode) img.hero-portrait(src="/file/db/thang.type/#{level.unlocksHero}/portrait.png") a(href=level.type == 'hero' ? '#' : level.disabled ? "/play" : "/play/#{level.levelPath || 'level'}/#{level.slug}", disabled=level.disabled, data-level-slug=level.slug, data-level-path=level.levelPath || 'level', data-level-name=level.name) - if level.slug == 'apocalypse' - img.star(src="/file/db/thang.type/54ea89112b7506e891ca717d/portrait.png") + if level.slug == 'lost-viking' + img.star(src="/file/db/thang.type/5441c3144e9aeb727cc97111/portrait.png") else if level.requiresSubscription img.star(src="/images/pages/play/star.png") if levelStatusMap[level.slug] === 'complete' @@ -79,7 +79,7 @@ else else if campaign btn(data-i18n="common.play").btn.btn-illustrated.btn-lg.btn-success.play-button if campaign && campaign.get('description') - h3.campaign-description + p.campaign-description span= i18n(campaign.attributes, 'description') .game-controls.header-font diff --git a/app/templates/play/ladder/ladder.jade b/app/templates/play/ladder/ladder.jade index 449453838..b92891c08 100644 --- a/app/templates/play/ladder/ladder.jade +++ b/app/templates/play/ladder/ladder.jade @@ -84,8 +84,7 @@ block content | . p strong Tournament ended! - //a(href="#winners") Behold the winners - span We will announce winners soon + a(href="#winners") Behold the winners | . Thanks for playing! You can strong still play | Zero Sum as long as you like. @@ -122,7 +121,7 @@ block content if level.get('name') == 'Greed' li a(href="#rules", data-toggle="tab", data-i18n="ladder.rules") Rules - if level.get('name') == 'Greed' || (level.get('name') == 'Criss-Cross') + if level.get('name') == 'Greed' || level.get('name') == 'Criss-Cross' || level.get('name') == 'Zero Sum' li a(href="#winners", data-toggle="tab", data-i18n="ladder.winners") Winners @@ -761,7 +760,7 @@ block content a(href="http://discourse.codecombat.com/") Discourse forum | . - if level.get('name') == 'Greed' || level.get('name') == 'Criss-Cross' + if level.get('name') == 'Greed' || level.get('name') == 'Criss-Cross' || level.get('name') == 'Zero Sum' .tab-pane.well#winners h1(data-i18n="ladder.winners") Winners @@ -769,17 +768,19 @@ block content thead tr th(data-i18n="ladder_prizes.rank") Rank - if level.get('name') == 'Criss-Cross' + if level.get('name') == 'Criss-Cross' || level.get('name') == 'Zero Sum' th th Human - if level.get('name') == 'Greed' + if level.get('name') == 'Greed' || level.get('name') == 'Zero Sum' th Human wins/losses/ties else th Human score - if level.get('name') == 'Criss-Cross' + if level.get('name') == 'Zero Sum' + th + if level.get('name') == 'Criss-Cross' || level.get('name') == 'Zero Sum' th th Ogre - if level.get('name') == 'Greed' + if level.get('name') == 'Greed' || level.get('name') == 'Zero Sum' th Ogre wins/losses/ties else th Ogre score @@ -789,30 +790,38 @@ block content - var ogre = winners.ogres[index] tr td= human.rank - if level.get('name') == 'Criss-Cross' + if level.get('name') == 'Criss-Cross' || level.get('name') == 'Zero Sum' td.code-language-cell(style="background-image: url(/images/common/code_languages/" + human.codeLanguage + "_icon.png)" title=_.string.capitalize(human.codeLanguage)) td= human.name - if level.get('name') == 'Greed' + if level.get('name') == 'Greed' || level.get('name') == 'Zero Sum' td span.win= human.wins | - span.loss= human.losses | - - span.tie= 377 - human.wins - human.losses + if level.get('name') == 'Greed' + span.tie= 377 - human.wins - human.losses + else if level.get('name') == 'Zero Sum' + span.tie= 108 - human.wins - human.losses else td span= Math.round(100 * human.score) if ogre - if level.get('name') == 'Criss-Cross' + if level.get('name') == 'Zero Sum' + td= ogre.rank + if level.get('name') == 'Criss-Cross' || level.get('name') == 'Zero Sum' td.code-language-cell(style="background-image: url(/images/common/code_languages/" + ogre.codeLanguage + "_icon.png)" title=_.string.capitalize(ogre.codeLanguage)) td= ogre.name - if level.get('name') == 'Greed' + if level.get('name') == 'Greed' || level.get('name') == 'Zero Sum' td span.win= ogre.wins | - span.loss= ogre.losses | - - span.tie= 407 - ogre.wins - ogre.losses + if level.get('name') == 'Greed' + span.tie= 407 - ogre.wins - ogre.losses + else if level.get('name') == 'Zero Sum' + span.tie= Math.max(0, 163 - ogre.wins - ogre.losses) else td span= Math.round(100 * ogre.score) diff --git a/app/templates/play/level/modal/hero-victory-modal.jade b/app/templates/play/level/modal/hero-victory-modal.jade index dfd6cf09b..3199d68ea 100644 --- a/app/templates/play/level/modal/hero-victory-modal.jade +++ b/app/templates/play/level/modal/hero-victory-modal.jade @@ -89,5 +89,12 @@ block modal-footer-content img(src="/images/level/csedweek-logo-final-small.jpg", alt="CS Ed Week Hour of Code", title="I'm finished with my Hour of Code", width=80) strong(data-i18n="play_level.victory_hour_of_code_done") Are You Done? a.text-link(href="http://code.org/api/hour/finish") - span(data-i18n="play_level.victory_hour_of_code_done_yes") Yes, I'm finished with my Hour of Code! - .clearfix \ No newline at end of file + span(data-i18n="play_level.victory_hour_of_code_done_yes") Yes, I am finished with my Hour of Code! + .clearfix + + .offer.lost-viking + p + img.pull-left(src="/file/db/level/55144b509f0c4854051769c1/viking1.png") + img.pull-right(src="/file/db/level/55144b509f0c4854051769c1/viking_2.png") + | Holy smokes, that was a hard level you just beat! If you aren't already a software developer, you should be. You just got fast-tracked for acceptance with Viking Code School, where you can take your skills to the next level and become a professional web developer in 14 weeks. + button.btn.btn-illustrated.btn-primary.btn-lg.world-map-button.continue-from-offer-button(data-i18n="play_level.victory_become_a_viking") Become a Viking diff --git a/app/templates/play/menu/guide-view.jade b/app/templates/play/menu/guide-view.jade index 4a90e6a6b..1ff5cf8d0 100644 --- a/app/templates/play/menu/guide-view.jade +++ b/app/templates/play/menu/guide-view.jade @@ -14,6 +14,14 @@ if docs.length === 1 hr h3 Want more programming lessons? ul + li + strong + a(class="resource-link", data-resource="breakout-mentors", href='http://breakoutmentors.com/?referral=codecombat') Breakout Mentors + | : Personalized code mentoring for kids from Stanford and UC Berkeley mentors, online or in person. + li + strong + a(class="resource-link", data-resource="ostraining", href='https://www.ostraining.com/codecombat/') OSTraining + | : Watch over 2600 videos on how to make great websites with Wordpress, Drupal, Joomla, and more. li strong a(class="resource-link", data-resource="one-month", href='http://mbsy.co/bVRtZ') One Month diff --git a/app/templates/play/modal/leaderboard-tab-view.jade b/app/templates/play/modal/leaderboard-tab-view.jade index 1b39108be..54ae254b0 100644 --- a/app/templates/play/modal/leaderboard-tab-view.jade +++ b/app/templates/play/modal/leaderboard-tab-view.jade @@ -25,7 +25,10 @@ if topScores td.ago-cell= row.ago td.viewable-cell if viewable - .glyphicon.glyphicon-eye-open + if (me.get('preferredLanguage', true) || 'en-US').substr(0, 2) == 'en' + .btn.btn-xs.btn-info Watch + else + .glyphicon.glyphicon-eye-open else .glyphicon.glyphicon-eye-close else if loading diff --git a/app/templates/play/modal/share-progress-modal.jade b/app/templates/play/modal/share-progress-modal.jade index 18b30a77a..c3feaf5a0 100644 --- a/app/templates/play/modal/share-progress-modal.jade +++ b/app/templates/play/modal/share-progress-modal.jade @@ -6,16 +6,6 @@ .blurb-container h1(data-i18n="share_progress_modal.title") p(data-i18n="share_progress_modal.blurb") - .container-fluid.btn-picker-container - .row - .col-xs-12.text-center - button.btn.btn-illustrated.tell-parent-btn(data-i18n="share_progress_modal.tell_parent") - .row - .col-xs-12.text-center - button.btn.btn-illustrated.tell-friend-btn(data-i18n="share_progress_modal.tell_friend") - .row.continue-container - .col-xs-12.text-right - a.continue-link(data-i18n="common.continue") .container-fluid.send-container .row @@ -30,7 +20,5 @@ .col-xs-4.text-right button.btn.btn-illustrated.send-btn(data-i18n="common.send") .row.continue-container - .col-xs-6 - a.back-link(data-i18n="common.back") - .col-xs-6.text-right + .col-xs-12.text-left a.continue-link(data-i18n="common.continue") diff --git a/app/views/CommunityView.coffee b/app/views/CommunityView.coffee index dc6f6839d..0186ede61 100644 --- a/app/views/CommunityView.coffee +++ b/app/views/CommunityView.coffee @@ -13,7 +13,7 @@ module.exports = class CommunityView extends RootView titleDescription = $.i18n.t("classes.#{characterClass}_title_description") summary = $.i18n.t("classes.#{characterClass}_summary") explanation = "<h4>#{title} #{titleDescription}</h4>#{summary}" - $(@).find('img').popover(placement: 'bottom', trigger: 'hover', container: 'body', content: explanation, html: true) + $(@).find('img').popover(placement: 'top', trigger: 'hover', container: 'body', content: explanation, html: true) @$el.find('.logo-row img').each -> - $(@).popover(placement: 'bottom', trigger: 'hover', container: 'body') + $(@).popover(placement: 'top', trigger: 'hover', container: 'body') diff --git a/app/views/admin/AnalyticsSubscriptionsView.coffee b/app/views/admin/AnalyticsSubscriptionsView.coffee index cd44a17aa..454b15f57 100644 --- a/app/views/admin/AnalyticsSubscriptionsView.coffee +++ b/app/views/admin/AnalyticsSubscriptionsView.coffee @@ -1,9 +1,8 @@ RootView = require 'views/core/RootView' template = require 'templates/admin/analytics-subscriptions' -RealTimeCollection = require 'collections/RealTimeCollection' +ThangType = require 'models/ThangType' +User = require 'models/User' -# TODO: Add last N subscribers table -# TODO: Add revenue line # TODO: Graphing code copied/mangled from campaign editor level view. OMG, DRY. require 'vendor/d3' @@ -11,10 +10,11 @@ require 'vendor/d3' module.exports = class AnalyticsSubscriptionsView extends RootView id: 'admin-analytics-subscriptions-view' template: template + targetSubCount: 2000 constructor: (options) -> super options - @resetData() + @resetSubscriptionsData() if me.isAdmin() @refreshData() _.delay (=> @refreshData()), 30 * 60 * 1000 @@ -23,6 +23,8 @@ module.exports = class AnalyticsSubscriptionsView extends RootView context = super() context.analytics = @analytics ? graphs: [] context.subs = _.cloneDeep(@subs ? []).reverse() + context.subscribers = @subscribers ? [] + context.subscriberCancelled = _.find context.subscribers, (subscriber) -> subscriber.cancel context.total = @total ? 0 context.cancelled = @cancelled ? 0 context.monthlyChurn = @monthlyChurn ? 0.0 @@ -33,17 +35,39 @@ module.exports = class AnalyticsSubscriptionsView extends RootView super() @updateAnalyticsGraphs() - resetData: -> + resetSubscriptionsData: -> @analytics = graphs: [] @subs = [] @total = 0 @cancelled = 0 @monthlyChurn = 0.0 + @monthlyGrowth = 0.0 refreshData: -> return unless me.isAdmin() - @resetData() + @resetSubscriptionsData() + @getSubscribers() + @getSubscriptions() + getSubscribers: -> + options = + url: '/db/subscription/-/subscribers' + method: 'POST' + data: {maxCount: 30} + options.error = (model, response, options) => + return if @destroyed + console.error 'Failed to get subscribers', response + options.success = (subscribers, response, options) => + return if @destroyed + @subscribers = subscribers + for subscriber in @subscribers + subscriber.level = User.levelFromExp subscriber.user.points + if hero = subscriber.user.heroConfig?.thangType + subscriber.hero = _.invert(ThangType.heroes)[hero] + @render?() + @supermodel.addRequestResource('get_subscribers', options, 0).load() + + getSubscriptions: -> options = url: '/db/subscription/-/subscriptions' method: 'GET' @@ -52,7 +76,7 @@ module.exports = class AnalyticsSubscriptionsView extends RootView console.error 'Failed to get subscriptions', response options.success = (subs, response, options) => return if @destroyed - @resetData() + @resetSubscriptionsData() subDayMap = {} for sub in subs startDay = sub.start.substring(0, 10) @@ -66,7 +90,7 @@ module.exports = class AnalyticsSubscriptionsView extends RootView for day of subDayMap @subs.push day: day - started: subDayMap[day]['start'] + started: subDayMap[day]['start'] or 0 cancelled: subDayMap[day]['cancel'] or 0 @subs.sort (a, b) -> a.day.localeCompare(b.day) @@ -78,9 +102,9 @@ module.exports = class AnalyticsSubscriptionsView extends RootView startedLastMonth += sub.started if @subs.length - i < 31 @monthlyChurn = @cancelled / startedLastMonth * 100.0 if startedLastMonth > 0 if @subs.length > 30 and @subs[@subs.length - 31].total > 0 - lastMonthTotal = @subs[@subs.length - 31].total - thisMonthTotal = @subs[@subs.length - 1].total - @monthlyGrowth = (thisMonthTotal - lastMonthTotal) / lastMonthTotal * 100 + startMonthTotal = @subs[@subs.length - 31].total + endMonthTotal = @subs[@subs.length - 1].total + @monthlyGrowth = (endMonthTotal / startMonthTotal - 1) * 100 @updateAnalyticsGraphData() @render?() @supermodel.addRequestResource('get_subscriptions', options, 0).load() @@ -98,6 +122,7 @@ module.exports = class AnalyticsSubscriptionsView extends RootView # TODO: Where should this metadata live? # TODO: lineIDs assumed to be unique across graphs totalSubsID = 'total-subs' + targetSubsID = 'target-subs' startedSubsID = 'started-subs' cancelledSubsID = 'cancelled-subs' netSubsID = 'net-subs' @@ -106,6 +131,11 @@ module.exports = class AnalyticsSubscriptionsView extends RootView description: 'Total Active Subscriptions' color: 'green' strokeWidth: 1 + lineMetadata[targetSubsID] = + description: 'Target Total Subscriptions' + color: 'gold' + strokeWidth: 4 + opacity: 1.0 lineMetadata[startedSubsID] = description: 'New Subscriptions' color: 'blue' @@ -162,8 +192,9 @@ module.exports = class AnalyticsSubscriptionsView extends RootView points: levelPoints description: lineMetadata[totalSubsID].description lineColor: lineMetadata[totalSubsID].color + strokeWidth: lineMetadata[totalSubsID].strokeWidth min: 0 - max: d3.max(@subs, (d) -> d.total) + max: Math.max(@targetSubCount, d3.max(@subs, (d) -> d.total)) ## Started @@ -196,9 +227,34 @@ module.exports = class AnalyticsSubscriptionsView extends RootView points: levelPoints description: lineMetadata[startedSubsID].description lineColor: lineMetadata[startedSubsID].color + strokeWidth: lineMetadata[startedSubsID].strokeWidth min: 0 max: d3.max(@subs, (d) -> d.started) + ## Total subs target + + # Build line data + levelPoints = [] + for sub, i in @subs + levelPoints.push + x: i + y: @targetSubCount + day: sub.day + pointID: "#{targetSubsID}#{i}" + values: [] + + levelPoints.splice(0, levelPoints.length - timeframeDays) if levelPoints.length > timeframeDays + + @analytics.graphs[0].lines.push + lineID: targetSubsID + enabled: true + points: levelPoints + description: lineMetadata[targetSubsID].description + lineColor: lineMetadata[targetSubsID].color + strokeWidth: lineMetadata[targetSubsID].strokeWidth + min: 0 + max: @targetSubCount + ## Cancelled averageCancelled = 0 @@ -235,6 +291,7 @@ module.exports = class AnalyticsSubscriptionsView extends RootView points: levelPoints description: lineMetadata[cancelledSubsID].description lineColor: lineMetadata[cancelledSubsID].color + strokeWidth: lineMetadata[cancelledSubsID].strokeWidth min: 0 max: d3.max(@subs, (d) -> d.started) @@ -310,7 +367,7 @@ module.exports = class AnalyticsSubscriptionsView extends RootView xRange = d3.scale.linear().range([0, width]).domain([d3.min(line.points, (d) -> d.x), d3.max(line.points, (d) -> d.x)]) yRange = d3.scale.linear().range([height, 0]).domain([line.min, line.max]) - # x-Axis and guideline once + # x-Axis if currentLine is 0 startDay = new Date(line.points[0].day) endDay = new Date(line.points[line.points.length - 1].day) @@ -369,7 +426,7 @@ module.exports = class AnalyticsSubscriptionsView extends RootView svg.append("text") .attr("x", margin + 40 + 10) .attr("y", margin + height + xAxisHeight + keyHeight * currentLine + (keyHeight + 10) / 2) - .attr("fill", line.lineColor) + .attr("fill", if line.lineColor is 'gold' then 'orange' else line.lineColor) .attr("class", "key-text") .text(line.description) diff --git a/app/views/core/AuthModal.coffee b/app/views/core/AuthModal.coffee index 8e4a2368d..1de0c80a7 100644 --- a/app/views/core/AuthModal.coffee +++ b/app/views/core/AuthModal.coffee @@ -33,6 +33,7 @@ module.exports = class AuthModal extends ModalView getRenderData: -> c = super() c.showRequiredError = @options.showRequiredError + c.showSignupRationale = @options.showSignupRationale c.mode = @mode c.formValues = @previousFormInputs or {} c.me = me diff --git a/app/views/core/SubscribeModal.coffee b/app/views/core/SubscribeModal.coffee index 547c5dd37..7d957abc5 100644 --- a/app/views/core/SubscribeModal.coffee +++ b/app/views/core/SubscribeModal.coffee @@ -37,6 +37,7 @@ module.exports = class SubscribeModal extends ModalView super() @setupParentButtonPopover() @setupParentInfoPopover() + @setupPaymentMethodsInfoPopover() setupParentButtonPopover: -> popoverTitle = $.i18n.t 'subscribe.parent_email_title' @@ -85,6 +86,21 @@ module.exports = class SubscribeModal extends ModalView ).on 'shown.bs.popover', => application.tracker?.trackEvent 'Subscription parent hover' + setupPaymentMethodsInfoPopover: -> + popoverTitle = $.i18n.t('subscribe.payment_methods_title') + popoverContent = "<p>" + $.i18n.t('subscribe.payment_methods_blurb1') + "</p>" + popoverContent += "<p>" + $.i18n.t('subscribe.payment_methods_blurb2') + " <a href='mailto:support@codecombat.com'>support@codecombat.com</a>." + @$el.find('#payment-methods-info').popover( + animation: true + html: true + placement: 'top' + trigger: 'click' + title: popoverTitle + content: popoverContent + container: @$el + ).on 'shown.bs.popover', => + application.tracker?.trackEvent 'Subscription payment methods hover' + onClickParentSendButton: (e) -> # TODO: Popover sometimes dismisses immediately after send diff --git a/app/views/i18n/I18NEditLevelView.coffee b/app/views/i18n/I18NEditLevelView.coffee index 90b083c94..bb797ca73 100644 --- a/app/views/i18n/I18NEditLevelView.coffee +++ b/app/views/i18n/I18NEditLevelView.coffee @@ -27,7 +27,7 @@ module.exports = class I18NEditLevelView extends I18NEditModelView for doc, index in @model.get('documentation')?.specificArticles ? [] if i18n = doc.i18n @wrapRow 'Guide article name', ['name'], doc.name, i18n[lang]?.name, ['documentation', 'specificArticles', index] - @wrapRow "'#{doc.name}' description", ['description'], doc.description, i18n[lang]?.description, ['documentation', 'specificArticles', index], 'markdown' + @wrapRow "'#{doc.name}' body", ['body'], doc.body, i18n[lang]?.body, ['documentation', 'specificArticles', index], 'markdown' # sprite dialogues for script, scriptIndex in @model.get('scripts') ? [] diff --git a/app/views/ladder/LadderView.coffee b/app/views/ladder/LadderView.coffee index e813bfb81..0c13316cd 100644 --- a/app/views/ladder/LadderView.coffee +++ b/app/views/ladder/LadderView.coffee @@ -110,6 +110,8 @@ module.exports = class LadderView extends RootView @$el.find('a[href="#rules"]').tab('show') if link and /#prizes/.test link @$el.find('a[href="#prizes"]').tab('show') + if link and /#winners/.test link + @$el.find('a[href="#winners"]').tab('show') destroy: -> clearInterval @refreshInterval diff --git a/app/views/ladder/SimulateTabView.coffee b/app/views/ladder/SimulateTabView.coffee index aca02117d..1fc3ab3b2 100644 --- a/app/views/ladder/SimulateTabView.coffee +++ b/app/views/ladder/SimulateTabView.coffee @@ -48,7 +48,7 @@ module.exports = class SimulateTabView extends CocoView @startSimulating() startSimulating: -> - @simulationPageRefreshTimeout = _.delay @refreshAndContinueSimulating, 20 * 60 * 1000 + @simulationPageRefreshTimeout = _.delay @refreshAndContinueSimulating, 30 * 60 * 1000 @simulateNextGame() $('#simulate-button').prop 'disabled', true $('#simulate-button').text 'Simulating...' @@ -65,7 +65,7 @@ module.exports = class SimulateTabView extends CocoView # Work around simulator getting super slow on Chrome fetchAndSimulateTaskOriginal = @simulator.fetchAndSimulateTask @simulator.fetchAndSimulateTask = => - if @simulator.simulatedByYou >= 5 + if @simulator.simulatedByYou >= 20 console.log '------------------- Destroying Simulator and making a new one -----------------' @simulator.destroy() @simulator = null diff --git a/app/views/ladder/tournament_results.coffee b/app/views/ladder/tournament_results.coffee index 6b4ae28fb..3b20b9a02 100644 --- a/app/views/ladder/tournament_results.coffee +++ b/app/views/ladder/tournament_results.coffee @@ -1,4 +1,4 @@ -module.exports = results = greed: {}, 'criss-cross': {} +module.exports = results = greed: {}, 'criss-cross': {}, 'zero-sum': {} results.greed.humans = [ {team: 'humans', rank: 1, sessionID: '5381e3537585483905a829c1', name: 'Wizard Dude', playtime: 63184, wins: 363, losses: 0, score: 363} @@ -746,3 +746,205 @@ results['criss-cross'].ogres = [ {team: 'ogres', rank: 72, sessionID: '53f4847afda22e3305bdbea5', codeLanguage: 'javascript', name: 'CodeMinion', score: 9.706964015} {team: 'ogres', rank: 73, sessionID: '53fba49c3baef834054b98c6', codeLanguage: 'javascript', name: 'Moises Banales', score: 8.991630973} ] + +results['zero-sum'].humans = [ + {team: 'humans', rank: 1, userID: '539b571db4c4f9380545317d', sessionID: '55188bcee3ae3a3505f7d1ad', name: 'NoJuice4u', wins: 105, losses: 3, playtime: 46222, codeLanguage: 'javascript'} + {team: 'humans', rank: 2, userID: '54ef65eaef838a790598b305', sessionID: '5518349d1f12482609b452ea', name: 'Qenf', wins: 99, losses: 9, playtime: 13554, codeLanguage: 'python'} + {team: 'humans', rank: 3, userID: '5308bb6cc326dda10cf62d6d', sessionID: '55172d95e3ae3a3505f7a6ed', name: 'Stofflon', wins: 95, losses: 13, playtime: 22609, codeLanguage: 'javascript'} + {team: 'humans', rank: 3, userID: '539bccfb6e1d92310506ffa9', sessionID: '5518d8624c73053505254062', name: 'Driphter', wins: 95, losses: 13, playtime: 32555, codeLanguage: 'javascript'} + {team: 'humans', rank: 5, userID: '54d2c6ac3e16915505f0cef3', sessionID: '551f2d159800ae33059c5052', name: 'KingCode', wins: 93, losses: 15, playtime: 13510, codeLanguage: 'javascript'} + {team: 'humans', rank: 5, userID: '549ee5208f3c153d0518ff24', sessionID: '55195098d69ccd3305a2ea0c', name: 'wabu', wins: 93, losses: 15, playtime: 3274, codeLanguage: 'python'} + {team: 'humans', rank: 5, userID: '5500505220b2567d0514bab9', sessionID: '551582ecf43d375105fbdf00', name: 'Muadibi', wins: 93, losses: 15, playtime: 30381, codeLanguage: 'javascript'} + {team: 'humans', rank: 5, userID: '54f015a0df1b7d7d05610870', sessionID: '55172f2ec13fa03205248953', name: 'Andre95', wins: 93, losses: 15, playtime: 53158, codeLanguage: 'python'} + {team: 'humans', rank: 9, userID: '54ff548501c724b9072f9f6d', sessionID: '551bd2f91794dc1a112bfc28', name: 'mAsTer_A', wins: 91, losses: 16, playtime: 11860, codeLanguage: 'javascript'} + {team: 'humans', rank: 10, userID: '539c13ba6e1d923105072c32', sessionID: '5515a210d792f354050c9339', name: 'rasdasd', wins: 89, losses: 19, playtime: 12710, codeLanguage: 'javascript'} + {team: 'humans', rank: 11, userID: '5516520db77a16330597d9a3', sessionID: '55165233de8bc03205975972', name: 'SlamBlasta', wins: 88, losses: 20, playtime: 10063, codeLanguage: 'python'} + {team: 'humans', rank: 12, userID: '512ef4805a67a8c507000001', sessionID: '550370aeec31df9c691ab632', name: 'Nick', wins: 87, losses: 20, playtime: 22856, codeLanguage: 'python'} + {team: 'humans', rank: 13, userID: '55164512de8bc032059758dc', sessionID: '55184ea8e3ae3a3505f7c811', name: 'Geoboardman', wins: 87, losses: 21, playtime: 11451, codeLanguage: 'python'} + {team: 'humans', rank: 13, userID: '551750ca81389437054def79', sessionID: '5517545fe3ae3a3505f7ac1f', name: 'the real Carl Maxwell', wins: 87, losses: 21, playtime: 6242, codeLanguage: 'python'} + {team: 'humans', rank: 15, userID: '537d01f484c54c6e05c05989', sessionID: '55164e9f4e83223605e7942a', name: 'Serg', wins: 85, losses: 23, playtime: 8176, codeLanguage: 'javascript'} + {team: 'humans', rank: 16, userID: '5478a26cc439b9160865b3b3', sessionID: '550ceb075834237a05acda6e', name: 'Tutor Delphia', wins: 83, losses: 25, playtime: 30978, codeLanguage: 'javascript'} + {team: 'humans', rank: 17, userID: '551d78734c73053505267238', sessionID: '551dc7046cc7da101fe5fe52', name: 'Kongou', wins: 79, losses: 29, playtime: 561, codeLanguage: 'python'} + {team: 'humans', rank: 18, userID: '53f4cb0cfda22e3305be24e7', sessionID: '5515ecc4b8185a5205e1a304', name: 'Dothgar', wins: 74, losses: 34, playtime: 4129, codeLanguage: 'javascript'} + {team: 'humans', rank: 19, userID: '5520a4caabdb444805e85da1', sessionID: '5522f7ae801bea3905cb6fd9', name: 'Bazhan', wins: 73, losses: 34, playtime: 4466, codeLanguage: 'python'} + {team: 'humans', rank: 20, userID: '5506e39e84ce5b7905627e41', sessionID: '551bed505afdf532055862e4', name: 'pixx', wins: 73, losses: 35, playtime: 12182, codeLanguage: 'javascript'} + {team: 'humans', rank: 21, userID: '5516aa174d24212f05944d19', sessionID: '5517065858852c3405f48e9d', name: 'Haruna', wins: 70, losses: 38, playtime: 19377, codeLanguage: 'javascript'} + {team: 'humans', rank: 22, userID: '54a800d3a487d53f056c0bb7', sessionID: '5519bac15cd6bae40951f460', name: 'Mensian', wins: 69, losses: 39, playtime: 17817, codeLanguage: 'javascript'} + {team: 'humans', rank: 23, userID: '5519d8885afdf5320557df5c', sessionID: '5519d88e8328b9020debf019', name: 'StabGun', wins: 69, losses: 39, playtime: 3710, codeLanguage: 'python'} + {team: 'humans', rank: 23, userID: '55187c2c5afdf532055782df', sessionID: '55187c63d69ccd3305a2c33b', name: 'shakesoda', wins: 69, losses: 39, playtime: 19789, codeLanguage: 'lua'} + {team: 'humans', rank: 25, userID: '5429a6d19f9fa2bf2c5a4e4e', sessionID: '55173873d69ccd3305a2918c', name: 'FadingSun32', wins: 65, losses: 43, playtime: 113, codeLanguage: 'javascript'} + {team: 'humans', rank: 25, userID: '54f9e344d12cf54d069d92dc', sessionID: '550d0ba29e22dc56056be1dd', name: 'xianjin', wins: 65, losses: 43, playtime: 693, codeLanguage: 'python'} + {team: 'humans', rank: 27, userID: '54fd36429ae7221e06728f3b', sessionID: '550d001c9e22dc56056be0d8', name: 'Jasmine49', wins: 59, losses: 49, playtime: 5222, codeLanguage: 'python'} + {team: 'humans', rank: 27, userID: '551b205cc13fa03205254f3e', sessionID: '551c04088328b9020dec9ef1', name: 'my98olds', wins: 59, losses: 49, playtime: 22943, codeLanguage: 'javascript'} + {team: 'humans', rank: 29, userID: '54bbb1016ef7bdde07101c4e', sessionID: '551807d0c13fa03205249b3d', name: 'PSL', wins: 57, losses: 51, playtime: 2523, codeLanguage: 'javascript'} + {team: 'humans', rank: 30, userID: '539ea2ba64edb6fa0bf584f7', sessionID: '5516a002b77a16330597e208', name: 'MarS explorer', wins: 55, losses: 53, playtime: 5966, codeLanguage: 'lua'} + {team: 'humans', rank: 30, userID: '548e1d2d24446d3d050281ed', sessionID: '55080c49039bafd50cb92fae', name: 'J_F_B_M', wins: 55, losses: 53, playtime: 7951, codeLanguage: 'javascript'} + {team: 'humans', rank: 32, userID: '5489342042443b56076a1ad8', sessionID: '55173465e3ae3a3505f7a7ff', name: 'AnnieHall', wins: 54, losses: 52, playtime: 5576, codeLanguage: 'python'} + {team: 'humans', rank: 33, userID: '54f1ddf248724e7d052b75fd', sessionID: '551a7f0e5cd6bae409522148', name: 'TiboW', wins: 54, losses: 54, playtime: 942, codeLanguage: 'python'} + {team: 'humans', rank: 34, userID: '55169c96aedec33205e8acfc', sessionID: '55169df0aedec33205e8ad47', name: 'funny_falcon', wins: 51, losses: 57, playtime: 4486, codeLanguage: 'python'} + {team: 'humans', rank: 35, userID: '54feee1ae950f7a707ec3461', sessionID: '5515d0933bdee5954e8246df', name: 'Khorrok', wins: 50, losses: 57, playtime: 387, codeLanguage: 'python'} + {team: 'humans', rank: 36, userID: '54f7e04e8ec032e705abbcd8', sessionID: '550cc8eba605ba5a05120514', name: 'Tan Chuan Jie', wins: 50, losses: 58, playtime: 4787, codeLanguage: 'python'} + {team: 'humans', rank: 36, userID: '551743df079f2833053c723a', sessionID: '5517582bd69ccd3305a29676', name: 'Majestik', wins: 50, losses: 58, playtime: 15118, codeLanguage: 'javascript'} + {team: 'humans', rank: 38, userID: '55005eb295a4228105f6bfc3', sessionID: '550d0e699e22dc56056be203', name: '2SHAWN4YOU', wins: 49, losses: 59, playtime: 935, codeLanguage: 'python'} + {team: 'humans', rank: 39, userID: '54dcf4ec7b4e13500586e511', sessionID: '5518609b5afdf53205577d82', name: 'Da5id', wins: 46, losses: 61, playtime: 711, codeLanguage: 'python'} + {team: 'humans', rank: 40, userID: '550420ad2c5fbf7b056a18a0', sessionID: '550cffa5a605ba5a051205d4', name: 'YuanFeng', wins: 46, losses: 62, playtime: 5471, codeLanguage: 'python'} + {team: 'humans', rank: 41, userID: '54f9cad2d12cf54d069d8465', sessionID: '550cc77d9e22dc56056bdfe8', name: 'abcdefguan', wins: 45, losses: 61, playtime: 4873, codeLanguage: 'python'} + {team: 'humans', rank: 42, userID: '54f914455cb508f3058b6553', sessionID: '550d00759e22dc56056be0e0', name: 'KaiXFlare', wins: 45, losses: 63, playtime: 5578, codeLanguage: 'python'} + {team: 'humans', rank: 42, userID: '5443c3609792f94d06eecbb3', sessionID: '5515afd91c3bb18709e26474', name: 'PiedotTaste', wins: 45, losses: 63, playtime: 503, codeLanguage: 'javascript'} + {team: 'humans', rank: 44, userID: '53b9fa0194abf748058ea71a', sessionID: '55160678b77a16330597d2ea', name: 'UMD_Liquidator', wins: 44, losses: 64, playtime: 16710, codeLanguage: 'javascript'} + {team: 'humans', rank: 45, userID: '550db4c425b6f688062cb7f5', sessionID: '5515bc21fd67e4b4095aae6e', name: 'coderg0d', wins: 43, losses: 65, playtime: 17150, codeLanguage: 'javascript'} + {team: 'humans', rank: 46, userID: '53e5783d6c59f5340504a6e9', sessionID: '55162c77de8bc03205975793', name: 'YodaEater', wins: 42, losses: 66, playtime: 15075, codeLanguage: 'python'} + {team: 'humans', rank: 47, userID: '539cec01ab5dfc3a05cbf2d2', sessionID: '55158457b8185a5205e172a7', name: 'matthewd', wins: 41, losses: 67, playtime: 2166, codeLanguage: 'javascript'} + {team: 'humans', rank: 48, userID: '535d52e90f77a8470b782df4', sessionID: '551676f64d24212f059446b6', name: 'binarychase', wins: 40, losses: 68, playtime: 13148, codeLanguage: 'javascript'} + {team: 'humans', rank: 49, userID: '54f9064ad12cf54d069d54a4', sessionID: '550cc7469e22dc56056bdfe3', name: 'hussain1998', wins: 39, losses: 69, playtime: 5516, codeLanguage: 'python'} + {team: 'humans', rank: 49, userID: '539bb5b7ab5dfc3a05cae063', sessionID: '55216e3885fca531055424d6', name: 'DollarAkshay', wins: 39, losses: 69, playtime: 965, codeLanguage: 'javascript'} + {team: 'humans', rank: 49, userID: '54cf001ead25d155057ec294', sessionID: '550cc77c9e22dc56056bdfe7', name: 'jasmineseah-17', wins: 39, losses: 69, playtime: 5260, codeLanguage: 'python'} + {team: 'humans', rank: 52, userID: '55159c561a93145605a65360', sessionID: '55159cde99d51b55053609b4', name: 'PaulT', wins: 37, losses: 71, playtime: 2635, codeLanguage: 'python'} + {team: 'humans', rank: 53, userID: '54ce3426c39305530570368c', sessionID: '5516a6c74d24212f05944ca9', name: 'Zenador', wins: 36, losses: 70, playtime: 6894, codeLanguage: 'javascript'} + {team: 'humans', rank: 54, userID: '550493e2836beb81054ad1c2', sessionID: '551822bc81389437054e089d', name: 'MrWooly', wins: 36, losses: 72, playtime: 440, codeLanguage: 'python'} + {team: 'humans', rank: 54, userID: '5501d57b3d219b9808c098e9', sessionID: '5517f863079f2833053c8413', name: 'Mouschti', wins: 36, losses: 72, playtime: 532, codeLanguage: 'javascript'} + {team: 'humans', rank: 54, userID: '535a3dd5f3c9943f0a4ed434', sessionID: '551f45faed37b43005e2c85d', name: 'Chankorinman', wins: 36, losses: 72, playtime: 581, codeLanguage: 'javascript'} + {team: 'humans', rank: 54, userID: '55156d00d792f354050c61ea', sessionID: '5519fe8c5afdf5320557e679', name: 'Pavel87', wins: 36, losses: 72, playtime: 1900, codeLanguage: 'python'} + {team: 'humans', rank: 54, userID: '5305df9df269d92647ceb862', sessionID: '551a81c2c13fa03205251429', name: 'TimTam', wins: 36, losses: 72, playtime: 1773, codeLanguage: 'python'} + {team: 'humans', rank: 59, userID: '54be1a95cfb4e9ab16128314', sessionID: '5516e7f758852c3405f487d2', name: 'Albertos', wins: 35, losses: 73, playtime: 335, codeLanguage: 'python'} + {team: 'humans', rank: 59, userID: '54dddee006024d52057534a0', sessionID: '551a4d835cd6bae409521577', name: 'ryu.dy', wins: 35, losses: 73, playtime: 4247, codeLanguage: 'python'} + {team: 'humans', rank: 61, userID: '548cf2d0457ef12c0922ce04', sessionID: '551680efc79ef1fd062b57df', name: 'Lee87', wins: 34, losses: 74, playtime: 243, codeLanguage: 'javascript'} + {team: 'humans', rank: 61, userID: '54f00e7cbc22bc830591b375', sessionID: '55222ad6d06c12300505737e', name: 'Fame7', wins: 34, losses: 74, playtime: 880, codeLanguage: 'python'} + {team: 'humans', rank: 61, userID: '527ba37865a2cf8339000efd', sessionID: '5516ea7758852c3405f48871', name: 'Elinus', wins: 34, losses: 74, playtime: 75, codeLanguage: 'javascript'} + {team: 'humans', rank: 61, userID: '54b87f637755bf5405a600f7', sessionID: '551dfedc4c73053505269424', name: 'Anonymous', wins: 34, losses: 74, playtime: 531, codeLanguage: 'javascript'} + {team: 'humans', rank: 61, userID: '55127452ee12f7580524512f', sessionID: '551c83fb4c73053505263a4e', name: 'Oxidis', wins: 34, losses: 74, playtime: 1526, codeLanguage: 'python'} + {team: 'humans', rank: 61, userID: '54f94d77802189c30518184c', sessionID: '550cffdfa605ba5a051205d6', name: 'OblivionOverlord', wins: 34, losses: 74, playtime: 4130, codeLanguage: 'python'} + {team: 'humans', rank: 67, userID: '5515d99c9f2b9c5305f56d5c', sessionID: '551ac6e24c7305350525bb5b', name: 'Anonymous', wins: 32, losses: 76, playtime: 5641, codeLanguage: 'javascript'} + {team: 'humans', rank: 67, userID: '540219a742fb9c380ad1eae3', sessionID: '551618f253665d3005251ae0', name: 'shadowfire', wins: 32, losses: 76, playtime: 1105, codeLanguage: 'javascript'} + {team: 'humans', rank: 69, userID: '5477bd26c439b9160865589f', sessionID: '5518a3a74c73053505253acf', name: 'anodinia', wins: 31, losses: 77, playtime: 231, codeLanguage: 'python'} + {team: 'humans', rank: 69, userID: '53346ca2523566907564fd53', sessionID: '5522edd6c9e6fd33051496ed', name: 'Ksionc', wins: 31, losses: 77, playtime: 289, codeLanguage: 'javascript'} + {team: 'humans', rank: 69, userID: '54f945e463684f2409c7d498', sessionID: '550cffe1a605ba5a051205d7', name: 'ItsBlitz', wins: 31, losses: 77, playtime: 4889, codeLanguage: 'python'} + {team: 'humans', rank: 72, userID: '5513153fad27c0b705c2829e', sessionID: '5516bb70b77a16330597e6e0', name: 'iPick', wins: 30, losses: 78, playtime: 1109, codeLanguage: 'javascript'} + {team: 'humans', rank: 72, userID: '53049f3350b42adb6e86e046', sessionID: '550cfffba605ba5a051205d8', name: 'gph004', wins: 30, losses: 78, playtime: 4679, codeLanguage: 'python'} + {team: 'humans', rank: 74, userID: '536eeed3bf08a63905efdd8a', sessionID: '550c79bca98c9c7f05ab05be', name: 'basicer', wins: 28, losses: 77, playtime: 1199, codeLanguage: 'lua'} + {team: 'humans', rank: 75, userID: '54623591da18079109220097', sessionID: '5518e6c01f12482609b47160', name: 'FreeKrad', wins: 29, losses: 79, playtime: 1384, codeLanguage: 'javascript'} + {team: 'humans', rank: 75, userID: '54cc2cf2f20cb05105c3d036', sessionID: '551bf5b24c73053505260370', name: 'Mihai2015', wins: 29, losses: 79, playtime: 1415, codeLanguage: 'python'} + {team: 'humans', rank: 75, userID: '550fe04ceb13a37c05136498', sessionID: '551ad43f5cd6bae409525096', name: 'FuzzicalLogic', wins: 29, losses: 79, playtime: 88327, codeLanguage: 'javascript'} + {team: 'humans', rank: 75, userID: '52d81ab38133efa92e0000d0', sessionID: '5515a7091a93145605a65bd9', name: 'DamienG002', wins: 29, losses: 79, playtime: 1619, codeLanguage: 'python'} + {team: 'humans', rank: 75, userID: '550161abf94fb5820504d6d9', sessionID: '551eb864d69ccd3305a4b4bd', name: 'Ien Clack', wins: 29, losses: 79, playtime: 610, codeLanguage: 'python'} + {team: 'humans', rank: 75, userID: '55080de2190b7bba08dab219', sessionID: '551f459f9800ae33059c539f', name: 'Anonymous', wins: 29, losses: 79, playtime: 651, codeLanguage: 'python'} + {team: 'humans', rank: 81, userID: '550fc1b5e8cfa180057bcf9a', sessionID: '551dbdb95afdf5320559095b', name: 'Jython', wins: 28, losses: 80, playtime: 965, codeLanguage: 'python'} + {team: 'humans', rank: 81, userID: '551711f88bdcbad0074fb07e', sessionID: '552189d56a8b7c22069934a6', name: 'GJW1', wins: 28, losses: 80, playtime: 320, codeLanguage: 'python'} + {team: 'humans', rank: 81, userID: '5391144f82f0bc470523c8ab', sessionID: '550cc74bca461f5705f3d144', name: 'Polaricicle', wins: 28, losses: 80, playtime: 5801, codeLanguage: 'python'} + {team: 'humans', rank: 84, userID: '548ae4ddaed203880bc9d72d', sessionID: '55213f1c85fca53105541f99', name: 'Brizar', wins: 26, losses: 82, playtime: 1827, codeLanguage: 'python'} + {team: 'humans', rank: 85, userID: '54fc40f847b0892406d7428c', sessionID: '550d004bca461f5705f3d1ed', name: 'galaxypantz', wins: 25, losses: 82, playtime: 3444, codeLanguage: 'python'} + {team: 'humans', rank: 86, userID: '55196a90e3ae3a3505f7fdcd', sessionID: '55196b035afdf5320557b249', name: 'zbx', wins: 24, losses: 84, playtime: 4048, codeLanguage: 'python'} + {team: 'humans', rank: 86, userID: '550d599a03cae479055c02bd', sessionID: '5516a33f58852c3405f47767', name: 'Ben0225', wins: 24, losses: 84, playtime: 6580, codeLanguage: 'python'} + {team: 'humans', rank: 88, userID: '55158827bf2bea55051d0a0a', sessionID: '551da49c5afdf532055901df', name: 'kpbochenek', wins: 22, losses: 82, playtime: 798, codeLanguage: 'python'} + {team: 'humans', rank: 89, userID: '547b41f59325e43e052e02a8', sessionID: '5515c3871a93145605a66b4b', name: 'Tamerlan4', wins: 23, losses: 84, playtime: 196, codeLanguage: 'javascript'} + {team: 'humans', rank: 90, userID: '53880299d06c503805fdd57e', sessionID: '5519aeb2c13fa0320524f401', name: 'Дор', wins: 22, losses: 85, playtime: 177, codeLanguage: 'python'} + {team: 'humans', rank: 91, userID: '550701ea75c0eb4a10ac7f4a', sessionID: '550d00bb9e22dc56056be0e5', name: 'Loh June Yong', wins: 22, losses: 86, playtime: 5443, codeLanguage: 'python'} + {team: 'humans', rank: 92, userID: '52a8f5e7a9fb033114000f08', sessionID: '55158154f43d375105fbdcf8', name: 'Mpgod1234', wins: 21, losses: 86, playtime: 558, codeLanguage: 'javascript'} + {team: 'humans', rank: 93, userID: '546e523a047aaa780854a46b', sessionID: '55087d90e810e35a09e335e8', name: 'Popey456963', wins: 21, losses: 87, playtime: 4724, codeLanguage: 'python'} + {team: 'humans', rank: 94, userID: '54f114d51022997e054ea52b', sessionID: '551d30c8e3ae3a3505f91191', name: 'F_Deity_Link', wins: 20, losses: 87, playtime: 1324, codeLanguage: 'lua'} + {team: 'humans', rank: 94, userID: '5515ffd982ee611b05aeb6f7', sessionID: '5516008aa174c81b05465604', name: 'Anonymous', wins: 20, losses: 87, playtime: 113, codeLanguage: 'javascript'} + {team: 'humans', rank: 96, userID: '54fad0665d8ec82806aad9bf', sessionID: '550d00129e22dc56056be0d7', name: 'vanessatan', wins: 19, losses: 89, playtime: 5013, codeLanguage: 'python'} + {team: 'humans', rank: 96, userID: '5487a14a4647d2b006cf7edd', sessionID: '551854a1e3ae3a3505f7c904', name: 'Endercore79', wins: 19, losses: 89, playtime: 769, codeLanguage: 'python'} + {team: 'humans', rank: 96, userID: '53416ac43a7f7a6358b7029a', sessionID: '55166a794d24212f05944596', name: 'Lylo', wins: 19, losses: 89, playtime: 359, codeLanguage: 'python'} + {team: 'humans', rank: 99, userID: '5470e99829e4c0710587df4c', sessionID: '5521b204abdb444805e883bb', name: 'Sthomas', wins: 18, losses: 89, playtime: 396, codeLanguage: 'javascript'} + {team: 'humans', rank: 99, userID: '54f240e481f9a6750530ed0c', sessionID: '5516db0153665d3005253b4d', name: 'Bosdet', wins: 18, losses: 89, playtime: 5448, codeLanguage: 'python'} + {team: 'humans', rank: 101, userID: '5495c837fcf9386d07d30866', sessionID: '550c73e1a98c9c7f05ab03ac', name: 'awesome3000', wins: 18, losses: 90, playtime: 2586, codeLanguage: 'python'} + {team: 'humans', rank: 102, userID: '54c3a0aa83b9575305363fbd', sessionID: '5515f79482ee611b05aeb454', name: 'ninja_star', wins: 17, losses: 90, playtime: 423, codeLanguage: 'javascript'} + {team: 'humans', rank: 103, userID: '54cbaa236947cf5405dab7e4', sessionID: '550cd526ca461f5705f3d1a0', name: 'hannie', wins: 16, losses: 90, playtime: 2400, codeLanguage: 'python'} + {team: 'humans', rank: 104, userID: '550cc15b0f7e6ece0684a2d4', sessionID: '550cc195fa4ee5e0062ed84d', name: 'The AI', wins: 15, losses: 92, playtime: 385, codeLanguage: 'clojure'} + {team: 'humans', rank: 105, userID: '546656d5f5522b9805dfd4ca', sessionID: '551f09a0921f633305d4d7d8', name: '1234526', wins: 15, losses: 93, playtime: 909, codeLanguage: 'javascript'} + {team: 'humans', rank: 106, userID: '5500418620b2567d0514b763', sessionID: '550d0037a605ba5a051205da', name: 'luxedlyani', wins: 14, losses: 94, playtime: 5487, codeLanguage: 'python'} + {team: 'humans', rank: 106, userID: '532795fcd2a31ed46c63770e', sessionID: '55205354be496e310568fe50', name: 'kevbot', wins: 14, losses: 94, playtime: 2118, codeLanguage: 'python'} + {team: 'humans', rank: 108, userID: '53de2603f9fd4335057a50ca', sessionID: '551632595ab8ae3105cad77a', name: 'Sunnyau', wins: 12, losses: 96, playtime: 9882, codeLanguage: 'python'} + {team: 'humans', rank: 109, userID: '550aa9c9c731583007335e14', sessionID: '55158850d792f354050c7eb5', name: 'Anonymous', wins: 11, losses: 97, playtime: 137, codeLanguage: 'python'} + {team: 'humans', rank: 110, userID: '551095ad3ab45d7d05d0290f', sessionID: '55209eeed06c123005054edf', name: 'The Dark Slayer 365', wins: 10, losses: 98, playtime: 695, codeLanguage: 'python'} + {team: 'humans', rank: 111, userID: '5519cb4ae3ae3a3505f828fe', sessionID: '551a570dd69ccd3305a34080', name: 'weiyun', wins: 9, losses: 99, playtime: 2574, codeLanguage: 'python'} + {team: 'humans', rank: 112, userID: '551285ff39ac155805f4aa0a', sessionID: '551e83bee311d80c07b35d46', name: 'M. Vincent', wins: 8, losses: 100, playtime: 6127, codeLanguage: 'javascript'} + {team: 'humans', rank: 113, userID: '54f62d7d50181a8505f97e1d', sessionID: '551f1f29526d5e3505807c00', name: 'Oscha Esservic', wins: 0, losses: 108, playtime: 386, codeLanguage: 'javascript'} + {team: 'humans', rank: 113, userID: '52cfa17ec0e2ea5d17001149', sessionID: '551716f258852c3405f49269', name: 'DarkLynk', wins: 0, losses: 108, playtime: 189, codeLanguage: 'python'} + {team: 'humans', rank: 113, userID: '54f1f2f89bc914830528271f', sessionID: '550cc75a9e22dc56056bdfe4', name: 'Reilord', wins: 0, losses: 108, playtime: 4752, codeLanguage: 'python'} + {team: 'humans', rank: 113, userID: '54aab1313feb6a3f05f20854', sessionID: '551c82a25cd6bae409530abb', name: 'Flamethowerland', wins: 0, losses: 108, playtime: 506, codeLanguage: 'python'} +] + +results['zero-sum'].ogres = [ + {team: 'ogres', rank: 1, userID: '532dbc73a622924444b68ed9', sessionID: '551599a499d51b55053606f2', name: 'Wizard Dude', wins: 162, losses: 1, playtime: 43223, codeLanguage: 'javascript'} + {team: 'ogres', rank: 2, userID: '54ffc9b8a043d19b0a457309', sessionID: '551e1a2ae3ae3a3505f96090', name: 'xxx987654321', wins: 157, losses: 5, playtime: 11649, codeLanguage: 'python'} + {team: 'ogres', rank: 3, userID: '531c8c3ccf439d790a23af04', sessionID: '550c2f5c1cd64bb7050fc8e5', name: 'nemoyatpeace', wins: 153, losses: 9, playtime: 4171, codeLanguage: 'python'} + {team: 'ogres', rank: 4, userID: '54ccc53ab4fb475505282187', sessionID: '55168b6353665d3005252860', name: 'ImDev', wins: 152, losses: 10, playtime: 4842, codeLanguage: 'python'} + {team: 'ogres', rank: 5, userID: '551995ec5cd6bae40951dec9', sessionID: '5519969e5cd6bae40951df59', name: 'wrdctr', wins: 151, losses: 11, playtime: 22070, codeLanguage: 'python'} + {team: 'ogres', rank: 5, userID: '54d9a5d2a9bd9f57050fe822', sessionID: '550c48b13045b78405c96775', name: 'Vlevo', wins: 151, losses: 11, playtime: 41246, codeLanguage: 'clojure'} + {team: 'ogres', rank: 7, userID: '548b8c556c32e64e1c437957', sessionID: '551625ac5ab8ae3105cad65f', name: 'Nisha Noire', wins: 150, losses: 12, playtime: 6977, codeLanguage: 'python'} + {team: 'ogres', rank: 7, userID: '551824a31f12482609b44fad', sessionID: '55185272d69ccd3305a2ba9d', name: 'Ovrmrrw', wins: 150, losses: 12, playtime: 4139, codeLanguage: 'python'} + {team: 'ogres', rank: 9, userID: '5503ac1a2c5fbf7b056a0eff', sessionID: '551766524c7305350525145f', name: 'David C Ellis', wins: 147, losses: 14, playtime: 5804, codeLanguage: 'javascript'} + {team: 'ogres', rank: 10, userID: '5452ed0623ef1e5d089d31e2', sessionID: '55164ac8de8bc0320597591e', name: 'Vivaldi', wins: 146, losses: 15, playtime: 20229, codeLanguage: 'python'} + {team: 'ogres', rank: 11, userID: '52debd1b5432dcf11c000164', sessionID: '55162fc358852c3405f468f6', name: 'Agathanar', wins: 144, losses: 18, playtime: 13849, codeLanguage: 'python'} + {team: 'ogres', rank: 12, userID: '55169fb1de8bc03205976007', sessionID: '5516bbd7aedec33205e8b3c4', name: 'XN137', wins: 140, losses: 22, playtime: 44494, codeLanguage: 'javascript'} + {team: 'ogres', rank: 13, userID: '55172d51502e8b37053130b2', sessionID: '551840461f12482609b45518', name: 'Sean653', wins: 140, losses: 23, playtime: 5501, codeLanguage: 'javascript'} + {team: 'ogres', rank: 14, userID: '5512ef72a4febf5905274f07', sessionID: '551851355afdf53205577ac4', name: 'Vincent Maths', wins: 137, losses: 25, playtime: 2812, codeLanguage: 'javascript'} + {team: 'ogres', rank: 15, userID: '526a4e91c0a4f3a21f000c50', sessionID: '5516728baedec33205e8a5b9', name: 'spicydog', wins: 133, losses: 28, playtime: 3790, codeLanguage: 'python'} + {team: 'ogres', rank: 16, userID: '5511931af72de65605f988b4', sessionID: '5515a3e3bf2bea55051d2225', name: 'Deipablo', wins: 130, losses: 32, playtime: 9331, codeLanguage: 'javascript'} + {team: 'ogres', rank: 17, userID: '5515b4e1fd67e4b4095aaa5f', sessionID: '5515c034d792f354050ca69e', name: 'i_eet_leefs', wins: 128, losses: 34, playtime: 158, codeLanguage: 'python'} + {team: 'ogres', rank: 18, userID: '54ab32c13feb6a3f05f55e94', sessionID: '5515debc64a969570abf9827', name: 'SaladTongs', wins: 125, losses: 37, playtime: 26496, codeLanguage: 'python'} + {team: 'ogres', rank: 19, userID: '54cb0fbd0623615605392f74', sessionID: '550cc86d9e22dc56056bdfec', name: 'Dragernix', wins: 124, losses: 38, playtime: 4365, codeLanguage: 'python'} + {team: 'ogres', rank: 19, userID: '54f609476b0774880597fdd4', sessionID: '55171a58b77a16330597f89e', name: 'Danylo Dubinin', wins: 124, losses: 38, playtime: 6951, codeLanguage: 'python'} + {team: 'ogres', rank: 21, userID: '549aed0eb530133e053a3acc', sessionID: '55159f149f2b9c5305f551a0', name: 'Spencer Tachick', wins: 123, losses: 39, playtime: 12292, codeLanguage: 'python'} + {team: 'ogres', rank: 21, userID: '5507e6c8e7d9907b054a61e9', sessionID: '55167b894d24212f05944728', name: 'NormannK', wins: 123, losses: 39, playtime: 9490, codeLanguage: 'python'} + {team: 'ogres', rank: 23, userID: '549b8ead1880d5b7065ff57c', sessionID: '55161e90aedec33205e89e2c', name: 'Dymarr', wins: 116, losses: 46, playtime: 281, codeLanguage: 'python'} + {team: 'ogres', rank: 24, userID: '53ca0f0aaa30cd860586b24f', sessionID: '5521bf1b32954a32050203ba', name: 'Edgar', wins: 115, losses: 47, playtime: 4999, codeLanguage: 'javascript'} + {team: 'ogres', rank: 25, userID: '54fdacd0106d15f105fc7d4c', sessionID: '550cfffbca461f5705f3d1ec', name: 'Midhat', wins: 114, losses: 48, playtime: 5557, codeLanguage: 'python'} + {team: 'ogres', rank: 26, userID: '54f5d94c9be7567905e95099', sessionID: '551d1124d69ccd3305a43329', name: 's_a_n_d', wins: 114, losses: 49, playtime: 3905, codeLanguage: 'javascript'} + {team: 'ogres', rank: 27, userID: '5515ff2482ee611b05aeb6c6', sessionID: '5515ff641bfec61c050245ab', name: 'Carl Maxwell', wins: 113, losses: 48, playtime: 10208, codeLanguage: 'python'} + {team: 'ogres', rank: 28, userID: '55066eefce02078605ce9126', sessionID: '550d29999e22dc56056be28a', name: 'Koyint', wins: 113, losses: 49, playtime: 524, codeLanguage: 'python'} + {team: 'ogres', rank: 29, userID: '5517d8b0e3ae3a3505f7b73d', sessionID: '5517de29079f2833053c8108', name: 'aknopf', wins: 113, losses: 50, playtime: 203, codeLanguage: 'python'} + {team: 'ogres', rank: 30, userID: '54ffbe6ee950f7a707ec9577', sessionID: '550cc7bc9e22dc56056bdfe9', name: 'chuayupeng', wins: 112, losses: 50, playtime: 4602, codeLanguage: 'python'} + {team: 'ogres', rank: 31, userID: '5506889b127bb387059def67', sessionID: '550d001435dc145905672238', name: 'En Hao', wins: 111, losses: 51, playtime: 5234, codeLanguage: 'python'} + {team: 'ogres', rank: 32, userID: '527bdd42dd3c4aea37001500', sessionID: '55159c75b8185a5205e183dc', name: 'Makaze', wins: 109, losses: 53, playtime: 2213, codeLanguage: 'coffeescript'} + {team: 'ogres', rank: 33, userID: '55181575e3ae3a3505f7bf46', sessionID: '55191d035afdf532055796d6', name: 'Satellite One', wins: 106, losses: 51, playtime: 16911, codeLanguage: 'python'} + {team: 'ogres', rank: 34, userID: '54b1773a75e3055205e5a449', sessionID: '550c3a98535111cc0539a3f9', name: 'Catsync', wins: 107, losses: 54, playtime: 381, codeLanguage: 'javascript'} + {team: 'ogres', rank: 35, userID: '53a0bc84610a6b3505561811', sessionID: '5516185f53665d3005251ac7', name: 'Fluzzarn', wins: 102, losses: 60, playtime: 1835, codeLanguage: 'javascript'} + {team: 'ogres', rank: 36, userID: '5516bf048bdcbad0074f9c29', sessionID: '5516d0a258852c3405f481da', name: 'Expote2', wins: 100, losses: 62, playtime: 4576, codeLanguage: 'python'} + {team: 'ogres', rank: 37, userID: '54ff5e1a00e4485a07e76bb9', sessionID: '5515ac67fd67e4b4095aa52f', name: 'Twonky', wins: 96, losses: 66, playtime: 6772, codeLanguage: 'python'} + {team: 'ogres', rank: 38, userID: '550003910f91fab20b3624e8', sessionID: '550d00439e22dc56056be0de', name: 'CyanLycan', wins: 95, losses: 66, playtime: 5482, codeLanguage: 'python'} + {team: 'ogres', rank: 39, userID: '54f2b39381f9a6750530f893', sessionID: '550ccb259e22dc56056be001', name: 'Flamanta', wins: 95, losses: 68, playtime: 4734, codeLanguage: 'python'} + {team: 'ogres', rank: 40, userID: '54f0775615cde87c05d6caf4', sessionID: '550cc7ef35dc1459056721be', name: 'Jericho Chua', wins: 93, losses: 69, playtime: 4409, codeLanguage: 'python'} + {team: 'ogres', rank: 41, userID: '539bfd0930a67c3b05d93f2a', sessionID: '55158a0bf43d375105fbe4ec', name: 'reezer', wins: 93, losses: 70, playtime: 5116, codeLanguage: 'javascript'} + {team: 'ogres', rank: 42, userID: '54d2c4024e4a08550556e01c', sessionID: '550cd3269e22dc56056be050', name: 'Alaete', wins: 92, losses: 69, playtime: 1804, codeLanguage: 'python'} + {team: 'ogres', rank: 43, userID: '53e2f1046c59f534050411f3', sessionID: '550d000e35dc145905672236', name: 'Live2Deliver', wins: 91, losses: 71, playtime: 5362, codeLanguage: 'python'} + {team: 'ogres', rank: 44, userID: '5517858d079f2833053c79a7', sessionID: '551786c7e3ae3a3505f7b0f6', name: 'Kevbot5000', wins: 88, losses: 72, playtime: 93126, codeLanguage: 'javascript'} + {team: 'ogres', rank: 45, userID: '54f3527fde0f173f14215f40', sessionID: '552210f33ffd333305f2e9b5', name: 'Anonymous', wins: 88, losses: 73, playtime: 346, codeLanguage: 'javascript'} + {team: 'ogres', rank: 46, userID: '55184fc7c13fa0320524a596', sessionID: '5518516ac13fa0320524a5f1', name: 'Mossan', wins: 85, losses: 77, playtime: 11842, codeLanguage: 'python'} + {team: 'ogres', rank: 47, userID: '539bb1d46e1d92310506ec6b', sessionID: '551ab214d69ccd3305a35b6c', name: 'Belackarad', wins: 84, losses: 78, playtime: 2921, codeLanguage: 'python'} + {team: 'ogres', rank: 48, userID: '534316e1d9a976607ace1f48', sessionID: '5518c7954c73053505253f23', name: 'Racksickle', wins: 84, losses: 79, playtime: 4118, codeLanguage: 'javascript'} + {team: 'ogres', rank: 49, userID: '5515b3d599d51b55053619e3', sessionID: '5517f05fe3ae3a3505f7b998', name: 'Crul', wins: 82, losses: 81, playtime: 99, codeLanguage: 'javascript'} + {team: 'ogres', rank: 50, userID: '548bc8bdcb1a6d754f530ef9', sessionID: '5518c2a0d69ccd3305a2cd93', name: 'MonkeykingZach1', wins: 80, losses: 82, playtime: 2904, codeLanguage: 'javascript'} + {team: 'ogres', rank: 51, userID: '54ea122b6a05ed9a0803f20b', sessionID: '55181b4de3ae3a3505f7c028', name: 'All3ck', wins: 77, losses: 84, playtime: 16269, codeLanguage: 'python'} + {team: 'ogres', rank: 52, userID: '5522bf863ffd333305f30ef5', sessionID: '5522c90cabdb444805e8c0b9', name: 'Fireball42', wins: 73, losses: 87, playtime: 3431, codeLanguage: 'javascript'} + {team: 'ogres', rank: 53, userID: '5514a8636b06ed1e09bc4c01', sessionID: '55204b8ffe6383360550157d', name: 'Hephaestus2', wins: 73, losses: 89, playtime: 1162, codeLanguage: 'python'} + {team: 'ogres', rank: 54, userID: '539189a2ff512d470582a570', sessionID: '550cc7f3a605ba5a0512050f', name: 'Lee Yang Peng', wins: 72, losses: 88, playtime: 5743, codeLanguage: 'python'} + {team: 'ogres', rank: 55, userID: '546e31004a0dd3de07f2b3f0', sessionID: '5515a3c3518f4e1409379f15', name: 'Blauelf', wins: 72, losses: 91, playtime: 119, codeLanguage: 'python'} + {team: 'ogres', rank: 56, userID: '55125f4ba4febf590526f3ea', sessionID: '551a8d32d69ccd3305a34b40', name: 'Yan4ik', wins: 71, losses: 91, playtime: 7018, codeLanguage: 'python'} + {team: 'ogres', rank: 57, userID: '54cba6498a09e554056f7e83', sessionID: '550cce4f9e22dc56056be01a', name: 'Skyhawk5', wins: 70, losses: 92, playtime: 1415, codeLanguage: 'python'} + {team: 'ogres', rank: 58, userID: '550126ad9201157c05677836', sessionID: '550d003ba605ba5a051205dc', name: 'ohichimaru', wins: 66, losses: 96, playtime: 5118, codeLanguage: 'python'} + {team: 'ogres', rank: 59, userID: '54ea04ede90cfb5005381cae', sessionID: '550d00bc9e22dc56056be0e6', name: 'fafazirah', wins: 65, losses: 98, playtime: 2494, codeLanguage: 'python'} + {team: 'ogres', rank: 60, userID: '54fd92b847b0892406d76ee6', sessionID: '550d015d9e22dc56056be0f2', name: 'Soon Wei', wins: 64, losses: 98, playtime: 5270, codeLanguage: 'python'} + {team: 'ogres', rank: 61, userID: '537d66783dcf67c40571fce9', sessionID: '550976d42e7f640f07bf7cbc', name: 'ProfBoesch', wins: 61, losses: 101, playtime: 2684, codeLanguage: 'python'} + {team: 'ogres', rank: 62, userID: '54ef1ac12fd7dd55052b4bf6', sessionID: '550cc78ea605ba5a0512050d', name: 'ZoppyOS', wins: 60, losses: 101, playtime: 5566, codeLanguage: 'python'} + {team: 'ogres', rank: 63, userID: '54f1e0f2d2969f8405ef6e93', sessionID: '550d03639e22dc56056be123', name: 'hongyue1995', wins: 57, losses: 104, playtime: 3402, codeLanguage: 'python'} + {team: 'ogres', rank: 64, userID: '53b54cda7e17883a0575767a', sessionID: '5515bde81c3bb18709e26cd3', name: 'JavaCaster1', wins: 55, losses: 106, playtime: 91, codeLanguage: 'javascript'} + {team: 'ogres', rank: 65, userID: '54e3389fab6f345305701d9d', sessionID: '550d003a35dc145905672239', name: 'Aswin A', wins: 54, losses: 108, playtime: 4830, codeLanguage: 'python'} + {team: 'ogres', rank: 66, userID: '53b8f7ab3a63df45051b31d6', sessionID: '551ff648b10646310516d109', name: 'Elizabeth20', wins: 46, losses: 117, playtime: 3329, codeLanguage: 'javascript'} + {team: 'ogres', rank: 67, userID: '54f82214cebfc7450c16bbe9', sessionID: '550cc7f49e22dc56056bdfeb', name: 'Chaoxide', wins: 45, losses: 118, playtime: 5296, codeLanguage: 'python'} + {team: 'ogres', rank: 68, userID: '54fa96ce9ae7221e0672306b', sessionID: '550cc7e29e22dc56056bdfea', name: 'Xyrilyn', wins: 41, losses: 121, playtime: 5516, codeLanguage: 'python'} + {team: 'ogres', rank: 69, userID: '54f420d8c43ea77705a27522', sessionID: '550cc78535dc1459056721bd', name: 'WangLu', wins: 40, losses: 122, playtime: 5460, codeLanguage: 'python'} + {team: 'ogres', rank: 70, userID: '54a976c1b9a10c3e059a5414', sessionID: '551c623f8328b9020decd431', name: 'germ13', wins: 35, losses: 127, playtime: 4753, codeLanguage: 'python'} + {team: 'ogres', rank: 71, userID: '52619a3e99987a8a0900009e', sessionID: '5516d34058852c3405f48284', name: 'iTruth', wins: 35, losses: 128, playtime: 5077, codeLanguage: 'javascript'} + {team: 'ogres', rank: 72, userID: '55197724e3ae3a3505f80446', sessionID: '551977265cd6bae40951cafb', name: 'Stowned', wins: 30, losses: 133, playtime: 1594, codeLanguage: 'python'} + {team: 'ogres', rank: 73, userID: '546e6be7da3c21f30848d235', sessionID: '551c5c0c1794dc1a112c536c', name: 'Jonas5', wins: 28, losses: 135, playtime: 663, codeLanguage: 'python'} + {team: 'ogres', rank: 73, userID: '55098a62a2012e800a354350', sessionID: '551dae53e3ae3a3505f94fb9', name: 'coding6', wins: 28, losses: 135, playtime: 66, codeLanguage: 'python'} + {team: 'ogres', rank: 73, userID: '54f160550ac4bd7c05458e7e', sessionID: '55166f02aedec33205e8a541', name: 'Dima2006', wins: 28, losses: 135, playtime: 61, codeLanguage: 'javascript'} + {team: 'ogres', rank: 76, userID: '54f8b3237a5c02820877960e', sessionID: '551aec19e3ae3a3505f87585', name: 'JakeWolt20', wins: 28, losses: 136, playtime: 34, codeLanguage: 'python'} + {team: 'ogres', rank: 77, userID: '54c6a197c597612313ca1520', sessionID: '5519a05c4c7305350525799e', name: 'maxx89', wins: 27, losses: 136, playtime: 408, codeLanguage: 'javascript'} + {team: 'ogres', rank: 78, userID: '550cc15b0f7e6ece0684a2d4', sessionID: '550cc20735f6fd2807b877ae', name: 'The AI', wins: 24, losses: 135, playtime: 128, codeLanguage: 'clojure'} + {team: 'ogres', rank: 79, userID: '54903e1e6f2e23450a4fd7ac', sessionID: '5519e6bc8328b9020debf33f', name: 'kev0', wins: 15, losses: 147, playtime: 3459, codeLanguage: 'python'} + {team: 'ogres', rank: 80, userID: '54fe734f834d927905307753', sessionID: '5515cefa1a93145605a66f9e', name: 'Anonymous', wins: 14, losses: 149, playtime: 1002, codeLanguage: 'python'} +] diff --git a/app/views/play/CampaignView.coffee b/app/views/play/CampaignView.coffee index c62c93d44..d83abe3a2 100644 --- a/app/views/play/CampaignView.coffee +++ b/app/views/play/CampaignView.coffee @@ -20,6 +20,7 @@ ShareProgressModal = require 'views/play/modal/ShareProgressModal' UserPollsRecord = require 'models/UserPollsRecord' Poll = require 'models/Poll' PollModal = require 'views/play/modal/PollModal' +storage = require 'core/storage' trackedHourOfCode = false @@ -148,10 +149,11 @@ module.exports = class CampaignView extends RootView @render() @preloadTopHeroes() unless me.get('heroConfig')?.thangType @$el.find('#campaign-status').delay(4000).animate({top: "-=58"}, 1000) unless @terrain is 'dungeon' - if @terrain and me.get('name') and me.get('lastLevel') in ['forgetful-gemsmith', 'signs-and-portents'] + if @terrain and me.get('anonymous') and me.get('lastLevel') is 'shadow-guard' and me.level() < 4 + @openModalView new AuthModal supermodel: @supermodel, showSignupRationale: true, mode: 'signup' + else if @terrain and me.get('name') and me.get('lastLevel') in ['forgetful-gemsmith', 'signs-and-portents'] and me.level() < 5 and not (me.get('ageRange') in ['18-24', '25-34', '35-44', '45-100']) and not storage.load('sent-parent-email') @openModalView new ShareProgressModal() - setCampaign: (@campaign) -> @render() @@ -198,7 +200,7 @@ module.exports = class CampaignView extends RootView if @campaigns context.campaigns = {} - for campaign in @campaigns.models + for campaign in @campaigns.models when campaign.get('slug') isnt 'auditions' context.campaigns[campaign.get('slug')] = campaign if @sessions.loaded levels = _.values($.extend true, {}, campaign.get('levels') ? {}) @@ -276,10 +278,14 @@ module.exports = class CampaignView extends RootView countLevels: (levels) -> count = total: 0, completed: 0 - for level in levels + for level, levelIndex in levels @annotateLevel level unless level.locked? # Annotate if we haven't already. unless level.disabled - ++count.total + unlockedInSameCampaign = levelIndex < 5 # First few are always counted (probably unlocked in previous campaign) + for otherLevel in levels when not unlockedInSameCampaign and otherLevel isnt level + for reward in (otherLevel.rewards ? []) when reward.level + unlockedInSameCampaign ||= reward.level is level.original + ++count.total if unlockedInSameCampaign or not level.locked ++count.completed if @levelStatusMap[level.slug] is 'complete' count @@ -295,7 +301,12 @@ module.exports = class CampaignView extends RootView unless foundNext for nextLevelOriginal in level.nextLevels nextLevel = _.find levels, original: nextLevelOriginal - if nextLevel and not nextLevel.locked and @levelStatusMap[nextLevel.slug] isnt 'complete' and (me.isPremium() or not nextLevel.requiresSubscription or nextLevel.slug is 'apocalypse') + if nextLevel and not nextLevel.locked and @levelStatusMap[nextLevel.slug] isnt 'complete' and ( + me.isPremium() or + not nextLevel.requiresSubscription or + nextLevel.slug is 'apocalypse' or + (nextLevel.slug is 'favorable-odds' and not @levelStatusMap['the-raised-sword']) + ) nextLevel.next = true foundNext = true break @@ -334,7 +345,7 @@ module.exports = class CampaignView extends RootView @particleMan ?= new ParticleMan() @particleMan.removeEmitters() @particleMan.attach @$el.find('.map') - for level in @campaign.renderedLevels ? {} when level.hidden or level.slug is 'apocalypse' + for level in @campaign.renderedLevels ? {} when level.hidden or (level.slug is 'apocalypse' and @levelStatusMap[level.slug] isnt 'complete') particleKey = ['level', @terrain] particleKey.push level.type if level.type and level.type isnt 'hero' particleKey.push 'premium' if level.requiresSubscription @@ -433,7 +444,7 @@ module.exports = class CampaignView extends RootView level = _.find _.values(@campaign.get('levels')), slug: levelSlug requiresSubscription = level.requiresSubscription or (me.get('chinaVersion') and not (level.slug in ['dungeons-of-kithgard', 'gems-in-the-deep', 'shadow-guard', 'forgetful-gemsmith', 'signs-and-portents', 'true-names'])) - canPlayAnyway = not @requiresSubscription or level.adventurer + canPlayAnyway = not @requiresSubscription or level.adventurer or @levelStatusMap[level.slug] if requiresSubscription and not canPlayAnyway @openModalView new SubscribeModal() window.tracker?.trackEvent 'Show subscription modal', category: 'Subscription', label: 'map level clicked', level: levelSlug diff --git a/app/views/play/level/modal/HeroVictoryModal.coffee b/app/views/play/level/modal/HeroVictoryModal.coffee index ddea82ed7..61381823b 100644 --- a/app/views/play/level/modal/HeroVictoryModal.coffee +++ b/app/views/play/level/modal/HeroVictoryModal.coffee @@ -26,6 +26,7 @@ module.exports = class HeroVictoryModal extends ModalView 'click .leaderboard-button': 'onClickLeaderboard' 'click .return-to-ladder-button': 'onClickReturnToLadder' 'click .sign-up-button': 'onClickSignupButton' + 'click .continue-from-offer-button': 'onClickContinueFromOffer' constructor: (options) -> super(options) @@ -339,7 +340,11 @@ module.exports = class HeroVictoryModal extends ModalView justBeatLevel: @level supermodel: if @options.hasReceivedMemoryWarning then null else @supermodel _.merge options, extraOptions if extraOptions - Backbone.Mediator.publish 'router:navigate', route: nextLevelLink, viewClass: require('views/play/CampaignView'), viewArgs: [options, @getNextLevelCampaign()] + navigationEvent = route: nextLevelLink, viewClass: require('views/play/CampaignView'), viewArgs: [options, @getNextLevelCampaign()] + if @level.get('slug') is 'lost-viking' and not (me.get('age') in ['0-13', '14-17']) + @showOffer navigationEvent + else + Backbone.Mediator.publish 'router:navigate', navigationEvent onClickLeaderboard: (e) -> @onClickContinue e, showLeaderboard: true @@ -355,3 +360,14 @@ module.exports = class HeroVictoryModal extends ModalView e.preventDefault() window.tracker?.trackEvent 'Started Signup', category: 'Play Level', label: 'Hero Victory Modal', level: @level.get('slug') @openModalView new AuthModal {mode: 'signup'} + + showOffer: (@navigationEventUponCompletion) -> + @$el.find('.modal-footer > *').hide() + @$el.find(".modal-footer > .offer.#{@level.get('slug')}").show() + + onClickContinueFromOffer: (e) -> + url = { + 'lost-viking': 'http://www.vikingcodeschool.com/codecombat?utm_source=codecombat&utm_medium=viking_level&utm_campaign=affiliate&ref=Code+Combat+Elite' + }[@level.get('slug')] + Backbone.Mediator.publish 'router:navigate', @navigationEventUponCompletion + window.open url, '_blank' if url diff --git a/app/views/play/level/tome/SpellListTabEntryView.coffee b/app/views/play/level/tome/SpellListTabEntryView.coffee index 3a2b9945e..65113cd1e 100644 --- a/app/views/play/level/tome/SpellListTabEntryView.coffee +++ b/app/views/play/level/tome/SpellListTabEntryView.coffee @@ -154,7 +154,7 @@ module.exports = class SpellListTabEntryView extends SpellListEntryView break $codearea = $('#code-area') $codearea.on transitionListener, => - $codearea.css 'z-index', 1 unless $('html').hasClass 'fullscreen-editor' + $codearea.css 'z-index', 2 unless $('html').hasClass 'fullscreen-editor' destroy: -> diff --git a/app/views/play/modal/LeaderboardModal.coffee b/app/views/play/modal/LeaderboardModal.coffee index 2e33093fe..6b0b1bd05 100644 --- a/app/views/play/modal/LeaderboardModal.coffee +++ b/app/views/play/modal/LeaderboardModal.coffee @@ -19,7 +19,9 @@ module.exports = class LeaderboardModal extends ModalView constructor: (options) -> super options @levelSlug = @options.levelSlug - @level = @supermodel.loadModel(new Level({_id: @levelSlug}, {project: ['name', 'i18n', 'scoreType', 'original']}), 'level').model + level = new Level({_id: @levelSlug}) + level.project = ['name', 'i18n', 'scoreType', 'original'] + @level = @supermodel.loadModel(level, 'level').model getRenderData: (c) -> c = super c diff --git a/app/views/play/modal/ShareProgressModal.coffee b/app/views/play/modal/ShareProgressModal.coffee index 39b9efe47..4b3c34943 100644 --- a/app/views/play/modal/ShareProgressModal.coffee +++ b/app/views/play/modal/ShareProgressModal.coffee @@ -1,5 +1,6 @@ ModalView = require 'views/core/ModalView' template = require 'templates/play/modal/share-progress-modal' +storage = require 'core/storage' module.exports = class SubscribeModal extends ModalView id: 'share-progress-modal' @@ -8,33 +9,9 @@ module.exports = class SubscribeModal extends ModalView closesOnClickOutside: false events: - 'click .back-link': 'onBackClick' 'click .close-btn': 'hide' 'click .continue-link': 'hide' 'click .send-btn': 'onClickSend' - 'click .tell-friend-btn': 'onClickTellFriend' - 'click .tell-parent-btn': 'onClickTellParent' - - onBackClick: (e) -> - $('.email-input').val('') - $('.send-container').hide() - $('.friend-blurb').hide() - $('.parent-blurb').hide() - $('.btn-picker-container').show() - $('.email-input').parent().removeClass('has-error') - $('.email-invalid').hide() - - onClickTellFriend: (e) -> - @emailType = 'share progress modal friend' - $('.btn-picker-container').hide() - $('.friend-blurb').show() - $('.send-container').show() - - onClickTellParent: (e) -> - @emailType = 'share progress modal parent' - $('.btn-picker-container').hide() - $('.parent-blurb').show() - $('.send-container').show() onClickSend: (e) -> email = $('.email-input').val() @@ -45,9 +22,10 @@ module.exports = class SubscribeModal extends ModalView request = @supermodel.addRequestResource 'send_one_time_email', { url: '/db/user/-/send_one_time_email' - data: {email: email, type: @emailType} + data: {email: email, type: 'share progress modal parent'} method: 'POST' }, 0 request.load() + storage.save 'sent-parent-email', true @hide() diff --git a/config.coffee b/config.coffee index e426a7aec..03d7b4a1e 100644 --- a/config.coffee +++ b/config.coffee @@ -199,6 +199,8 @@ exports.config = sass: mode: 'ruby' allowCache: true + bless: + cacheBuster: false modules: definition: (path, data) -> diff --git a/server/commons/Handler.coffee b/server/commons/Handler.coffee index 44f459518..844b81e10 100644 --- a/server/commons/Handler.coffee +++ b/server/commons/Handler.coffee @@ -206,13 +206,15 @@ module.exports = class Handler return @sendForbiddenError(res) getById: (req, res, id) -> - # return @sendNotFoundError(res) # for testing return @sendForbiddenError(res) unless @hasAccess(req) - - @getDocumentForIdOrSlug id, (err, document) => + if req.query.project + projection = {} + projection[field] = 1 for field in req.query.project.split(',') + @getDocumentForIdOrSlug id, projection, (err, document) => return @sendDatabaseError(res, err) if err return @sendNotFoundError(res) unless document? return @sendForbiddenError(res) unless @hasAccessToDocument(req, document) + res.setHeader 'Cache-Control', 'no-cache' unless Handler.isID(id + '') # Don't cache if it's a slug instead of an ID @sendSuccess(res, @formatEntity(req, document)) getByRelationship: (req, res, args...) -> @@ -490,14 +492,18 @@ module.exports = class Handler @isID: (id) -> _.isString(id) and id.length is 24 and id.match(/[a-f0-9]/gi)?.length is 24 - getDocumentForIdOrSlug: (idOrSlug, done) -> + getDocumentForIdOrSlug: (idOrSlug, projection, done) -> + unless done + done = projection # projection is optional argument + projection = null idOrSlug = idOrSlug+'' if Handler.isID(idOrSlug) - @modelClass.findById(idOrSlug).exec (err, document) -> - done(err, document) + query = @modelClass.findById(idOrSlug) else - @modelClass.findOne {slug: idOrSlug}, (err, document) -> - done(err, document) + query = @modelClass.findOne {slug: idOrSlug} + query.select projection if projection + query.exec (err, document) -> + done(err, document) doWaterfallChecks: (req, document, done) -> return done(null, document) unless @waterfallFunctions.length diff --git a/server/levels/level_handler.coffee b/server/levels/level_handler.coffee index 5c14ac20a..97fab4513 100644 --- a/server/levels/level_handler.coffee +++ b/server/levels/level_handler.coffee @@ -158,7 +158,8 @@ LevelHandler = class LevelHandler extends Handler majorVersion: level.version.major creator: req.user._id+'' - query = Session.find(sessionQuery).select('-screenshot') + query = Session.find(sessionQuery).select('-screenshot -transpiledCode') + # TODO: take out "code" as well, since that can get huge containing the transpiled code for the lat hero, and find another way of having the LadderSubmissionViews in the MyMatchesTab determine rankin readiness query.exec (err, results) => if err then @sendDatabaseError(res, err) else @sendSuccess res, results diff --git a/server/levels/sessions/level_session_handler.coffee b/server/levels/sessions/level_session_handler.coffee index 208b68071..5e4780d89 100644 --- a/server/levels/sessions/level_session_handler.coffee +++ b/server/levels/sessions/level_session_handler.coffee @@ -18,7 +18,7 @@ class LevelSessionHandler extends Handler if req.user?.isAdmin() or req.user?.id is document.creator or ('employer' in (req.user?.get('permissions') ? [])) or - !document.submittedCode # TODO: only allow leaderboard access to non-top-5 solutions + not document.submittedCode # TODO: only allow leaderboard access to non-top-5 solutions return documentObject else return _.omit documentObject, @privateProperties @@ -53,6 +53,7 @@ class LevelSessionHandler extends Handler get = (method ? req.method).toLowerCase() is 'get' return true if get and document.get('submitted') return true if get and ('employer' in (req.user?.get('permissions') ? [])) + return true if get and not document.get('submittedCode') # Allow leaderboard access to non-multiplayer sessions super(arguments...) getCodeLanguageCounts: (req, res) -> diff --git a/server/payments/subscription_handler.coffee b/server/payments/subscription_handler.coffee index 79005ea0f..d8fc6ea52 100644 --- a/server/payments/subscription_handler.coffee +++ b/server/payments/subscription_handler.coffee @@ -1,6 +1,7 @@ # Not paired with a document in the DB, just handles coordinating between # the stripe property in the user with what's being stored in Stripe. +mongoose = require 'mongoose' async = require 'async' config = require '../../server_config' Handler = require '../commons/Handler' @@ -23,9 +24,70 @@ class SubscriptionHandler extends Handler console.warn "Subscription Error: #{user.get('slug')} (#{user._id}): '#{msg}'" getByRelationship: (req, res, args...) -> + return @getSubscribers(req, res) if args[1] is 'subscribers' return @getSubscriptions(req, res) if args[1] is 'subscriptions' super(arguments...) + getSubscribers: (req, res) -> + return @sendForbiddenError(res) unless req.user and req.user.isAdmin() + + maxReturnCount = req.body.maxCount or 20 + + # @subscribers ?= [] + # return @sendSuccess(res, @subscribers) unless _.isEmpty(@subscribers) + @subscribers = [] + + subscriberIDs = [] + + customersProcessed = 0 + nextBatch = (starting_after, done) => + options = limit: 100 + options.starting_after = starting_after if starting_after + stripe.customers.list options, (err, customers) => + return done(err) if err + customersProcessed += customers.data.length + + for customer in customers.data + break unless @subscribers.length < maxReturnCount + continue unless customer?.subscriptions?.data?.length > 0 + for subscription in customer.subscriptions.data + continue unless subscription.plan.id is 'basic' + + amount = subscription.plan.amount + if subscription?.discount?.coupon? + if subscription.discount.coupon.percent_off + amount = amount * (100 - subscription.discount.coupon.percent_off) / 100; + else if subscription.discount.coupon.amount_off + amount -= subscription.discount.coupon.amount_off + else if customer.discount?.coupon? + if customer.discount.coupon.percent_off + amount = amount * (100 - customer.discount.coupon.percent_off) / 100 + else if customer.discount.coupon.amount_off + amount -= customer.discount.coupon.amount_off + + continue unless amount > 0 + + subscriber = start: new Date(subscription.start * 1000) + if subscription.metadata?.id? + subscriber.userID = subscription.metadata.id + subscriberIDs.push subscription.metadata.id + if subscription.cancel_at_period_end + subscriber.cancel = new Date(subscription.canceled_at * 1000) + subscriber.end = new Date(subscription.current_period_end * 1000) + @subscribers.push(subscriber) + + if customers.has_more and @subscribers.length < maxReturnCount + return nextBatch(customers.data[customers.data.length - 1].id, done) + else + return done() + nextBatch null, (err) => + return @sendDatabaseError(res, err) if err + User.find {_id: {$in: subscriberIDs}}, (err, users) => + return @sendDatabaseError(res, err) if err + for user in users + subscriber.user = user for subscriber in @subscribers when subscriber.userID is user.id + @sendSuccess(res, @subscribers) + getSubscriptions: (req, res) -> # Returns a list of active subscriptions # TODO: does not handle customers with 11+ active subscriptions @@ -54,7 +116,6 @@ class SubscriptionHandler extends Handler for subscription in customer.subscriptions.data continue unless subscription.plan.id is 'basic' - amount = subscription.plan.amount if subscription?.discount?.coupon? if subscription.discount.coupon.percent_off @@ -72,7 +133,7 @@ class SubscriptionHandler extends Handler sub = start: new Date(subscription.start * 1000) if subscription.cancel_at_period_end sub.cancel = new Date(subscription.canceled_at * 1000) - sub.end = new Date(sub.current_period_end * 1000) + sub.end = new Date(subscription.current_period_end * 1000) @subs.push(sub) # Can't fetch all the test Stripe data @@ -84,9 +145,6 @@ class SubscriptionHandler extends Handler return @sendDatabaseError(res, err) if err @sendSuccess(res, @subs) - - - subscribeUser: (req, user, done) -> if (not req.user) or req.user.isAnonymous() or user.isAnonymous() return done({res: 'You must be signed in to subscribe.', code: 403}) diff --git a/server/queues/scoring.coffee b/server/queues/scoring.coffee index cab685ccc..2fb9c8d31 100644 --- a/server/queues/scoring.coffee +++ b/server/queues/scoring.coffee @@ -527,11 +527,11 @@ updateMatchesInSession = (matchObject, sessionID, callback) -> opponentsArray = _.toArray opponentsClone currentMatchObject.opponents = opponentsArray currentMatchObject.codeLanguage = matchObject.opponents[opponentsArray[0].sessionID].codeLanguage - currentMatchObject.simulator = @clientResponseObject.simulator - currentMatchObject.randomSeed = parseInt(@clientResponseObject.randomSeed or 0, 10) + #currentMatchObject.simulator = @clientResponseObject.simulator # Uncomment when actively debugging simulation mismatches + #currentMatchObject.randomSeed = parseInt(@clientResponseObject.randomSeed or 0, 10) # Uncomment when actively debugging simulation mismatches LevelSession.findOne {'_id': sessionID}, (err, session) -> session = session.toObject() - currentMatchObject.playtime = session.playtime ? 0 + #currentMatchObject.playtime = session.playtime ? 0 # Not useful if we can only see last 200 sessionUpdateObject = $push: {matches: {$each: [currentMatchObject], $slice: -200}} #log.info "Updating session #{sessionID}" diff --git a/server/routes/mail.coffee b/server/routes/mail.coffee index 2f698cdc4..af4008698 100644 --- a/server/routes/mail.coffee +++ b/server/routes/mail.coffee @@ -727,8 +727,9 @@ sendNextStepsEmail = (user, now, daysAgo) -> 'maker-square': isAdult and isFast 'the-firehose-project': isAdult and isFast #'mv-code-club': isKid # TODO: geodetect, get landing page URL + 'breakout-mentors': isKid nAdditionalOffers = Math.max 0, 4 - _.filter(offers).length - possibleAdditionalOffers = ['code-school', 'one-month', 'learnable', 'pluralsight'] + possibleAdditionalOffers = ['ostraining', 'code-school', 'one-month', 'learnable', 'pluralsight'] for offer in _.sample possibleAdditionalOffers, nAdditionalOffers offers[offer] = true if user.isPremium() diff --git a/vendor/scripts/checkout.js b/vendor/scripts/checkout.js index 5d8551546..bcb1b6572 100644 --- a/vendor/scripts/checkout.js +++ b/vendor/scripts/checkout.js @@ -1,3 +1,3 @@ -if(typeof JSON!=="object"){JSON={}}(function(){"use strict";function f(n){return n<10?"0"+n:n}if(typeof Date.prototype.toJSON!=="function"){Date.prototype.toJSON=function(){return isFinite(this.valueOf())?this.getUTCFullYear()+"-"+f(this.getUTCMonth()+1)+"-"+f(this.getUTCDate())+"T"+f(this.getUTCHours())+":"+f(this.getUTCMinutes())+":"+f(this.getUTCSeconds())+"Z":null};String.prototype.toJSON=Number.prototype.toJSON=Boolean.prototype.toJSON=function(){return this.valueOf()}}var cx,escapable,gap,indent,meta,rep;function quote(string){escapable.lastIndex=0;return escapable.test(string)?'"'+string.replace(escapable,function(a){var c=meta[a];return typeof c==="string"?c:"\\u"+("0000"+a.charCodeAt(0).toString(16)).slice(-4)})+'"':'"'+string+'"'}function str(key,holder){var i,k,v,length,mind=gap,partial,value=holder[key];if(value&&typeof value==="object"&&typeof value.toJSON==="function"){value=value.toJSON(key)}if(typeof rep==="function"){value=rep.call(holder,key,value)}switch(typeof value){case"string":return quote(value);case"number":return isFinite(value)?String(value):"null";case"boolean":case"null":return String(value);case"object":if(!value){return"null"}gap+=indent;partial=[];if(Object.prototype.toString.apply(value)==="[object Array]"){length=value.length;for(i=0;i<length;i+=1){partial[i]=str(i,value)||"null"}v=partial.length===0?"[]":gap?"[\n"+gap+partial.join(",\n"+gap)+"\n"+mind+"]":"["+partial.join(",")+"]";gap=mind;return v}if(rep&&typeof rep==="object"){length=rep.length;for(i=0;i<length;i+=1){if(typeof rep[i]==="string"){k=rep[i];v=str(k,value);if(v){partial.push(quote(k)+(gap?": ":":")+v)}}}}else{for(k in value){if(Object.prototype.hasOwnProperty.call(value,k)){v=str(k,value);if(v){partial.push(quote(k)+(gap?": ":":")+v)}}}}v=partial.length===0?"{}":gap?"{\n"+gap+partial.join(",\n"+gap)+"\n"+mind+"}":"{"+partial.join(",")+"}";gap=mind;return v}}if(typeof JSON.stringify!=="function"){escapable=/[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;meta={"\b":"\\b"," ":"\\t","\n":"\\n","\f":"\\f","\r":"\\r",'"':'\\"',"\\":"\\\\"};JSON.stringify=function(value,replacer,space){var i;gap="";indent="";if(typeof space==="number"){for(i=0;i<space;i+=1){indent+=" "}}else if(typeof space==="string"){indent=space}rep=replacer;if(replacer&&typeof replacer!=="function"&&(typeof replacer!=="object"||typeof replacer.length!=="number")){throw new Error("JSON.stringify")}return str("",{"":value})}}if(typeof JSON.parse!=="function"){cx=/[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;JSON.parse=function(text,reviver){var j;function walk(holder,key){var k,v,value=holder[key];if(value&&typeof value==="object"){for(k in value){if(Object.prototype.hasOwnProperty.call(value,k)){v=walk(value,k);if(v!==undefined){value[k]=v}else{delete value[k]}}}}return reviver.call(holder,key,value)}text=String(text);cx.lastIndex=0;if(cx.test(text)){text=text.replace(cx,function(a){return"\\u"+("0000"+a.charCodeAt(0).toString(16)).slice(-4)})}if(/^[\],:{}\s]*$/.test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,"@").replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,"]").replace(/(?:^|:|,)(?:\s*\[)+/g,""))){j=eval("("+text+")");return typeof reviver==="function"?walk({"":j},""):j}throw new SyntaxError("JSON.parse")}}})();(function(){var namespace="StripeCheckout.require".split("."),name=namespace[namespace.length-1],base=this,i;for(i=0;i<namespace.length-1;i++){base=base[namespace[i]]=base[namespace[i]]||{}}if(base[name]===undefined){base[name]=function(){var modules={},cache={};var requireRelative=function(name,root){var path=expand(root,name),indexPath=expand(path,"./index"),module,fn;module=cache[path]||cache[indexPath];if(module){return module}else if(fn=modules[path]||modules[path=indexPath]){module={id:path,exports:{}};cache[path]=module.exports;fn(module.exports,function(name){return require(name,dirname(path))},module);return cache[path]=module.exports}else{throw"module "+name+" not found"}};var expand=function(root,name){var results=[],parts,part;if(/^\.\.?(\/|$)/.test(name)){parts=[root,name].join("/").split("/")}else{parts=name.split("/")}for(var i=0,length=parts.length;i<length;i++){part=parts[i];if(part==".."){results.pop()}else if(part!="."&&part!=""){results.push(part)}}return results.join("/")};var dirname=function(path){return path.split("/").slice(0,-1).join("/")};var require=function(name){return requireRelative(name,"")};require.define=function(bundle){for(var key in bundle){modules[key]=bundle[key]}};require.modules=modules;require.cache=cache;return require}.call()}})();StripeCheckout.require.define({"vendor/cookie":function(exports,require,module){var cookie={};var pluses=/\+/g;function extend(target,other){target=target||{};for(var prop in other){if(typeof source[prop]==="object"){target[prop]=extend(target[prop],source[prop])}else{target[prop]=source[prop]}}return target}function raw(s){return s}function decoded(s){return decodeURIComponent(s.replace(pluses," "))}function converted(s){if(s.indexOf('"')===0){s=s.slice(1,-1).replace(/\\"/g,'"').replace(/\\\\/g,"\\")}try{return config.json?JSON.parse(s):s}catch(er){}}var config=cookie.set=cookie.get=function(key,value,options){if(value!==undefined){options=extend(options,config.defaults);if(typeof options.expires==="number"){var days=options.expires,t=options.expires=new Date;t.setDate(t.getDate()+days)}value=config.json?JSON.stringify(value):String(value);return document.cookie=[config.raw?key:encodeURIComponent(key),"=",config.raw?value:encodeURIComponent(value),options.expires?"; expires="+options.expires.toUTCString():"",options.path?"; path="+options.path:"",options.domain?"; domain="+options.domain:"",options.secure?"; secure":""].join("")}var decode=config.raw?raw:decoded;var cookies=document.cookie.split("; ");var result=key?undefined:{};for(var i=0,l=cookies.length;i<l;i++){var parts=cookies[i].split("=");var name=decode(parts.shift());var cookie=decode(parts.join("="));if(key&&key===name){result=converted(cookie);break}if(!key){result[name]=converted(cookie)}}return result};config.defaults={};cookie.remove=function(key,options){if(cookie.get(key)!==undefined){cookie.set(key,"",extend(options,{expires:-1}));return true}return false};module.exports=cookie}});StripeCheckout.require.define({"vendor/ready":function(exports,require,module){!function(name,definition){if(typeof module!="undefined")module.exports=definition();else if(typeof define=="function"&&typeof define.amd=="object")define(definition);else this[name]=definition()}("domready",function(ready){var fns=[],fn,f=false,doc=document,testEl=doc.documentElement,hack=testEl.doScroll,domContentLoaded="DOMContentLoaded",addEventListener="addEventListener",onreadystatechange="onreadystatechange",readyState="readyState",loadedRgx=hack?/^loaded|^c/:/^loaded|c/,loaded=loadedRgx.test(doc[readyState]);function flush(f){loaded=1;while(f=fns.shift())f()}doc[addEventListener]&&doc[addEventListener](domContentLoaded,fn=function(){doc.removeEventListener(domContentLoaded,fn,f);flush()},f);hack&&doc.attachEvent(onreadystatechange,fn=function(){if(/^c/.test(doc[readyState])){doc.detachEvent(onreadystatechange,fn);flush()}});return ready=hack?function(fn){self!=top?loaded?fn():fns.push(fn):function(){try{testEl.doScroll("left")}catch(e){return setTimeout(function(){ready(fn)},50)}fn()}()}:function(fn){loaded?fn():fns.push(fn)}})}});(function(){if(!Array.prototype.indexOf){Array.prototype.indexOf=function(obj,start){var f,i,j,_i;j=this.length;f=start?start:0;for(i=_i=f;f<=j?_i<j:_i>j;i=f<=j?++_i:--_i){if(this[i]===obj){return i}}return-1}}}).call(this);StripeCheckout.require.define({"lib/helpers":function(exports,require,module){(function(){var delurkWinPhone,helpers,uaVersionFn;uaVersionFn=function(re){return function(){var uaMatch;uaMatch=helpers.userAgent.match(re);return uaMatch&&parseInt(uaMatch[1])}};delurkWinPhone=function(fn){return function(){return fn()&&!helpers.isWindowsPhone()}};helpers={userAgent:window.navigator.userAgent,escape:function(value){return value&&(""+value).replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/\"/g,""")},trim:function(value){return value.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,"")},sanitizeURL:function(value){var SCHEME_WHITELIST,allowed,scheme,_i,_len;if(!value){return}value=helpers.trim(value);SCHEME_WHITELIST=["data:","http:","https:"];allowed=false;for(_i=0,_len=SCHEME_WHITELIST.length;_i<_len;_i++){scheme=SCHEME_WHITELIST[_i];if(value.indexOf(scheme)===0){allowed=true;break}}if(!allowed){return null}return encodeURI(value)},iOSVersion:uaVersionFn(/(?:iPhone OS |iPad; CPU OS )(\d+)_\d+/),iOSMinorVersion:uaVersionFn(/(?:iPhone OS |iPad; CPU OS )\d+_(\d+)/),iOSBuildVersion:uaVersionFn(/(?:iPhone OS |iPad; CPU OS )\d+_\d+_(\d+)/),androidWebkitVersion:uaVersionFn(/Mozilla\/5\.0.*Android.*AppleWebKit\/([\d]+)/),androidVersion:uaVersionFn(/Android (\d+)\.\d+/),firefoxVersion:uaVersionFn(/Firefox\/(\d+)\.\d+/),chromeVersion:uaVersionFn(/Chrome\/(\d+)\.\d+/),safariVersion:uaVersionFn(/Version\/(\d+)\.\d+ Safari/),iOSChromeVersion:uaVersionFn(/CriOS\/(\d+)\.\d+/),iOSNativeVersion:uaVersionFn(/Stripe\/(\d+)\.\d+/),ieVersion:uaVersionFn(/(?:MSIE |Trident\/.*rv:)(\d{1,2})\./),isiOSChrome:function(){return/CriOS/.test(helpers.userAgent)},isiOSWebView:function(){return/(iPhone|iPod|iPad).*AppleWebKit((?!.*Safari)|(.*\([^)]*like[^)]*Safari[^)]*\)))/i.test(helpers.userAgent)},isiOS:delurkWinPhone(function(){return/(iPhone|iPad|iPod)/i.test(helpers.userAgent)}),isiOSNative:function(){return this.isiOS()&&this.iOSNativeVersion()>=3},isiPad:function(){return/(iPad)/i.test(helpers.userAgent)},isMac:delurkWinPhone(function(){return/mac/i.test(helpers.userAgent)}),isWindowsPhone:function(){return/(Windows\sPhone|IEMobile)/i.test(helpers.userAgent)},isWindowsOS:function(){return/(Windows NT \d\.\d)/i.test(helpers.userAgent)},isIE:function(){return/(MSIE ([0-9]{1,}[\.0-9]{0,})|Trident\/)/i.test(helpers.userAgent)},isChrome:function(){return"chrome"in window},isSafari:delurkWinPhone(function(){var userAgent;userAgent=helpers.userAgent;return/Safari/i.test(userAgent)&&!/Chrome/i.test(userAgent)}),isFirefox:delurkWinPhone(function(){return helpers.firefoxVersion()!=null}),isAndroidBrowser:function(){var version;version=helpers.androidWebkitVersion();return version&&version<537},isAndroidChrome:function(){var version;version=helpers.androidWebkitVersion();return version&&version>=537},isAndroidDevice:delurkWinPhone(function(){return/Android/.test(helpers.userAgent)}),isAndroidWebView:function(){return helpers.isAndroidChrome()&&/Version\/\d+\.\d+/.test(helpers.userAgent)},isNativeWebContainer:function(){return window.cordova!=null},isSupportedMobileOS:function(){return helpers.isiOS()||helpers.isAndroidDevice()},isAndroidWebapp:function(){var metaTag;if(!helpers.isAndroidChrome()){return false}metaTag=document.getElementsByName("apple-mobile-web-app-capable")[0]||document.getElementsByName("mobile-web-app-capable")[0];return metaTag&&metaTag.content==="yes"},isiOSBroken:function(){if(!(helpers.isiPad()&&helpers.iOSVersion()===8)){return false}switch(helpers.iOSMinorVersion()){case 0:return true;case 1:return helpers.iOSBuildVersion()<1}return false},isInsideFrame:function(){return window.top!==window.self},isFallback:function(){var androidVersion,criosVersion,ffVersion,iOSVersion;if(!("postMessage"in window)||window.postMessageDisabled||document.documentMode&&document.documentMode<8){return true}androidVersion=helpers.androidVersion();if(androidVersion&&androidVersion<4){return true}iOSVersion=helpers.iOSVersion();if(iOSVersion&&iOSVersion<6){return true}ffVersion=helpers.firefoxVersion();if(ffVersion&&ffVersion<11){return true}criosVersion=helpers.iOSChromeVersion();if(criosVersion&&criosVersion<36){return true}return false},isSmallScreen:function(){return Math.min(window.screen.availHeight,window.screen.availWidth)<=640||/FakeCheckoutMobile/.test(helpers.userAgent)},pad:function(number,width,padding){var leading;if(width==null){width=2}if(padding==null){padding="0"}number=number+"";if(number.length>width){return number}leading=new Array(width-number.length+1).join(padding);return leading+number},requestAnimationFrame:function(callback){return(typeof window.requestAnimationFrame==="function"?window.requestAnimationFrame(callback):void 0)||(typeof window.webkitRequestAnimationFrame==="function"?window.webkitRequestAnimationFrame(callback):void 0)||window.setTimeout(callback,100)},requestAnimationInterval:function(func,interval){var callback,previous;previous=new Date;callback=function(){var frame,now,remaining;frame=helpers.requestAnimationFrame(callback);now=new Date;remaining=interval-(now-previous);if(remaining<=0){previous=now;func()}return frame};return callback()},getQueryParameterByName:function(name){var match;match=RegExp("[?&]"+name+"=([^&]*)").exec(window.location.search);return match&&decodeURIComponent(match[1].replace(/\+/g," "))},addQueryParameter:function(url,name,value){var hashParts,query;query=encodeURIComponent(name)+"="+encodeURIComponent(value);hashParts=new String(url).split("#");hashParts[0]+=hashParts[0].indexOf("?")!==-1?"&":"?";hashParts[0]+=query;return hashParts.join("#")},bind:function(element,name,callback){if(element.addEventListener){return element.addEventListener(name,callback,false)}else{return element.attachEvent("on"+name,callback)}},unbind:function(element,name,callback){if(element.removeEventListener){return element.removeEventListener(name,callback,false)}else{return element.detachEvent("on"+name,callback)}},host:function(url){var parent,parser;parent=document.createElement("div");parent.innerHTML='<a href="'+this.escape(url)+'">x</a>';parser=parent.firstChild;return""+parser.protocol+"//"+parser.host},strip:function(html){var tmp,_ref,_ref1;tmp=document.createElement("div");tmp.innerHTML=html;return(_ref=(_ref1=tmp.textContent)!=null?_ref1:tmp.innerText)!=null?_ref:""},setAutocomplete:function(el,type){var secureCCFill;secureCCFill=helpers.chromeVersion()>14||helpers.safariVersion()>7;if(type!=="cc-csc"&&(!/^cc-/.test(type)||secureCCFill)){el.setAttribute("x-autocompletetype",type);el.setAttribute("autocompletetype",type)}else{el.setAttribute("autocomplete","off")}if(!(type==="country-name"||type==="language"||type==="sex"||type==="gender-identity")){el.setAttribute("autocorrect","off");el.setAttribute("spellcheck","off")}if(!(/name|honorific/.test(type)||(type==="locality"||type==="city"||type==="adminstrative-area"||type==="state"||type==="province"||type==="region"||type==="language"||type==="org"||type==="organization-title"||type==="sex"||type==="gender-identity"))){return el.setAttribute("autocapitalize","off")}},hashCode:function(str){var hash,i,_i,_ref;hash=5381;for(i=_i=0,_ref=str.length;_i<_ref;i=_i+=1){hash=(hash<<5)+hash+str.charCodeAt(i)}return(hash>>>0)%65535},stripeUrlPrefix:function(){var match;match=window.location.hostname.match("^([a-z-]*)checkout.");if(match){return match[1]}else{return""}}};module.exports=helpers}).call(this)}});StripeCheckout.require.define({"lib/rpc":function(exports,require,module){(function(){var RPC,helpers,tracker,__bind=function(fn,me){return function(){return fn.apply(me,arguments)}},__slice=[].slice;helpers=require("lib/helpers");tracker=require("lib/tracker");RPC=function(){function RPC(target,options){if(options==null){options={}}this.processMessage=__bind(this.processMessage,this);this.sendMessage=__bind(this.sendMessage,this);this.invoke=__bind(this.invoke,this);this.startSession=__bind(this.startSession,this);this.rpcID=0;this.target=target;this.callbacks={};this.readyQueue=[];this.readyStatus=false;this.methods={};helpers.bind(window,"message",function(_this){return function(){var args;args=1<=arguments.length?__slice.call(arguments,0):[];return _this.message.apply(_this,args)}}(this))}RPC.prototype.startSession=function(){this.sendMessage("frameReady");return this.frameReady()};RPC.prototype.invoke=function(){var args,method;method=arguments[0],args=2<=arguments.length?__slice.call(arguments,1):[];tracker.trace.rpcInvoke(method);return this.ready(function(_this){return function(){return _this.sendMessage(method,args)}}(this))};RPC.prototype.message=function(e){var shouldProcess;shouldProcess=false;try{shouldProcess=e.source===this.target}catch(_error){}if(shouldProcess){return this.processMessage(e.data)}};RPC.prototype.ready=function(fn){if(this.readyStatus){return fn()}else{return this.readyQueue.push(fn)}};RPC.prototype.frameCallback=function(id,result){var _base;if(typeof(_base=this.callbacks)[id]==="function"){_base[id](result)}delete this.callbacks[id];return true};RPC.prototype.frameReady=function(){var callbacks,cb,_i,_len;this.readyStatus=true;callbacks=this.readyQueue.slice(0);for(_i=0,_len=callbacks.length;_i<_len;_i++){cb=callbacks[_i];cb()}return false};RPC.prototype.isAlive=function(){return true};RPC.prototype.sendMessage=function(method,args){var err,id,message,_ref;if(args==null){args=[]}id=++this.rpcID;if(typeof args[args.length-1]==="function"){this.callbacks[id]=args.pop()}message=JSON.stringify({method:method,args:args,id:id});if(((_ref=this.target)!=null?_ref.postMessage:void 0)==null){err=new Error("Unable to communicate with Checkout. Please contact support@stripe.com if the problem persists.");if(this.methods.rpcError!=null){this.methods.rpcError(err)}else{throw err}return}this.target.postMessage(message,"*");return tracker.trace.rpcPostMessage(method,args,id)};RPC.prototype.processMessage=function(data){var method,result,_base,_name;try{data=JSON.parse(data)}catch(_error){return}if(["frameReady","frameCallback","isAlive"].indexOf(data.method)!==-1){result=null;method=this[data.method];if(method!=null){result=method.apply(this,data.args)}}else{result=typeof(_base=this.methods)[_name=data.method]==="function"?_base[_name].apply(_base,data.args):void 0}if(data.method!=="frameCallback"){return this.invoke("frameCallback",data.id,result)}};return RPC}();module.exports=RPC}).call(this)}});StripeCheckout.require.define({"lib/uuid":function(exports,require,module){(function(){var S4;S4=function(){return((1+Math.random())*65536|0).toString(16).substring(1)};module.exports.generate=function(){var delim;delim="-";return S4()+S4()+delim+S4()+delim+S4()+delim+S4()+delim+S4()+S4()+S4()}}).call(this)}});StripeCheckout.require.define({"lib/pixel":function(exports,require,module){(function(){var canTrack,encode,generateID,getCookie,getCookieID,getLocalStorageID,request,setCookie,track;generateID=function(){return"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,function(c){var r,v;r=Math.random()*16|0;v=c==="x"?r:r&3|8;return v.toString(16)})};setCookie=function(name,value,options){var cookie,expires;if(options==null){options={}}if(options.expires===true){options.expires=-1}if(typeof options.expires==="number"){expires=new Date;expires.setTime(expires.getTime()+options.expires*24*60*60*1e3);options.expires=expires}if(options.path==null){options.path="/"}value=(value+"").replace(/[^!#-+\--:<-\[\]-~]/g,encodeURIComponent);cookie=encodeURIComponent(name)+"="+value;if(options.expires){cookie+=";expires="+options.expires.toGMTString()}if(options.path){cookie+=";path="+options.path}if(options.domain){cookie+=";domain="+options.domain}return document.cookie=cookie};getCookie=function(name){var cookie,cookies,index,key,value,_i,_len;cookies=document.cookie.split("; ");for(_i=0,_len=cookies.length;_i<_len;_i++){cookie=cookies[_i];index=cookie.indexOf("=");key=decodeURIComponent(cookie.substr(0,index));value=decodeURIComponent(cookie.substr(index+1));if(key===name){return value}}return null};encode=function(param){if(typeof param==="string"){return encodeURIComponent(param)}else{return encodeURIComponent(JSON.stringify(param))}};request=function(url,params,callback){var image,k,v;if(params==null){params={}}params.i=(new Date).getTime();params=function(){var _results;_results=[];for(k in params){v=params[k];_results.push(""+k+"="+encode(v))}return _results}().join("&");image=new Image;if(callback){image.onload=callback}image.src=""+url+"?"+params;return true};canTrack=function(){var dnt,_ref;dnt=(_ref=window.navigator.doNotTrack)!=null?_ref.toString().toLowerCase():void 0;switch(dnt){case"1":case"yes":case"true":return false;default:return true}};getLocalStorageID=function(){var err,lsid;if(!canTrack()){return"DNT"}try{lsid=localStorage.getItem("lsid");if(!lsid){lsid=generateID();localStorage.setItem("lsid",lsid)}return lsid}catch(_error){err=_error;return"NA"}};getCookieID=function(){var err,id;if(!canTrack()){return"DNT"}try{id=getCookie("cid")||generateID();setCookie("cid",id,{expires:360*20,domain:".stripe.com"});return id}catch(_error){err=_error;return"NA"}};track=function(event,params,callback){var k,referrer,request_params,search,v;if(params==null){params={}}referrer=document.referrer;search=window.location.search;request_params={event:event,rf:referrer,sc:search};for(k in params){v=params[k];request_params[k]=v}request_params.lsid||(request_params.lsid=getLocalStorageID());request_params.cid||(request_params.cid=getCookieID());return request("https://q.stripe.com",request_params,callback)};module.exports.track=track;module.exports.getLocalStorageID=getLocalStorageID;module.exports.getCookieID=getCookieID}).call(this)}});StripeCheckout.require.define({"vendor/base64":function(exports,require,module){var utf8Encode=function(string){string=(string+"").replace(/\r\n/g,"\n").replace(/\r/g,"\n");var utftext="",start,end;var stringl=0,n;start=end=0;stringl=string.length;for(n=0;n<stringl;n++){var c1=string.charCodeAt(n);var enc=null;if(c1<128){end++}else if(c1>127&&c1<2048){enc=String.fromCharCode(c1>>6|192,c1&63|128)}else{enc=String.fromCharCode(c1>>12|224,c1>>6&63|128,c1&63|128)}if(enc!==null){if(end>start){utftext+=string.substring(start,end)}utftext+=enc;start=end=n+1}}if(end>start){utftext+=string.substring(start,string.length)}return utftext};module.exports.encode=function(data){var b64="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";var o1,o2,o3,h1,h2,h3,h4,bits,i=0,ac=0,enc="",tmp_arr=[];if(!data){return data}data=utf8Encode(data);do{o1=data.charCodeAt(i++);o2=data.charCodeAt(i++);o3=data.charCodeAt(i++);bits=o1<<16|o2<<8|o3;h1=bits>>18&63;h2=bits>>12&63;h3=bits>>6&63;h4=bits&63;tmp_arr[ac++]=b64.charAt(h1)+b64.charAt(h2)+b64.charAt(h3)+b64.charAt(h4)}while(i<data.length);enc=tmp_arr.join("");switch(data.length%3){case 1:enc=enc.slice(0,-2)+"==";break;case 2:enc=enc.slice(0,-1)+"=";break}return enc}}});StripeCheckout.require.define({"lib/tracker":function(exports,require,module){(function(){var base64,config,isEventNameExisting,mixpanel,pixel,stateParameters,trace,traceSerialize,track,tracker,uuid,__indexOf=[].indexOf||function(item){for(var i=0,l=this.length;i<l;i++){if(i in this&&this[i]===item)return i}return-1};uuid=require("lib/uuid");pixel=require("lib/pixel");base64=require("vendor/base64");config={enabled:false,tracingEnabled:false,eventNamePrefix:"checkout.",distinctId:uuid.generate(),mixpanelKey:null};stateParameters={};tracker={};tracker.setEnabled=function(enabled){return config.enabled=enabled};tracker.setTracingEnabled=function(enabled){return config.tracingEnabled=enabled};tracker.setMixpanelKey=function(mixpanelKey){return config.mixpanelKey=mixpanelKey};tracker.track={outerOpen:function(parameters){var requiredKeys;requiredKeys=["key"];return track("outer.open",parameters,requiredKeys,{appendStateParameters:false})},open:function(options){var k,v;for(k in options){v=options[k];stateParameters["option-"+k]=v}return track("open")},close:function(parameters){return track("close",parameters,["withToken"])},rememberMe:function(parameters){return track("checkbox.rememberMe",parameters,["checked"])},authorizeAccount:function(){return track("account.authorize")},login:function(){return track("account.authorize.success")},wrongVerificationCode:function(){return track("account.authorize.fail")},keepMeLoggedIn:function(parameters){return track("checkbox.keepMeLoggedIn",parameters,["checked"])},logout:function(){return track("account.logout")},submit:function(){return track("submit")},invalid:function(parameters){if(parameters["err"]==null&¶meters["fields"]==null){throw new Error("Cannot track invalid because err or fields should be provided")}return track("invalid",parameters)},tokenError:function(msg){return track("token.error",{message:msg,type:"exception"})},moreInfo:function(){return track("moreInfoLink.click")},accountCreateSuccess:function(){return track("account.create.success")},accountCreateFail:function(){return track("account.create.fail")},addressAutocompleteShow:function(){return track("addressAutoComplete.show")},addressAutocompleteResultSelected:function(){return track("addressAutocomplete.result.selected")},back:function(parameters){return track("back",parameters,["from_step","to_step"])},token:function(parameters){return track("token",parameters,["stripe_token"])},phoneVerificationShow:function(){return track("phoneVerification.show")},phoneVerificationCreate:function(parameters){return track("phoneVerification.create",parameters,["use_sms"])},phoneVerificationAuthorize:function(parameters){return track("fraudCodeVerification.authorize",parameters,["valid"])},addressVerificationShow:function(){return track("addressVerification.show")}};tracker.trace={trigger:function(eventName,args){var EXCLUDED_EVENTS;EXCLUDED_EVENTS=["didResize","viewAddedToDOM","valueDidChange","checkedDidChange","keyUp","keyDown","keyPress","keyInput","click","blur"];eventName=eventName.split(".");if(eventName[eventName.length-1]==="checkout"){eventName.pop()}eventName=eventName.join(".");if(__indexOf.call(EXCLUDED_EVENTS,eventName)<0){if(this._triggerQueue==null){this._triggerQueue={}}this._triggerQueue[eventName]=traceSerialize(args);return this._triggerTimeout!=null?this._triggerTimeout:this._triggerTimeout=setTimeout(function(_this){return function(){var _ref;_ref=_this._triggerQueue;for(eventName in _ref){args=_ref[eventName];trace("trigger."+eventName,{args:args})}_this._triggerQueue={};return _this._triggerTimeout=null}}(this),0)}},rpcInvoke:function(method){return trace("rpc.invoke."+method)},rpcPostMessage:function(method,args,id){return trace("rpc.postMessage."+method,{id:id,args:traceSerialize(args)})}};tracker.state={setUIType:function(type){return stateParameters["st-ui-type"]=type},setUIIntegration:function(integration){return stateParameters["st-ui-integration"]=integration},setAccountsEnabled:function(bool){return stateParameters["st-accounts-enabled"]=bool},setRememberMeEnabled:function(bool){return stateParameters["st-remember-me-enabled"]=bool},setRememberMeChecked:function(bool){return stateParameters["st-remember-me-checked"]=bool},setAccountCreated:function(bool){return stateParameters["st-account-created"]=bool},setLoggedIn:function(bool){return stateParameters["st-logged-in"]=bool},setVariants:function(variants){var k,v,_results;_results=[];for(k in variants){v=variants[k];_results.push(stateParameters["st-variant-"+k]=v)}return _results},setPhoneVerificationShown:function(bool){return stateParameters["st-phone-verification-shown"]=bool},setAddressVerificationShown:function(bool){return stateParameters["st-address-verification-shown"]=bool}};tracker.dontTrack=function(fn){var enabled;enabled=config.enabled;config.enabled=false;fn();return config.enabled=enabled};isEventNameExisting=function(eventName){var exists,k,v,_ref;exists=false;_ref=tracker.events;for(k in _ref){v=_ref[k];if(v===eventName){exists=true;break}}return exists};trace=function(eventName,parameters,requiredKeys,options){if(parameters==null){parameters={}}if(requiredKeys==null){requiredKeys=[]}if(options==null){options={}}if(!config.tracingEnabled){return}eventName="trace."+eventName;options.excludeMixpanel=true;return track.apply(this,arguments)};track=function(eventName,parameters,requiredKeys,options){var fullEventName,k,key,missingKeys,v,_i,_len;if(parameters==null){parameters={}}if(requiredKeys==null){requiredKeys=[]}if(options==null){options={}}if(!config.enabled){return}missingKeys=function(){var _i,_len,_results;_results=[];for(_i=0,_len=requiredKeys.length;_i<_len;_i++){key=requiredKeys[_i];if(!(key in parameters)){_results.push(key)}}return _results}();if(missingKeys.length>0){throw new Error("Missing required data ("+missingKeys.join(", ")+") for tracking "+eventName+".")}parameters.distinct_id=config.distinctId;if(options.appendStateParameters==null){options.appendStateParameters=true}if(options.appendStateParameters){for(k in stateParameters){v=stateParameters[k];parameters[k]=v}}parameters.h=screen.height;parameters.w=screen.width;for(v=_i=0,_len=parameters.length;_i<_len;v=++_i){k=parameters[v];if(v instanceof Array){v.sort()}}fullEventName=""+config.eventNamePrefix+eventName;if(!options.excludeMixpanel){mixpanel.track(fullEventName,parameters)}return pixel.track(fullEventName,parameters)};mixpanel={};mixpanel.track=function(eventName,options){var dataStr,properties;if(options==null){options={}}if(!(typeof $!=="undefined"&&$!==null&&config.mixpanelKey!=null)){return}properties=$.extend({token:config.mixpanelKey,userAgent:window.navigator.userAgent},options);delete properties["stripe_token"];dataStr=base64.encode(JSON.stringify({event:eventName,properties:properties}));return(new Image).src="https://api.mixpanel.com/track/?ip=1&img=1&data="+dataStr};traceSerialize=function(value){var k,obj,v;if(value instanceof Array){return JSON.stringify(function(){var _i,_len,_results;_results=[];for(_i=0,_len=value.length;_i<_len;_i++){v=value[_i];_results.push(traceSerialize(v))}return _results}())}else if(value!=null&&value.target!=null&&value.type!=null){return traceSerialize({type:value.type,target_id:value.target.id})}else if(value instanceof Object){if(value.constructor===Object){obj={};for(k in value){v=value[k];obj[k]=traceSerialize(v)}return JSON.stringify(obj)}else{return value.toString()}}else{return value}};module.exports=tracker}).call(this)}});StripeCheckout.require.define({"outer/lib/fallbackRpc":function(exports,require,module){(function(){var FallbackRPC,cacheBust,interval,lastHash,re,__bind=function(fn,me){return function(){return fn.apply(me,arguments)}};cacheBust=1;interval=null;lastHash=null;re=/^#?\d+&/;FallbackRPC=function(){function FallbackRPC(target,host){this.invokeTarget=__bind(this.invokeTarget,this);this.target=target;this.host=host}FallbackRPC.prototype.invokeTarget=function(message){var url;message=+new Date+cacheBust++ +"&"+encodeURIComponent(message);url=this.host+"";return this.target.location=url.replace(/#.*$/,"")+"#"+message};FallbackRPC.prototype.receiveMessage=function(callback,delay){if(delay==null){delay=100}interval&&clearInterval(interval);return interval=setInterval(function(){var hash;hash=decodeURIComponent(window.location.hash);if(hash!==lastHash&&re.test(hash)){window.location.hash="";lastHash=hash;return callback({data:hash.replace(re,"")})}},delay)};return FallbackRPC}();module.exports=FallbackRPC}).call(this)}});StripeCheckout.require.define({"outer/lib/utils":function(exports,require,module){(function(){var $,$$,addClass,append,css,hasAttr,hasClass,insertAfter,insertBefore,parents,remove,resolve,text,trigger,__indexOf=[].indexOf||function(item){for(var i=0,l=this.length;i<l;i++){if(i in this&&this[i]===item)return i}return-1};$=function(sel){return document.querySelectorAll(sel)};$$=function(cls){var el,reg,_i,_len,_ref,_results;if(typeof document.getElementsByClassName==="function"){return document.getElementsByClassName(cls)}else if(typeof document.querySelectorAll==="function"){return document.querySelectorAll("."+cls)}else{reg=new RegExp("(^|\\s)"+cls+"(\\s|$)");_ref=document.getElementsByTagName("*");_results=[];for(_i=0,_len=_ref.length;_i<_len;_i++){el=_ref[_i];if(reg.test(el.className)){_results.push(el)}}return _results -}};hasAttr=function(element,attr){var node;if(typeof element.hasAttribute==="function"){return element.hasAttribute(attr)}else{node=element.getAttributeNode(attr);return!!(node&&(node.specified||node.nodeValue))}};trigger=function(element,name,data,bubble){if(data==null){data={}}if(bubble==null){bubble=true}if(window.jQuery){return jQuery(element).trigger(name,data)}};addClass=function(element,name){return element.className+=" "+name};hasClass=function(element,name){return __indexOf.call(element.className.split(" "),name)>=0};css=function(element,css){return element.style.cssText+=";"+css};insertBefore=function(element,child){return element.parentNode.insertBefore(child,element)};insertAfter=function(element,child){return element.parentNode.insertBefore(child,element.nextSibling)};append=function(element,child){return element.appendChild(child)};remove=function(element){var _ref;return(_ref=element.parentNode)!=null?_ref.removeChild(element):void 0};parents=function(node){var ancestors;ancestors=[];while((node=node.parentNode)&&node!==document&&__indexOf.call(ancestors,node)<0){ancestors.push(node)}return ancestors};resolve=function(url){var parser;parser=document.createElement("a");parser.href=url;return""+parser.href};text=function(element,value){if("innerText"in element){element.innerText=value}else{element.textContent=value}return value};module.exports={$:$,$$:$$,hasAttr:hasAttr,trigger:trigger,addClass:addClass,hasClass:hasClass,css:css,insertBefore:insertBefore,insertAfter:insertAfter,append:append,remove:remove,parents:parents,resolve:resolve,text:text}}).call(this)}});StripeCheckout.require.define({"outer/controllers/app":function(exports,require,module){(function(){var App,Checkout,RPC,TokenCallback,tracker,utils,__bind=function(fn,me){return function(){return fn.apply(me,arguments)}};Checkout=require("outer/controllers/checkout");TokenCallback=require("outer/controllers/tokenCallback");RPC=require("lib/rpc");tracker=require("lib/tracker");utils=require("outer/lib/utils");App=function(){function App(options){var _ref,_ref1;if(options==null){options={}}this.setHost=__bind(this.setHost,this);this.configure=__bind(this.configure,this);this.close=__bind(this.close,this);this.open=__bind(this.open,this);this.configurations={};this.checkouts={};this.host="https://checkout.stripe.com";this.timeLoaded=Math.floor((new Date).getTime()/1e3);this.totalButtons=0;if(((_ref=window.Prototype)!=null?(_ref1=_ref.Version)!=null?_ref1.indexOf("1.6"):void 0:void 0)===0){console.error("Stripe Checkout is not compatible with your version of Prototype.js. Please upgrade to version 1.7 or greater.")}}App.prototype.open=function(options,buttonId){var checkout,k,mergedOptions,v,_ref;if(buttonId==null){buttonId=null}mergedOptions={referrer:document.referrer,url:document.URL,timeLoaded:this.timeLoaded};if(buttonId&&this.configurations[buttonId]){_ref=this.configurations[buttonId];for(k in _ref){v=_ref[k];mergedOptions[k]=v}}for(k in options){v=options[k];mergedOptions[k]=v}if(mergedOptions.image){mergedOptions.image=utils.resolve(mergedOptions.image)}this.validateOptions(options,"open");if(buttonId){checkout=this.checkouts[buttonId]}else{checkout=new Checkout(new TokenCallback(options),this.host)}this.trackOpen(checkout,mergedOptions);return checkout.open(mergedOptions)};App.prototype.close=function(buttonId){var _ref;return(_ref=this.checkouts[buttonId])!=null?_ref.close():void 0};App.prototype.configure=function(buttonId,options){if(options==null){options={}}if(buttonId instanceof Object){options=buttonId;buttonId="button"+this.totalButtons++}if(options.image){options.image=utils.resolve(options.image)}this.validateOptions(options,"configure");this.configurations[buttonId]=options;this.checkouts[buttonId]=new Checkout(new TokenCallback(options),this.host);this.checkouts[buttonId].preload(options);return{open:function(_this){return function(options){return _this.open(options,buttonId)}}(this),close:function(_this){return function(){return _this.close(buttonId)}}(this)}};App.prototype.validateOptions=function(options,which){var url;try{return JSON.stringify(options)}catch(_error){url="https://stripe.com/docs/checkout#integration-custom";throw new Error("Stripe Checkout was unable to serialize the options passed to StripeCheckout."+which+"(). Please consult the doumentation to confirm that you're supplying values of the expected type: "+url)}};App.prototype.setHost=function(host){return this.host=host};App.prototype.trackOpen=function(checkout,options){tracker.setEnabled(!options.notrack);return tracker.track.outerOpen({key:options.key,lsid:"NA",cid:"NA"})};return App}();module.exports=App}).call(this)}});StripeCheckout.require.define({"outer/controllers/button":function(exports,require,module){(function(){var $$,Button,addClass,append,hasAttr,hasClass,helpers,insertAfter,parents,text,trigger,_ref,__bind=function(fn,me){return function(){return fn.apply(me,arguments)}};_ref=require("outer/lib/utils"),$$=_ref.$$,hasClass=_ref.hasClass,addClass=_ref.addClass,trigger=_ref.trigger,append=_ref.append,text=_ref.text,parents=_ref.parents,insertAfter=_ref.insertAfter,hasAttr=_ref.hasAttr;helpers=require("lib/helpers");Button=function(){Button.totalButtonId=0;Button.load=function(app){var button,el,element;element=$$("stripe-button");element=function(){var _i,_len,_results;_results=[];for(_i=0,_len=element.length;_i<_len;_i++){el=element[_i];if(!hasClass(el,"active")){_results.push(el)}}return _results}();element=element[element.length-1];if(!element){return}addClass(element,"active");button=new Button(element,app);return button.append()};function Button(scriptEl,app){this.parseOptions=__bind(this.parseOptions,this);this.parentHead=__bind(this.parentHead,this);this.parentForm=__bind(this.parentForm,this);this.onToken=__bind(this.onToken,this);this.open=__bind(this.open,this);this.submit=__bind(this.submit,this);this.append=__bind(this.append,this);this.render=__bind(this.render,this);var _base;this.scriptEl=scriptEl;this.app=app;this.document=this.scriptEl.ownerDocument;this.nostyle=helpers.isFallback();this.options=this.parseOptions();(_base=this.options).label||(_base.label="Pay with Card");this.options.token=this.onToken;this.$el=document.createElement("button");this.$el.setAttribute("type","submit");this.$el.className="stripe-button-el";helpers.bind(this.$el,"click",this.submit);helpers.bind(this.$el,"touchstart",function(){});this.render()}Button.prototype.render=function(){this.$el.innerHTML="";this.$span=document.createElement("span");text(this.$span,this.options.label);if(!this.nostyle){this.$el.style.visibility="hidden";this.$span.style.display="block";this.$span.style.minHeight="30px"}this.$style=document.createElement("link");this.$style.setAttribute("type","text/css");this.$style.setAttribute("rel","stylesheet");this.$style.setAttribute("href",this.app.host+"/v3/checkout/button-qpwW2WfkB0oGWVWIASjIOQ.css");return append(this.$el,this.$span)};Button.prototype.append=function(){var head;if(this.scriptEl){insertAfter(this.scriptEl,this.$el)}if(!this.nostyle){head=this.parentHead();if(head){append(head,this.$style)}}if(this.$form=this.parentForm()){helpers.unbind(this.$form,"submit",this.submit);helpers.bind(this.$form,"submit",this.submit)}if(!this.nostyle){setTimeout(function(_this){return function(){return _this.$el.style.visibility="visible"}}(this),1e3)}this.app.setHost(helpers.host(this.scriptEl.src));return this.appHandler=this.app.configure(this.options,{form:this.$form})};Button.prototype.disable=function(){return this.$el.setAttribute("disabled",true)};Button.prototype.enable=function(){return this.$el.removeAttribute("disabled")};Button.prototype.isDisabled=function(){return hasAttr(this.$el,"disabled")};Button.prototype.submit=function(e){if(typeof e.preventDefault==="function"){e.preventDefault()}if(!this.isDisabled()){this.open()}return false};Button.prototype.open=function(){return this.appHandler.open(this.options)};Button.prototype.onToken=function(token,args){var $input,$tokenInput,$tokenTypeInput,key,value;trigger(this.scriptEl,"token",token);if(this.$form){$tokenInput=this.renderInput("stripeToken",token.id);append(this.$form,$tokenInput);$tokenTypeInput=this.renderInput("stripeTokenType",token.type);append(this.$form,$tokenTypeInput);if(token.email){append(this.$form,this.renderInput("stripeEmail",token.email))}if(args){for(key in args){value=args[key];$input=this.renderInput(this.formatKey(key),value);append(this.$form,$input)}}this.$form.submit()}return this.disable()};Button.prototype.formatKey=function(key){var arg,args,_i,_len;args=key.split("_");key="";for(_i=0,_len=args.length;_i<_len;_i++){arg=args[_i];if(arg.length>0){key=key+arg.substr(0,1).toUpperCase()+arg.substr(1).toLowerCase()}}return"stripe"+key};Button.prototype.renderInput=function(name,value){var input;input=document.createElement("input");input.type="hidden";input.name=name;input.value=value;return input};Button.prototype.parentForm=function(){var el,elements,_i,_len,_ref1;elements=parents(this.$el);for(_i=0,_len=elements.length;_i<_len;_i++){el=elements[_i];if(((_ref1=el.tagName)!=null?_ref1.toLowerCase():void 0)==="form"){return el}}return null};Button.prototype.parentHead=function(){var _ref1,_ref2;return((_ref1=this.document)!=null?_ref1.head:void 0)||((_ref2=this.document)!=null?_ref2.getElementsByTagName("head")[0]:void 0)||this.document.body};Button.prototype.parseOptions=function(){var attr,match,options,_i,_len,_ref1;options={};_ref1=this.scriptEl.attributes;for(_i=0,_len=_ref1.length;_i<_len;_i++){attr=_ref1[_i];match=attr.name.match(/^data-(.+)$/);if(match!=null?match[1]:void 0){options[match[1]]=attr.value}}return options};return Button}();module.exports=Button}).call(this)}});StripeCheckout.require.define({"outer/controllers/checkout":function(exports,require,module){(function(){var Checkout,FallbackView,IframeView,TabView,cookie,helpers,__bind=function(fn,me){return function(){return fn.apply(me,arguments)}};helpers=require("lib/helpers");IframeView=require("outer/views/iframeView");TabView=require("outer/views/tabView");FallbackView=require("outer/views/fallbackView");cookie=require("vendor/cookie");Checkout=function(){Checkout.activeView=null;function Checkout(tokenCallback,host){this.onTokenCallback=__bind(this.onTokenCallback,this);this.preload=__bind(this.preload,this);this.open=__bind(this.open,this);var path,shouldPopup,viewClass;this.tokenCallback=tokenCallback;this.host=host;this.onToken=function(_this){return function(data){return tokenCallback.trigger(data.token,data.args,_this.onTokenCallback)}}(this);if(helpers.isFallback()){viewClass=FallbackView;path="/v3/fallback/6UQ6gx0KTH1syE44E6yZA.html"}else{path="/v3/lB3wUljfuCi9MIXuTlvvg.html";if(Math.random()<.1){path="/v3/nocdn-hlnqFn7LdeQOmPLkwVzeA.html"}shouldPopup=helpers.isSupportedMobileOS()&&!(helpers.isNativeWebContainer()||helpers.isiOSWebView()||helpers.isAndroidWebapp()||helpers.isiOSBroken());if(shouldPopup){viewClass=TabView}else{viewClass=IframeView}}this.view=new viewClass(this.onToken,this.host,path)}Checkout.prototype.open=function(options){if(options==null){options={}}if(Checkout.activeView&&Checkout.activeView!==this.view){Checkout.activeView.close()}Checkout.activeView=this.view;options.supportsTokenCallback=this.tokenCallback.supportsTokenCallback();return this.view.open(options,function(_this){return function(status){if(status){return}if(!(_this.view instanceof TabView)){return}_this.view=new IframeView(_this.onToken,_this.host,"/v3/lB3wUljfuCi9MIXuTlvvg.html");return _this.open(options)}}(this))};Checkout.prototype.close=function(){var _ref;return(_ref=this.view)!=null?_ref.close():void 0};Checkout.prototype.preload=function(options){return this.view.preload(options)};Checkout.prototype.onTokenCallback=function(){return this.view.triggerTokenCallback.apply(this.view,arguments)};return Checkout}();module.exports=Checkout}).call(this)}});StripeCheckout.require.define({"outer/controllers/tokenCallback":function(exports,require,module){(function(){var TokenCallback,__bind=function(fn,me){return function(){return fn.apply(me,arguments)}};TokenCallback=function(){function TokenCallback(options){this.supportsTokenCallback=__bind(this.supportsTokenCallback,this);this.trigger=__bind(this.trigger,this);if(options.token){this.fn=options.token;this.version=1}else if(options.onToken){this.fn=options.onToken;this.version=2}}TokenCallback.prototype.trigger=function(token,addresses,callback){var data,k,shipping,v;if(this.version===2){data={token:token};shipping=null;for(k in addresses){v=addresses[k];if(/^shipping_/.test(k)){if(shipping==null){shipping={}}shipping[k.replace(/^shipping_/,"")]=v}}if(shipping!=null){data.shipping=shipping}return this.fn(data,callback)}else{return this.fn(token,addresses)}};TokenCallback.prototype.supportsTokenCallback=function(){return this.version>1};return TokenCallback}();module.exports=TokenCallback}).call(this)}});StripeCheckout.require.define({"outer/views/fallbackView":function(exports,require,module){(function(){var FallbackRPC,FallbackView,View,__bind=function(fn,me){return function(){return fn.apply(me,arguments)}},__hasProp={}.hasOwnProperty,__extends=function(child,parent){for(var key in parent){if(__hasProp.call(parent,key))child[key]=parent[key]}function ctor(){this.constructor=child}ctor.prototype=parent.prototype;child.prototype=new ctor;child.__super__=parent.prototype;return child};FallbackRPC=require("outer/lib/fallbackRpc");View=require("outer/views/view");FallbackView=function(_super){__extends(FallbackView,_super);function FallbackView(){this.triggerTokenCallback=__bind(this.triggerTokenCallback,this);this.close=__bind(this.close,this);this.open=__bind(this.open,this);FallbackView.__super__.constructor.apply(this,arguments)}FallbackView.prototype.open=function(options,callback){var message,url;FallbackView.__super__.open.apply(this,arguments);url=this.host+this.path;this.frame=window.open(url,"stripe_checkout_app","width=400,height=400,location=yes,resizable=yes,scrollbars=yes");if(this.frame==null){alert("Disable your popup blocker to proceed with checkout.");url="https://stripe.com/docs/checkout#integration-more-runloop";throw new Error("To learn how to prevent the Stripe Checkout popup from being blocked, please visit "+url)}this.rpc=new FallbackRPC(this.frame,url);this.rpc.receiveMessage(function(_this){return function(e){var data;try{data=JSON.parse(e.data)}catch(_error){return}return _this.onToken(data)}}(this));message=JSON.stringify(this.options);this.rpc.invokeTarget(message);return callback(true)};FallbackView.prototype.close=function(){var _ref;return(_ref=this.frame)!=null?_ref.close():void 0};FallbackView.prototype.triggerTokenCallback=function(err){if(err){return alert(err)}};return FallbackView}(View);module.exports=FallbackView}).call(this)}});StripeCheckout.require.define({"outer/views/iframeView":function(exports,require,module){(function(){var IframeView,RPC,View,helpers,ready,utils,__bind=function(fn,me){return function(){return fn.apply(me,arguments)}},__hasProp={}.hasOwnProperty,__extends=function(child,parent){for(var key in parent){if(__hasProp.call(parent,key))child[key]=parent[key]}function ctor(){this.constructor=child}ctor.prototype=parent.prototype;child.prototype=new ctor;child.__super__=parent.prototype;return child};utils=require("outer/lib/utils");helpers=require("lib/helpers");RPC=require("lib/rpc");View=require("outer/views/view");ready=require("vendor/ready");IframeView=function(_super){__extends(IframeView,_super);function IframeView(){this.configure=__bind(this.configure,this);this.removeFrame=__bind(this.removeFrame,this);this.removeTouchOverlay=__bind(this.removeTouchOverlay,this);this.showTouchOverlay=__bind(this.showTouchOverlay,this);this.attachIframe=__bind(this.attachIframe,this);this.setToken=__bind(this.setToken,this);this.closed=__bind(this.closed,this);this.close=__bind(this.close,this);this.preload=__bind(this.preload,this);this.open=__bind(this.open,this);return IframeView.__super__.constructor.apply(this,arguments)}IframeView.prototype.open=function(options,callback){IframeView.__super__.open.apply(this,arguments);return ready(function(_this){return function(){var left,loaded,_ref;_this.originalOverflowValue=document.body.style.overflow;if(_this.frame==null){_this.configure()}if(typeof $!=="undefined"&&$!==null?(_ref=$.fn)!=null?_ref.modal:void 0:void 0){$(document).off("focusin.bs.modal").off("focusin.modal")}_this.frame.style.display="block";if(_this.shouldShowTouchOverlay()){_this.showTouchOverlay();_this.frame.style.top=(window.scrollY||window.pageYOffset)+"px";left=(window.scrollX||window.pageXOffset)+(window.innerWidth-_this.iframeWidth())/2;left=Math.min(window.innerWidth-_this.iframeWidth(),Math.max(0,left));left=Math.max(0,left);_this.frame.style.left=left+"px"}loaded=false;setTimeout(function(){if(loaded){return}loaded=true;callback(false);return _this.removeFrame()},8e3);return _this.rpc.ready(function(){if(loaded){return}loaded=true;callback(true);_this.rpc.invoke("render","","iframe",_this.options);document.body.style.overflow="hidden";return _this.rpc.invoke("open",{timeLoaded:_this.options.timeLoaded},function(success){var _base;if(success){return typeof(_base=_this.options).opened==="function"?_base.opened():void 0}})})}}(this))};IframeView.prototype.preload=function(options){return ready(function(_this){return function(){_this.configure();return _this.rpc.invoke("preload",options)}}(this))};IframeView.prototype.iframeWidth=function(){if(helpers.isSmallScreen()){return 328}else{return 380}};IframeView.prototype.close=function(){return this.rpc.invoke("close")};IframeView.prototype.closed=function(){var _base;document.body.style.overflow=this.originalOverflowValue;this.removeFrame();if(typeof(_base=this.options).closed==="function"){_base.closed()}clearTimeout(this.tokenTimeout);if(this.token!=null){this.onToken(this.token)}this.token=null;this.preload(this.options);return true};IframeView.prototype.setToken=function(data){this.token=data;return this.tokenTimeout!=null?this.tokenTimeout:this.tokenTimeout=setTimeout(function(_this){return function(){_this.onToken(_this.token);_this.tokenTimeout=null;return _this.token=null}}(this),2500)};IframeView.prototype.attachIframe=function(){var cssText,iframe;iframe=document.createElement("iframe");iframe.setAttribute("frameBorder","0");iframe.setAttribute("allowtransparency","true");cssText="z-index: 9999;\ndisplay: none;\nbackground: transparent;\nbackground: rgba(0,0,0,0.005);\nborder: 0px none transparent;\noverflow-x: hidden;\noverflow-y: auto;\nvisibility: hidden;\nmargin: 0;\npadding: 0;\n-webkit-tap-highlight-color: transparent;\n-webkit-touch-callout: none;";if(this.shouldShowTouchOverlay()){cssText+="position: absolute;\nwidth: "+this.iframeWidth()+"px;\nheight: 100%;"}else{cssText+="position: fixed;\nleft: 0;\ntop: 0;\nwidth: 100%;\nheight: 100%;"}iframe.style.cssText=cssText;helpers.bind(iframe,"load",function(){return iframe.style.visibility="visible"});iframe.src=this.host+this.path;iframe.className=iframe.name="stripe_checkout_app";utils.append(document.body,iframe);return iframe};IframeView.prototype.showTouchOverlay=function(){var toRepaint;if(this.overlay){return}this.overlay=document.createElement("div");this.overlay.style.cssText="z-index: 9998;\nbackground: #000;\nopacity: 0;\nborder: 0px none transparent;\noverflow: none;\nmargin: 0;\npadding: 0;\n-webkit-tap-highlight-color: transparent;\n-webkit-touch-callout: none;\nposition: fixed;\nleft: 0;\ntop: 0;\nwidth: 200%;\nheight: 200%;\ntransition: opacity 320ms ease;\n-webkit-transition: opacity 320ms ease;\n-moz-transition: opacity 320ms ease;\n-ms-transition: opacity 320ms ease;";utils.append(document.body,this.overlay);toRepaint=this.overlay.offsetHeight;return this.overlay.style.opacity="0.5"};IframeView.prototype.removeTouchOverlay=function(){var overlay;if(!this.overlay){return}overlay=this.overlay;overlay.style.opacity="0";setTimeout(function(){return utils.remove(overlay)},400);return this.overlay=null};IframeView.prototype.removeFrame=function(){var frame;if(this.shouldShowTouchOverlay()){this.removeTouchOverlay()}frame=this.frame;setTimeout(function(){return utils.remove(frame)},500);return this.frame=null};IframeView.prototype.configure=function(){if(this.frame!=null){this.removeFrame()}this.frame=this.attachIframe();this.rpc=new RPC(this.frame.contentWindow,{host:this.host});this.rpc.methods.closed=this.closed;return this.rpc.methods.setToken=this.setToken};IframeView.prototype.shouldShowTouchOverlay=function(){return helpers.isSupportedMobileOS()};return IframeView}(View);module.exports=IframeView}).call(this)}});StripeCheckout.require.define({"outer/views/tabView":function(exports,require,module){(function(){var RPC,TabView,View,helpers,__bind=function(fn,me){return function(){return fn.apply(me,arguments)}},__hasProp={}.hasOwnProperty,__extends=function(child,parent){for(var key in parent){if(__hasProp.call(parent,key))child[key]=parent[key]}function ctor(){this.constructor=child}ctor.prototype=parent.prototype;child.prototype=new ctor;child.__super__=parent.prototype;return child};RPC=require("lib/rpc");helpers=require("lib/helpers");View=require("outer/views/view");TabView=function(_super){__extends(TabView,_super);function TabView(){this.closed=__bind(this.closed,this);this.checkForClosedTab=__bind(this.checkForClosedTab,this);this.setToken=__bind(this.setToken,this);this.fullPath=__bind(this.fullPath,this);this.close=__bind(this.close,this);this.open=__bind(this.open,this);TabView.__super__.constructor.apply(this,arguments);this.closedTabInterval=null;this.color=null;this.colorSet=false}TabView.prototype.open=function(options,callback){var targetName,url,_base,_ref,_ref1;TabView.__super__.open.apply(this,arguments);try{if((_ref=this.frame)!=null){_ref.close()}}catch(_error){}if(window.name==="stripe_checkout_tabview"){window.name=""}if(helpers.isiOSChrome()){targetName="_blank"}else{targetName="stripe_checkout_tabview"}this.frame=window.open(this.fullPath(),targetName);if(!this.frame&&((_ref1=this.options.key)!=null?_ref1.indexOf("test"):void 0)!==-1){url="https://stripe.com/docs/checkout#integration-more-runloop";console.error("Stripe Checkout was unable to open a new window, possibly due to a popup blocker.\nTo provide the best experience for your users, follow the guide at "+url+".\nThis message will only appear when using a test publishable key.")}if(!this.frame||this.frame===window){this.close();callback(false);return}if(typeof(_base=this.frame).focus==="function"){_base.focus()}this.rpc=new RPC(this.frame,{host:this.host});this.rpc.methods.setToken=this.setToken;this.rpc.methods.closed=this.closed;return this.rpc.ready(function(_this){return function(){var _base1;callback(true);_this.rpc.invoke("render","","tab",_this.options);_this.rpc.invoke("open");if(typeof(_base1=_this.options).opened==="function"){_base1.opened()}return _this.checkForClosedTab()}}(this))};TabView.prototype.close=function(){if(this.frame&&this.frame!==window){return this.frame.close()}};TabView.prototype.fullPath=function(){return this.host+this.path};TabView.prototype.setToken=function(data){this.token=data;return this.tokenTimeout!=null?this.tokenTimeout:this.tokenTimeout=setTimeout(function(_this){return function(){_this.onToken(_this.token);_this.tokenTimeout=null;return _this.token=null}}(this),2500)};TabView.prototype.checkForClosedTab=function(){if(this.closedTabInterval){clearInterval(this.closedTabInterval)}return this.closedTabInterval=setInterval(function(_this){return function(){if(!_this.frame||!_this.frame.postMessage||_this.frame.closed){return _this.closed()}}}(this),100)};TabView.prototype.closed=function(){var _base;clearInterval(this.closedTabInterval);if(typeof(_base=this.options).closed==="function"){_base.closed()}clearTimeout(this.tokenTimeout);if(this.token!=null){return this.onToken(this.token)}};return TabView}(View);module.exports=TabView}).call(this)}});StripeCheckout.require.define({"outer/views/view":function(exports,require,module){(function(){var View,__bind=function(fn,me){return function(){return fn.apply(me,arguments)}},__slice=[].slice;View=function(){function View(onToken,host,path){this.triggerTokenCallback=__bind(this.triggerTokenCallback,this);this.open=__bind(this.open,this);this.onToken=onToken;this.host=host;this.path=path}View.prototype.open=function(options,callback){return this.options=options};View.prototype.close=function(){};View.prototype.preload=function(options){};View.prototype.triggerTokenCallback=function(){var args;args=arguments;return this.rpc.ready(function(_this){return function(){var _ref;return(_ref=_this.rpc).invoke.apply(_ref,["tokenCallback"].concat(__slice.call(args)))}}(this))};return View}();module.exports=View}).call(this)}});(function(){var App,Button,app,require,_ref,_ref1;require=require||this.StripeCheckout.require;Button=require("outer/controllers/button");App=require("outer/controllers/app");if(((_ref=this.StripeCheckout)!=null?_ref.__app:void 0)==null){this.StripeCheckout||(this.StripeCheckout={});this.StripeCheckout.__app=app=new App;this.StripeCheckout.open=app.open;this.StripeCheckout.configure=app.configure;this.StripeButton=this.StripeCheckout;if(((_ref1=this.StripeCheckout)!=null?_ref1.__host:void 0)&&this.StripeCheckout.__host!==""){app.setHost(this.StripeCheckout.__host)}}Button.load(this.StripeCheckout.__app)}).call(this); +if(typeof JSON!=="object"){JSON={}}(function(){"use strict";function f(n){return n<10?"0"+n:n}if(typeof Date.prototype.toJSON!=="function"){Date.prototype.toJSON=function(){return isFinite(this.valueOf())?this.getUTCFullYear()+"-"+f(this.getUTCMonth()+1)+"-"+f(this.getUTCDate())+"T"+f(this.getUTCHours())+":"+f(this.getUTCMinutes())+":"+f(this.getUTCSeconds())+"Z":null};String.prototype.toJSON=Number.prototype.toJSON=Boolean.prototype.toJSON=function(){return this.valueOf()}}var cx,escapable,gap,indent,meta,rep;function quote(string){escapable.lastIndex=0;return escapable.test(string)?'"'+string.replace(escapable,function(a){var c=meta[a];return typeof c==="string"?c:"\\u"+("0000"+a.charCodeAt(0).toString(16)).slice(-4)})+'"':'"'+string+'"'}function str(key,holder){var i,k,v,length,mind=gap,partial,value=holder[key];if(value&&typeof value==="object"&&typeof value.toJSON==="function"){value=value.toJSON(key)}if(typeof rep==="function"){value=rep.call(holder,key,value)}switch(typeof value){case"string":return quote(value);case"number":return isFinite(value)?String(value):"null";case"boolean":case"null":return String(value);case"object":if(!value){return"null"}gap+=indent;partial=[];if(Object.prototype.toString.apply(value)==="[object Array]"){length=value.length;for(i=0;i<length;i+=1){partial[i]=str(i,value)||"null"}v=partial.length===0?"[]":gap?"[\n"+gap+partial.join(",\n"+gap)+"\n"+mind+"]":"["+partial.join(",")+"]";gap=mind;return v}if(rep&&typeof rep==="object"){length=rep.length;for(i=0;i<length;i+=1){if(typeof rep[i]==="string"){k=rep[i];v=str(k,value);if(v){partial.push(quote(k)+(gap?": ":":")+v)}}}}else{for(k in value){if(Object.prototype.hasOwnProperty.call(value,k)){v=str(k,value);if(v){partial.push(quote(k)+(gap?": ":":")+v)}}}}v=partial.length===0?"{}":gap?"{\n"+gap+partial.join(",\n"+gap)+"\n"+mind+"}":"{"+partial.join(",")+"}";gap=mind;return v}}if(typeof JSON.stringify!=="function"){escapable=/[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;meta={"\b":"\\b"," ":"\\t","\n":"\\n","\f":"\\f","\r":"\\r",'"':'\\"',"\\":"\\\\"};JSON.stringify=function(value,replacer,space){var i;gap="";indent="";if(typeof space==="number"){for(i=0;i<space;i+=1){indent+=" "}}else if(typeof space==="string"){indent=space}rep=replacer;if(replacer&&typeof replacer!=="function"&&(typeof replacer!=="object"||typeof replacer.length!=="number")){throw new Error("JSON.stringify")}return str("",{"":value})}}if(typeof JSON.parse!=="function"){cx=/[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;JSON.parse=function(text,reviver){var j;function walk(holder,key){var k,v,value=holder[key];if(value&&typeof value==="object"){for(k in value){if(Object.prototype.hasOwnProperty.call(value,k)){v=walk(value,k);if(v!==undefined){value[k]=v}else{delete value[k]}}}}return reviver.call(holder,key,value)}text=String(text);cx.lastIndex=0;if(cx.test(text)){text=text.replace(cx,function(a){return"\\u"+("0000"+a.charCodeAt(0).toString(16)).slice(-4)})}if(/^[\],:{}\s]*$/.test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,"@").replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,"]").replace(/(?:^|:|,)(?:\s*\[)+/g,""))){j=eval("("+text+")");return typeof reviver==="function"?walk({"":j},""):j}throw new SyntaxError("JSON.parse")}}})();(function(){var namespace="StripeCheckout.require".split("."),name=namespace[namespace.length-1],base=this,i;for(i=0;i<namespace.length-1;i++){base=base[namespace[i]]=base[namespace[i]]||{}}if(base[name]===undefined){base[name]=function(){var modules={},cache={};var requireRelative=function(name,root){var path=expand(root,name),indexPath=expand(path,"./index"),module,fn;module=cache[path]||cache[indexPath];if(module){return module}else if(fn=modules[path]||modules[path=indexPath]){module={id:path,exports:{}};cache[path]=module.exports;fn(module.exports,function(name){return require(name,dirname(path))},module);return cache[path]=module.exports}else{throw"module "+name+" not found"}};var expand=function(root,name){var results=[],parts,part;if(/^\.\.?(\/|$)/.test(name)){parts=[root,name].join("/").split("/")}else{parts=name.split("/")}for(var i=0,length=parts.length;i<length;i++){part=parts[i];if(part==".."){results.pop()}else if(part!="."&&part!=""){results.push(part)}}return results.join("/")};var dirname=function(path){return path.split("/").slice(0,-1).join("/")};var require=function(name){return requireRelative(name,"")};require.define=function(bundle){for(var key in bundle){modules[key]=bundle[key]}};require.modules=modules;require.cache=cache;return require}.call()}})();StripeCheckout.require.define({"vendor/cookie":function(exports,require,module){var cookie={};var pluses=/\+/g;function extend(target,other){target=target||{};for(var prop in other){if(typeof source[prop]==="object"){target[prop]=extend(target[prop],source[prop])}else{target[prop]=source[prop]}}return target}function raw(s){return s}function decoded(s){return decodeURIComponent(s.replace(pluses," "))}function converted(s){if(s.indexOf('"')===0){s=s.slice(1,-1).replace(/\\"/g,'"').replace(/\\\\/g,"\\")}try{return config.json?JSON.parse(s):s}catch(er){}}var config=cookie.set=cookie.get=function(key,value,options){if(value!==undefined){options=extend(options,config.defaults);if(typeof options.expires==="number"){var days=options.expires,t=options.expires=new Date;t.setDate(t.getDate()+days)}value=config.json?JSON.stringify(value):String(value);return document.cookie=[config.raw?key:encodeURIComponent(key),"=",config.raw?value:encodeURIComponent(value),options.expires?"; expires="+options.expires.toUTCString():"",options.path?"; path="+options.path:"",options.domain?"; domain="+options.domain:"",options.secure?"; secure":""].join("")}var decode=config.raw?raw:decoded;var cookies=document.cookie.split("; ");var result=key?undefined:{};for(var i=0,l=cookies.length;i<l;i++){var parts=cookies[i].split("=");var name=decode(parts.shift());var cookie=decode(parts.join("="));if(key&&key===name){result=converted(cookie);break}if(!key){result[name]=converted(cookie)}}return result};config.defaults={};cookie.remove=function(key,options){if(cookie.get(key)!==undefined){cookie.set(key,"",extend(options,{expires:-1}));return true}return false};module.exports=cookie}});StripeCheckout.require.define({"vendor/ready":function(exports,require,module){!function(name,definition){if(typeof module!="undefined")module.exports=definition();else if(typeof define=="function"&&typeof define.amd=="object")define(definition);else this[name]=definition()}("domready",function(ready){var fns=[],fn,f=false,doc=document,testEl=doc.documentElement,hack=testEl.doScroll,domContentLoaded="DOMContentLoaded",addEventListener="addEventListener",onreadystatechange="onreadystatechange",readyState="readyState",loadedRgx=hack?/^loaded|^c/:/^loaded|c/,loaded=loadedRgx.test(doc[readyState]);function flush(f){loaded=1;while(f=fns.shift())f()}doc[addEventListener]&&doc[addEventListener](domContentLoaded,fn=function(){doc.removeEventListener(domContentLoaded,fn,f);flush()},f);hack&&doc.attachEvent(onreadystatechange,fn=function(){if(/^c/.test(doc[readyState])){doc.detachEvent(onreadystatechange,fn);flush()}});return ready=hack?function(fn){self!=top?loaded?fn():fns.push(fn):function(){try{testEl.doScroll("left")}catch(e){return setTimeout(function(){ready(fn)},50)}fn()}()}:function(fn){loaded?fn():fns.push(fn)}})}});(function(){if(!Array.prototype.indexOf){Array.prototype.indexOf=function(obj,start){var f,i,j,_i;j=this.length;f=start?start:0;for(i=_i=f;f<=j?_i<j:_i>j;i=f<=j?++_i:--_i){if(this[i]===obj){return i}}return-1}}}).call(this);StripeCheckout.require.define({"lib/helpers":function(exports,require,module){(function(){var delurkWinPhone,helpers,uaVersionFn;uaVersionFn=function(re){return function(){var uaMatch;uaMatch=helpers.userAgent.match(re);return uaMatch&&parseInt(uaMatch[1])}};delurkWinPhone=function(fn){return function(){return fn()&&!helpers.isWindowsPhone()}};helpers={userAgent:window.navigator.userAgent,escape:function(value){return value&&(""+value).replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/\"/g,""")},trim:function(value){return value.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,"")},sanitizeURL:function(value){var SCHEME_WHITELIST,allowed,scheme,_i,_len;if(!value){return}value=helpers.trim(value);SCHEME_WHITELIST=["data:","http:","https:"];allowed=false;for(_i=0,_len=SCHEME_WHITELIST.length;_i<_len;_i++){scheme=SCHEME_WHITELIST[_i];if(value.indexOf(scheme)===0){allowed=true;break}}if(!allowed){return null}return encodeURI(value)},iOSVersion:uaVersionFn(/(?:iPhone OS |iPad; CPU OS )(\d+)_\d+/),iOSMinorVersion:uaVersionFn(/(?:iPhone OS |iPad; CPU OS )\d+_(\d+)/),iOSBuildVersion:uaVersionFn(/(?:iPhone OS |iPad; CPU OS )\d+_\d+_(\d+)/),androidWebkitVersion:uaVersionFn(/Mozilla\/5\.0.*Android.*AppleWebKit\/([\d]+)/),androidVersion:uaVersionFn(/Android (\d+)\.\d+/),firefoxVersion:uaVersionFn(/Firefox\/(\d+)\.\d+/),chromeVersion:uaVersionFn(/Chrome\/(\d+)\.\d+/),safariVersion:uaVersionFn(/Version\/(\d+)\.\d+ Safari/),iOSChromeVersion:uaVersionFn(/CriOS\/(\d+)\.\d+/),iOSNativeVersion:uaVersionFn(/Stripe\/(\d+)\.\d+/),ieVersion:uaVersionFn(/(?:MSIE |Trident\/.*rv:)(\d{1,2})\./),isiOSChrome:function(){return/CriOS/.test(helpers.userAgent)},isiOSWebView:function(){return/(iPhone|iPod|iPad).*AppleWebKit((?!.*Safari)|(.*\([^)]*like[^)]*Safari[^)]*\)))/i.test(helpers.userAgent)},isiOS:delurkWinPhone(function(){return/(iPhone|iPad|iPod)/i.test(helpers.userAgent)}),isiOSNative:function(){return this.isiOS()&&this.iOSNativeVersion()>=3},isiPad:function(){return/(iPad)/i.test(helpers.userAgent)},isMac:delurkWinPhone(function(){return/mac/i.test(helpers.userAgent)}),isWindowsPhone:function(){return/(Windows\sPhone|IEMobile)/i.test(helpers.userAgent)},isWindowsOS:function(){return/(Windows NT \d\.\d)/i.test(helpers.userAgent)},isIE:function(){return/(MSIE ([0-9]{1,}[\.0-9]{0,})|Trident\/)/i.test(helpers.userAgent)},isChrome:function(){return"chrome"in window},isSafari:delurkWinPhone(function(){var userAgent;userAgent=helpers.userAgent;return/Safari/i.test(userAgent)&&!/Chrome/i.test(userAgent)}),isFirefox:delurkWinPhone(function(){return helpers.firefoxVersion()!=null}),isAndroidBrowser:function(){var version;version=helpers.androidWebkitVersion();return version&&version<537},isAndroidChrome:function(){var version;version=helpers.androidWebkitVersion();return version&&version>=537},isAndroidDevice:delurkWinPhone(function(){return/Android/.test(helpers.userAgent)}),isAndroidWebView:function(){return helpers.isAndroidChrome()&&/Version\/\d+\.\d+/.test(helpers.userAgent)},isNativeWebContainer:function(){return window.cordova!=null||/GSA\/\d+\.\d+/.test(helpers.userAgent)},isSupportedMobileOS:function(){return helpers.isiOS()||helpers.isAndroidDevice()},isAndroidWebapp:function(){var metaTag;if(!helpers.isAndroidChrome()){return false}metaTag=document.getElementsByName("apple-mobile-web-app-capable")[0]||document.getElementsByName("mobile-web-app-capable")[0];return metaTag&&metaTag.content==="yes"},isiOSBroken:function(){if(!(helpers.isiPad()&&helpers.iOSVersion()===8)){return false}switch(helpers.iOSMinorVersion()){case 0:return true;case 1:return helpers.iOSBuildVersion()<1}return false},isUserGesture:function(){var _ref,_ref1;return(_ref=(_ref1=window.event)!=null?_ref1.type:void 0)==="click"||_ref==="touchstart"||_ref==="touchend"},isInsideFrame:function(){return window.top!==window.self},isFallback:function(){var androidVersion,criosVersion,ffVersion,iOSVersion;if(!("postMessage"in window)||window.postMessageDisabled||document.documentMode&&document.documentMode<8){return true}androidVersion=helpers.androidVersion();if(androidVersion&&androidVersion<4){return true}iOSVersion=helpers.iOSVersion();if(iOSVersion&&iOSVersion<6){return true}ffVersion=helpers.firefoxVersion();if(ffVersion&&ffVersion<11){return true}criosVersion=helpers.iOSChromeVersion();if(criosVersion&&criosVersion<36){return true}return false},isSmallScreen:function(){return Math.min(window.screen.availHeight,window.screen.availWidth)<=640||/FakeCheckoutMobile/.test(helpers.userAgent)},pad:function(number,width,padding){var leading;if(width==null){width=2}if(padding==null){padding="0"}number=number+"";if(number.length>width){return number}leading=new Array(width-number.length+1).join(padding);return leading+number},requestAnimationFrame:function(callback){return(typeof window.requestAnimationFrame==="function"?window.requestAnimationFrame(callback):void 0)||(typeof window.webkitRequestAnimationFrame==="function"?window.webkitRequestAnimationFrame(callback):void 0)||window.setTimeout(callback,100)},requestAnimationInterval:function(func,interval){var callback,previous;previous=new Date;callback=function(){var frame,now,remaining;frame=helpers.requestAnimationFrame(callback);now=new Date;remaining=interval-(now-previous);if(remaining<=0){previous=now;func()}return frame};return callback()},getQueryParameterByName:function(name){var match;match=RegExp("[?&]"+name+"=([^&]*)").exec(window.location.search);return match&&decodeURIComponent(match[1].replace(/\+/g," "))},addQueryParameter:function(url,name,value){var hashParts,query;query=encodeURIComponent(name)+"="+encodeURIComponent(value);hashParts=new String(url).split("#");hashParts[0]+=hashParts[0].indexOf("?")!==-1?"&":"?";hashParts[0]+=query;return hashParts.join("#")},bind:function(element,name,callback){if(element.addEventListener){return element.addEventListener(name,callback,false)}else{return element.attachEvent("on"+name,callback)}},unbind:function(element,name,callback){if(element.removeEventListener){return element.removeEventListener(name,callback,false)}else{return element.detachEvent("on"+name,callback)}},host:function(url){var parent,parser;parent=document.createElement("div");parent.innerHTML='<a href="'+this.escape(url)+'">x</a>';parser=parent.firstChild;return""+parser.protocol+"//"+parser.host},strip:function(html){var tmp,_ref,_ref1;tmp=document.createElement("div");tmp.innerHTML=html;return(_ref=(_ref1=tmp.textContent)!=null?_ref1:tmp.innerText)!=null?_ref:""},setAutocomplete:function(el,type){var secureCCFill;secureCCFill=helpers.chromeVersion()>14||helpers.safariVersion()>7;if(type!=="cc-csc"&&(!/^cc-/.test(type)||secureCCFill)){el.setAttribute("x-autocompletetype",type);el.setAttribute("autocompletetype",type)}else{el.setAttribute("autocomplete","off")}if(!(type==="country-name"||type==="language"||type==="sex"||type==="gender-identity")){el.setAttribute("autocorrect","off");el.setAttribute("spellcheck","off")}if(!(/name|honorific/.test(type)||(type==="locality"||type==="city"||type==="adminstrative-area"||type==="state"||type==="province"||type==="region"||type==="language"||type==="org"||type==="organization-title"||type==="sex"||type==="gender-identity"))){return el.setAttribute("autocapitalize","off")}},hashCode:function(str){var hash,i,_i,_ref;hash=5381;for(i=_i=0,_ref=str.length;_i<_ref;i=_i+=1){hash=(hash<<5)+hash+str.charCodeAt(i)}return(hash>>>0)%65535},stripeUrlPrefix:function(){var match;match=window.location.hostname.match("^([a-z-]*)checkout.");if(match){return match[1]}else{return""}}};module.exports=helpers}).call(this)}});StripeCheckout.require.define({"lib/rpc":function(exports,require,module){(function(){var RPC,helpers,tracker,__bind=function(fn,me){return function(){return fn.apply(me,arguments)}},__slice=[].slice;helpers=require("lib/helpers");tracker=require("lib/tracker");RPC=function(){function RPC(target,options){if(options==null){options={}}this.processMessage=__bind(this.processMessage,this);this.sendMessage=__bind(this.sendMessage,this);this.invoke=__bind(this.invoke,this);this.startSession=__bind(this.startSession,this);this.rpcID=0;this.target=target;this.callbacks={};this.readyQueue=[];this.readyStatus=false;this.methods={};helpers.bind(window,"message",function(_this){return function(){var args;args=1<=arguments.length?__slice.call(arguments,0):[];return _this.message.apply(_this,args)}}(this))}RPC.prototype.startSession=function(){this.sendMessage("frameReady");return this.frameReady()};RPC.prototype.invoke=function(){var args,method;method=arguments[0],args=2<=arguments.length?__slice.call(arguments,1):[];tracker.trace.rpcInvoke(method);return this.ready(function(_this){return function(){return _this.sendMessage(method,args)}}(this))};RPC.prototype.message=function(e){var shouldProcess;shouldProcess=false;try{shouldProcess=e.source===this.target}catch(_error){}if(shouldProcess){return this.processMessage(e.data)}};RPC.prototype.ready=function(fn){if(this.readyStatus){return fn()}else{return this.readyQueue.push(fn)}};RPC.prototype.frameCallback=function(id,result){var _base;if(typeof(_base=this.callbacks)[id]==="function"){_base[id](result)}delete this.callbacks[id];return true};RPC.prototype.frameReady=function(){var callbacks,cb,_i,_len;this.readyStatus=true;callbacks=this.readyQueue.slice(0);for(_i=0,_len=callbacks.length;_i<_len;_i++){cb=callbacks[_i];cb()}return false};RPC.prototype.isAlive=function(){return true};RPC.prototype.sendMessage=function(method,args){var err,id,message,_ref;if(args==null){args=[]}id=++this.rpcID;if(typeof args[args.length-1]==="function"){this.callbacks[id]=args.pop()}message=JSON.stringify({method:method,args:args,id:id});if(((_ref=this.target)!=null?_ref.postMessage:void 0)==null){err=new Error("Unable to communicate with Checkout. Please contact support@stripe.com if the problem persists.");if(this.methods.rpcError!=null){this.methods.rpcError(err)}else{throw err}return}this.target.postMessage(message,"*");return tracker.trace.rpcPostMessage(method,args,id)};RPC.prototype.processMessage=function(data){var method,result,_base,_name;try{data=JSON.parse(data)}catch(_error){return}if(["frameReady","frameCallback","isAlive"].indexOf(data.method)!==-1){result=null;method=this[data.method];if(method!=null){result=method.apply(this,data.args)}}else{result=typeof(_base=this.methods)[_name=data.method]==="function"?_base[_name].apply(_base,data.args):void 0}if(data.method!=="frameCallback"){return this.invoke("frameCallback",data.id,result)}};return RPC}();module.exports=RPC}).call(this)}});StripeCheckout.require.define({"lib/uuid":function(exports,require,module){(function(){var S4;S4=function(){return((1+Math.random())*65536|0).toString(16).substring(1)};module.exports.generate=function(){var delim;delim="-";return S4()+S4()+delim+S4()+delim+S4()+delim+S4()+delim+S4()+S4()+S4()}}).call(this)}});StripeCheckout.require.define({"lib/pixel":function(exports,require,module){(function(){var canTrack,encode,generateID,getCookie,getCookieID,getLocalStorageID,request,setCookie,track;generateID=function(){return"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,function(c){var r,v;r=Math.random()*16|0;v=c==="x"?r:r&3|8;return v.toString(16)})};setCookie=function(name,value,options){var cookie,expires;if(options==null){options={}}if(options.expires===true){options.expires=-1}if(typeof options.expires==="number"){expires=new Date;expires.setTime(expires.getTime()+options.expires*24*60*60*1e3);options.expires=expires}if(options.path==null){options.path="/"}value=(value+"").replace(/[^!#-+\--:<-\[\]-~]/g,encodeURIComponent);cookie=encodeURIComponent(name)+"="+value;if(options.expires){cookie+=";expires="+options.expires.toGMTString()}if(options.path){cookie+=";path="+options.path}if(options.domain){cookie+=";domain="+options.domain}return document.cookie=cookie};getCookie=function(name){var cookie,cookies,index,key,value,_i,_len;cookies=document.cookie.split("; ");for(_i=0,_len=cookies.length;_i<_len;_i++){cookie=cookies[_i];index=cookie.indexOf("=");key=decodeURIComponent(cookie.substr(0,index));value=decodeURIComponent(cookie.substr(index+1));if(key===name){return value}}return null};encode=function(param){if(typeof param==="string"){return encodeURIComponent(param)}else{return encodeURIComponent(JSON.stringify(param))}};request=function(url,params,callback){var image,k,v;if(params==null){params={}}params.i=(new Date).getTime();params=function(){var _results;_results=[];for(k in params){v=params[k];_results.push(""+k+"="+encode(v))}return _results}().join("&");image=new Image;if(callback){image.onload=callback}image.src=""+url+"?"+params;return true};canTrack=function(){var dnt,_ref;dnt=(_ref=window.navigator.doNotTrack)!=null?_ref.toString().toLowerCase():void 0;switch(dnt){case"1":case"yes":case"true":return false;default:return true}};getLocalStorageID=function(){var err,lsid;if(!canTrack()){return"DNT"}try{lsid=localStorage.getItem("lsid");if(!lsid){lsid=generateID();localStorage.setItem("lsid",lsid)}return lsid}catch(_error){err=_error;return"NA"}};getCookieID=function(){var err,id;if(!canTrack()){return"DNT"}try{id=getCookie("cid")||generateID();setCookie("cid",id,{expires:360*20,domain:".stripe.com"});return id}catch(_error){err=_error;return"NA"}};track=function(event,params,callback){var k,referrer,request_params,search,v;if(params==null){params={}}referrer=document.referrer;search=window.location.search;request_params={event:event,rf:referrer,sc:search};for(k in params){v=params[k];request_params[k]=v}request_params.lsid||(request_params.lsid=getLocalStorageID());request_params.cid||(request_params.cid=getCookieID());return request("https://q.stripe.com",request_params,callback)};module.exports.track=track;module.exports.getLocalStorageID=getLocalStorageID;module.exports.getCookieID=getCookieID}).call(this)}});StripeCheckout.require.define({"vendor/base64":function(exports,require,module){var utf8Encode=function(string){string=(string+"").replace(/\r\n/g,"\n").replace(/\r/g,"\n");var utftext="",start,end;var stringl=0,n;start=end=0;stringl=string.length;for(n=0;n<stringl;n++){var c1=string.charCodeAt(n);var enc=null;if(c1<128){end++}else if(c1>127&&c1<2048){enc=String.fromCharCode(c1>>6|192,c1&63|128)}else{enc=String.fromCharCode(c1>>12|224,c1>>6&63|128,c1&63|128)}if(enc!==null){if(end>start){utftext+=string.substring(start,end)}utftext+=enc;start=end=n+1}}if(end>start){utftext+=string.substring(start,string.length)}return utftext};module.exports.encode=function(data){var b64="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";var o1,o2,o3,h1,h2,h3,h4,bits,i=0,ac=0,enc="",tmp_arr=[];if(!data){return data}data=utf8Encode(data);do{o1=data.charCodeAt(i++);o2=data.charCodeAt(i++);o3=data.charCodeAt(i++);bits=o1<<16|o2<<8|o3;h1=bits>>18&63;h2=bits>>12&63;h3=bits>>6&63;h4=bits&63;tmp_arr[ac++]=b64.charAt(h1)+b64.charAt(h2)+b64.charAt(h3)+b64.charAt(h4)}while(i<data.length);enc=tmp_arr.join("");switch(data.length%3){case 1:enc=enc.slice(0,-2)+"==";break;case 2:enc=enc.slice(0,-1)+"=";break}return enc}}});StripeCheckout.require.define({"lib/tracker":function(exports,require,module){(function(){var base64,config,isEventNameExisting,mixpanel,pixel,stateParameters,trace,traceSerialize,track,tracker,uuid,__indexOf=[].indexOf||function(item){for(var i=0,l=this.length;i<l;i++){if(i in this&&this[i]===item)return i}return-1};uuid=require("lib/uuid");pixel=require("lib/pixel");base64=require("vendor/base64");config={enabled:false,tracingEnabled:false,eventNamePrefix:"checkout.",distinctId:uuid.generate(),mixpanelKey:null};stateParameters={};tracker={};tracker.setEnabled=function(enabled){return config.enabled=enabled};tracker.setTracingEnabled=function(enabled){return config.tracingEnabled=enabled};tracker.setDistinctID=function(value){if(value){return config.distinctId=value}};tracker.getDistinctID=function(){return config.distinctId};tracker.setMixpanelKey=function(mixpanelKey){return config.mixpanelKey=mixpanelKey};tracker.track={outerOpen:function(parameters){var requiredKeys;requiredKeys=["key"];return track("outer.open",parameters,requiredKeys,{appendStateParameters:false})},open:function(options){var k,v;for(k in options){v=options[k];stateParameters["option-"+k]=v}return track("open")},close:function(parameters){return track("close",parameters,["withToken"])},rememberMe:function(parameters){return track("checkbox.rememberMe",parameters,["checked"])},authorizeAccount:function(){return track("account.authorize")},login:function(){return track("account.authorize.success")},wrongVerificationCode:function(){return track("account.authorize.fail")},keepMeLoggedIn:function(parameters){return track("checkbox.keepMeLoggedIn",parameters,["checked"])},logout:function(){return track("account.logout")},submit:function(){return track("submit")},invalid:function(parameters){if(parameters["err"]==null&¶meters["fields"]==null){throw new Error("Cannot track invalid because err or fields should be provided")}return track("invalid",parameters)},tokenError:function(msg){return track("token.error",{message:msg,type:"exception"})},moreInfo:function(){return track("moreInfoLink.click")},accountCreateSuccess:function(){return track("account.create.success")},accountCreateFail:function(){return track("account.create.fail")},addressAutocompleteShow:function(){return track("addressAutoComplete.show")},addressAutocompleteResultSelected:function(){return track("addressAutocomplete.result.selected")},back:function(parameters){return track("back",parameters,["from_step","to_step"])},token:function(parameters){return track("token",parameters,["stripe_token"])},phoneVerificationShow:function(){return track("phoneVerification.show")},phoneVerificationCreate:function(parameters){return track("phoneVerification.create",parameters,["use_sms"])},phoneVerificationAuthorize:function(parameters){return track("fraudCodeVerification.authorize",parameters,["valid"])},addressVerificationShow:function(){return track("addressVerification.show")}};tracker.trace={trigger:function(eventName,args){var EXCLUDED_EVENTS;EXCLUDED_EVENTS=["didResize","viewAddedToDOM","valueDidChange","checkedDidChange","keyUp","keyDown","keyPress","keyInput","click","blur"];eventName=eventName.split(".");if(eventName[eventName.length-1]==="checkout"){eventName.pop()}eventName=eventName.join(".");if(__indexOf.call(EXCLUDED_EVENTS,eventName)<0){if(this._triggerQueue==null){this._triggerQueue={}}this._triggerQueue[eventName]=traceSerialize(args);return this._triggerTimeout!=null?this._triggerTimeout:this._triggerTimeout=setTimeout(function(_this){return function(){var _ref;_ref=_this._triggerQueue;for(eventName in _ref){args=_ref[eventName];trace("trigger."+eventName,{args:args})}_this._triggerQueue={};return _this._triggerTimeout=null}}(this),0)}},rpcInvoke:function(method){return trace("rpc.invoke."+method)},rpcPostMessage:function(method,args,id){return trace("rpc.postMessage."+method,{id:id,args:traceSerialize(args)})}};tracker.state={setUIType:function(type){return stateParameters["st-ui-type"]=type},setUIIntegration:function(integration){return stateParameters["st-ui-integration"]=integration},setAccountsEnabled:function(bool){return stateParameters["st-accounts-enabled"]=bool},setRememberMeEnabled:function(bool){return stateParameters["st-remember-me-enabled"]=bool},setRememberMeChecked:function(bool){return stateParameters["st-remember-me-checked"]=bool},setAccountCreated:function(bool){return stateParameters["st-account-created"]=bool},setLoggedIn:function(bool){return stateParameters["st-logged-in"]=bool},setVariants:function(variants){var k,v,_results;_results=[];for(k in variants){v=variants[k];_results.push(stateParameters["st-variant-"+k]=v)}return _results},setPhoneVerificationShown:function(bool){return stateParameters["st-phone-verification-shown"]=bool},setAddressVerificationShown:function(bool){return stateParameters["st-address-verification-shown"]=bool}};tracker.dontTrack=function(fn){var enabled;enabled=config.enabled;config.enabled=false;fn();return config.enabled=enabled};isEventNameExisting=function(eventName){var exists,k,v,_ref;exists=false;_ref=tracker.events;for(k in _ref){v=_ref[k];if(v===eventName){exists=true;break}}return exists};trace=function(eventName,parameters,requiredKeys,options){if(parameters==null){parameters={}}if(requiredKeys==null){requiredKeys=[]}if(options==null){options={}}if(!config.tracingEnabled){return}eventName="trace."+eventName;options.excludeMixpanel=true;return track.apply(this,arguments)};track=function(eventName,parameters,requiredKeys,options){var fullEventName,k,key,missingKeys,v,_i,_len;if(parameters==null){parameters={}}if(requiredKeys==null){requiredKeys=[]}if(options==null){options={}}if(!config.enabled){return}missingKeys=function(){var _i,_len,_results;_results=[];for(_i=0,_len=requiredKeys.length;_i<_len;_i++){key=requiredKeys[_i];if(!(key in parameters)){_results.push(key)}}return _results}();if(missingKeys.length>0){throw new Error("Missing required data ("+missingKeys.join(", ")+") for tracking "+eventName+".")}parameters.distinct_id=config.distinctId;if(options.appendStateParameters==null){options.appendStateParameters=true}if(options.appendStateParameters){for(k in stateParameters){v=stateParameters[k];parameters[k]=v}}parameters.h=screen.height;parameters.w=screen.width;for(v=_i=0,_len=parameters.length;_i<_len;v=++_i){k=parameters[v];if(v instanceof Array){v.sort()}}fullEventName=""+config.eventNamePrefix+eventName;if(!options.excludeMixpanel){mixpanel.track(fullEventName,parameters)}return pixel.track(fullEventName,parameters)};mixpanel={};mixpanel.track=function(eventName,options){var dataStr,properties;if(options==null){options={}}if(!(typeof $!=="undefined"&&$!==null&&config.mixpanelKey!=null)){return}properties=$.extend({token:config.mixpanelKey,userAgent:window.navigator.userAgent},options);delete properties["stripe_token"];dataStr=base64.encode(JSON.stringify({event:eventName,properties:properties}));return(new Image).src="https://api.mixpanel.com/track/?ip=1&img=1&data="+dataStr};traceSerialize=function(value){var k,obj,v;if(value instanceof Array){return JSON.stringify(function(){var _i,_len,_results;_results=[];for(_i=0,_len=value.length;_i<_len;_i++){v=value[_i];_results.push(traceSerialize(v))}return _results}())}else if(value!=null&&value.target!=null&&value.type!=null){return traceSerialize({type:value.type,target_id:value.target.id})}else if(value instanceof Object){if(value.constructor===Object){obj={};for(k in value){v=value[k];obj[k]=traceSerialize(v)}return JSON.stringify(obj)}else{return value.toString()}}else{return value}};module.exports=tracker}).call(this)}});StripeCheckout.require.define({"outer/lib/fallbackRpc":function(exports,require,module){(function(){var FallbackRPC,cacheBust,interval,lastHash,re,__bind=function(fn,me){return function(){return fn.apply(me,arguments)}};cacheBust=1;interval=null;lastHash=null;re=/^#?\d+&/;FallbackRPC=function(){function FallbackRPC(target,host){this.invokeTarget=__bind(this.invokeTarget,this);this.target=target;this.host=host}FallbackRPC.prototype.invokeTarget=function(message){var url;message=+new Date+cacheBust++ +"&"+encodeURIComponent(message);url=this.host+"";return this.target.location=url.replace(/#.*$/,"")+"#"+message};FallbackRPC.prototype.receiveMessage=function(callback,delay){if(delay==null){delay=100}interval&&clearInterval(interval);return interval=setInterval(function(){var hash;hash=decodeURIComponent(window.location.hash);if(hash!==lastHash&&re.test(hash)){window.location.hash="";lastHash=hash;return callback({data:hash.replace(re,"")})}},delay)};return FallbackRPC}();module.exports=FallbackRPC}).call(this)}});StripeCheckout.require.define({"outer/lib/utils":function(exports,require,module){(function(){var $,$$,addClass,append,css,hasAttr,hasClass,insertAfter,insertBefore,parents,remove,resolve,text,trigger,__indexOf=[].indexOf||function(item){for(var i=0,l=this.length;i<l;i++){if(i in this&&this[i]===item)return i}return-1};$=function(sel){return document.querySelectorAll(sel)};$$=function(cls){var el,reg,_i,_len,_ref,_results;if(typeof document.getElementsByClassName==="function"){return document.getElementsByClassName(cls) +}else if(typeof document.querySelectorAll==="function"){return document.querySelectorAll("."+cls)}else{reg=new RegExp("(^|\\s)"+cls+"(\\s|$)");_ref=document.getElementsByTagName("*");_results=[];for(_i=0,_len=_ref.length;_i<_len;_i++){el=_ref[_i];if(reg.test(el.className)){_results.push(el)}}return _results}};hasAttr=function(element,attr){var node;if(typeof element.hasAttribute==="function"){return element.hasAttribute(attr)}else{node=element.getAttributeNode(attr);return!!(node&&(node.specified||node.nodeValue))}};trigger=function(element,name,data,bubble){if(data==null){data={}}if(bubble==null){bubble=true}if(window.jQuery){return jQuery(element).trigger(name,data)}};addClass=function(element,name){return element.className+=" "+name};hasClass=function(element,name){return __indexOf.call(element.className.split(" "),name)>=0};css=function(element,css){return element.style.cssText+=";"+css};insertBefore=function(element,child){return element.parentNode.insertBefore(child,element)};insertAfter=function(element,child){return element.parentNode.insertBefore(child,element.nextSibling)};append=function(element,child){return element.appendChild(child)};remove=function(element){var _ref;return(_ref=element.parentNode)!=null?_ref.removeChild(element):void 0};parents=function(node){var ancestors;ancestors=[];while((node=node.parentNode)&&node!==document&&__indexOf.call(ancestors,node)<0){ancestors.push(node)}return ancestors};resolve=function(url){var parser;parser=document.createElement("a");parser.href=url;return""+parser.href};text=function(element,value){if("innerText"in element){element.innerText=value}else{element.textContent=value}return value};module.exports={$:$,$$:$$,hasAttr:hasAttr,trigger:trigger,addClass:addClass,hasClass:hasClass,css:css,insertBefore:insertBefore,insertAfter:insertAfter,append:append,remove:remove,parents:parents,resolve:resolve,text:text}}).call(this)}});StripeCheckout.require.define({"outer/controllers/app":function(exports,require,module){(function(){var App,Checkout,RPC,TokenCallback,tracker,utils,__bind=function(fn,me){return function(){return fn.apply(me,arguments)}};Checkout=require("outer/controllers/checkout");TokenCallback=require("outer/controllers/tokenCallback");RPC=require("lib/rpc");tracker=require("lib/tracker");utils=require("outer/lib/utils");App=function(){function App(options){var _ref,_ref1;if(options==null){options={}}this.setHost=__bind(this.setHost,this);this.configure=__bind(this.configure,this);this.close=__bind(this.close,this);this.open=__bind(this.open,this);this.configurations={};this.checkouts={};this.host="https://checkout.stripe.com";this.timeLoaded=Math.floor((new Date).getTime()/1e3);this.totalButtons=0;if(((_ref=window.Prototype)!=null?(_ref1=_ref.Version)!=null?_ref1.indexOf("1.6"):void 0:void 0)===0){console.error("Stripe Checkout is not compatible with your version of Prototype.js. Please upgrade to version 1.7 or greater.")}}App.prototype.open=function(options,buttonId){var checkout,k,mergedOptions,v,_ref;if(buttonId==null){buttonId=null}mergedOptions={referrer:document.referrer,url:document.URL,timeLoaded:this.timeLoaded};if(buttonId&&this.configurations[buttonId]){_ref=this.configurations[buttonId];for(k in _ref){v=_ref[k];mergedOptions[k]=v}}for(k in options){v=options[k];mergedOptions[k]=v}if(mergedOptions.image){mergedOptions.image=utils.resolve(mergedOptions.image)}this.validateOptions(options,"open");if(buttonId){checkout=this.checkouts[buttonId]}else{checkout=new Checkout(new TokenCallback(options),this.host)}this.trackOpen(checkout,mergedOptions);return checkout.open(mergedOptions)};App.prototype.close=function(buttonId){var _ref;return(_ref=this.checkouts[buttonId])!=null?_ref.close():void 0};App.prototype.configure=function(buttonId,options){if(options==null){options={}}if(buttonId instanceof Object){options=buttonId;buttonId="button"+this.totalButtons++}if(options.image){options.image=utils.resolve(options.image)}this.validateOptions(options,"configure");this.configurations[buttonId]=options;this.checkouts[buttonId]=new Checkout(new TokenCallback(options),this.host);this.checkouts[buttonId].preload(options);return{open:function(_this){return function(options){return _this.open(options,buttonId)}}(this),close:function(_this){return function(){return _this.close(buttonId)}}(this)}};App.prototype.validateOptions=function(options,which){var url;try{return JSON.stringify(options)}catch(_error){url="https://stripe.com/docs/checkout#integration-custom";throw new Error("Stripe Checkout was unable to serialize the options passed to StripeCheckout."+which+"(). Please consult the doumentation to confirm that you're supplying values of the expected type: "+url)}};App.prototype.setHost=function(host){return this.host=host};App.prototype.trackOpen=function(checkout,options){tracker.setEnabled(!options.notrack);return tracker.track.outerOpen({key:options.key,lsid:"NA",cid:"NA"})};return App}();module.exports=App}).call(this)}});StripeCheckout.require.define({"outer/controllers/button":function(exports,require,module){(function(){var $$,Button,addClass,append,hasAttr,hasClass,helpers,insertAfter,parents,text,trigger,_ref,__bind=function(fn,me){return function(){return fn.apply(me,arguments)}};_ref=require("outer/lib/utils"),$$=_ref.$$,hasClass=_ref.hasClass,addClass=_ref.addClass,trigger=_ref.trigger,append=_ref.append,text=_ref.text,parents=_ref.parents,insertAfter=_ref.insertAfter,hasAttr=_ref.hasAttr;helpers=require("lib/helpers");Button=function(){Button.totalButtonId=0;Button.load=function(app){var button,el,element;element=$$("stripe-button");element=function(){var _i,_len,_results;_results=[];for(_i=0,_len=element.length;_i<_len;_i++){el=element[_i];if(!hasClass(el,"active")){_results.push(el)}}return _results}();element=element[element.length-1];if(!element){return}addClass(element,"active");button=new Button(element,app);return button.append()};function Button(scriptEl,app){this.parseOptions=__bind(this.parseOptions,this);this.parentHead=__bind(this.parentHead,this);this.parentForm=__bind(this.parentForm,this);this.onToken=__bind(this.onToken,this);this.open=__bind(this.open,this);this.submit=__bind(this.submit,this);this.append=__bind(this.append,this);this.render=__bind(this.render,this);var _base;this.scriptEl=scriptEl;this.app=app;this.document=this.scriptEl.ownerDocument;this.nostyle=helpers.isFallback();this.options=this.parseOptions();(_base=this.options).label||(_base.label="Pay with Card");this.options.token=this.onToken;this.$el=document.createElement("button");this.$el.setAttribute("type","submit");this.$el.className="stripe-button-el";helpers.bind(this.$el,"click",this.submit);helpers.bind(this.$el,"touchstart",function(){});this.render()}Button.prototype.render=function(){this.$el.innerHTML="";this.$span=document.createElement("span");text(this.$span,this.options.label);if(!this.nostyle){this.$el.style.visibility="hidden";this.$span.style.display="block";this.$span.style.minHeight="30px"}this.$style=document.createElement("link");this.$style.setAttribute("type","text/css");this.$style.setAttribute("rel","stylesheet");this.$style.setAttribute("href",this.app.host+"/v3/checkout/button-qpwW2WfkB0oGWVWIASjIOQ.css");return append(this.$el,this.$span)};Button.prototype.append=function(){var head;if(this.scriptEl){insertAfter(this.scriptEl,this.$el)}if(!this.nostyle){head=this.parentHead();if(head){append(head,this.$style)}}if(this.$form=this.parentForm()){helpers.unbind(this.$form,"submit",this.submit);helpers.bind(this.$form,"submit",this.submit)}if(!this.nostyle){setTimeout(function(_this){return function(){return _this.$el.style.visibility="visible"}}(this),1e3)}this.app.setHost(helpers.host(this.scriptEl.src));return this.appHandler=this.app.configure(this.options,{form:this.$form})};Button.prototype.disable=function(){return this.$el.setAttribute("disabled",true)};Button.prototype.enable=function(){return this.$el.removeAttribute("disabled")};Button.prototype.isDisabled=function(){return hasAttr(this.$el,"disabled")};Button.prototype.submit=function(e){if(typeof e.preventDefault==="function"){e.preventDefault()}if(!this.isDisabled()){this.open()}return false};Button.prototype.open=function(){return this.appHandler.open(this.options)};Button.prototype.onToken=function(token,args){var $input,$tokenInput,$tokenTypeInput,key,value;trigger(this.scriptEl,"token",token);if(this.$form){$tokenInput=this.renderInput("stripeToken",token.id);append(this.$form,$tokenInput);$tokenTypeInput=this.renderInput("stripeTokenType",token.type);append(this.$form,$tokenTypeInput);if(token.email){append(this.$form,this.renderInput("stripeEmail",token.email))}if(args){for(key in args){value=args[key];$input=this.renderInput(this.formatKey(key),value);append(this.$form,$input)}}this.$form.submit()}return this.disable()};Button.prototype.formatKey=function(key){var arg,args,_i,_len;args=key.split("_");key="";for(_i=0,_len=args.length;_i<_len;_i++){arg=args[_i];if(arg.length>0){key=key+arg.substr(0,1).toUpperCase()+arg.substr(1).toLowerCase()}}return"stripe"+key};Button.prototype.renderInput=function(name,value){var input;input=document.createElement("input");input.type="hidden";input.name=name;input.value=value;return input};Button.prototype.parentForm=function(){var el,elements,_i,_len,_ref1;elements=parents(this.$el);for(_i=0,_len=elements.length;_i<_len;_i++){el=elements[_i];if(((_ref1=el.tagName)!=null?_ref1.toLowerCase():void 0)==="form"){return el}}return null};Button.prototype.parentHead=function(){var _ref1,_ref2;return((_ref1=this.document)!=null?_ref1.head:void 0)||((_ref2=this.document)!=null?_ref2.getElementsByTagName("head")[0]:void 0)||this.document.body};Button.prototype.parseOptions=function(){var attr,match,options,_i,_len,_ref1;options={};_ref1=this.scriptEl.attributes;for(_i=0,_len=_ref1.length;_i<_len;_i++){attr=_ref1[_i];match=attr.name.match(/^data-(.+)$/);if(match!=null?match[1]:void 0){options[match[1]]=attr.value}}return options};return Button}();module.exports=Button}).call(this)}});StripeCheckout.require.define({"outer/controllers/checkout":function(exports,require,module){(function(){var Checkout,FallbackView,IframeView,TabView,helpers,tracker,__bind=function(fn,me){return function(){return fn.apply(me,arguments)}};helpers=require("lib/helpers");IframeView=require("outer/views/iframeView");TabView=require("outer/views/tabView");FallbackView=require("outer/views/fallbackView");tracker=require("lib/tracker");Checkout=function(){Checkout.activeView=null;function Checkout(tokenCallback,host){this.onTokenCallback=__bind(this.onTokenCallback,this);this.preload=__bind(this.preload,this);this.open=__bind(this.open,this);var path,shouldPopup,viewClass;this.tokenCallback=tokenCallback;this.host=host;this.onToken=function(_this){return function(data){return tokenCallback.trigger(data.token,data.args,_this.onTokenCallback)}}(this);if(helpers.isFallback()){viewClass=FallbackView;path="/v3/fallback/k2cOG4aMoRCi4ihFwg.html"}else{path="/v3/JOxxtiCiYdXIToC8is2w.html";if(Math.random()<.5){path="/v3/var-7kWUNyrVt1xEYx3R74jxg.html"}shouldPopup=helpers.isSupportedMobileOS()&&!(helpers.isNativeWebContainer()||helpers.isAndroidWebapp()||helpers.isiOSWebView()||helpers.isiOSChrome()&&!helpers.isUserGesture()||helpers.isiOSBroken());if(shouldPopup){viewClass=TabView}else{viewClass=IframeView}}path=""+path+"?distinct_id="+tracker.getDistinctID();this.view=new viewClass(this.onToken,this.host,path)}Checkout.prototype.open=function(options){if(options==null){options={}}if(Checkout.activeView&&Checkout.activeView!==this.view){Checkout.activeView.close()}Checkout.activeView=this.view;options.supportsTokenCallback=this.tokenCallback.supportsTokenCallback();return this.view.open(options,function(_this){return function(status){if(status){return}if(!(_this.view instanceof TabView)){return}_this.view=new IframeView(_this.onToken,_this.host,"/v3/JOxxtiCiYdXIToC8is2w.html");return _this.open(options)}}(this))};Checkout.prototype.close=function(){var _ref;return(_ref=this.view)!=null?_ref.close():void 0};Checkout.prototype.preload=function(options){return this.view.preload(options)};Checkout.prototype.onTokenCallback=function(){return this.view.triggerTokenCallback.apply(this.view,arguments)};return Checkout}();module.exports=Checkout}).call(this)}});StripeCheckout.require.define({"outer/controllers/tokenCallback":function(exports,require,module){(function(){var TokenCallback,__bind=function(fn,me){return function(){return fn.apply(me,arguments)}};TokenCallback=function(){function TokenCallback(options){this.supportsTokenCallback=__bind(this.supportsTokenCallback,this);this.trigger=__bind(this.trigger,this);if(options.token){this.fn=options.token;this.version=1}else if(options.onToken){this.fn=options.onToken;this.version=2}}TokenCallback.prototype.trigger=function(token,addresses,callback){var data,k,shipping,v;if(this.version===2){data={token:token};shipping=null;for(k in addresses){v=addresses[k];if(/^shipping_/.test(k)){if(shipping==null){shipping={}}shipping[k.replace(/^shipping_/,"")]=v}}if(shipping!=null){data.shipping=shipping}return this.fn(data,callback)}else{return this.fn(token,addresses)}};TokenCallback.prototype.supportsTokenCallback=function(){return this.version>1};return TokenCallback}();module.exports=TokenCallback}).call(this)}});StripeCheckout.require.define({"outer/views/fallbackView":function(exports,require,module){(function(){var FallbackRPC,FallbackView,View,__bind=function(fn,me){return function(){return fn.apply(me,arguments)}},__hasProp={}.hasOwnProperty,__extends=function(child,parent){for(var key in parent){if(__hasProp.call(parent,key))child[key]=parent[key]}function ctor(){this.constructor=child}ctor.prototype=parent.prototype;child.prototype=new ctor;child.__super__=parent.prototype;return child};FallbackRPC=require("outer/lib/fallbackRpc");View=require("outer/views/view");FallbackView=function(_super){__extends(FallbackView,_super);function FallbackView(){this.triggerTokenCallback=__bind(this.triggerTokenCallback,this);this.close=__bind(this.close,this);this.open=__bind(this.open,this);FallbackView.__super__.constructor.apply(this,arguments)}FallbackView.prototype.open=function(options,callback){var message,url;FallbackView.__super__.open.apply(this,arguments);url=this.host+this.path;this.frame=window.open(url,"stripe_checkout_app","width=400,height=400,location=yes,resizable=yes,scrollbars=yes");if(this.frame==null){alert("Disable your popup blocker to proceed with checkout.");url="https://stripe.com/docs/checkout#integration-more-runloop";throw new Error("To learn how to prevent the Stripe Checkout popup from being blocked, please visit "+url)}this.rpc=new FallbackRPC(this.frame,url);this.rpc.receiveMessage(function(_this){return function(e){var data;try{data=JSON.parse(e.data)}catch(_error){return}return _this.onToken(data)}}(this));message=JSON.stringify(this.options);this.rpc.invokeTarget(message);return callback(true)};FallbackView.prototype.close=function(){var _ref;return(_ref=this.frame)!=null?_ref.close():void 0};FallbackView.prototype.triggerTokenCallback=function(err){if(err){return alert(err)}};return FallbackView}(View);module.exports=FallbackView}).call(this)}});StripeCheckout.require.define({"outer/views/iframeView":function(exports,require,module){(function(){var IframeView,RPC,View,helpers,ready,utils,__bind=function(fn,me){return function(){return fn.apply(me,arguments)}},__hasProp={}.hasOwnProperty,__extends=function(child,parent){for(var key in parent){if(__hasProp.call(parent,key))child[key]=parent[key]}function ctor(){this.constructor=child}ctor.prototype=parent.prototype;child.prototype=new ctor;child.__super__=parent.prototype;return child};utils=require("outer/lib/utils");helpers=require("lib/helpers");RPC=require("lib/rpc");View=require("outer/views/view");ready=require("vendor/ready");IframeView=function(_super){__extends(IframeView,_super);function IframeView(){this.configure=__bind(this.configure,this);this.removeFrame=__bind(this.removeFrame,this);this.removeTouchOverlay=__bind(this.removeTouchOverlay,this);this.showTouchOverlay=__bind(this.showTouchOverlay,this);this.attachIframe=__bind(this.attachIframe,this);this.setToken=__bind(this.setToken,this);this.closed=__bind(this.closed,this);this.close=__bind(this.close,this);this.preload=__bind(this.preload,this);this.open=__bind(this.open,this);return IframeView.__super__.constructor.apply(this,arguments)}IframeView.prototype.open=function(options,callback){IframeView.__super__.open.apply(this,arguments);return ready(function(_this){return function(){var left,loaded,_ref;_this.originalOverflowValue=document.body.style.overflow;if(_this.frame==null){_this.configure()}if(typeof $!=="undefined"&&$!==null?(_ref=$.fn)!=null?_ref.modal:void 0:void 0){$(document).off("focusin.bs.modal").off("focusin.modal")}_this.frame.style.display="block";if(_this.shouldShowTouchOverlay()){_this.showTouchOverlay();_this.frame.style.top=(window.scrollY||window.pageYOffset)+"px";left=(window.scrollX||window.pageXOffset)+(window.innerWidth-_this.iframeWidth())/2;left=Math.min(window.innerWidth-_this.iframeWidth(),Math.max(0,left));left=Math.max(0,left);_this.frame.style.left=left+"px"}loaded=false;setTimeout(function(){if(loaded){return}loaded=true;callback(false);return _this.removeFrame()},8e3);return _this.rpc.ready(function(){if(loaded){return}loaded=true;callback(true);_this.rpc.invoke("render","","iframe",_this.options);document.body.style.overflow="hidden";return _this.rpc.invoke("open",{timeLoaded:_this.options.timeLoaded},function(success){var _base;if(success){return typeof(_base=_this.options).opened==="function"?_base.opened():void 0}})})}}(this))};IframeView.prototype.preload=function(options){return ready(function(_this){return function(){_this.configure();return _this.rpc.invoke("preload",options)}}(this))};IframeView.prototype.iframeWidth=function(){if(helpers.isSmallScreen()){return 328}else{return 380}};IframeView.prototype.close=function(){return this.rpc.invoke("close")};IframeView.prototype.closed=function(){var _base;document.body.style.overflow=this.originalOverflowValue;this.removeFrame();clearTimeout(this.tokenTimeout);if(this.token!=null){this.onToken(this.token)}this.token=null;if(typeof(_base=this.options).closed==="function"){_base.closed()}this.preload(this.options);return true};IframeView.prototype.setToken=function(data){this.token=data;return this.tokenTimeout!=null?this.tokenTimeout:this.tokenTimeout=setTimeout(function(_this){return function(){_this.onToken(_this.token);_this.tokenTimeout=null;return _this.token=null}}(this),3e3)};IframeView.prototype.attachIframe=function(){var cssText,iframe;iframe=document.createElement("iframe");iframe.setAttribute("frameBorder","0");iframe.setAttribute("allowtransparency","true");cssText="z-index: 9999;\ndisplay: none;\nbackground: transparent;\nbackground: rgba(0,0,0,0.005);\nborder: 0px none transparent;\noverflow-x: hidden;\noverflow-y: auto;\nvisibility: hidden;\nmargin: 0;\npadding: 0;\n-webkit-tap-highlight-color: transparent;\n-webkit-touch-callout: none;";if(this.shouldShowTouchOverlay()){cssText+="position: absolute;\nwidth: "+this.iframeWidth()+"px;\nheight: 100%;"}else{cssText+="position: fixed;\nleft: 0;\ntop: 0;\nwidth: 100%;\nheight: 100%;"}iframe.style.cssText=cssText;helpers.bind(iframe,"load",function(){return iframe.style.visibility="visible"});iframe.src=this.host+this.path;iframe.className=iframe.name="stripe_checkout_app";utils.append(document.body,iframe);return iframe};IframeView.prototype.showTouchOverlay=function(){var toRepaint;if(this.overlay){return}this.overlay=document.createElement("div");this.overlay.style.cssText="z-index: 9998;\nbackground: #000;\nopacity: 0;\nborder: 0px none transparent;\noverflow: none;\nmargin: 0;\npadding: 0;\n-webkit-tap-highlight-color: transparent;\n-webkit-touch-callout: none;\nposition: fixed;\nleft: 0;\ntop: 0;\nwidth: 200%;\nheight: 200%;\ntransition: opacity 320ms ease;\n-webkit-transition: opacity 320ms ease;\n-moz-transition: opacity 320ms ease;\n-ms-transition: opacity 320ms ease;";utils.append(document.body,this.overlay);toRepaint=this.overlay.offsetHeight;return this.overlay.style.opacity="0.5"};IframeView.prototype.removeTouchOverlay=function(){var overlay;if(!this.overlay){return}overlay=this.overlay;overlay.style.opacity="0";setTimeout(function(){return utils.remove(overlay)},400);return this.overlay=null};IframeView.prototype.removeFrame=function(){var frame;if(this.shouldShowTouchOverlay()){this.removeTouchOverlay()}frame=this.frame;setTimeout(function(){return utils.remove(frame)},500);return this.frame=null};IframeView.prototype.configure=function(){if(this.frame!=null){this.removeFrame()}this.frame=this.attachIframe();this.rpc=new RPC(this.frame.contentWindow,{host:this.host});this.rpc.methods.closed=this.closed;return this.rpc.methods.setToken=this.setToken};IframeView.prototype.shouldShowTouchOverlay=function(){return helpers.isSupportedMobileOS()};return IframeView}(View);module.exports=IframeView}).call(this)}});StripeCheckout.require.define({"outer/views/tabView":function(exports,require,module){(function(){var RPC,TabView,View,helpers,__bind=function(fn,me){return function(){return fn.apply(me,arguments)}},__hasProp={}.hasOwnProperty,__extends=function(child,parent){for(var key in parent){if(__hasProp.call(parent,key))child[key]=parent[key]}function ctor(){this.constructor=child}ctor.prototype=parent.prototype;child.prototype=new ctor;child.__super__=parent.prototype;return child};RPC=require("lib/rpc");helpers=require("lib/helpers");View=require("outer/views/view");TabView=function(_super){__extends(TabView,_super);function TabView(){this.closed=__bind(this.closed,this);this.checkForClosedTab=__bind(this.checkForClosedTab,this);this.setToken=__bind(this.setToken,this);this.fullPath=__bind(this.fullPath,this);this.close=__bind(this.close,this);this.open=__bind(this.open,this);TabView.__super__.constructor.apply(this,arguments);this.closedTabInterval=null;this.color=null;this.colorSet=false}TabView.prototype.open=function(options,callback){var targetName,url,_base,_ref,_ref1;TabView.__super__.open.apply(this,arguments);try{if((_ref=this.frame)!=null){_ref.close()}}catch(_error){}if(window.name==="stripe_checkout_tabview"){window.name=""}if(helpers.isiOSChrome()){targetName="_blank"}else{targetName="stripe_checkout_tabview"}this.frame=window.open(this.fullPath(),targetName);if(!this.frame&&((_ref1=this.options.key)!=null?_ref1.indexOf("test"):void 0)!==-1){url="https://stripe.com/docs/checkout#integration-more-runloop";console.error("Stripe Checkout was unable to open a new window, possibly due to a popup blocker.\nTo provide the best experience for your users, follow the guide at "+url+".\nThis message will only appear when using a test publishable key.")}if(!this.frame||this.frame===window){this.close();callback(false);return}if(typeof(_base=this.frame).focus==="function"){_base.focus()}this.rpc=new RPC(this.frame,{host:this.host});this.rpc.methods.setToken=this.setToken;this.rpc.methods.closed=this.closed;return this.rpc.ready(function(_this){return function(){var _base1;callback(true);_this.rpc.invoke("render","","tab",_this.options);_this.rpc.invoke("open");if(typeof(_base1=_this.options).opened==="function"){_base1.opened()}return _this.checkForClosedTab()}}(this))};TabView.prototype.close=function(){if(this.frame&&this.frame!==window){return this.frame.close()}};TabView.prototype.fullPath=function(){return this.host+this.path};TabView.prototype.setToken=function(data){this.token=data;return this.tokenTimeout!=null?this.tokenTimeout:this.tokenTimeout=setTimeout(function(_this){return function(){_this.onToken(_this.token);_this.tokenTimeout=null;return _this.token=null}}(this),3e3)};TabView.prototype.checkForClosedTab=function(){if(this.closedTabInterval){clearInterval(this.closedTabInterval)}return this.closedTabInterval=setInterval(function(_this){return function(){if(!_this.frame||!_this.frame.postMessage||_this.frame.closed){return _this.closed()}}}(this),100)};TabView.prototype.closed=function(){var _base;clearInterval(this.closedTabInterval);clearTimeout(this.tokenTimeout);if(this.token!=null){this.onToken(this.token)}return typeof(_base=this.options).closed==="function"?_base.closed():void 0};return TabView}(View);module.exports=TabView}).call(this)}});StripeCheckout.require.define({"outer/views/view":function(exports,require,module){(function(){var View,__bind=function(fn,me){return function(){return fn.apply(me,arguments)}},__slice=[].slice;View=function(){function View(onToken,host,path){this.triggerTokenCallback=__bind(this.triggerTokenCallback,this);this.open=__bind(this.open,this);this.onToken=onToken;this.host=host;this.path=path}View.prototype.open=function(options,callback){return this.options=options};View.prototype.close=function(){};View.prototype.preload=function(options){};View.prototype.triggerTokenCallback=function(){var args;args=arguments;return this.rpc.ready(function(_this){return function(){var _ref;return(_ref=_this.rpc).invoke.apply(_ref,["tokenCallback"].concat(__slice.call(args)))}}(this))};return View}();module.exports=View}).call(this)}});(function(){var App,Button,app,require,_ref,_ref1;require=require||this.StripeCheckout.require;Button=require("outer/controllers/button");App=require("outer/controllers/app");if(((_ref=this.StripeCheckout)!=null?_ref.__app:void 0)==null){this.StripeCheckout||(this.StripeCheckout={});this.StripeCheckout.__app=app=new App;this.StripeCheckout.open=app.open;this.StripeCheckout.configure=app.configure;this.StripeButton=this.StripeCheckout;if(((_ref1=this.StripeCheckout)!=null?_ref1.__host:void 0)&&this.StripeCheckout.__host!==""){app.setHost(this.StripeCheckout.__host)}}Button.load(this.StripeCheckout.__app)}).call(this); //# sourceMappingURL=https://sourcemaps.stripe.com/checkout/checkout.js.map