Update ja.coffee

Update ja.coffee

--- app/locale/ja.coffee
+++ app/locale/ja.coffee
@@ -25,9 +25,9 @@
     im_a_student: "私は学生です"
     learn_more: "もっと知りたい"
     classroom_in_a_box: "コンピュータサイエンスを教えるための箱の中の教室"
-    codecombat_is: "CodeCombatは実際にゲームを遊びながらコンピュータサイエンスを学べるプラットフォームです" # {change}
-    our_courses: "私たちのコースは実際に学校ですばらしい体験プレイをされ、あまりプログラミング経験のない先生でも安心です。" # {change}
-#    top_screenshots_hint: "Students write code and see their changes update in real-time"
+    codecombat_is: "CodeCombatは生徒のための実際にゲームを遊びながらコンピュータサイエンスを学べるプラットフォームです"
+    our_courses: "私たちのコースはそれまでプログラミング経験がなかった先生でも教室ですばらしいプレイテストをされています。"
+    top_screenshots_hint: "生徒がコードを書くとリアルタイムでその変更による変化を見れます"
     designed_with: "先生のための設計"
     real_code: "実際に,コードをタイピング"
     from_the_first_level: "それもはじめから"
@@ -437,18 +437,18 @@
     tip_compiler_ignores_comments: "時々コンパイラは僕のコメントを無視してるんじゃないかと思う。"
     tip_understand_recursion: "再帰を理解するための唯一の方法は再帰を理解することだ。"
     tip_life_and_polymorphism: "オープンソースはtotally polymorphic heterogeneous構造のようなものだ:どんなタイプの人もウェルカムです。"
-#    tip_mistakes_proof_of_trying: "Mistakes in your code are just proof that you are trying."
-#    tip_adding_orgres: "Rounding up ogres."
-#    tip_sharpening_swords: "Sharpening the swords."
-#    tip_ratatouille: "You must not let anyone define your limits because of where you come from. Your only limit is your soul. - Gusteau, Ratatouille"
-#    tip_nemo: "When life gets you down, want to know what you've gotta do? Just keep swimming, just keep swimming. - Dory, Finding Nemo"
+    tip_mistakes_proof_of_trying: "コードのミスはあなたがやろうとしていることの証明しているだけだ。"
+    tip_adding_orgres: "オーガを狩れ。"
+    tip_sharpening_swords: "剣を研ぎ澄ます。"
+    tip_ratatouille: "どこで生まれ育とうが他人に限界を決めさせてはいけない あきらめなければなんでもできるのです。- グストー, レミーのおいしいレストラン"
+    tip_nemo: "人生にがっくりきたとき、何をすべきか知りたくない? 泳ぎましょ、 泳ぎましょ。 - ドリー、 ファインディング・ニモ"
 #    tip_internet_weather: "Just move to the internet, it's great here. We get to live inside where the weather is always awesome. - John Green"
 #    tip_nerds: "Nerds are allowed to love stuff, like jump-up-and-down-in-the-chair-can't-control-yourself love it. - John Green"
 #    tip_self_taught: "I taught myself 90% of what I've learned. And that's normal! - Hank Green"
 #    tip_luna_lovegood: "Don't worry, you're just as sane as I am. - Luna Lovegood"
-#    tip_good_idea: "The best way to have a good idea is to have a lot of ideas. - Linus Pauling"
-#    tip_programming_not_about_computers: "Computer Science is no more about computers than astronomy is about telescopes. - Edsger Dijkstra"
-#    tip_mulan: "Believe you can, then you will. - Mulan"
+    tip_good_idea: "優れたアイディアを得る最善の方法は、多くのアイディアを得ることだ。 - ライナス・ポーリング"
+    tip_programming_not_about_computers: "天文学が望遠鏡に関する学問でないのと同様に、計算機科学はコンピュータに関する学問ではない。 - エドガー・ダイクストラ"
+    tip_mulan: "できると信じていれば、できる。 - ムーラン"

   game_menu:
     inventory_tab: "インベントリー"


More norwegian translations.

More norwegian translations.

--- app/locale/nb.coffee
+++ app/locale/nb.coffee
@@ -7,7 +7,7 @@
     old_browser: "Å nei, nettleseren din er for gammel til å kjøre CodeCombat. Beklager!" # Warning that shows up on really old Firefox/Chrome/Safari
     old_browser_suffix: "Du kan prøve likevel, men det vil kanskje ikke virke."
     ipad_browser: "Dårlige nyheter: CodeCombat kjører ikke i nettleseren på iPad. Gode nyheter: iPad appen vår venter bare på godkjenning av Apple."
-    campaign: "Kampaje"
+    campaign: "Kampanje"
     for_beginners: "For nybegynnere"
     multiplayer: "Flerspiller" # Not currently shown on home page
     for_developers: "For Utviklere" # Not currently shown on home page.
@@ -78,7 +78,7 @@
     awaiting_levels_adventurer_prefix: "Vi lanserer fem nye brett hver uke"
     awaiting_levels_adventurer: "Registrer deg som Eventyrer"
     awaiting_levels_adventurer_suffix: "for å få spille nye brett før alle andre."
-    adjust_volume: "Juster volum"
+    adjust_volume: "Juster lydnivå"
     choose_your_level: "Velg Ditt Nivå" # The rest of this section is the old play view at /play-old and isn't very important.
     adventurer_prefix: "Du kan hoppe til hvilket som helst brett under, eller diskutere nivåene på "
     adventurer_forum: "Eventyrer forumet"
@@ -106,7 +106,7 @@
     finishing: "Fullfører"
     sign_in_with_facebook: "Logg på med Facebook"
     sign_in_with_gplus: "Logg på med G+"
-    signup_switch: "Vil du opprette en konto?"
+    signup_switch: "Vil du lage en konto?"

   signup:
     email_announcements: "Motta kunngjøringer på epost"
@@ -155,9 +155,9 @@
     and: "og"
     name: "Navn"
     date: "Dato"
-    body: "Kropp"
+    body: "Kropp" # "kropp" ??
     version: "Versjon"
-    pending: "Venter"
+    pending: "Avventer"
     accepted: "Akseptert"
     rejected: "Avvist"
     withdrawn: "Trukket tilbake"
@@ -172,7 +172,7 @@
     undo_shortcut: "(Ctrl+Z)"
     redo_prefix: "Gjenta"
     redo_shortcut: "(Ctrl+Shift+Z)"
-    play_preview: "Spill av forhåndsvisning av valgt nivå"
+    play_preview: "Spill av forhåndsvisning av valgt brett"
     result: "Resultat"
     results: "Resultater"
     description: "Beskrivelse"
@@ -233,7 +233,7 @@
     action_timeline: "Hendelsestidslinje"
     click_to_select: "Klikk på en enhet for å velge den."
     control_bar_multiplayer: "Flerspiller"
-    control_bar_join_game: "Bli med i Spillet"
+    control_bar_join_game: "Bli med i spillet"
     reload: "Tilbakestill"
     reload_title: "Tilbakestille all koden?"
     reload_really: "Er du sikker på at du vil tilbakestille dette brettet til begynnelsen?"
@@ -252,7 +252,7 @@
     victory_hour_of_code_done: "Er du ferdig?"
     victory_hour_of_code_done_yes: "Ja, jeg er ferdig med min Kodetime!"
     victory_experience_gained: "XP Opparbeidet"
-    victory_gems_gained: "Gems Opparbeidet"
+    victory_gems_gained: "Mottatte juveler"
     guide_title: "Guide"
     tome_minion_spells: "Din Minions' Trylleformularer" # Only in old-style levels.
     tome_read_only_spells: "Kun-Lesbare Trylleformularer" # Only in old-style levels.
@@ -310,14 +310,14 @@
     tip_first_language: "Den mest katastrofale tingen du noen sinne kan lære er ditt første programmeringsspråk. - Alan Kay"
     tip_hardware_problem: "Q: Hvor mange programmerere trengs det for å skifte en lyspære?  A: Inge, det er et hardware problem."
     tip_hofstadters_law: "Hofstadters Lov: Ting tar alltid lenger tid enn du tror, selv når du tar Hofstadters Lov med i beregningen."
-#    tip_premature_optimization: "Premature optimization is the root of all evil. - Donald Knuth"
+    tip_premature_optimization: "For tidlig optimering er roten til alt ondt. - Donald Knuth"
 #    tip_brute_force: "When in doubt, use brute force. - Ken Thompson"
-#    tip_extrapolation: "There are only two kinds of people: those that can extrapolate from incomplete data..."
+    tip_extrapolation: "Det finnes to typer mennesker: De som kan ekstrapolere fra ufulstendige data..."
 #    tip_superpower: "Coding is the closest thing we have to a superpower."
 #    tip_control_destiny: "In real open source, you have the right to control your own destiny. - Linus Torvalds"
-#    tip_no_code: "No code is faster than no code."
+    tip_no_code: "Ingen kode er raskere enn ingen kode."
 #    tip_code_never_lies: "Code never lies, comments sometimes do. — Ron Jeffries"
-#    tip_reusable_software: "Before software can be reusable it first has to be usable."
+    tip_reusable_software: "Før programvare kan bli gjenbrukbart må det først bli brukbart."
 #    tip_optimization_operator: "Every language has an optimization operator. In most languages that operator is ‘//’"
 #    tip_lines_of_code: "Measuring programming progress by lines of code is like measuring aircraft building progress by weight. — Bill Gates"
 #    tip_source_code: "I want to change the world but they would not give me the source code."
@@ -329,8 +329,8 @@
     save_load_tab: "Lagre/Laste"
     options_tab: "Innstillinger"
     guide_tab: "Guide"
-#    guide_video_tutorial: "Video Tutorial"
-#    guide_tips: "Tips"
+    guide_video_tutorial: "Opplæringsvideo"
+    guide_tips: "Tips"
     multiplayer_tab: "Flerspiller"
     auth_tab: "Lag konto"
     inventory_caption: "Utstyr helten din"
@@ -339,26 +339,25 @@
     options_caption: "Velg innstillinger"
     guide_caption: "Dokumentasjon og tips"
     multiplayer_caption: "Spill med venner"
-#    auth_caption: "Save your progress."
-
-#  leaderboard:
-#    leaderboard: "Leaderboard"
-#    view_other_solutions: "View Other Solutions"
-#    scores: "Scores"
-#    top_solutions: "Top Solutions"
-#    day: "Today"
-#    week: "This Week"
-#    all: "All-Time"
-#    time: "Time"
-#    damage_taken: "Damage Taken"
-#    damage_dealt: "Damage Dealt"
-#    difficulty: "Difficulty"
-#    gold_collected: "Gold Collected"
+    auth_caption: "Lagre fremdriften din."
+
+  leaderboard:
+    leaderboard: "Ledertavla"
+    view_other_solutions: "Se andre løsninger"
+    top_solutions: "Beste løsninger"
+    day: "I dag"
+    week: "Denne uken"
+    all: "Tidenes"
+    time: "Tid"
+    damage_taken: "Mottat skade"
+    damage_dealt: "Avgitt skade"
+    difficulty: "Vanskelighetsgrad"
+    gold_collected: "Samlet gull"

   inventory:
     choose_inventory: "Velg utstyr"
     equipped_item: "I Bruk"
-#    required_purchase_title: "Required"
+    required_purchase_title: "Påkrevd"
     available_item: "Tilgjengelig"
     restricted_title: "Ikke tilgjengelig"
     should_equip: "(dobbel-klikk for å bruke)"
@@ -378,9 +377,9 @@
     prompt_title: "Ikke nok juveler"
     prompt_body: "Har du lyst på flere?"
     prompt_button: "Til Butikken"
-#    recovered: "Previous gems purchase recovered. Please refresh the page."
-
-#  subscribe:
+    recovered: "Tidligere juvelkjøp gjenopprettet. Vennligst last inn siden på nytt."
+
+  subscribe:
 #    comparison_blurb: "Sharpen your skills with a CodeCombat subscription!"
 #    feature1: "60+ basic levels across 4 worlds"
 #    feature2: "7 powerful new heroes with unique skills!"
@@ -390,15 +389,15 @@
 #    feature6: "Premium email support"
 #    free: "Free"
 #    month: "month"
-#    subscribe_title: "Subscribe"
-#    unsubscribe: "Unsubscribe"
-#    confirm_unsubscribe: "Confirm Unsubscribe"
-#    never_mind: "Never Mind, I Still Love You"
-#    thank_you_months_prefix: "Thank you for supporting us these last"
-#    thank_you_months_suffix: "months."
-#    thank_you: "Thank you for supporting CodeCombat."
-#    sorry_to_see_you_go: "Sorry to see you go! Please let us know what we could have done better."
-#    unsubscribe_feedback_placeholder: "O, what have we done?"
+    subscribe_title: "Abonner"
+    unsubscribe: "Si opp abonnement"
+    confirm_unsubscribe: "Bekreft oppsigelse av abonnement"
+    never_mind: "Det går bra, jeg elsker deg fortsatt"
+    thank_you_months_prefix: "Takk for at du støttet oss i de siste"
+    thank_you_months_suffix: "månedene."
+    thank_you: "Takk for at du støtter CodeCombat."
+    sorry_to_see_you_go: "Leit at du ikke blir med videre. Vennligst fortell oss hva vi kunne gjort bedre."
+    unsubscribe_feedback_placeholder: "Åh, hva har vi gjort?"
 #    parent_button: "Ask your parent"
 #    parent_email_description: "We'll email them so they can buy you a CodeCombat subscription."
 #    parent_email_input_invalid: "Email address invalid."
@@ -407,14 +406,14 @@
 #    parent_email_send: "Send Email"
 #    parent_email_sent: "Email sent!"
 #    parent_email_title: "What's your parent's email?"
-#    parents: "For Parents"
-#    parents_title: "Your child will learn to code."
-#    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."
-#    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."
+    parents: "For foreldre"
+    parents_title: "Barnet ditt vil lære å kode."
+    parents_blurb1: "Med CodeCombat, lærer barnet ditt å skrive ekte kode. De starter med enkle kommandoer, og går videre til mer avanserte temaer."
+    parents_blurb2: "For $9.99 USD/mo, får de nye utfordringer hver uke samt personlig e-poststøtte fre profesjonelle programmerere.
+    parents_blurb3: "Risikofritt: 100% pengene-tilbake garanti, lett 1-klikk oppsigelse av abonnementet."
+    stripe_description: "Månedlig abonnement"
+    subscription_required_to_play: "Du trenger et abonnement for å spille dette brettet."
+    unlock_help_videos: "Abonner for å låse opp alle opplæringsvideoene."

   choose_hero:
     choose_hero: "Velg Din Helt"
@@ -498,12 +497,12 @@
     why_paragraph_2_prefix: "Det er det programmering handler om. Det må være gøy. Ikke gøy som i"
     why_paragraph_2_italic: "jippi et merke"
     why_paragraph_2_center: "men gøy som i"
-    why_paragraph_2_italic_caps: "NEI MOR JEG MÅ FULLFØRE DETTE BRETTET!"
-    why_paragraph_2_suffix: "Det er derfor CodeCombat er et flerspiller spill, ikke et spillaktig programmeringskurs. Vi slutter ikke før du ikke klarer å slutte – men i denne sammenhengen er det en god ting."
+    why_paragraph_2_italic_caps: "NEI MAMMA JEG MÅ FULLFØRE DETTE BRETTET!"
+    why_paragraph_2_suffix: "Det er derfor CodeCombat er et flerspiller-spill, ikke et spillaktig programmeringskurs. Vi slutter ikke før du ikke klarer å slutte – men i denne sammenhengen er det en god ting."
     why_paragraph_3: "Hvis du skal bli avhengig av et spill, bli avhengig av dette og bli en av trollmennene i den nye teknologiske tidsalderen."
     press_title: "Bloggere/Presse"
     press_paragraph_1_prefix: "Har du lyst til å skrive om oss? Last gjerne ned og bruk alle ressursene i vår"
-    press_paragraph_1_link: "presse pakke"
+    press_paragraph_1_link: "pressepakke"
     press_paragraph_1_suffix: ". Alle logoer og bilder kan brukes uten å kontakte oss direkte."
     team: "Teamet"
     george_title: "Adm.dir."
@@ -513,54 +512,54 @@
     nick_title: "Programmerer"
     nick_blurb: "Motivasjonsguru"
     michael_title: "Programmerer"
-    michael_blurb: "System Administrator"
+    michael_blurb: "Systemadministrator"
     matt_title: "Programmerer"
     matt_blurb: "Syklist"

-#  teachers:
-#    title: "CodeCombat for Teachers"
-#    preparation_title: "Preparation"
-#    preparation_1: "CodeCombat is free to play for the core level progression and does not require students to sign up. We encourage teachers to"
-#    preparation_play_campaign: "play through the campaign"
-#    preparation_2: "to try it out, but the only thing you absolutely need to do to be ready is ensure students have access to a computer."
-#    preparation_3: "It is not necessary for teachers to be comfortable with computer science concepts for students to have fun learning with CodeCombat."
-#    violent_title: "Is it violent?"
-#    violent_1: "We get this from teachers a lot due to our name. Although CodeCombat does contain cartoon violence, there is nothing graphic in either the visuals or language."
-#    violent_2: "If you are comfortable having your students play Angry Birds, you will be comfortable with CodeCombat."
-#    for_girls_title: "Is it for girls?"
-#    for_girls_1: "There are three game modes in CodeCombat: building, puzzles, and combat. We have intentionally designed each to appeal to both boys and girls and think that the building and puzzle levels especially differentiate the game from violent triple A titles that repel female players."
-#    what_cover_title: "What do we cover?"
-#    what_cover_1: "There are 20 levels in the Hour of Code tutorial that teach and reinforce 6 specific computer science concepts:"
-#    what_cover_notation_1: "Formal notation"
-#    what_cover_notation_2: "- builds an understanding of the importance of syntax in programming."
-#    what_cover_methods_1: "Calling methods"
-#    what_cover_methods_2: "- familiarizes students with the syntax of object-oriented method calls."
-#    what_cover_parameters_1: "Parameters"
-#    what_cover_parameters_2: "- trains how to pass parameters to functions."
-#    what_cover_strings_1: "Strings"
-#    what_cover_strings_2: "- teaches students about string notation and passing strings as parameters."
-#    what_cover_loops_1: "Loops"
+  teachers:
+    title: "CodeCombat for lærere"
+    preparation_title: "Forberdelser"
+    preparation_1: "CodeCombat er gratis å spille for progresjon på kjernenivå, og krever ikke at elevene registrerer seg. Vi anbefaler lærere å"
+    preparation_play_campaign: "spill gjennom kampanjen"
+    preparation_2: "å forsøke det, men det eneste absolutte kravet er at elevene har tilgang til en datamaskin."
+    preparation_3: "Det er ikke nødvendig med datakyndige lærere for at elevene skal ha det gøy mens de lærer med CodeCombat." # "It is not necessary for teachers to be comfortable with computer science concepts for students to have fun learning with CodeCombat."
+    violent_title: "Er det voldelig?"
+    violent_1: "Vi hører dette fra lærere en del på grunn av navnet. Selv om CodeCombat inneholder tegneserievold, er det ikke noe grafisk i hverken det visuelle eller i språket."
+    violent_2: "Hvis du er komfortabel med at elevene spille Angry Birds, vil du være komfortabel med CodeCombat."
+    for_girls_title: "Er det for jenter?"
+    for_girls_1: "Det er tre spillmodus i CodeCombat: bygging, puslespill og angrep. Vi har med vilje utformet hver av de for å appelere til både gutter og jenter, og tror at bygge- og puslebrettene især skiller spillet fra voldelige spill som driver bort kvinnelige spillere."
+    what_cover_title: "Hva dekker vi?"
+    what_cover_1: "Det er 20 nivåer i Hour of Code-opplæringen som lærer og forsterker 6 konkrete konsepter innenfor informatikk:"
+    what_cover_notation_1: "Formell notasjon"
+    what_cover_notation_2: "- bygger en forståelse for viktigheten av syntaks i programmering."
+    what_cover_methods_1: "Å kalle metoder"
+    what_cover_methods_2: "- gjør elevene kjent med syntaksen til objektorienterte metodekall."
+    what_cover_parameters_1: "Parametere"
+    what_cover_parameters_2: "- viser hvordan sende parametre til funksjoner."
+    what_cover_strings_1: "Strenger"
+    what_cover_strings_2: "- lærer elevene om strengnotasjon og å sende strenger som parametre."
+    what_cover_loops_1: "Løkker"
 #    what_cover_loops_2: "- develops the abstraction of designing short programs with loops."
-#    what_cover_variables_1: "Variables"
-#    what_cover_variables_2: "- adds the skill of referencing values that change over time."
-#    what_cover_2: "Students may continue past level 20, depending on their speed and interest, to learn two additional concepts in later levels:"
+    what_cover_variables_1: "Variabler"
+    what_cover_variables_2: "- legger til kunnskapen om å referere til verdier som kan forandres over tid."
+    what_cover_2: "Elevene kan fortsette forbi brett 20 avhengig av hastigheten og interessen, for å lære to tilleggskonsepter i senere brett:"
 #    what_cover_logic_1: "Conditional logic"
-#    what_cover_logic_2: "- when and how to use if/else to control in-game outcomes."
-#    what_cover_input_1: "Handling player input"
-#    what_cover_input_2: "- responding to input events to create a user interface."
-#    sys_requirements_title: "System Requirements"
-#    sys_requirements_1: "Because CodeCombat is a game, it is more intensive for computers to run smoothly than video or written tutorials. We have optimized it to run quickly on all modern browsers and on older machines so that everyone can play. That said, here are our suggestions for getting the most out of your Hour of Code experience:"
-#    sys_requirements_2: "Use newer versions of Chrome or Firefox."
-#    sys_requirements_3: "Although CodeCombat will work on browsers as old as IE9, the performance is not as good. Chrome is best."
-#    sys_requirements_4: "Use newer computers."
-#    sys_requirements_5: "Older computers, Chromebooks, and netbooks tend to have very few system resources, which makes for a less enjoyable experience. At least 2GB of RAM is required."
-#    sys_requirements_6: "Allow players to wear headphones/earbuds to hear the audio."
-#    sys_requirements_7: "We help players learn through voiceover and sound effects, which will make classrooms noisy and distracting."
+    what_cover_logic_2: "- når og hvordan bruke if/else for å kontrollere utfallet av spillet."
+    what_cover_input_1: "Håndtering av input fra spilleren."
+    what_cover_input_2: "- å reagere på input for å bygge et brukergrensesnitt."
+    sys_requirements_title: "Systemkrav"
+    sys_requirements_1: "Siden CodeCombat er et spill, er det mer intensivt for datamaskiner å kjøre jevnt enn opplæringsvideo eller -tekst. Vi har optimert det for å kjøre raskt på alle moderne nettlesere, og på eldre maskiner slik at alle kan spille. Når det er sagt, her følger våre anbefalinger for å gå mest ut av din Hour of Code:" ### Puh! "Because CodeCombat is a game, it is more intensive for computers to run smoothly than video or written tutorials. We have optimized it to run quickly on all modern browsers and on older machines so that everyone can play. That said, here are our suggestions for getting the most out of your Hour of Code experience:"
+    sys_requirements_2: "Bruk nye versjoner av Chrome eller Firefox."
+    sys_requirements_3: "Selv om CodeCombat virker på nettlesere så gamle som IE9, er ikke ytelsen like bra. Chrome er best."
+    sys_requirements_4: "Bruk nyere datamaskiner."
+    sys_requirements_5: "Eldre maskiner, Chromebooks, og tavler har ofte færre ressurser, noe som gir en dårligere opplevelse. Minst 2GB internminne er påkrevet."
+    sys_requirements_6: "La spillerne ha på øretelefoner for å høre lyden."
+    sys_requirements_7: "Vi hjelper spillerne å lære med voiceoverd og lydeffekter, noe som medfører at klasserommet blir bråkete."

   versions:
     save_version_title: "Lagre ny version"
     new_major_version: "Ny hovedversjon"
-#    submitting_patch: "Submitting Patch..."
+    submitting_patch: "Sender inn patch..."
     cla_prefix: "For å lagre endringer må du først akseptere vår"
     cla_url: "CLA"
     cla_suffix: "."
@@ -572,15 +571,15 @@
     forum_prefix: "For allment tilgjengelige henvendelser, vennligst prøv "
     forum_page: "forumet vårt"
     forum_suffix: " i stedet."
-#    faq_prefix: "There's also a"
-#    faq: "FAQ"
-#    subscribe_prefix: "If you need help figuring out a level, please"
-#    subscribe: "buy a CodeCombat subscription"
-#    subscribe_suffix: "and we'll be happy to help you with your code."
-#    subscriber_support: "Since you're a CodeCombat subscriber, your email will get our priority support."
-#    screenshot_included: "Screenshot included."
-#    where_reply: "Where should we reply?"
-    send: "Send Tilbakemelding"
+    faq_prefix: "Det finnes også en"
+    faq: "OSS"
+    subscribe_prefix: "Hvis du trenger hjelp med å forstå en level, vennligst"
+    subscribe: "kjøp et abonnement på CodeCombat"
+    subscribe_suffix: "og vi hjelper deg gjerne med koden din."
+    subscriber_support: "Siden du er en CodeCombat-abonnent, vil din e-post få fortrinn hos kundestøtte."
+    screenshot_included: "Skjermbilde vedlagt."
+    where_reply: "Hvor skal vi sende svaret?"
+    send: "Send tilbakemelding"
     contact_candidate: "Kontakt kandidat" # Deprecated
 #    recruitment_reminder: "Use this form to reach out to candidates you are interested in interviewing. Remember that CodeCombat charges 15% of first-year salary. The fee is due upon hiring the employee and is refundable for 90 days if the employee does not remain employed. Part time, remote, and contract employees are free, as are interns." # Deprecated

@@ -631,11 +630,11 @@
     run_code: "Kjør koden."
     run_real_time: "Kjør i sanntid."
     continue_script: "Fortsett forbi det kjørende skriptet."
-    skip_scripts: "Hopp over alle skrip som kan hoppes over."
+    skip_scripts: "Hopp over alle skript som kan hoppes over."
     toggle_playback: "Play/Pause."
     scrub_playback: "Spol tiden frem og tilbake"
     single_scrub_playback: "Spol tiden frem og tilbake, steg for steg"
-#    scrub_execution: "Scrub through current spell execution."
+    scrub_execution: "Spol gjennom gjeldende trylleformular-kjøring."
     toggle_debug: "Skru på/av feilrettingsvindu"
     toggle_grid: "Skru på/av rutenett"
     toggle_pathfinding: "Skru på/av stifinnervindu"
@@ -663,22 +662,22 @@
   classes:
     archmage_title: "Erketrollmann"
     archmage_title_description: "(Koder)"
-#    archmage_summary: "If you are a developer interested in coding educational games, become an archmage to help us build CodeCombat!"
+    archmage_summary: "Hvis du er en utvikler som er interessert i å lage utdanningsrettede spill, bli en erketrollmann, og hjelp oss bygge CodeCombat!"
     artisan_title: "Artisan"
     artisan_title_description: "(Brettbygger)"
-#    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."
+    artisan_summary: "Bygg og del brett som du og vennene dine kan spille.  Bli en Artisan for å lære kunsten å lære andre å programmere."
     adventurer_title: "Eventyrer"
     adventurer_title_description: "(Spilltester)"
-#    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."
+    adventurer_summary: "Få våre nye brett (til-og-med innhold for abonnenter) gratis, en uke tidligere, og hjelp oss finne og fjerne feil før de blir gjort tilgjengelige for alle."
     scribe_title: "Skriver"
     scribe_title_description: "(Artikkelforfatter)"
-#    scribe_summary: "Good code needs good documentation. Write, edit, and improve the docs read by millions of players across the globe."
+    scribe_summary: "God kode trenger god dokumentasjon. Skriv, rediger, og forbedre dok'en som leses av millioner av spillere, verden over."
     diplomat_title: "Diplomat"
     diplomat_title_description: "(Oversetter)"
-#    diplomat_summary: "CodeCombat is localized in 45+ languages by our Diplomats. Help us out and contribute translations."
+    diplomat_summary: "CodeCombat er oversatt til 45+ språk av våre diplomater. Hjelp oss ved å bidra med oversettelser."
     ambassador_title: "Ambassadør"
     ambassador_title_description: "(Brukerstøtte)"
-#    ambassador_summary: "Tame our forum users and provide direction for those with questions. Our ambassadors represent CodeCombat to the world."
+    ambassador_summary: "Temm våre forumbrukere og tilby hjelp for de med spørsmål. Våre ambassadører representerer CodeCombat ute i verden." # "Temm"?

   editor:
     main_title: "CodeCombat Editorer"
@@ -690,22 +689,22 @@
     revert: "Tilbakestill"
     revert_models: "Tilbakestill Modeller"
     pick_a_terrain: "Velg Terreng"
-#    dungeon: "Dungeon"
-#    indoor: "Indoor"
-#    desert: "Desert"
-#    grassy: "Grassy"
-#    small: "Small"
-#    large: "Large"
-#    fork_title: "Fork New Version"
-#    fork_creating: "Creating Fork..."
+    dungeon: "Grotte"
+    indoor: "Innendørs"
+    desert: "Ørken"
+    grassy: "Gresset"
+    small: "Liten"
+    large: "Stor"
+    fork_title: "Lag ny forgrening"
+    fork_creating: "Lager forgrening..."
     generate_terrain: "Generer Terreng"
     more: "Mer"
     wiki: "Wiki"
 #    live_chat: "Live Chat"
-#    thang_main: "Main"
+    thang_main: "Hoved"
 #    thang_spritesheets: "Spritesheets"
-#    thang_colors: "Colors"
-#    level_some_options: "Some Options?"
+    thang_colors: "Farger"
+    level_some_options: "Noen valg?"
     level_tab_thangs: "Thangs"
     level_tab_scripts: "Skript"
     level_tab_settings: "Innstillinger"
@@ -717,11 +716,11 @@
     level_tab_thangs_conditions: "Utgangsforhold"
     level_tab_thangs_add: "Legg til Thangs"
     add_components: "Legg til komponenter"
-    component_configs: "Komponent konfigurasjoner"
+    component_configs: "Komponentoppsett"
     config_thang: "Dobbeltklikk for å konfigurere en thang"
     delete: "Slett"
     duplicate: "Kopier"
-    stop_duplicate: "Stopp Duplikater"
+    stop_duplicate: "Stopp duplikat"
     rotate: "Rotér"
     level_settings_title: "Innstillinger"
     level_component_tab_title: "Gjeldende Komponenter"
@@ -732,7 +731,7 @@
     level_components_title: "Tilbake til alle Thangs"
     level_components_type: "Type"
     level_component_edit_title: "Rediger Component"
-    level_component_config_schema: "Config Schema"
+    level_component_config_schema: "Config-skjema"
     level_component_settings: "Innstillinger"
     level_system_edit_title: "Rediger System"
     create_system_title: "Lag Nytt System"
@@ -752,10 +751,10 @@
     achievement_search_title: "Søk i Prestasjoner"
     read_only_warning2: "Merk: Du kan ikke lagre endringene fordi du ikke er logget inn."
     no_achievements: "Ingen prestasjoner er lagt til på dette brettet ennå."
-    achievement_query_misc: "Oppnådde nøkkelmål av miscellanea"
+    achievement_query_misc: "Oppnådde nøkkelmål av diverse"
     achievement_query_goals: "Oppnådde nøkkelmål"
     level_completion: "Komplett Nivå"
-    pop_i18n: "Poppuler I18N"
+    pop_i18n: "Fullfør I18N"
     tasks: "Oppgaver"

   article:
@@ -764,7 +763,7 @@

   contribute:
     page_title: "Bidrag"
-    intro_blurb: "CodeCombat er 100% åpen kildekode! Hundrevis av dedikerte spillere har hjulpet oss å bygge spillet til det det har blitt i dag. Foren deg med oss og bli med og skrive det neste kapittelet i CodeCombat sin søken etter å lære hele verden koding!"
+    intro_blurb: "CodeCombat er 100% åpen kildekode! Hundrevis av dedikerte spillere har hjulpet oss å bygge spillet til det det er blitt i dag. Foren deg med oss og bli med og skriv neste kapittel i CodeCombat sin søken etter å lære hele verden koding!"
     alert_account_message_intro: "Heisann!"
     alert_account_message: "For å abonnere på klasse-eposter må du være logget inn først."
     archmage_introduction: "En av de beste tingene med å lage spill er at det bestaår av så mye forskjellig. Grafikk, lyd, sanntidsnettverk, sosiale nettverk, og selvfølgelig mange av de vanlige aspektene ved programmering, fra lav-nivå database drift og server administrasjon til design og bygging av brukergrensesnitt. Det er mye å gjøre og hvis du er en erfaren utvikler som har lyst til å dykke ned i de tekniske detaljene i CodeCombat, da er dette kanskje klassen for deg. Vi vil veldig gjerne ha din hjelp til å lage det beste programmeringsspillet noensinne."
@@ -861,11 +860,11 @@
     no_ranked_matches_post: " laget! Spill mot noen motstandere og kom tilbake hit etterpå for å få spillet ditt rangert."
     choose_opponent: "Velg en motstander"
     select_your_language: "Velg språk!"
-    tutorial_play: "Spill opplæring"
+    tutorial_play: "Spill opplæringsspill"
     tutorial_recommended: "Anbefalt hvis du ikke har spilt før"
     tutorial_skip: "Hopp over opplæring"
     tutorial_not_sure: "Usikker på hva som foregår?"
-    tutorial_play_first: "Spill opplæringen først."
+    tutorial_play_first: "Spill opplæringsspillet først."
     simple_ai: "Enkel AI"
     warmup: "Oppvarming"
     friends_playing: "Venner som spiller"
@@ -901,13 +900,13 @@

   achievements:
     last_earned: "Sist oppnådd"
-    amount_achieved: "Beløp"
+    amount_achieved: "Mengde"
     achievement: "Prestasjon"
     category_contributor: "Bidragsyter"
     category_ladder: "Stige"
-    category_level: "Nivå"
+    category_level: "Brett" # Eller nivå?
     category_miscellaneous: "Forskjellig"
-    category_levels: "Nivåer"
+    category_levels: "Brett" # Eller nivåer?
     category_undefined: "Ukategorisert"
     current_xp_prefix: ""
     current_xp_postfix: " totalt"
@@ -949,19 +948,19 @@
     timeout: "Tidsavbrudd på server"
     conflict: "Ressurskonflikt."
     bad_input: "Feil i inndata"
-    server_error: "Server feil."
+    server_error: "Serverfeil."
     unknown: "Ukjent feil."

   resources:
     sessions: "Sesjoner"
     your_sessions: "Dine sesjoner"
     level: "Nivå"
-    social_network_apis: "Sosiale Nettverk APIer"
-    facebook_status: "Facebook Status"
-    facebook_friends: "Facebook Venner"
-    facebook_friend_sessions: "Facebook venners Sesjoner"
-    gplus_friends: "G+ Venner"
-    gplus_friend_sessions: "G+ Venners Sesjoner"
+    social_network_apis: "Sosiale Nettverk-APIer"
+    facebook_status: "Facebook status"
+    facebook_friends: "Facebook venner"
+    facebook_friend_sessions: "Facebook venners sesjoner"
+    gplus_friends: "G+ venner"
+    gplus_friend_sessions: "G+ venners sesjoner"
     leaderboard: "Poengtavle"
     user_schema: "Brukerskjema"
     user_profile: "Brukerprofil"
@@ -976,7 +975,7 @@
     thang: "Thang"
     thangs: "Thangs"
     level_session: "Din sesjon"
-    opponent_session: "Motstanders Sesjon"
+    opponent_session: "Motstanders sesjon"
     article: "Artikkel"
     user_names: "Brukernavn"
     thang_names: "Thang Navn"
@@ -984,7 +983,7 @@
     top_simulators: "Topp Simulatorer"
     source_document: "Kildedokument"
     document: "Dokument"
-    sprite_sheet: "Sprite Ark"
+    sprite_sheet: "Sprite-ark"
     employers: "Arbeidsgivere"
     candidates: "Kandidater"
     candidate_sessions: "Kandidat Sesjoner"
@@ -995,10 +994,10 @@
     heroes: "Helter"
     achievement: "Prestasjon"
     clas: "CLAer"
-    play_counts: "Spill Tellinger"
+    play_counts: "Spillteller"
     feedback: "Tilbakemelding"
     payment_info: "Betalingsinformasjon"
-#    campaigns: "Campaigns"
+    campaigns: "Kampanjer"

   delta:
     added: "Opprettet"


Update ru.coffee

Update ru.coffee

--- app/locale/ru.coffee
+++ app/locale/ru.coffee
@@ -12,7 +12,7 @@
     manual: "Вручную"
     fork: "Форк"
     play: "Играть"
-#    retry: "Retry"
+    retry: "Повторить"

   units:
     second: "секунда"
@@ -327,7 +327,7 @@
     article_search_title: "Искать статьи"
     thang_search_title: "Искать типы объектов"
     level_search_title: "Искать уровни"
-#    read_only_warning: "Note: you can't save any edits here, because you're not logged in as an admin."
+    read_only_warning: "Примечание: вы не можете сохранять здесь любые правки, потому что вы не вошли как администратор."

   article:
     edit_btn_preview: "Предпросмотр"
@@ -564,7 +564,7 @@
     simulate_all: "СБРОСИТЬ И СИМУЛИРОВАТЬ ИГРЫ"
     games_simulated_by: "Игры, симулированные вами:"
     games_simulated_for: "Игры, симулированные за вас:"
-    leaderboard: "Таблица лидеров"
+    leaderboard: "таблица лидеров"
     battle_as: "Сразиться за "
     summary_your: "Ваши "
     summary_matches: "матчи - "
@@ -603,26 +603,26 @@
     new_to_programming: ". Новичок в программировании? Пройдите нашу кампанию для новичков, чтобы повысить навык."
     so_ready: "Я полностью готов(а) для этого"

-#  loading_error:
-#    could_not_load: "Error loading from server"
-#    connection_failure: "Connection failed."
-#    unauthorized: "You need to be signed in. Do you have cookies disabled?"
-#    forbidden: "You do not have the permissions."
-#    not_found: "Not found."
-#    not_allowed: "Method not allowed."
-#    timeout: "Server timeout."
-#    conflict: "Resource conflict."
-#    bad_input: "Bad input."
-#    server_error: "Server error."
-#    unknown: "Unknown error."
-
-#  resources:
-#    your_sessions: "Your Sessions"
-#    level: "Level"
-#    social_network_apis: "Social Network APIs"
-#    facebook_status: "Facebook Status"
-#    facebook_friends: "Facebook Friends"
-#    facebook_friend_sessions: "Facebook Friend Sessions"
-#    gplus_friends: "G+ Friends"
-#    gplus_friend_sessions: "G+ Friend Sessions"
-#    leaderboard: "leaderboard"
+  loading_error:
+    could_not_load: "Ошибка загрузки с сервера"
+    connection_failure: "Соединение прервано."
+    unauthorized: "Вам необходимо авторизоваться. У вас отключены cookie?"
+    forbidden: "У вас нет прав доступа."
+    not_found: "Не найдено."
+    not_allowed: "Метод не поддерживается."
+    timeout: "Тайм-аут сервера."
+    conflict: "Конфликт ресурсов."
+    bad_input: "Неверные входные данные."
+    server_error: "Ошибка сервера."
+    unknown: "Неизвестная ошибка."
+
+  resources:
+    your_sessions: "Ваши сессии"
+    level: "Уровень"
+    social_network_apis: "API социальных сетей"
+    facebook_status: "Статус Facebook"
+    facebook_friends: "Друзья Facebook"
+    facebook_friend_sessions: "Сессии друзей Facebook"
+    gplus_friends: "Друзья G+"
+    gplus_friend_sessions: "Сессии друзей G+"
+    leaderboard: "таблица лидеров"


Updated tr.coffee

Updated tr.coffee

--- app/locale/tr.coffee
+++ app/locale/tr.coffee
@@ -45,7 +45,7 @@
     cla_agree: "KABUL EDİYORUM"

   login:
-#    login_modal_title: "Log In"
+    login_modal_title: "Giriş Yap"
     log_in: "Giriş Yap"
     sign_up: "Yeni hesap oluşturabilir,"
     or: " ya da mevcut hesabınızın şifresini unuttuysanız"


fix artist meta test

fix artist meta test

--- apps/artist/test/meta.coffee
+++ apps/artist/test/meta.coffee
@@ -26,7 +26,7 @@
       @html.should.containEql "<link rel=\"canonical\" href=\"http://localhost:5000/artist/pablo-picasso"
       @html.should.containEql "<meta property=\"og:url\" content=\"http://localhost:5000/artist/pablo-picasso"
       @html.should.containEql "<meta property=\"og:description\" content=\"#{@artist.toPageDescription(155)}"
-      @html.should.containEql "<meta property=\"og:title\" content=\"Pablo Picasso | Artist Biography, Artwork for Sale | Artsy"
+      @html.should.containEql "<meta property=\"og:title\" content=\"Pablo Picasso - Explore their Artworks, Biography"

   describe 'artist with name no blurb, nationality, or years', ->

@@ -42,7 +42,7 @@

     it 'renders correctly', ->
       @html.should.containEql "<meta property=\"og:description\" content=\"Find the latest shows, biography, and artworks for sale by Pablo Picasso"
-      @html.should.containEql "<meta property=\"og:title\" content=\"Pablo Picasso | Artist Biography, Artwork for Sale | Artsy"
+      @html.should.containEql "<meta property=\"og:title\" content=\"Pablo Picasso - Explore their Artworks, Biography"

   describe 'with an image', ->


Minor change: 301 redirect /resume.doc to /resume

Whatever bots these are hitting that URL probably won't like this. But...

8                       :-)
    8                   :-)
        8               :-)
            8           :-)
                8       :-)
                    8   :-)
                        8-)    DEAL WITH IT

--- app.coffee
+++ app.coffee
@@ -166,6 +166,9 @@
       "tags": tags
   blog.get_posts pCb, -1

+app.get '/resume.doc', (request, response) ->
+  response.redirect '/resume', '301'
+
 # Read config and listen
 start = (err, data) ->
   if err?


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/approachable.coffee
+++ src/approachable.coffee
@@ -6,7 +6,7 @@
     for name, cooldownOptions of I.cooldowns
       {approachBy, target} = cooldownOptions

-      newValue = I[name].approachBy(target, approachBy)
+      newValue = I[name].approach(target, approachBy)

       I[name] = newValue


Fix propagation of errorCode and response for failure callbacks

The failureResponse methods didn't have the right number of paramers,
so weren't propagating all the parts of the exception.

--- lib/calatrava/templates/kernel/app/calatrava.coffee
+++ lib/calatrava/templates/kernel/app/calatrava.coffee
@@ -22,7 +22,7 @@
     calatrava.bridge.requests.successfulResponse(requestId, response)

   failureResponse: (requestId, errorCode, response) ->
-    calatrava.bridge.requests.failureResponse(requestId,errorCode, response)
+    calatrava.bridge.requests.failureResponse(requestId, errorCode, response)

   fireTimer: (timerId) ->
     calatrava.bridge.timers.fireTimer(timerId)
@@ -156,8 +156,8 @@
     successHandlersById[requestId](response) if successHandlersById[requestId]
     clearHandlers(requestId)

-  failureResponse: (requestId, response) ->
-    failureHandlersById[requestId](response) if failureHandlersById[requestId]
+  failureResponse: (requestId, errorCode, response) ->
+    failureHandlersById[requestId](errorCode, response) if failureHandlersById[requestId]
     clearHandlers(requestId)
 )()


Fixed recipient list (exclude now username) on twitter reply.

--- app/assets/javascripts/app/controllers/ticket_zoom/article_actions.coffee
+++ app/assets/javascripts/app/controllers/ticket_zoom/article_actions.coffee
@@ -218,15 +218,22 @@
       recipientString = ''
       recipientScreenNames = recipients.split(',')
       for recipientScreenName in recipientScreenNames
-
-        # exclude already listed screen name
-        if !body || !body.match(recipientScreenName)
+        if recipientScreenName
+          recipientScreenName = recipientScreenName.trim().toLowerCase()
+
+          # exclude already listed screen name
+          exclude = false
+          if body && body.toLowerCase().match(recipientScreenName)
+            exclude = true

           # exclude own screen_name
-          if !body || !body.match(@ticket.preferences.channel_screen_name)
+          if recipientScreenName is "@#{@ticket.preferences.channel_screen_name}".toLowerCase()
+            exclude = true
+
+          if exclude is false
             if recipientString isnt ''
               recipientString += ' '
-            recipientString += recipientScreenName.trim()
+            recipientString += recipientScreenName

     if body
       articleNew.body = "#{recipientString} #{body} "


ComputeProviders: AWS: create: set `assignedLabel` as given label under `JMachine.meta`

--- workers/social/lib/social/models/computeproviders/aws.coffee
+++ workers/social/lib/social/models/computeproviders/aws.coffee
@@ -17,7 +17,7 @@

   @create = (client, options, callback) ->

-    { credential, instanceType, region, ami, storage } = options
+    { credential, instanceType, region, ami, storage, label } = options

     storage ?= 8
     if isNaN storage
@@ -29,6 +29,7 @@
       region        : region ? 'us-east-1'
       instance_type : instanceType ? 't2.micro'
       storage_size  : storage
+      assignedLabel : label

     if ami?
       meta.source_ami = ami


renames finish button to archive

renames finish button to archive

--- app/assets/javascripts/oxalis/view/action-bar/dataset_actions_view.coffee
+++ app/assets/javascripts/oxalis/view/action-bar/dataset_actions_view.coffee
@@ -17,7 +17,7 @@
     <% } %>

       <% if(tracing.restrictions.allowFinish) { %>
-        <a href="/annotations/<%= tracingType %>/<%= tracingId %>/finishAndRedirect" class="btn btn-default" id="trace-finish-button">Finish
+        <a href="/annotations/<%= tracingType %>/<%= tracingId %>/finishAndRedirect" class="btn btn-default" id="trace-finish-button">Archive
       <% } %>
       <% if(tracing.restrictions.allowDownload || ! tracing.downloadUrl) { %>
         Download


Fix TinyMce bug introduced by a previous refacto

--- BackofficeBundle/Resources/public/coffee/OrchestraView.coffee
+++ BackofficeBundle/Resources/public/coffee/OrchestraView.coffee
@@ -57,7 +57,7 @@
     if $("[data-prototype*='content_type_change_type']", @$el).length > 0
       loadExtendView(@, 'contentTypeChange')
     if $("textarea.tinymce", @$el).length > 0
-      activateTinyMce(view, $("textarea.tinymce", @$el).attr('disabled') == 'disabled')
+      activateTinyMce(@$el, $("textarea.tinymce", @$el).attr('disabled') == 'disabled')
     return

   onViewReady: ->


Invert marker patches when inverting buffer patches

--- src/buffer-patch.coffee
+++ src/buffer-patch.coffee
@@ -1,10 +1,11 @@
 module.exports =
 class BufferPatch
-  constructor: (@oldRange, @newRange, @oldText, @newText) ->
-    @markerPatches = {}
+  constructor: (@oldRange, @newRange, @oldText, @newText, @markerPatches={}) ->

   invert: ->
-    new @constructor(@newRange, @oldRange, @newText, @oldText)
+    markerPatches = {}
+    markerPatches[id] = patch.invert() for id, patch of @markerPatches
+    new @constructor(@newRange, @oldRange, @newText, @oldText, markerPatches)

   applyTo: (textBuffer) ->
     textBuffer.applyPatch(this)


renamed upload button

renamed upload button

--- app/assets/javascripts/dashboard/views/explorative_tracing_list_view.coffee
+++ app/assets/javascripts/dashboard/views/explorative_tracing_list_view.coffee
@@ -21,11 +21,11 @@
           id="upload-and-explore-form"
           class="form-inline inline-block">

-
+

-                Upload NML & explore
+                Upload Annotation

               <input type="file" name="nmlFile" multiple accept=".nml, .zip">


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/clamp_bounds.coffee
+++ src/clamp_bounds.coffee
@@ -1,5 +1,5 @@
 ###*
-The ClampBou module provides a declarative way to manage cooldowns on
+The ClampBounds module provides a declarative way to manage cooldowns on
 GameObject's properties.

 <code><pre>


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/clamp_bounds.coffee
+++ src/clamp_bounds.coffee
@@ -6,7 +6,7 @@
     height: 32

   App ||= {}
-  App.width ||
+  App.width ||= 480

   self.bind "update", ->
     I.x = I.x.clamp(I.width / 2, App.width - I.width / 2)


groups: wip links

groups: wip links

--- client/app/Applications/Groups.kdapplication/Views/GroupsListItemView.coffee
+++ client/app/Applications/Groups.kdapplication/Views/GroupsListItemView.coffee
@@ -87,17 +87,25 @@

     # TODO: hide enter button for non-admins

-    @enterButton = new KDButtonView
-      cssClass        : 'follow-btn following-btn enter-group hidden'
-      title           : "Enter"
-      dataPath        : "member"
-      # icon : yes
-      # iconClass : 'enter-group'
-      callback        : (event)=>
-        group = @getData().slug
-        KD.getSingleton('router').handleRoute "#{unless group is 'koding' then '/'+group else ''}/Activity"
-
-    , data
+    # @enterButton = new KDButtonView
+    #   cssClass        : 'follow-btn following-btn enter-group hidden'
+    #   title           : "Enter"
+    #   dataPath        : "member"
+    #   # icon : yes
+    #   # iconClass : 'enter-group'
+    #   callback        : (event)=>
+    #     group = @getData().slug
+    #     KD.getSingleton('router').handleRoute "#{unless group is 'koding' then '/'+group else ''}/Activity"
+
+    # , data
+
+    @enterButton = new KDCustomHTMLView
+      cssClass : 'enter-group'
+      tagName : 'a'
+      attributes :
+        href : '/'+@getData().slug+"/Activity"
+        target : @getData().slug
+      partial : 'Open Group'

   settingsMenu:(data)->


redeem popup was on profile page should be on just groups

--- client/landing/app/Applications/Home.kdapplication/Views/homeloginbar.coffee
+++ client/landing/app/Applications/Home.kdapplication/Views/homeloginbar.coffee
@@ -214,11 +214,16 @@

     if entryPoint?.type is 'profile'
       if KD.isLoggedIn() then @hide()
-      else @request.hide()
+      else
+        @request.hide()
+        @redeem.hide()

     if 'member' not in KD.config.roles
       if KD.isLoggedIn()
         @login.hide()
+        @register.hide()
+      else
+        @redeem.hide()

       KD.remote.cacheable entryPoint.slug, (err, models)=>
         if err then callback err
@@ -274,6 +279,7 @@

{{> @request}}{{> @access}}{{> @join}}{{> @invited}}{{> @requested}}

+        {{> @register}}
         {{> @redeem}}
         {{> @login}}


improved visibility listener. renamed to focus listener.

--- client/landing/app/Applications/Activity.kdapplication/AppController.coffee
+++ client/landing/app/Applications/Activity.kdapplication/AppController.coffee
@@ -56,10 +56,12 @@

     @docTitle = document.title
     windowController = KD.getSingleton "windowController"
-    windowController.addVisibilityListener (hidden)=>
-      if hidden
+    windowController.addFocusListener (blurred)=>
+      if blurred
         @listController.activityHeader.showNewItemsInTitle = yes
+        @listController.activityHeader.updateShowNewItemsTitle()
       else
+        @listController.activityHeader.showNewItemsInTitle = no
         @listController.activityHeader.hideDocumentTitleCount()

   loadView:->


Update title if using back button.

Update title if using back button.

--- _includes/coffeescript/scripts.coffee
+++ _includes/coffeescript/scripts.coffee
@@ -28,4 +28,5 @@
         window.history.pushState('all', '', '/')

     window.onpopstate = ->
+      document.title = location.title
       $('#content').load(location.href + ' #content')


:fire: DRY up the specs

:fire: DRY up the specs

--- spec/indentation-indicator-spec.coffee
+++ spec/indentation-indicator-spec.coffee
@@ -1,6 +1,8 @@
 {WorkspaceView} = require 'atom'

 describe 'IndentationIndicator', ->
+  [indicator] = []
+
   beforeEach ->
     atom.workspaceView = new WorkspaceView
     atom.workspace = atom.workspaceView.model
@@ -12,22 +14,24 @@
       atom.config.set('editor', {softTabs: false, tabLength: 3})
       atom.packages.emit('activated')
       atom.workspaceView.simulateDomAttachment()
+      indicator = atom.workspaceView.find('.indentation-indicator')

   describe '.initialize', ->
     it 'displays in the status bar', ->
-      expect(atom.workspaceView.find('.indentation-indicator').length).toBe 1
+      expect(indicator.length).toBe 1

     it 'has placeholder text if there is no file open', ->
-      view = atom.workspaceView.find('.indentation-indicator')
-      expect(view.text()).toBe 'foo:42'
+      expect(indicator.text()).toBe 'foo:42'
+
+    it 'is hidden if there is no file open', ->
+      expect(indicator).toBeHidden()

     it 'reflects the editor settings if there is a file open', ->
       waitsForPromise ->
         atom.workspace.open('sample.js')

       runs ->
-        view = atom.workspaceView.find('.indentation-indicator')
-        expect(view.text()).toBe 'Tabs:3'
+        expect(indicator.text()).toBe 'Tabs:3'

     it 'represents softTabs true as "Spaces"', ->
       atom.config.set('editor', {softTabs: true, tabLength: 6})
@@ -36,8 +40,7 @@
         atom.workspace.open('sample.js')

       runs ->
-        view = atom.workspaceView.find('.indentation-indicator')
-        expect(view.text()).toBe 'Spaces:6'
+        expect(indicator.text()).toBe 'Spaces:6'

     it 'uses the defaults if no editor settings are available', ->
       atom.config.set('editor', {})
@@ -46,8 +49,7 @@
         atom.workspace.open('sample.js')

       runs ->
-        view = atom.workspaceView.find('.indentation-indicator')
-        expect(view.text()).toBe 'Spaces:2'
+        expect(indicator.text()).toBe 'Spaces:2'

     describe 'when spaceAfterColon is true', ->
       it 'has a space after the colon in the indicator', ->
@@ -58,18 +60,16 @@
           atom.workspace.open('sample.js')

         runs ->
-          view = atom.workspaceView.find('.indentation-indicator')
-          expect(view.text()).toBe 'Spaces: 6'
+          expect(indicator.text()).toBe 'Spaces: 6'

   describe '.deactivate', ->
     it 'removes the indicator view', ->
-      view = atom.workspaceView.find('.indentation-indicator')
-      expect(view).toExist()
+      expect(indicator).toExist()

       atom.packages.deactivatePackage('indentation-indicator')

-      view = atom.workspaceView.find('.indentation-indicator')
-      expect(view).not.toExist()
+      indicator = atom.workspaceView.find('.indentation-indicator')
+      expect(indicator).not.toExist()

     it 'can be executed twice', ->
       atom.packages.deactivatePackage('indentation-indicator')


Spec for having no line-cursor decoration

--- spec/markdown-preview-view-spec.coffee
+++ spec/markdown-preview-view-spec.coffee
@@ -98,6 +98,17 @@
             return x++;
           }
         """
+
+  describe "editor behaves read-only", ->
+    beforeEach ->
+      waitsForPromise ->
+        preview.renderMarkdown()
+
+    describe "when a code block is rendered", ->
+      it "it does not have line-cursor decorations", ->
+        plainEditor = preview.find("atom-text-editor[data-grammar='text plain null-grammar']")
+        decorations = plainEditor[0].getModel().getDecorations(class: 'cursor-line', type: 'line')
+        expect(decorations.length).toBe 0

   describe "image resolving", ->
     beforeEach ->


Fixed compatibility issue with Coffeescript 1.9 as required for pimatic 0.9

--- unipi-evok.coffee
+++ unipi-evok.coffee
@@ -59,11 +59,11 @@
     # @param [Object] lastState state information stored in database
     constructor: (@config, plugin, lastState) ->
       @debug = plugin.config.debug ? plugin.config.__proto__.debug
-      env.logger.debug "[UniPiRelay] initializing:", util.inspect(config) if @debug
-      @_lastError = ""
-      @id = config.id
-      @name = config.name
-      @circuit = config.circuit
+      env.logger.debug "[UniPiRelay] initializing:", util.inspect(@config) if @debug
+      @_lastError = ""
+      @id = @config.id
+      @name = @config.name
+      @circuit = @config.circuit
       @evokDeviceUrl = uniPiHelper.createDeviceUrl plugin.config.url, "relay", @circuit
       @options = {
         timeout: 1000 * uniPiHelper.normalize plugin.config.timeout ? plugin.config.__proto__.timeout, 5, 86400
@@ -110,11 +110,11 @@
     # @param [Object] lastState state information stored in database
     constructor: (@config, plugin, lastState) ->
       @debug = plugin.config.debug ? plugin.config.__proto__.debug
-      env.logger.debug "[UniPiAnalogOutput] initializing:", util.inspect(config) if @debug
-      @_lastError = ""
-      @id = config.id
-      @name = config.name
-      @circuit = config.circuit
+      env.logger.debug "[UniPiAnalogOutput] initializing:", util.inspect(@config) if @debug
+      @_lastError = ""
+      @id = @config.id
+      @name = @config.name
+      @circuit = @config.circuit
       @evokDeviceUrl = uniPiHelper.createDeviceUrl plugin.config.url, "ao", @circuit
       @options = {
         timeout: 1000 * uniPiHelper.normalize plugin.config.timeout ? plugin.config.__proto__.timeout, 5, 86400
@@ -186,11 +186,11 @@
     # @param [Object] lastState state information stored in database
     constructor: (@config, plugin, lastState) ->
       @debug = plugin.config.debug ? plugin.config.__proto__.debug
-      env.logger.debug '[UniPiAnalogInput] initializing:', util.inspect(config) if @debug
+      env.logger.debug '[UniPiAnalogInput] initializing:', util.inspect(@config) if @debug
       @_inputVoltage = lastState?.inputVoltage?.value or 0.0
-      @id = config.id
-      @name = config.name
-      @circuit = config.circuit
+      @id = @config.id
+      @name = @config.name
+      @circuit = @config.circuit
       @_lastError = ""

       super()
@@ -218,11 +218,11 @@
     # @param [Object] lastState state information stored in database
     constructor: (@config, plugin, lastState) ->
       @debug = plugin.config.debug ? plugin.config.__proto__.debug
-      env.logger.debug '[UniPiDigitalInput] initializing:', util.inspect(config) if @debug
+      env.logger.debug '[UniPiDigitalInput] initializing:', util.inspect(@config) if @debug
       @_contact = lastState?.contact?.value or 0.0
-      @id = config.id
-      @name = config.name
-      @circuit = config.circuit
+      @id = @config.id
+      @name = @config.name
+      @circuit = @config.circuit
       @_lastError = ""

       super()
@@ -251,11 +251,11 @@
     # @param [Object] lastState state information stored in database
     constructor: (@config, plugin, lastState) ->
       @debug = plugin.config.debug ? plugin.config.__proto__.debug
-      env.logger.debug '[UniPiTemperature] initializing:', util.inspect(config) if @debug
+      env.logger.debug '[UniPiTemperature] initializing:', util.inspect(@config) if @debug
       @_temperature = lastState?.temperature?.value or 0.0
-      @id = config.id
-      @name = config.name
-      @circuit = config.circuit
+      @id = @config.id
+      @name = @config.name
+      @circuit = @config.circuit
       @_lastError = ""

       super()


updatesVia uses try{new WebSocket}catch{}

--- updatesVia.coffee
+++ updatesVia.coffee
@@ -9,11 +9,15 @@
         @connected = false
         @pending = {}
         @subscribed = {}
-        @socket = new WebSocket via
-        @socket.onopen = @onOpen
-        @socket.onclose = @onClose
-        @socket.onmessage = @onMessage
-        @socket.onerror = @onError
+        @socket = {}
+        try
+            @socket = new WebSocket via
+            @socket.onopen = @onOpen
+            @socket.onclose = @onClose
+            @socket.onmessage = @onMessage
+            @socket.onerror = @onError
+        catch error
+            @onError error

     _decode: (q) ->
         r = {}
@@ -26,7 +30,7 @@

     _send: (method, uri, data) =>
         message = [method, uri, data].join ' '
-        @socket.send message
+        @socket.send? message

     _subscribe: (uri) =>
         @_send 'sub', uri, ''
@@ -47,7 +51,7 @@
     onMessage: (e) =>
         message = e.data.split ' '
         if message[0] is 'ping'
-            @socket.send 'pong ' + message[1...].join(' ')
+            @socket.send? 'pong ' + message[1...].join(' ')
         else if message[0] is 'pub'
             @parent.onUpdate message[1], @_decode(message[2])


Removed unused variable (results to err) (#44, #72)

--- packages/custom/transparency/coffee/public/controllers/flowController.coffee
+++ packages/custom/transparency/coffee/public/controllers/flowController.coffee
@@ -134,7 +134,6 @@

     translate = ->
         $scope.typesText.forEach (t) -> t.text = gettextCatalog.getString TPAService.decodeType t.type
-        $scope.federalStates.forEach (state) -> state.name = gettextCatalog.getString state.value

     $scope.$on 'gettextLanguageChanged', translate


Remove plans redirect

Remove plans redirect

--- services/web/app/coffee/Features/Subscription/SubscriptionController.coffee
+++ services/web/app/coffee/Features/Subscription/SubscriptionController.coffee
@@ -15,33 +15,30 @@
 module.exports = SubscriptionController =

 	plansPage: (req, res, next) ->
-		if Settings.overleaf? && !req.query.plns
-			res.redirect "#{Settings.overleaf.host}/plans"
-		else
-			plans = SubscriptionViewModelBuilder.buildViewModel()
-			viewName = "subscriptions/plans"
-			if req.query.v?
-				viewName = "#{viewName}_#{req.query.v}"
-			logger.log viewName:viewName, "showing plans page"
-			currentUser = null
-
-			GeoIpLookup.getCurrencyCode req.query?.ip || req.ip, (err, recomendedCurrency)->
-				return next(err) if err?
-				render = () ->
-					res.render viewName,
-						title: "plans_and_pricing"
-						plans: plans
-						gaExperiments: Settings.gaExperiments.plansPage
-						recomendedCurrency:recomendedCurrency
-						planFeatures: planFeatures
-				user_id = AuthenticationController.getLoggedInUserId(req)
-				if user_id?
-					UserGetter.getUser user_id, {signUpDate: 1}, (err, user) ->
-						return next(err) if err?
-						currentUser = user
-						render()
-				else
+		plans = SubscriptionViewModelBuilder.buildViewModel()
+		viewName = "subscriptions/plans"
+		if req.query.v?
+			viewName = "#{viewName}_#{req.query.v}"
+		logger.log viewName:viewName, "showing plans page"
+		currentUser = null
+
+		GeoIpLookup.getCurrencyCode req.query?.ip || req.ip, (err, recomendedCurrency)->
+			return next(err) if err?
+			render = () ->
+				res.render viewName,
+					title: "plans_and_pricing"
+					plans: plans
+					gaExperiments: Settings.gaExperiments.plansPage
+					recomendedCurrency:recomendedCurrency
+					planFeatures: planFeatures
+			user_id = AuthenticationController.getLoggedInUserId(req)
+			if user_id?
+				UserGetter.getUser user_id, {signUpDate: 1}, (err, user) ->
+					return next(err) if err?
+					currentUser = user
 					render()
+			else
+				render()

 	#get to show the recurly.js page
 	paymentPage: (req, res, next) ->


Fix #403 "XHTML output: JavaScript error with loading indicator"

--- src/resources-packaged/ops/javascript/orbeon/xforms/LoadingIndicator.coffee
+++ src/resources-packaged/ops/javascript/orbeon/xforms/LoadingIndicator.coffee
@@ -24,8 +24,8 @@
     constructor: (@form) ->
         @shownCounter = 0

-        # For now hide the loading indicator
-        @loadingSpan = _.detect @form.childNodes, (node) -> YD.hasClass node, "xforms-loading-loading"
+        # For now hide the loading indicator (use jQuery to fix #403)
+        @loadingSpan = (f$.children '.xforms-loading-loading', $ @form)[0]
         @loadingSpan.style.display = "none"

         # Differ creation of the overlay to the first time we need it


removing variable for areContainedPublishable

--- src/scripts/modules/media/editbar/block-publish/modals/block-publish.coffee
+++ src/scripts/modules/media/editbar/block-publish/modals/block-publish.coffee
@@ -19,7 +19,6 @@
       book = model.isBook()
       title = model.get('title')
       isPublishable = model.get('isPublishable')
-      containedPublishable = model.get('areContainedPublishable')
       contents = model.get('contents')?.models
       publishBlockers = model.get('publishBlockers')
       formatted = []


Recipe: use rimeSharedDir when specified.

--- rime/recipe.coffee
+++ rime/recipe.coffee
@@ -152,9 +152,10 @@
         unless typeof c.get('customization') is 'number'
           return path
       catch e
-    path = "#{@rimeSharedDir}/#{fileName}"
-    if fs.existsSync path
-      return path
+    if @rimeSharedDir != @rimeUserDir
+      path = "#{@rimeSharedDir}/#{fileName}"
+      if fs.existsSync path
+        return path
     null

   getDefaultSchemaList: ->


I don’t understand the globals option in jade…

--- compile.coffee
+++ compile.coffee
@@ -9,7 +9,7 @@

 # Render Jade file
 jade = require 'jade'
-html = jade.renderFile './template.jade', {pretty: true, globals:['work']}
+html = jade.renderFile './template.jade', pretty: true

 # Save file
 fs = require 'fs'


update static file src

update static file src

--- device/test/10-static.coffee
+++ device/test/10-static.coffee
@@ -1,4 +1,4 @@
 describe 'static', ->
   it 'GET /static/js/app.js', ->
-    fetch '/static/js/app.js'
+    fetch '/static/js/test.js'
       .then ok


Remove a bug that prevented console output from appearing Change the text filter to require all words entered into filter field to be present in text

--- tapestry-core/src/main/coffeescript/META-INF/modules/t5/core/console.coffee
+++ tapestry-core/src/main/coffeescript/META-INF/modules/t5/core/console.coffee
@@ -31,9 +31,15 @@
         filter = noFilter
         return

-      text = text.toLowerCase()
-
-      filter = (e) -> e.text().toLowerCase().indexOf(text) >= 0
+      words = text.toLowerCase().split /\s+/
+
+      filter = (e) ->
+        content = e.text().toLowerCase()
+
+        for word in words
+          return false if content.indexOf(word) < 0
+
+        return true

       return

@@ -84,55 +90,55 @@
         if consoleAttribute is "invisible"
           floatingConsole.hide()

-        messages = floatingConsole.findFirst ".message-container"
-
-        floatingConsole.findFirst("[data-action=enable]").attribute "disabled", true
-
-        floatingConsole.on "click", "[data-action=clear]", ->
-          floatingConsole.hide()
-          messages.update ""
-
-        floatingConsole.on "click", "[data-action=disable]", ->
-
-          @attribute "disabled", true
-          floatingConsole.findFirst("[data-action=enable]").attribute "disabled", false
-
-          messages.hide()
-
-          return false
-
-        floatingConsole.on "click", "[data-action=enable]", ->
-
-          @attribute "disabled", true
-          floatingConsole.findFirst("[data-action=disable]").attribute "disabled", false
-
-          messages.show()
-
-          return false
-
-        floatingConsole.on "change keyup", "input", ->
-          updateFilter @value()
-
-          for e in messages.children()
-            visible = filter e
-
-            e[if visible then "show" else "hide"]()
-
-          return false
-
-        div = dom.create
-          class: className,
-          _.escape message
-
-          # Should really filter on original message, not escaped.
-
-        unless filter div
-          div.hide()
-
-        messages.append div
-
-        # A slightly clumsy way to ensure that the container is scrolled to the bottom.
-        _.delay -> messages.element.scrollTop = messages.element.scrollHeight
+      messages = floatingConsole.findFirst ".message-container"
+
+      floatingConsole.findFirst("[data-action=enable]").attribute "disabled", true
+
+      floatingConsole.on "click", "[data-action=clear]", ->
+        floatingConsole.hide()
+        messages.update ""
+
+      floatingConsole.on "click", "[data-action=disable]", ->
+
+        @attribute "disabled", true
+        floatingConsole.findFirst("[data-action=enable]").attribute "disabled", false
+
+        messages.hide()
+
+        return false
+
+      floatingConsole.on "click", "[data-action=enable]", ->
+
+        @attribute "disabled", true
+        floatingConsole.findFirst("[data-action=disable]").attribute "disabled", false
+
+        messages.show()
+
+        return false
+
+      floatingConsole.on "change keyup", "input", ->
+        updateFilter @value()
+
+        for e in messages.children()
+          visible = filter e
+
+          e[if visible then "show" else "hide"]()
+
+        return false
+
+      div = dom.create
+        class: className,
+        _.escape message
+
+        # Should really filter on original message, not escaped.
+
+      unless filter div
+        div.hide()
+
+      messages.append div
+
+      # A slightly clumsy way to ensure that the container is scrolled to the bottom.
+      _.delay -> messages.element.scrollTop = messages.element.scrollHeight

     level = (className, consolefn) ->
       (message) ->


ConfigParser got new merge method

ConfigParser got new merge method

--- src/configParser.coffee
+++ src/configParser.coffee
@@ -4,9 +4,12 @@
 extend = require 'extend'

 module.exports = class ConfigParser
+  merge: (config1, config2) ->
+    extend true, {}, config1, config2
+
   load: (path, config = {}) ->
     newConfig = @_parse path, []
-    extend true, {}, config, newConfig
+    @merge config, newConfig

   _parse: (path, included) ->
     return {} if @_isRecursiveInclude path, included
@@ -18,7 +21,7 @@

   _loadYamlFile: (path) ->
     throw new Error "Config not found: #{path}" if not fs.existsSync path
-    return yml.safeLoad fs.readFileSync path, 'utf8'
+    return yml.safeLoad fs.readFileSync path, 'utf8'

   _processIncludeDirective: (path, config, included) ->
     return config if not config.include
@@ -28,7 +31,7 @@

     for includePath in config.include
       includePath = @_buildPathToInclude path, includePath
-      config = extend true, {}, config, @_parse(includePath, included)
+      config = @merge config, @_parse(includePath, included)

     delete config.include


Remove commented-out code.

Remove commented-out code.

--- services/web/public/coffee/ide/history/controllers/HistoryV2ListController.coffee
+++ services/web/public/coffee/ide/history/controllers/HistoryV2ListController.coffee
@@ -73,43 +73,4 @@

 		$scope.$watch "history.updates.length", () ->
 			$scope.recalculateSelectedUpdates()
-	]
-
-	# App.controller "HistoryListItemController", ["$scope", "event_tracking", ($scope, event_tracking) ->
-	# 	$scope.$watch "update.selectedFrom", (selectedFrom, oldSelectedFrom) ->
-	# 		if selectedFrom
-	# 			for update in $scope.history.updates
-	# 				update.selectedFrom = false unless update == $scope.update
-	# 			$scope.recalculateSelectedUpdates()
-
-	# 	$scope.$watch "update.selectedTo", (selectedTo, oldSelectedTo) ->
-	# 		if selectedTo
-	# 			for update in $scope.history.updates
-	# 				update.selectedTo = false unless update == $scope.update
-	# 			$scope.recalculateSelectedUpdates()
-
-	# 	$scope.select = () ->
-	# 		event_tracking.sendMB "history-view-change"
-	# 		$scope.update.selectedTo = true
-	# 		$scope.update.selectedFrom = true
-
-	# 	$scope.mouseOverSelectedFrom = () ->
-	# 		$scope.history.hoveringOverListSelectors = true
-	# 		$scope.update.hoverSelectedFrom = true
-	# 		$scope.recalculateHoveredUpdates()
-
-	# 	$scope.mouseOutSelectedFrom = () ->
-	# 		$scope.history.hoveringOverListSelectors = false
-	# 		$scope.resetHoverState()
-
-	# 	$scope.mouseOverSelectedTo = () ->
-	# 		$scope.history.hoveringOverListSelectors = true
-	# 		$scope.update.hoverSelectedTo = true
-	# 		$scope.recalculateHoveredUpdates()
-
-	# 	$scope.mouseOutSelectedTo = () ->
-	# 		$scope.history.hoveringOverListSelectors = false
-	# 		$scope.resetHoverState()
-
-	# 	$scope.displayName = displayNameForUser
-	# ]
+	]


Fix WebKit repaint bug on new article textarea

--- app/assets/javascripts/domready.js.coffee
+++ app/assets/javascripts/domready.js.coffee
@@ -72,14 +72,19 @@
     #   Fullscreen Editor
     # -------------------------------------

+    $.fn.redraw = ->
+      $(@).each ->
+        redraw = this.offsetHeight
+
     $('.js-editor-open').on 'click', (event) ->
       event.preventDefault()

       $('.js-editor-textarea')
         .addClass('is-editing')
-        .focus()
         .parent('.js-editor-overlay')
         .addClass('is-active')
+
+      setTimeout do $('.js-editor-textarea').focus(), 50

     $(document).on 'click', '.js-editor-close', (event) ->
       event.preventDefault()


snap: rollback -- check that bup ls works, and if not, rollback to the *previous* logged refs/heads/master, then check, etc.

--- salvus/snap.coffee
+++ salvus/snap.coffee
@@ -79,6 +79,7 @@
         args    : opts.args
         timeout : opts.timeout
         env     : {BUP_DIR : opts.bup_dir}
+        err_on_exit : true
         cb      : opts.cb

 ##------------------------------------------
@@ -634,7 +635,7 @@
                             c()
                     async.map(files, f, cb)
         (cb) ->
-            winston.debug("removing refs/heads/master.lock if present")
+            winston.debug("rollback_last_save: removing refs/heads/master.lock if present")
             lock = "#{info.bup_dir}/refs/heads/master.lock"
             fs.exists lock, (exists) ->
                 if exists
@@ -642,6 +643,29 @@
                 else
                     cb()

+        (cb) ->
+            winston.debug("rollback_last_save: testing that bup ls works, so head commit is valid")
+            bup
+                args    : ['ls']
+                bup_dir : info.bup_dir
+                cb      : (err, output) ->
+                    if not err # repo works fine
+                        cb()
+                    if err
+                        # revert to the previously specified commit, as in the log.
+                        fs.readFile "#{info.bup_dir}/logs/HEAD", (err, data) ->
+                            if err
+                                cb(err); return
+                            v = data.toString().split('\n')
+                            commit = v[v.length-1].split(' ')[0]
+                            fs.writeFile("#{info.bup_dir}/refs/heads/master", commit, cb)
+
+        (cb) ->
+            winston.debug("rollback_last_save: test again that bup ls works, so head commit is valid and rollback worked")
+            bup
+                args    : ['ls']
+                bup_dir : info.bup_dir
+                cb      : cb
     ], opts.cb)

@@ -1017,8 +1041,8 @@
 # 30 minutes.
 ensure_snapshot_queue_working = () ->
     if monitor_snapshot_queue_last_run?
-        if misc.walltime() - monitor_snapshot_queue_last_run > 60*15
-            winston.debug("ensure_snapshot_queue_working: BUG/ERROR ** monitor_snapshot_queue has not been called in over 15 minutes -- restarting, but you need to fix this. check logs!")
+        if misc.walltime() - monitor_snapshot_queue_last_run > DEFAULT_TIMEOUT*1.2
+            winston.debug("ensure_snapshot_queue_working: BUG/ERROR ** monitor_snapshot_queue has not been called in too long -- restarting, but you need to fix this. check logs!")
             winston.debug("ensure_snapshot_queue_working: connecting to database")
             connect_to_database (err) =>
                 winston.debug("ensure_snapshot_queue_working: connect_to_databasegot back err=#{err}")


enable unrolls on edit

enable unrolls on edit

--- app/assets/javascripts/selector.js.coffee
+++ app/assets/javascripts/selector.js.coffee
@@ -363,9 +363,15 @@
       item.addClass "selected"
       false

-  $(document).behave "load", "input[data-selector]", (event) ->
-    $("input[data-selector]").each ->
+  enableSelectors = ($collection) =>
+    $collection.each ->
       $(this).selector()
+
+  document.addEventListener 'DOMContentLoaded', ->
+    enableSelectors($("input[data-selector]"))
+
+  E.onDOMElementAdded("input[data-selector]", enableSelectors)
+

   $(document).on "selector:change", (changeEvent, value) ->
     $("*[data-selector-update]").each ->


Use $ instead of jQuery

Use $ instead of jQuery

--- app/assets/javascripts/ui/popup.js.coffee
+++ app/assets/javascripts/ui/popup.js.coffee
@@ -75,7 +75,7 @@
     sublimevideo.pause() if typeof(sublimevideo) is 'object' and SublimeVideo.Misc.Utils.iOS()

     unless @element?
-      @element = jQuery '<div>'
+      @element = $ '<div>'
                    id: "#{@options.id or ''}"
                    class: "#{@options.class or ''} loading"
       @element.html("<div class='popup_wrap'>
@@ -89,7 +89,7 @@
       else if @options.anchor
         this.setContent(@options.anchor.html())
         @options.anchor.html('')
-      jQuery('#content').append @element
+      $('#content').append @element

     if @options.url?
       # the called method will take care of replacing the wrap div with the response content
@@ -108,4 +108,4 @@
       @element.remove()

     if @options.form?
-      @options.form.find('input[type=submit]', 'button').each -> jQuery(this).removeAttr 'disabled'
+      @options.form.find('input[type=submit]', 'button').each -> $(this).removeAttr 'disabled'


can now start reducing

can now start reducing

--- providers/blend.coffee
+++ providers/blend.coffee
@@ -3,6 +3,13 @@
 async = require 'async'
 im = require 'imagemagick'

+flibA = (buff)->
+	i = 3
+	len = buff.length
+	while i<len
+		buff[i] = 0xff - buff[i]
+		i = i + 4
+	buff

 parsePng = (buff, cb)->
 	pngparse.parse buff, (err, data) ->
@@ -31,15 +38,12 @@
 		len = base.length
 		while i < len
 			j = i+((4 - ((i+1) % 4)) %4)
-			if (j - i ) == 3
-				top[j] = 0xff - top[j]
-				base[j] = 0xff - base[j]
 			b = base[i]
 			t = top[i]
-			c = (255-top[j]) / 255
+			c = top[j] / 255
 			base[i]= b + c * (t - b)
 			i++
-		cb null, new Image('png', "rgba").encodeSync(base, 256, 256)
+		cb null, new Image('png', "rgba").encodeSync(flibA(base), 256, 256)

 cbo =
 	set:()->undefined


Copy over source attribute.

Copy over source attribute.

--- indexer.coffee
+++ indexer.coffee
@@ -91,6 +91,7 @@
 			for name in pip_and_conda
 				p = Object.assign(pip_packages[name])
 				p.command = conda_packages[name].command
+				p.source = 'conda'
 				python_packages[name] = p

 			for name in pip_only


Remove --one flag

Remove --one flag

--- build/tasks/spec-task.coffee
+++ build/tasks/spec-task.coffee
@@ -54,14 +54,14 @@
       if process.platform in ['darwin', 'linux']
         options =
           cmd: appPath
-          args: ['--test', "--resource-path=#{resourcePath}", "--spec-directory=#{path.join(packagePath, 'spec')}", '--one']
+          args: ['--test', "--resource-path=#{resourcePath}", "--spec-directory=#{path.join(packagePath, 'spec')}"]
           opts:
             cwd: packagePath
             env: _.extend({}, process.env, ATOM_PATH: rootDir)
       else if process.platform is 'win32'
         options =
           cmd: process.env.comspec
-          args: ['/c', appPath, '--test', "--resource-path=#{resourcePath}", "--spec-directory=#{path.join(packagePath, 'spec')}", "--log-file=ci.log", '--one']
+          args: ['/c', appPath, '--test', "--resource-path=#{resourcePath}", "--spec-directory=#{path.join(packagePath, 'spec')}", "--log-file=ci.log"]
           opts:
             cwd: packagePath
             env: _.extend({}, process.env, ATOM_PATH: rootDir)


- added id to crystal init - updated prompt descriptions - fixed path

--- src/crystal/init.coffee
+++ src/crystal/init.coffee
@@ -1,12 +1,13 @@
 # load deps
-assert = require 'assert'
 crystal = {
 	config: require './config'
 	generate: require './generate'
 }
-fs = require 'fs'
+assert = require 'assert'
+colors = require 'colors'
+fs     = require 'fs'
 prompt = require 'prompt'
-yaml = require 'js-yaml'
+yaml   = require 'js-yaml'

 initProject = (opts, path) ->
 	# validate name
@@ -19,6 +20,7 @@

 	# create config
 	config = {
+		id: opts.id
 		name: opts.name
 		version: opts.version
 	}
@@ -47,7 +49,7 @@
 init = (opts) ->

 	# get path
-	opts.path = opts._[1] || opts.path || this.path || '.'
+	opts.path = opts._[1] || opts.path || this.path || process.cwd()

 	# validate path
 	if !opts.path
@@ -60,7 +62,7 @@
 	if config != false
 		throw new Error "Crystal has already been initialized in: #{opts.path}"

-	console.log "Initializing Crystal for: #{opts.path}"
+	console.log "Initializing Crystal in: #{opts.path}".green.bold

 	# setup prompt
 	prompt.message = ''
@@ -72,22 +74,28 @@
 	else
 		properties = {}

+		if !opts.id
+			properties.id = {
+				description: "ID (ex: acme.website)"
+				required: true
+				type: 'string'
+			}
 		if !opts.name
 			properties.name = {
-				description: "Enter your project's name"
+				description: "Name (ex: Acme Website)"
 				required: true
 				type: 'string'
 			}
 		if !opts.version
 			properties.version = {
 				default: '0.1.0'
-				description: "Enter your project's version"
+				description: "Version"
 				required: true
 				type: 'string'
 			}
 		if !opts.description
 			properties.description = {
-				description: "Enter your project's description"
+				description: "Description (ex: website for Acme, Inc.)"
 				type: 'string'
 			}


[remove] ReverseGeocodingAPI

[remove] ReverseGeocodingAPI

--- app/scripts/apis/reverse_geocoding.coffee
+++ app/scripts/apis/reverse_geocoding.coffee
@@ -1,35 +0,0 @@
-define [
-  'apis/base'
-], (BaseAPI) ->
-
-  class ReverseGeocodingAPI extends BaseAPI
-
-    baseUrl: 'http://maps.googleapis.com/maps/api/geocode/json'
-
-    dataDefaults:
-      sensor: 'false'
-      language: 'en'
-      # lat: undefined
-      # lng: undefined
-
-    prepareData: ->
-      @prepareDataLatLng()
-      super
-
-    prepareResult: ->
-      data = super?.results
-      data = data && _(data).first()?.address_components
-      data = data? && _(data).find (i) ->
-        _(i.types).include('locality')
-      data = data?.long_name
-      @result = data || ''
-
-    prepareDataLatLng: ->
-      if @options.data?.lat? and @options.data?.lng?
-        latlng = [
-          @options.data.lat
-          @options.data.lng
-        ].join(',')
-        delete @options.data.lat
-        delete @options.data.lng
-        @options.data.latlng = latlng


FasterKoding: KD.profile fallback for KD.nick

--- client/Main/KD.extend.coffee
+++ client/Main/KD.extend.coffee
@@ -228,7 +228,7 @@
           @notify_ "You have joined to #{groupName} group!", "success"
           return callback null

-  nick:-> KD.whoami().profile.nickname
+  nick:-> KD.whoami()?.profile?.nickname or KD.profile.nickname

   whoami:-> KD.userAccount


1. set periodEnd to the next month if subscription cancelled at periodEnd

--- app/views/account/SubscriptionView.coffee
+++ app/views/account/SubscriptionView.coffee
@@ -197,6 +197,7 @@
         if sub = info.subscription
           periodEnd = new Date((sub.trial_end or sub.current_period_end) * 1000)
           if sub.cancel_at_period_end
+            periodEnd.setMonth(periodEnd.getMonth() + 1)
             @activeUntil = periodEnd
           else if sub.discount?.coupon?.id isnt 'free'
             @nextPaymentDate = periodEnd


Update keyValueDb logic to mirror Ozaria, for more level types

--- app/views/play/level/PlayLevelView.coffee
+++ app/views/play/level/PlayLevelView.coffee
@@ -103,6 +103,7 @@
     'ipad:memory-warning': 'onIPadMemoryWarning'
     'store:item-purchased': 'onItemPurchased'
     'tome:manual-cast': 'onRunCode'
+    'world:update-key-value-db': 'updateKeyValueDb'

   events:
     'click #level-done-button': 'onDonePressed'
@@ -824,7 +825,8 @@
       continue unless thangType = _.find thangTypes, (m) -> m.get('name') is spriteName
       continue unless sound = AudioPlayer.soundForDialogue message, thangType.get('soundTriggers')
       AudioPlayer.preloadSoundReference sound
-    @session.updateKeyValueDb(e.keyValueDb) if @level.isType('game-dev')
+    if @level.isType('game-dev', 'hero', 'course')
+      @session.updateKeyValueDb(e.keyValueDb)

   # Real-time playback
   onRealTimePlaybackStarted: (e) ->
@@ -845,6 +847,11 @@
     @renderSelectors('#how-to-play-game-dev-panel')
     @$('#how-to-play-game-dev-panel').removeClass('hide')

+  updateKeyValueDb: ->
+    return unless @world.keyValueDb
+    @session.updateKeyValueDb _.cloneDeep(@world.keyValueDb)
+    @session.saveKeyValueDb()
+
   updateLevelName: () ->
     if @world.uiText?.levelName
       @controlBar.setLevelName(@world.uiText.levelName)
@@ -854,7 +861,8 @@
     @$('#how-to-play-game-dev-panel').addClass('hide') if @level.isType('game-dev')
     @$el.removeClass 'real-time'
     @onWindowResize()
-    @session.saveKeyValueDb() if @level.isType('game-dev')
+    if @level.isType('game-dev', 'hero', 'course')
+      @session.saveKeyValueDb()
     if @world.frames.length is @world.totalFrames and not @surface.countdownScreen?.showing and not @realTimePlaybackWaitingForFrames
       _.delay @onSubmissionComplete, 750  # Wait for transition to end.
     else
@@ -922,4 +930,5 @@
     @level?.get 'slug'

   onRunCode: ->
+    @updateKeyValueDb()
     store.commit('game/incrementTimesCodeRun')


Correctly replace @mentions in Talker adapter

--- src/hubot/talker.coffee
+++ src/hubot/talker.coffee
@@ -38,8 +38,14 @@

     bot.on "TextMessage", (message)->
       console.log message
+
       author = self.userForId(message.user.id, message.user)
-      self.receive new Robot.TextMessage(author, message.content.replace(/^\s*@hubot\s+/, "Hubot: "))
+
+      # Replace "@mention" with "mention: ", case-insensitively
+      regexp = new RegExp("\\b@#{self.quoteRegex(self.name)}\\b", 'i')
+      content = message.content.replace(regexp, "#{self.name}: ")
+
+      self.receive new Robot.TextMessage(author, content)

     bot.on "EnterMessage", (message) ->
       console.log message
@@ -52,6 +58,9 @@
       self.receive new Robot.LeaveMessage(author)

     @bot = bot
+
+  quoteRegex: (string) ->
+    string.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&")

 module.exports = Talker


Add global event `unread-changed-by-subscription`

--- client/startup/unread.coffee
+++ client/startup/unread.coffee
@@ -13,6 +13,7 @@
 				openedRoomId = Session.get 'openedRoom'

 		for subscription in subscriptions.fetch()
+			fireGlobalEvent 'unread-changed-by-subscription', subscription

 			if subscription.alert or subscription.unread > 0
 				# This logic is duplicated in /client/notifications/notification.coffee.


Whenever a kdapp is deleted refreshApps

Whenever a kdapp is deleted refreshApps

--- client/landing/app/MainApp/filetree/controllers/findercontextmenucontroller.coffee
+++ client/landing/app/MainApp/filetree/controllers/findercontextmenucontroller.coffee
@@ -176,6 +176,8 @@
             separator             : yes
           "Publish to App Catalog":
             action                : "publish"
+      fileData.on "fs.delete.finished", =>
+        @getSingleton("kodingAppsController").refreshApps()

     return items


Metrics: timestamp fix

Metrics: timestamp fix

--- src/api/metrics.coffee
+++ src/api/metrics.coffee
@@ -32,7 +32,10 @@

   if m[0]?._id?.year? # if there are time components
     m = m.map (item) ->
-      item.timestamp = moment(item._id)
+      date = Object.assign {}, item._id
+      # adapt for moment (month starting at 0)
+      if date.month then date.month = date.month - 1
+      item.timestamp = moment(date)
       return item

   this.body = m


Use generated name on empty input.

Use generated name on empty input.

--- src/app-manager.coffee
+++ src/app-manager.coffee
@@ -12,7 +12,7 @@

 getOptions = (repo, options={}, callback) ->
   [options, callback] = [{}, options] if _.isFunction(options)
-  options.appName ?= repo.workingDir()
+  options.appName ?= repo.workingDir() unless options.allowEmpty
   [options, callback]

 exports.promptAppName = (callback) ->
@@ -21,14 +21,16 @@

 exports.createApp = (repo, api, options, callback) ->
   [options, callback] = getOptions repo, options, callback
-  api.postApp name: options.appName, (err, app) ->
+  params = if options.appName then {name: options.appName} else {}
+  api.postApp params, (err, app) ->
     return callback(err, app) if err == null
     if err.code == 422 && options.retry
       console.warn err.message
       exports.promptAppName (err, result) ->
         return callback err unless err is null
         options.appName = result.appName
-        exports.createApp repo, api, options, callback
+        delete options.appName if _.isEmpty(result.appName)
+        exports.createApp repo, api, _.extend(allowEmpty: true, options), callback
     else
       callback err


Updated Io stub

Updated Io stub

--- src/languages/io.coffee
+++ src/languages/io.coffee
@@ -1,6 +1,28 @@
 Language = require './language'
+iota = require 'iota-compiler'
+esprima = require 'esprima'

 module.exports = class Io extends Language
   name: 'Io'
   id: 'io'
   parserID: 'iota'
+  runtimeGlobals: iota.lib
+
+  obviouslyCannotTranspile: (rawCode) ->
+    false
+
+  wrap: (rawCode, aether) ->
+    @wrappedCodePrefix = """chooseAction := method("""
+    @wrappedCodeSuffix = """)\nplayer chooseAction := getSlot("chooseAction")\nplayer chooseAction"""
+
+    @wrappedCodePrefix + rawCode + @wrappedCodeSuffix
+
+  parse: (code, aether) ->
+
+    wrappedCode = iota.compile(code, true);
+    wrappedCode = wrappedCode.replace('execute', aether.options.functionName) if aether.options.functionName
+
+    console.log wrappedCode
+
+    ast = esprima.parse(wrappedCode)
+    ast


Make all applications privileged

Make all applications privileged

--- src/application.coffee
+++ src/application.coffee
@@ -67,7 +67,7 @@
 			Cmd: ['/bin/bash', '-c', '/start web']
 		)
 	).then((container) ->
-		container.startAsync()
+		container.startAsync(Privileged: true)
 	)

 exports.restart = restart = (app) ->


Major pass on interpolating templates

Major pass on interpolating templates

--- convert.coffee
+++ convert.coffee
@@ -5,24 +5,31 @@
 file = fs.readFileSync argv.file, 'utf8'

 selfClosingTags = 'area, base, br, col, command, embed, hr, img, input,
-keygen, link, meta, param, source, track, wbr'.split ', '
+keygen, link, meta, param, source, track, wbr'.split /,\s*/

 getCloseTag = (string) ->
   index = 0
   depth = 0
+  open = string.match(/<.*?>/)[0]
+  string = string.replace open, ''
+
   for char, index in string
     # Close tag
     if char is '<' and string[index + 1] is '/'
       if not depth
         after = string.substr index
         close = after.match(/<\/.*?>/)[0]
-        return
+        afterWithTag = after + close
+        afterWithoutTag = after.substring close.length
+
+        return (
           index: index
           closeTag: close
-          after: after
+          after: afterWithoutTag
           startIndex: index
-          endIndex: index + after.length
-          before: string.substr 0, index
+          endIndex: index + afterWithTag.length
+          before: open + '\n' + string.substr(0, index) + close
+        )
       else
         depth--
     # Open tag
@@ -40,46 +47,44 @@
       else
         depth++

-flat = file
-  .replace(/<[^>]*?ng\-repeat="(.*)".*?>(.|\s)*?<\/.*?>/g, (match, text) ->
+interpolated = file
+  .replace(/<[^>]*?ng\-repeat="(.*?)">([\S\s]+)/gi, (match, text, post) ->
     varName = text.split(' in ')[1]
-    "{{##{varName}}}\n#{match}\n{{/#{varName}}}"
+    close = getCloseTag match
+    if close
+      "{{##{varName}}}\n#{close.before}\n{{/#{varName}}}\n#{close.after}"
+    else
+      throw new Error 'Parse error! Coudlnt find close tag for ng-repeat'
   )
-  .replace(/<[^>]*?ng\-if="(.*)".*?>(.|\s)*?<\/.*?>/, (match, varName) ->
+  .replace(/<[^>]*?ng\-if="(.*)".*?>([\S\s]+)/, (match, varName, post) ->
     # Unless
     if varName.indexOf('!') is 0
       varName = varName.substr 1
-      "{{^#{varName}}}\n#{match}\n{{/#{varName}}}"
+      close = getCloseTag match
+      if close
+        "{{##{varName}}}\n#{close.before}\n{{/#{varName}}}\n#{close.after}"
+      else
+        throw new Error 'Parse error! Coudlnt find close tag for ng-repeat'
     else
-      "{{##{varName}}}\n#{match}\n{{/#{varName}}}"
+      close = getCloseTag match
+      if close
+        "{{##{varName}}}\n#{close.before}\n{{/#{varName}}}\n#{close.after}"
+      else
+        throw new Error 'Parse error! Coudlnt find close tag for ng-repeat'
   )
-  .replace(/<[^>]*?ng\-show="(.*)".*?>(.|\s)*?<\/.*?>/g, (match, varName) ->
-
-    "{{##{varName}}}\n#{match}\n{{/#{varName}}}"
+  .replace(/<[^>]*?ng\-show="(.*)".*?>([\S\s]+)/g, (match, varName, post) ->
+    close = getCloseTag match
+    if close
+      "{{##{varName}}}\n#{close.before}\n{{/#{varName}}}\n#{close.after}"
+    else
+      throw new Error 'Parse error! Coudlnt find close tag for ng-repeat'
   )
-  .replace(/<[^>]*?ng\-hide="(.*)".*?>(.|\s)*?<\/.*?>/g, (match, varName) ->
-    "{{^#{varName}}}\n#{match}\n{{/#{varName}}}"
+  .replace(/<[^>]*?ng\-hide="(.*)".*?>([\S\s]+)/g, (match, varName, post) ->
+    close = getCloseTag match
+    if close
+      "{{##{varName}}}\n#{close.before}\n{{/#{varName}}}\n#{close.after}"
+    else
+      throw new Error 'Parse error! Coudlnt find close tag for ng-repeat'
   )

-interpolated = file
-  .replace(/<[^>]*?ng\-repeat="(.*)".*?>(.|\s)*/g, (match, text, post) ->
-    varName = text.split(' in ')[1]
-    "{{##{varName}}}\n#{match}\n{{/#{varName}}}"
-  )
-  .replace(/<[^>]*?ng\-if="(.*)".*?>(.|\s)*?<\/.*?>/, (match, varName) ->
-    # Unless
-    if varName.indexOf('!') is 0
-      varName = varName.substr 1
-      "{{^#{varName}}}\n#{match}\n{{/#{varName}}}"
-    else
-      "{{##{varName}}}\n#{match}\n{{/#{varName}}}"
-  )
-  .replace(/<[^>]*?ng\-show="(.*)".*?>(.|\s)*?<\/.*?>/g, (match, varName) ->
-    "{{##{varName}}}\n#{match}\n{{/#{varName}}}"
-  )
-  .replace(/<[^>]*?ng\-hide="(.*)".*?>(.|\s)*?<\/.*?>/g, (match, varName) ->
-    "{{^#{varName}}}\n#{match}\n{{/#{varName}}}"
-  )
-
-console.log 'interpolated:', interpolated
-console.log 'flat:', flat
+console.log '\n\n\n\n\n\n\NINTERPOLATED:\n\n', interpolated


expose default title for testing

expose default title for testing

--- bokehjs/src/coffee/common/document.coffee
+++ bokehjs/src/coffee/common/document.coffee
@@ -571,4 +571,5 @@
   TitleChangedEvent : TitleChangedEvent
   RootAddedEvent : RootAddedEvent
   RootRemovedEvent : RootRemovedEvent
+  DEFAULT_TITLE : DEFAULT_TITLE
 }