Fifth batch of Swedish translations. (#6127)

--- app/locale/sv.coffee
+++ app/locale/sv.coffee
@@ -885,133 +885,133 @@
     prompt_body: "Vill du skaffa flera?"
     prompt_button: "Gå till affären"
     recovered: "Föregående köp av ädelstenar återskapat. Var vänlig och uppdatera sidan."
-#    price: "x{{gems}} / mo"
-#    buy_premium: "Buy Premium"
-#    purchase: "Purchase"
-#    purchased: "Purchased"
-
-#  subscribe_for_gems:
-#    prompt_title: "Not Enough Gems!"
-#    prompt_body: "Subscribe to Premium to get gems and access to even more levels!"
-
-#  earn_gems:
-#    prompt_title: "Not Enough Gems"
-#    prompt_body: "Keep playing to earn more!"
-
-#  subscribe:
-#    best_deal: "Best Deal!"
-#    confirmation: "Congratulations! You now have a CodeCombat Premium Subscription!"
-#    premium_already_subscribed: "You're already subscribed to Premium!"
-#    subscribe_modal_title: "CodeCombat Premium"
-#    comparison_blurb: "Become a Master Coder - subscribe to Premium today!"
-#    must_be_logged: "You must be logged in first. Please create an account or log in from the menu above."
-#    subscribe_title: "Subscribe" # Actually used in subscribe buttons, too
-#    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?"
-#    stripe_description: "Monthly Subscription"
-#    stripe_yearly_description: "Annual Subscription"
-#    buy_now: "Buy Now"
-#    subscription_required_to_play: "You'll need a subscription to play this level."
-#    unlock_help_videos: "Subscribe to unlock all video tutorials."
-#    personal_sub: "Personal Subscription" # Accounts Subscription View below
-#    loading_info: "Loading subscription information..."
-#    managed_by: "Managed by"
-#    will_be_cancelled: "Will be cancelled on"
-#    currently_free: "You currently have a free subscription"
-#    currently_free_until: "You currently have a subscription until"
-#    free_subscription: "Free subscription"
-#    was_free_until: "You had a free subscription until"
-#    managed_subs: "Managed Subscriptions"
-#    subscribing: "Subscribing..."
-#    current_recipients: "Current Recipients"
-#    unsubscribing: "Unsubscribing"
-#    subscribe_prepaid: "Click Subscribe to use prepaid code"
-#    using_prepaid: "Using prepaid code for monthly subscription"
-#    feature_level_access: "Access 300+ levels available"
-#    feature_heroes: "Unlock exclusive heroes and pets"
-#    feature_learn: "Learn to make games and websites"
-#    month_price: "$__price__"
-#    first_month_price: "Only $__price__ for your first month!"
-#    lifetime: "Lifetime Access"
-#    lifetime_price: "$__price__"
-#    year_subscription: "Annual Subscription"
-#    year_price: "$__price__/year"
-#    support_part1: "Need help with payment or prefer PayPal? Email"
-#    support_part2: "support@codecombat.com"
-
-#  announcement:
-#    now_available: "Now available for subscribers!"
-#    subscriber: "subscriber"
-#    cuddly_companions: "Cuddly Companions!" # Pet Announcement Modal
-#    kindling_name: "Kindling Elemental"
-#    kindling_description: "Kindling Elementals just want to keep you warm at night. And during the day. All the time, really."
-#    griffin_name: "Baby Griffin"
-#    griffin_description: "Griffins are half eagle, half lion, all adorable."
-#    raven_name: "Raven"
-#    raven_description: "Ravens are excellent at gathering shiny bottles full of health for you."
-#    mimic_name: "Mimic"
-#    mimic_description: "Mimics can pick up coins for you. Move them on top of coins to increase your gold supply."
-#    cougar_name: "Cougar"
-#    cougar_description: "Cougars like to earn a PhD by Purring Happily Daily."
-#    fox_name: "Blue Fox"
-#    fox_description: "Blue foxes are very clever and love digging in the dirt and snow!"
-#    pugicorn_name: "Pugicorn"
-#    pugicorn_description: "Pugicorns are some of the rarest creatures and can cast spells!"
-#    wolf_name: "Wolf Pup"
-#    wolf_description: "Wolf pups excel in hunting, gathering, and playing a mean game of hide-and-seek!"
-#    ball_name: "Red Squeaky Ball"
-#    ball_description: "ball.squeak()"
-#    collect_pets: "Collect pets for your heroes!"
-#    each_pet: "Each pet has a unique helper ability!"
-#    upgrade_to_premium: "Become a {{subscriber}} to equip pets."
-#    play_second_kithmaze: "Play {{the_second_kithmaze}} to unlock the Wolf Pup!"
-#    the_second_kithmaze: "The Second Kithmaze"
-#    keep_playing: "Keep playing to discover the first pet!"
-#    coming_soon: "Coming soon"
-#    ritic: "Ritic the Cold" # Ritic Announcement Modal
-#    ritic_description: "Ritic the Cold. Trapped in Kelvintaph Glacier for countless ages, finally free and ready to tend to the ogres that imprisoned him."
-#    ice_block: "A block of ice"
-#    ice_description: "There appears to be something trapped inside..."
-#    blink_name: "Blink"
-#    blink_description: "Ritic disappears and reappears in a blink of an eye, leaving nothing but a shadow."
-#    shadowStep_name: "Shadowstep"
-#    shadowStep_description: "A master assassin knows how to walk between the shadows."
-#    tornado_name: "Tornado"
-#    tornado_description: "It is good to have a reset button when one's cover is blown."
-#    wallOfDarkness_name: "Wall of Darkness"
-#    wallOfDarkness_description: "Hide behind a wall of shadows to prevent the gaze of prying eyes."
-
-#  avatar_selection:
-#    pick_an_avatar: "Pick an avatar that will represent you as a player"
-
-#  premium_features:
-#    get_premium: "Get
CodeCombat
Premium" # Fit into the banner on the /features page
-#    master_coder: "Become a Master Coder by subscribing today!"
-#    paypal_redirect: "You will be redirected to PayPal to complete the subscription process."
-#    subscribe_now: "Subscribe Now"
-#    hero_blurb_1: "Get access to __premiumHeroesCount__ super-charged subscriber-only heroes! Harness the unstoppable power of Okar Stompfoot, the deadly precision of Naria of the Leaf, or summon \"adorable\" skeletons with Nalfar Cryptor."
-#    hero_blurb_2: "Premium Warriors unlock stunning martial skills like Warcry, Stomp, and Hurl Enemy. Or, play as a Ranger, using stealth and bows, throwing knives, traps! Try your skill as a true coding Wizard, and unleash a powerful array of Primordial, Necromantic or Elemental magic!"
-#    hero_caption: "Exciting new heroes!"
-#    pet_blurb_1: "Pets aren't just adorable companions, they also provide unique functionality and methods. The Baby Griffin can carry units through the air, the Wolf Pup plays catch with enemy arrows, the Cougar is fond of chasing ogres around, and the Mimic attracts coins like a magnet!"
-#    pet_blurb_2: "Collect all the pets to discover their unique abilities!"
-#    pet_caption: "Adopt pets to accompany your hero!"
-#    game_dev_blurb: "Learn game scripting and build new levels to share with your friends! Place the items you want, write code for unit logic and behavior, and see if your friends can beat the level!"
-#    game_dev_caption: "Design your own games to challenge your friends!"
-#    everything_in_premium: "Everything you get in CodeCombat Premium:"
-#    list_gems: "Receive bonus gems to buy gear, pets, and heroes"
-#    list_levels: "Gain access to __premiumLevelsCount__ more levels"
-#    list_heroes: "Unlock exclusive heroes, include Ranger and Wizard classes"
-#    list_game_dev: "Make and share games with friends"
-#    list_web_dev: "Build websites and interactive apps"
-#    list_items: "Equip Premium-only items like pets"
-#    list_support: "Get Premium support to help you debug tricky code"
-#    list_clans: "Create private clans to invite your friends and compete on a group leaderboard"
+    price: "x{{gems}} / mån"
+    buy_premium: "Köp Premium"
+    purchase: "Köp"
+    purchased: "Köpt"
+
+  subscribe_for_gems:
+    prompt_title: "Inte tillräckligt med ädelstenar!"
+    prompt_body: "Prenumerera på Premium för att få ädelstenar och få tillgång till ännu fler nivåer!"
+
+  earn_gems:
+    prompt_title: "Inte tillräckligt med ädelstenar"
+    prompt_body: "Fortsätt spela för att tjäna mer!"
+
+  subscribe:
+    best_deal: "Bästa erbjudandet!"
+    confirmation: "Grattis! Du har nu en CodeCombat Premium-prenumeration!"
+    premium_already_subscribed: "Du prenumererar redan på Premium!"
+    subscribe_modal_title: "CodeCombat Premium"
+    comparison_blurb: "Bli en Master Coder - prenumerera på Premium idag!"
+    must_be_logged: "Du måste vara inloggad först. Vänligen skapa ett konto eller logga in från menyn ovan."
+    subscribe_title: "Prenumerera" # Actually used in subscribe buttons, too
+    unsubscribe: "Avsluta prenumeration"
+    confirm_unsubscribe: "Bekräfta avslutande av prenumerationen"
+    never_mind: "Glöm det, jag älskar dig fortfarande"
+    thank_you_months_prefix: "Tack för att du stöttade oss dessa senaste"
+    thank_you_months_suffix: "månaderna."
+    thank_you: "Tack för att du stöder CodeCombat."
+    sorry_to_see_you_go: "Ledsen att se dig gå! Berätta gärna hur vi kan bli bättre."
+    unsubscribe_feedback_placeholder: "Oj, vad har vi gjort?"
+    stripe_description: "Månadsprenumeration"
+    stripe_yearly_description: "Årlig prenumeration"
+    buy_now: "Köp nu"
+    subscription_required_to_play: "Du behöver ett abonnemang för att spela den här nivån."
+    unlock_help_videos: "Prenumerera för att låsa upp alla självstudier."
+    personal_sub: "Personlig prenumeration" # Accounts Subscription View below
+    loading_info: "Laddar prenumerationsinformation ..."
+    managed_by: "Hanteras av"
+    will_be_cancelled: "Avslutas den"
+    currently_free: "Du har för närvarande en gratis prenumeration"
+    currently_free_until: "Du har för närvarande en prenumeration till"
+    free_subscription: "Gratis prenumeration"
+    was_free_until: "Du hade en gratis prenumeration fram till"
+    managed_subs: "Hanterade prenumerationer"
+    subscribing: "Prenumererar..."
+    current_recipients: "Nuvarande mottagare"
+    unsubscribing: "Avregistrerar dig"
+    subscribe_prepaid: "Klicka på Prenumerera för att använda förbetald kod"
+    using_prepaid: "Använd förbetald kod för månadsabonnemang"
+    feature_level_access: "Få tillgång till mer än 300 nivåer"
+    feature_heroes: "Lås upp exklusiva hjältar och husdjur"
+    feature_learn: "Lär dig att skapa spel och webbplatser"
+    month_price: "$__price__"
+    first_month_price: "Endast $__price__ för din första månad!"
+    lifetime: "Livstidsåtkomst"
+    lifetime_price: "$__price__"
+    year_subscription: "Årlig prenumeration"
+    year_price: "$__price__/år"
+    support_part1: "Behöver du hjälp med betalning eller föredrar PayPal? E-post"
+    support_part2: "support@codecombat.com"
+
+  announcement:
+    now_available: "Nu tillgängligt för prenumeranter!"
+    subscriber: "prenumeranter"
+    cuddly_companions: "Gosiga följeslagare!" # Pet Announcement Modal
+    kindling_name: "Kindling Elemental"
+    kindling_description: "Kindling Elementals vill bara hålla dig varm på natten. Och under dagen. Hela tiden, verkligen."
+    griffin_name: "Baby Griffin"
+    griffin_description: "Griffins är halv örn, halv lejon, alla bedårande."
+    raven_name: "Korpar"
+    raven_description: "Korpar är utmärkta för att samla blanka flaskor fulla av hälsa åt dig."
+    mimic_name: "Mimic"
+    mimic_description: "Mimics kan plocka upp mynt åt dig. Flytta dem ovanpå mynt för att öka din guldförsörjning."
+    cougar_name: "Pumor"
+    cougar_description: "Pumor gillar att ta doktorsexamen av Purring Happily Daily."
+    fox_name: "Blå räv"
+    fox_description: "Blå rävar är väldigt smarta och älskar att gräva i smuts och snö!"
+    pugicorn_name: "Pugicorn"
+    pugicorn_description: "Pugicorns är några av de sällsynta varelserna och kan använda magi!"
+    wolf_name: "Vargunge"
+    wolf_description: "Vargungar utmärker sig i att jaga, samla och spela ett genomsnittligt spel av kurra-gömma!"
+    ball_name: "Röd knarrande boll"
+    ball_description: "ball.squeak()"
+    collect_pets: "Samla husdjur till dina hjältar!"
+    each_pet: "Varje husdjur har en unik hjälparförmåga!"
+    upgrade_to_premium: "Bli en {{subscriber}} för att utrusta husdjur."
+    play_second_kithmaze: "Spela {{the_second_kithmaze}} för att låsa upp Vargunge!"
+    the_second_kithmaze: "Andra Kithmaze"
+    keep_playing: "Fortsätt spela för att upptäcka det första husdjuret!"
+    coming_soon: "Kommer snart"
+    ritic: "Ritic den kalle" # Ritic Announcement Modal
+    ritic_description: "Ritic den kalle. Fångad i Kelvintaph-glaciären i otaliga åldrar, äntligen fri och redo att ta sig till trollen som fängslade honom."
+    ice_block: "Ett block av is"
+    ice_description: "Det verkar vara något som är fångat inuti..."
+    blink_name: "Blinka"
+    blink_description: "Ritic försvinner och dyker upp igen på ett ögonblick och lämnar inget annat än en skugga."
+    shadowStep_name: "Skugg-gång"
+    shadowStep_description: "En mästare mördare vet hur man går mellan skuggorna."
+    tornado_name: "Tornado"
+    tornado_description: "Det är bra att ha en återställningsknapp när man blir avslöjad."
+    wallOfDarkness_name: "Vägg av mörker"
+    wallOfDarkness_description: "Dölj dig bakom en skuggvägg för att förhindra at bli sedd av nyfikna ögon."
+
+  avatar_selection:
+    pick_an_avatar: "Välj en avatar som representerar dig som spelare"
+
+  premium_features:
+    get_premium: "Skaffa
CodeCombat
Premium" # Fit into the banner on the /features page
+    master_coder: "Bli en Master Coder genom att prenumerera idag!"
+    paypal_redirect: "Du kommer att omdirigeras till PayPal för att slutföra prenumerationsprocessen."
+    subscribe_now: "Prenumerera nu"
+    hero_blurb_1: "Få tillgång till __premiumHeroesCount__ superladdade prenumeranter. Utnyttja den ostoppbara kraften hos Okar Stompfoot, den dödliga precisionen hos Naria of the Leaf, eller kalla till \"bedårande\" skelett med Nalfar Cryptor."
+    hero_blurb_2: "Premium Warriors låser upp fantastiska kampsport som Warcry, Stomp och Hurl Enemy. Eller spela som en Ranger, med smyg och bågar, kastknivar, fällor! Testa din skicklighet som en riktig kodningstrollkarl och släpp loss ett kraftfullt urval av primordial, nekromantisk eller elementär magi!"
+    hero_caption: "Spännande nya hjältar!"
+    pet_blurb_1: "Husdjur är inte bara bedårande följeslagare, de ger också unik funktionalitet och metoder. Baby Griffin kan bära enheter genom luften, Vargungar fångar fiendens pilar, Pumor är förtjust i att jaga ograr och Mimic plockar mynt som en magnet!"
+    pet_blurb_2: "Samla alla husdjur för att upptäcka deras unika förmågor!"
+    pet_caption: "Välj husdjur att följa med din hjälte!"
+    game_dev_blurb: "Lär dig skriptspel och bygg nya nivåer för att dela med dina vänner! Placera de föremål du vill ha, skriv kod för enhetslogik och beteende och se om dina vänner kan klara nivån!"
+    game_dev_caption: "Skapa dina egna spel för att utmana dina vänner!"
+    everything_in_premium: "Allt du får med CodeCombat Premium:"
+    list_gems: "Få bonusädelstenar för att köpa redskap, husdjur och hjältar"
+    list_levels: "Få tillgång till __premiumLevelsCount__ extra nivåer"
+    list_heroes: "Lås upp exklusiva hjältar, så som Ranger och Wizard"
+    list_game_dev: "Skapa och dela spel med vänner"
+    list_web_dev: "Bygg webbplatser och interaktiva appar"
+    list_items: "Utrusta dig med Premium föremål så som husdjur"
+    list_support: "Få Premium-support för att hjälpa dig felsöka knepig kod"
+    list_clans: "Skapa privata klaner för att bjuda in dina vänner och tävla på en leaderboard"

   choose_hero:
     choose_hero: "Välj hjälte"
@@ -1023,8 +1023,8 @@
     javascript_blurb: "Webbens språk. (Inte samma sak som Java.)"
     coffeescript_blurb: "Trevligare JavaScript-syntax."
     lua_blurb: "Språk för spelskript."
-#    java_blurb: "(Subscriber Only) Android and enterprise."
-#    cpp_blurb: "(Subscriber Only) Game development and high performance computing."
+    java_blurb: "(Endast för prenumerant) Android och företag."
+    cpp_blurb: "(Endast för prenumerant) Spelutveckling och högpresterande datorer."
     status: "Status"
     weapons: "Vapen"
     weapons_warrior: "Svärd - Kort räckvidd, ingen magi"
@@ -1050,12 +1050,12 @@
     level_to_unlock: "Nivå som låser upp:" # Label for which level you have to beat to unlock a particular hero (click a locked hero in the store to see)
     restricted_to_certain_heroes: "Det är bara vissa hjältar som kan spela den här nivån."

-#  char_customization_modal:
-#    heading: "Customize Your Hero"
-#    body: "Body"
-#    name_label: "Hero's Name"
-#    hair_label: "Hair Color"
-#    skin_label: "Skin Color"
+  char_customization_modal:
+    heading: "Anpassa din hjälte"
+    body: "Kropp"
+    name_label: "Hjältens namn"
+    hair_label: "Hårfärg"
+    skin_label: "Hudfärg"

   skill_docs:
     function: "funktion" # skill types
@@ -1085,7 +1085,7 @@
     optional_parameters: "Valfria parametrar"
     returns: "Returnerar"
     granted_by: "Ges av"
-#    still_undocumented: "Still undocumented, sorry."
+    still_undocumented: "Fortfarande odokumenterad, sorry."

   save_load:
     granularity_saved_games: "Sparat"
@@ -1097,7 +1097,7 @@
     music_label: "Musik"
     music_description: "Stäng av/sätt på bakgrundsmusik."
     editor_config_title: "Redigerarinställningar"
-#    editor_config_livecompletion_label: "Live Autocompletion"
+    editor_config_livecompletion_label: "Live autoslutförande"
     editor_config_livecompletion_description: "Visar förslag medans du skriver"
     editor_config_invisibles_label: "Visa osynliga"
     editor_config_invisibles_description: "Visar osynliga tecken, till exempel mellanrum och nyradstecken."


Add integration spec for syncing tax category changes.

--- src/spec/integration/integration-product.spec.coffee
+++ src/spec/integration/integration-product.spec.coffee
@@ -16,7 +16,7 @@
     @sync = new ProductSync config: Config.prod
     @sphereClient = new SphereClient config: Config.prod

-    unique = new Date().getTime()
+    @unique = new Date().getTime()
     pt =
       name: 'myType'
       description: 'foo'
@@ -24,7 +24,7 @@
       name:
         en: 'Foo'
       slug:
-        en: "foo-#{unique}"
+        en: "foo-#{@unique}"
       productType:
         typeId: 'product-type'
       # without all these default the syncer does not work!
@@ -66,6 +66,59 @@
       expect(r.statusCode).toBe 200
       expect(b.masterData.staged.name.en).toBe "Hello"
       expect(b.masterData.staged.name.de).toBe "Hallo"
+      done()
+
+  it 'should add, update and delete tax category', (done) ->
+    tax =
+      name: "myTax-#{@unique}"
+      rates: []
+
+    # addition
+    @sphereClient.taxCategories.save(tax).then (taxCategory) =>
+      @newProduct.taxCategory =
+        typeId: 'tax-category'
+        id: taxCategory.id
+      data = @sync.buildActions @newProduct, @oldProduct
+      data.update (e, r, b) =>
+        expect(r.statusCode).toBe 200
+        expect(b.taxCategory).toBeDefined()
+        expect(b.taxCategory.typeId).toBe 'tax-category'
+        expect(b.taxCategory.id).toBe taxCategory.id
+
+    # change
+        tax =
+          name: "myTax2-#{@unique}"
+          rates: []
+        @sphereClient.taxCategories.save(tax).then (taxCategory2) =>
+          @newProduct.taxCategory.id = taxCategory2.id
+
+          # TODO: provide method to extract compare data from products endpoint
+          @oldProduct = b.masterData.staged
+          @oldProduct.productType = b.productType # set product type to staged subset
+          # set id for matching and version for update
+          @oldProduct.id = b.id
+          @oldProduct.version = b.version
+
+          data = @sync.buildActions @newProduct, @oldProduct
+          data.update (e, r, b) =>
+            expect(r.statusCode).toBe 200
+            expect(b.taxCategory).toBeDefined()
+            expect(b.taxCategory.typeId).toBe 'tax-category'
+            expect(b.taxCategory.id).toBe taxCategory2.id
+
+    # deletion
+            @newProduct.taxCategory = null
+            @oldProduct.version = b.version
+
+            data = @sync.buildActions @newProduct, @oldProduct
+            data.update (e, r, b) ->
+              expect(r.statusCode).toBe 200
+              expect(b.taxCategory).toBeUndefined()
+              done()
+
+    .fail (msg) ->
+      console.log msg
+      expect(true).toBe false
       done()


temporarily increase start date of magma-mountain


I forgot about turbolinks, lets attach the event looking for a tab in the textarea to html, since the body gets replaced on page load, which clears events

--- app/assets/javascripts/articles.js.coffee
+++ app/assets/javascripts/articles.js.coffee
@@ -15,8 +15,10 @@
     clearTimeout(timeout) if timeout
     timeout = delay 400, -> submit_form()

-  $('textarea#article_content').on 'keydown', (evt)->
+  $('html').on 'keydown','#article_content', (evt)->
     if evt.keyCode == 9
       keycode = evt.keycode
       evt.preventDefault()
-      $('textarea#article_content').insertAtCaret('  ')+      $('textarea#article_content').insertAtCaret('  ')
+
+  return


hotfix for image edit

hotfix for image edit

--- app/assets/javascripts/listings.js.coffee
+++ app/assets/javascripts/listings.js.coffee
@@ -25,12 +25,13 @@
     $('#sidebar .category').each ->
       $(this).addClass('active') if $(this).find('a').text() is selected_category

-  if $('.images-block').exists()
-    $('.image-upload').hide()
-    $('.image-upload').first().show()
+  if $('body.new').exists()
+    if $('.images-block').exists()
+      $('.image-upload').hide()
+      $('.image-upload').first().show()

-  # Needs some work
-  $('span#add-image a').click ->
-    $('.image-upload:visible').last().next().show()
-    return false
+    # Needs some work
+    $('span#add-image a').click ->
+      $('.image-upload:visible').last().next().show()
+      return false


fix!!!

fix!!!

--- app/assets/javascripts/restaurants.coffee
+++ app/assets/javascripts/restaurants.coffee
@@ -30,7 +30,7 @@
     commentId = commentNumber
     restaurantId = restaurantNumber
     userId = userNumber
-    newURL = "/restaurants/cancel_link?comment_id=#{commentId}&restaurant_id=#{restaurantId}&user_id=#{userId}"
+    newURL = "/restaurants/cancel_like?comment_id=#{commentId}&restaurant_id=#{restaurantId}&user_id=#{userId}"
     thisId = "not-good-#{restaurantNumber}"
     newId = "good-#{restaurantNumber}"


Add active state to Lyrics History button.

--- app/client/js/react/pages/editsong.coffee
+++ app/client/js/react/pages/editsong.coffee
@@ -91,16 +91,13 @@
         span className: 'lyrics-history',
           button
             ref: 'lyrics-history-button'
-            className: 'btn btn-default'
+            className: 'btn btn-default ' + if lyricsHistoryShown then 'active' else ''
             onPointerUp: @onLyricsHistoryBtnPointerUp
             type: 'button'
-          ,
-            if lyricsHistoryShown
-              EditSong.MSG_HIDE_LYRICS_HISTORY
-            else
-              EditSong.MSG_SHOW_LYRICS_HISTORY
-          lyricsHistoryShown && ol {}, lyrics
-          lyricsHistoryShown && p {}, EditSong.MSG_LYRICS_HISTORY_P
+          , EditSong.MSG_LYRICS_HISTORY
+          lyricsHistoryShown && div {},
+            ol {}, lyrics
+            p {}, EditSong.MSG_LYRICS_HISTORY_P

       onLyricsHistoryBtnPointerUp: ->
         lyricsHistoryShown = !lyricsHistoryShown
@@ -116,7 +113,7 @@
         @doYellowFadeIfHistoryChanged()

       doYellowFadeIfHistoryChanged: ->
-        if lyricsHistoryChanged
+        if !lyricsHistoryShown && lyricsHistoryChanged
           el = @refs['lyrics-history-button'].getDOMNode()
           return if !el
           goog.dom.classlist.remove el, 'yellow-fade'
@@ -149,18 +146,17 @@
         routes.home.redirect()

       getLyricsHistory: (song) ->
-        userStore.getSongLyricsLocalHistory(song).filter (lyrics) ->
-          lyrics != song.lyrics
+        userStore.getSongLyricsLocalHistory song
+          .filter (lyrics) -> lyrics != song.lyrics

   # PATTERN: String localization. Remember, every string has to be wrapped with
   # goog.getMsg method.
   @MSG_CREATE_NEW_SONG: goog.getMsg 'Add New Song'
   @MSG_DELETE: goog.getMsg 'Delete'
-  @MSG_HIDE_LYRICS_HISTORY: goog.getMsg 'hide'
   @MSG_HOW_TO_WRITE_LYRICS: goog.getMsg 'How to write lyrics'
   @MSG_LYRICS_HISTORY_P: goog.getMsg 'This is just MVP version. Formatting, cleaning, merging etc. will be implemented later. For now, you can merge with copy&paste :-P'
   @MSG_RESTORE: goog.getMsg 'Restore'
-  @MSG_SHOW_LYRICS_HISTORY: goog.getMsg 'show lyrics history'
+  @MSG_LYRICS_HISTORY: goog.getMsg 'Lyrics History'
   @MSG_SONG_ARTIST: goog.getMsg 'Artist (or band)'
   @MSG_SONG_NAME: goog.getMsg 'Song name'
   @MSG_WRITE_LYRICS_HERE: goog.getMsg '[F]Michelle [Bmi7]ma belle...'


fix(kanban): animation drag same status

fix(kanban): animation drag same status

--- app/coffee/modules/kanban/sortable.coffee
+++ app/coffee/modules/kanban/sortable.coffee
@@ -81,6 +81,7 @@
                 $(item).addClass('multiple-drag-mirror')

             drake.on 'dragend', (item) ->
+
                 parentEl = item.parentNode
                 dragMultipleItems = window.dragMultiple.stop()

@@ -93,10 +94,11 @@
                 newStatus = Number(parentEl.dataset.statusId)
                 newSwimlane = Number(parentEl.dataset.swimlane)

-                $(parentEl).addClass('new')
+                if initialContainer != parentEl
+                    $(parentEl).addClass('new')

-                $(parentEl).one 'animationend', ()  ->
-                    $(parentEl).removeClass('new')
+                    $(parentEl).one 'animationend', ()  ->
+                        $(parentEl).removeClass('new')

                 usList = _.map dragMultipleItems, (item) ->
                     return kanbanUserstoriesService.usMap.get(Number(item.dataset.id))


Hack LevelEditor to load web-dev levels

Hack LevelEditor to load web-dev levels

--- app/lib/LevelLoader.coffee
+++ app/lib/LevelLoader.coffee
@@ -76,6 +76,13 @@
       @sessionDependenciesRegistered = {}
     if @level.isType('web-dev')
       @headless = true
+      if @sessionless
+        # When loading a web-dev level in the level editor, pretend it's a normal hero level so we can put down our placeholder Thang.
+        # TODO: avoid this whole roundabout Thang-based way of doing web-dev levels
+        originalGet = @level.get
+        @level.get = ->
+          return 'hero' if arguments[0] is 'type'
+          originalGet.apply @, arguments
     if (@courseID and not @level.isType('course', 'course-ladder')) or window.serverConfig.picoCTF
       # Because we now use original hero levels for both hero and course levels, we fake being a course level in this context.
       originalGet = @level.get


Put volume bars in the background of sparkcharts

--- app/js/directives/market_thumbnail.coffee
+++ app/js/directives/market_thumbnail.coffee
@@ -162,44 +162,34 @@

                     area_color = if market.change > 0 then '#28a92e' else '#c90808'

-                    series = [
+                    series = [
+                            {data: market.volume_data
+                            pointStart: 1
+                            name: 'Volume'
+                            type: 'column'
+                            yAxis: 1
+                            dataGrouping:
+                              enabled: true
+                            tooltip:
+                              valueDecimals: 0
+                              valueSuffix: ' BTS'
+                            },
                             {data: market.ohlc_data
                             pointStart: 1
                             name: 'Price'
                             dataGrouping:
                               enabled: true
-                            yAxis: 1
                             tooltip:
                               valueDecimals: 2
                               valueSuffix: ' BTS/'+market.asset_quantity_symbol
                             min: market.min_price
                             color: area_color
-                            },
-                            {data: market.volume_data
-                            pointStart: 1
-                            name: 'Volume'
-                            type: 'column'
-                            dataGrouping:
-                              enabled: true
-                            tooltip:
-                              valueDecimals: 0
-                              valueSuffix: ' BTS'
                             }
                     ]

                     yAxis = [
-                      {endOnTick: false
-                      startOnTick: false
-                      labels:
-                        enabled: false
-
-                      title:
-                        text: null
-
-                      gridLineWidth: 0
-                      },
                       {
                         opposite: true,
                         labels:
@@ -208,6 +198,17 @@
                           text: null
                         gridLineWidth: 0
                         min: 0.98 * market.min_price
+                      },
+                      {
+                        endOnTick: false
+                        startOnTick: false
+                        labels:
+                          enabled: false
+
+                        title:
+                          text: null
+
+                        gridLineWidth: 0
                       }]

                     $(".sparkchart", $element).highcharts('SparkLine', {series: series, yAxis: yAxis})


Fixed vertical positioning of button when scrolling

--- app/js/jail_iframe/classes/buttons.coffee
+++ app/js/jail_iframe/classes/buttons.coffee
@@ -47,6 +47,7 @@

   placeNearSelection: (mouseX=null) ->
     selectionBox = window.document.getSelection().getRangeAt(0).getBoundingClientRect()
+    top = selectionBox.top + $(window).scrollTop() - 2
     left = mouseX ? (selectionBox.left + selectionBox.width/2)

-    @setCoordinates selectionBox.top, left
+    @setCoordinates top, left


Fix some errors

Fix some errors

--- app/pages/lab/gold-standard-importer.cjsx
+++ app/pages/lab/gold-standard-importer.cjsx
@@ -87,7 +87,7 @@
       Import gold standard classifications

         {Array::map.call @props.files, (file) =>
-

+

             {file.name}
             {if @state.errorsByFile[file.name]?

@@ -97,8 +97,9 @@
             else if @state.classificationsByFile[file.name]?.length > 0

                 {@state.classificationsByFile[file.name].map (classification, i) =>
-                  progress = @state.progress[file.name + i]
-

+                  stateKey = file.name + i
+                  progress = @state.progress?[stateKey]
+

                     {classification.links.subjects.join ', '}{' '}
                     {if progress? then switch progress
                       when @IN_PROGRESS then


Remove extraneous line

Remove extraneous line

--- app/routes/treatise.coffee
+++ app/routes/treatise.coffee
@@ -2,8 +2,6 @@

 Route = Ember.Route.extend
   model: (params) ->
-    @get('store').all('treatise').findProperty('key', params.treatise_key)
-
     store = @get 'store'
     treatise = store.all('treatise').findProperty('key', params.treatise_key)


Use onDidChange to get highlights on open

--- lib/highlight-bad-chars.coffee
+++ lib/highlight-bad-chars.coffee
@@ -71,7 +71,7 @@

     console.log 'highlight-bad-chars activate.'
     atom.workspace.observeTextEditors (editor) =>
-      editor.onDidStopChanging =>
+      editor.onDidChange =>
         d.getMarker().destroy() for d in @decorations
         @decorations = []


This seems to fix chrome books from confusing the player by starting to play the old world before the new world comes in.

--- app/views/play/level/tome/TomeView.coffee
+++ app/views/play/level/tome/TomeView.coffee
@@ -159,6 +159,7 @@
     difficulty = sessionState.difficulty ? 0
     if @options.observing
       difficulty = Math.max 0, difficulty - 1  # Show the difficulty they won, not the next one.
+    Backbone.Mediator.publish 'level:set-playing', {playing: false}
     Backbone.Mediator.publish 'tome:cast-spells', {
       @spells,
       preload,


Add smooth down arrow navigation to /schools

--- app/views/SalesView.coffee
+++ app/views/SalesView.coffee
@@ -11,6 +11,7 @@
     'click .btn-contact-us': 'onClickContactUs'
     'click .btn-create-account': 'onClickSignup'
     'click .btn-login-account': 'onClickLogin'
+    'click #down-arrow': 'onClickDownArrow'

   getTitle: ->
     'CodeCombat'
@@ -27,3 +28,9 @@
     window.tracker?.trackEvent 'Started Signup', category: 'Sales', label: 'Sales Create'

   logoutRedirectURL: false
+
+  onClickDownArrow: (e) ->
+    $('#page-container').animate({
+      scrollTop: $('[name="' + $(e.target).closest('a').attr('href').substr(1) + '"]').offset().top
+    }, 300)
+    false


Ensure we wait for the clock to return so that auctionState is set

--- apps/artwork/client/mixins/auction.coffee
+++ apps/artwork/client/mixins/auction.coffee
@@ -11,7 +11,6 @@

     @$('.artwork-detail').addClass 'is-auction'

-    @setupAuctionClock()
     @setupAuctionDetailView()

   setupAuctionClock: ->
@@ -19,8 +18,8 @@
       modelName : 'Auction'
       model     : @auction
       el        : @$auctionClock = @$('#artwork-auction-clock')
+    @$auctionClock.addClass 'is-fade-in'
     @clock.start()
-    @$auctionClock.addClass 'is-fade-in'

   setupSaleArtwork: ->
     @saleArtwork = new SaleArtwork
@@ -31,6 +30,7 @@

   setupAuctionDetailView: ->
     $.when.apply(null, _.compact([
+      @setupAuctionClock()
       @setupAuctionUser()
       @setupSaleArtwork()
       @setupBidderPositions()


Only handle events for package associated with view

--- lib/package-detail-view.coffee
+++ lib/package-detail-view.coffee
@@ -121,13 +121,15 @@

   subscribeToPackageManager: ->
     @subscribe @packageManager, 'theme-installed package-installed', (pack) =>
+      return unless @pack.name is pack.name
+
       @loadPackage()
       @updateInstalledState()

     @subscribe @packageManager, 'theme-uninstalled package-uninstalled', (pack) =>
-      @updateInstalledState()
-
-    @subscribe @packageManager, 'theme-updated package-updated', (pack, newVersion) =>
+      @updateInstalledState() if @pack.name is pack.name
+
+    @subscribe @packageManager, 'theme-updated package-updated', (pack) =>
       return unless @pack.name is pack.name

       @loadPackage()


Tweak update label

Tweak update label

--- lib/package-update-view.coffee
+++ lib/package-update-view.coffee
@@ -18,7 +18,7 @@
   initialize: (@pack, @packageManager) ->
     @type = if @pack.theme then 'theme' else 'package'

-    @latestVersion.text("An update from #{@pack.version} to #{@pack.latestVersion} is available")
+    @latestVersion.text("Version #{@pack.latestVersion} is now available. #{@pack.version} is currently installed.")

     @handlePackageEvents()


maincontroller: wait ready event for initializing searchcontroller

--- client/app/lib/maincontroller.coffee
+++ client/app/lib/maincontroller.coffee
@@ -137,7 +137,6 @@
     kd.registerSingleton 'mainViewController',  mvc = new MainViewController view : mv
     kd.registerSingleton 'kodingAppsController',      new KodingAppsController
     kd.registerSingleton 'socialapi',                 new SocialApiController
-    kd.registerSingleton 'search',                    new SearchController
     kd.registerSingleton 'realtime',                  new RealtimeController
     kd.registerSingleton 'pageTitle',                 new PageTitleController

@@ -146,6 +145,8 @@
     mv.appendToDomBody()

     @ready =>
+
+      kd.registerSingleton 'search',                  new SearchController
       kd.registerSingleton 'widgetController',        new WidgetController
       kd.registerSingleton 'onboardingController',    new OnboardingController


app: rm shortcuts singleton

app: rm shortcuts singleton

--- client/app/lib/maincontroller.coffee
+++ client/app/lib/maincontroller.coffee
@@ -43,8 +43,6 @@
 WelcomeModal             = require './welcomemodal'
 WidgetController         = require './widgetcontroller'
 PageTitleController      = require './pagetitlecontroller'
-Shortcuts                = require 'shortcuts'
-defaultShortcuts         = require './shortcuts/defaults'

 module.exports = class MainController extends KDController
@@ -138,7 +136,6 @@
     kd.registerSingleton 'search',                    new SearchController
     kd.registerSingleton 'realtime',                  new RealtimeController
     kd.registerSingleton 'pageTitle',                 new PageTitleController
-    kd.registerSingleton 'shortcuts',                 new Shortcuts defaultShortcuts

     router.listen()
     @mainViewController = mvc


Stop easyXDM from calling success callback when doing async operation.

--- client/code/view/tool/content.coffee
+++ client/code/view/tool/content.coffee
@@ -97,6 +97,7 @@
             error: ->
               if typeof error is 'function'
                 error()
+          undefined # required to stop easyXDM calling the success callback

 class Cu.View.AppContent extends Cu.View.ToolContent


refactored show all view

refactored show all view

--- lib/views/show-all-view.coffee
+++ lib/views/show-all-view.coffee
@@ -1,30 +1,13 @@
-{SelectListView, $$} = require "atom-space-pen-views"
+SelectListView = require "./select-list-view"
 path = require "path"

 module.exports = class ShowAllView extends SelectListView

-    initialize: () ->
-        super()
-        @addClass('command-palette')
-
     getFilterKey: () ->
         return "annotationName"

-    cancelled: () ->
-        @restoreFocus()
-        return @hide()
-
-    toggle: () ->
-        if @panel?.isVisible()
-            @cancel()
-        else
-            @show()
-        return @
-
-    show: (groupedItems) ->
-        @storeFocusedElement()
-
+    beforeShow: (groupedItems) ->
         items = []
         for editorPath, annotations of groupedItems
             for annotation in annotations
@@ -34,20 +17,10 @@
                     annotationName: annotation.name
                     lineNumber: annotation.marker.getBufferRange().start.row
                 }
-
-        @setItems(items)
-        @panel ?= atom.workspace.addModalPanel(item: @)
-        @panel.show()
-        @focusFilterEditor()
-        return @
-
-    hide: () ->
-        @panel?.hide()
-        return @
+        return items

     viewForItem: ({annotationName, filename, lineNumber}) ->
-        return $$ () ->
-            # return @li("#{name} (#{editorPath})")
+        return @$$ () ->
             return @li class: 'event', 'data-event-name': annotationName, =>
                 @div class: 'pull-right', =>
                     @span "#{filename} @ #{lineNumber + 1}"


Minor change

Minor change

--- library/gearing/scoping.coffee
+++ library/gearing/scoping.coffee
@@ -86,7 +86,7 @@
         noLevel = "No logging level specified"
         throw new Error(noLevel) unless options.level
         logger.remove logger.transports.Console
-        logger.add(logger.transports.Console, options)
+        logger.add logger.transports.Console, options

     # This method is responsible for starting up the scope object.
     # This means initialization of all its necessary routines and


less obtrusive colors

less obtrusive colors

--- library/nucleus/service.coffee
+++ library/nucleus/service.coffee
@@ -139,7 +139,7 @@
         apply = (s) => (method) => method.apply this, s
         execute = => _.each @$lazy or [], apply arguments
         assert id = try @identify().toString().underline
-        m = "Executing lazy configuration for #{id}".blue
+        m = "Executing lazy configuration for #{id}".grey
         return if this.lazyexc? and this.lazyexc is yes
         logger.debug m unless (arguments.length or 0) > 0
         @lazyexc = yes unless (arguments.length or 0) > 0


Restore back some changes

Restore back some changes

--- library/nucleus/service.coffee
+++ library/nucleus/service.coffee
@@ -35,14 +35,13 @@
 extendz = require "./extends"
 routing = require "./routing"
 scoping = require "./scoping"
-{EventEmitter2} = events

 # This is an abstract base class for every kind of service in this
 # framework and the end user application. It provides the matching
 # and processing logic based on domain matches and RE match/extract
 # logics, to deal with paths. Remember that this service is just a
 # an internal base class, you generally should not use it directly.
-module.exports.Service = class Service extends EventEmitter2
+module.exports.Service = class Service extends events.EventEmitter2

     # This is a marker that indicates to some internal subsystems
     # that this class has to be considered abstract and therefore


autocomplete off for datepicker

autocomplete off for datepicker

--- example/example.coffee
+++ example/example.coffee
@@ -16,6 +16,7 @@
     type: Date
     autoform:
       type: "bootstrap-datepicker" # it work on modalForm
+      autocomplete: "off"
       datePickerOptions:
         autoclose: true
   "hobby":


rollbar: close around rollbar stuff

rollbar: close around rollbar stuff

--- client/landing/app/MainApp/rollbar.coffee
+++ client/landing/app/MainApp/rollbar.coffee
@@ -1,27 +1,28 @@
 # Wrapper for pushing events to Rollbar.
-logToExternal = KD.logToExternal = (args) ->
-  _rollbar.push args
+if _rollbar? then do ->
+  logToExternal = KD.logToExternal = (args) ->
+    _rollbar.push args

 # Push status events to Rollbar.
-connections     = []
-disconnections  = []
+  connections     = []
+  disconnections  = []

-KD.remote.on 'connected', ->
-  connections.push new Date
+  KD.remote.on 'connected', ->
+    connections.push new Date

-KD.remote.on 'disconnected', ->
-  disconnections.push new Date
+  KD.remote.on 'disconnected', ->
+    disconnections.push new Date

-KD.remote.on 'reconnected', ->
-  connections.push new Date
-  data =
-    connections:connections
-    disconnections: disconnections
-  logToExternal msg:"disconnected, then reconnected", data:data
+  KD.remote.on 'reconnected', ->
+    connections.push new Date
+    data =
+      connections:connections
+      disconnections: disconnections
+    logToExternal msg:"disconnected, then reconnected", data:data

-KD.getSingleton('mainController').on "AccountChanged", (account) ->
-  user = KD.whoami?().profile or KD.whoami()
-  _rollbarParams.person =
-    id: user.hash or user.nickname
-    username: user.nickname
-    name: user.firstName + " " + user.lastName
+  KD.getSingleton('mainController').on "AccountChanged", (account) ->
+    user = KD.whoami?().profile or KD.whoami()
+    _rollbarParams.person =
+      id: user.hash or user.nickname
+      username: user.nickname
+      name: user.firstName + " " + user.lastName


KDMultipleChoice: Fix query selector

KDMultipleChoice: Fix query selector

--- components/inputs/KDMultipleChoice.coffee
+++ components/inputs/KDMultipleChoice.coffee
@@ -80,7 +80,7 @@
       do @switchStateChanged if wCallback
     else
       @$("a").removeClass('active')
-      @$("a[name$='#{label}']").addClass('active')
+      @$("a[name='#{label}']").addClass('active')

       @oldValue     = @currentValue
       @currentValue = label


Only save user if show_tour is true

Only save user if show_tour is true

--- components/new_user_messages/index.coffee
+++ components/new_user_messages/index.coffee
@@ -36,7 +36,7 @@
   initialize: ({ @container })->
     hasReadMessages = _.every @messages, (message) -> Cookies.get message.id
     # if they all have cookies, update the user, don't show the tour
-    if hasReadMessages
+    if hasReadMessages and mediator.shared.current_user.get('show_tour') is true
       mediator.shared.current_user.save show_tour: false
     else
       for message in @messages


skew lower in random method picking

skew lower in random method picking

--- demo/demo.coffee
+++ demo/demo.coffee
@@ -26,13 +26,13 @@
   , 1000

-  methods = ['accordion', 'curl', 'foldUp', 'reveal', 'fracture', 'ramp', 'stairs', 'twist']
+  methods = ['accordion', 'stairs', 'curl', 'reveal', 'foldUp', 'ramp', 'twist', 'fracture']

   document.getElementById('demos').addEventListener 'click', (e) ->

     return unless (el = e.target).className is 'button'
     n      = el.getAttribute 'data-n'
-    method = methods[Math.floor Math.random() * methods.length]
+    method = methods[Math.abs Math.floor Math.random() * methods.length - Math.random()]
     angle  = Math.floor Math.random() * 80 * (if Math.random() > .5 then -1 else 1)

     demos[n][method] if method isnt 'foldUp' then angle else undefined


Fix month

Fix month

--- views/akashic-resource-table-area.cjsx
+++ views/akashic-resource-table-area.cjsx
@@ -5,7 +5,7 @@
 # can change Pager to Pagination

 dateToString = (date)->
-  month = date.getMonth()
+  month = date.getMonth() + 1
   if month < 10
     month = "0#{month}"
   day = date.getDate()


Added Lib to Compiler

Added Lib to Compiler

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -28,6 +28,7 @@
         src     : [
           'bin/**/*.coffee'
           'help/**/*.coffee'
+          'lib/**/*.coffee'
         ]

     # grunt-contrib-copy copies our js file to the bin dir. See the JS file


Removed extra shell demo task

Removed extra shell demo task

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -63,7 +63,6 @@

   grunt.registerTask 'gh-pages', [
     'build'
-    'shell:demo'
     'shell:gh-pages-push'
   ]


fix: Remove test artifacts before minification

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -654,7 +654,7 @@
                 start_comment: "<testing>"
                 end_comment: "</testing>"
             files:
-                src: "#{paths.dist}/**/*.js"
+                src: "#{paths.build}/**/*.js"

     # Dependencies
     # ==========
@@ -678,12 +678,12 @@

     grunt.registerTask 'travis', 'Test with Travis CI', ['check_pull_req', 'saucetests:default']

-    grunt.registerTask 'dev', 'Prepare code for testing', ['clean', 'shell:npm_install', 'bower', 'package', 'copy:test']
+    grunt.registerTask 'dev', 'Prepare code for testing', ['clean', 'shell:npm_install', 'bower', 'build', 'copy:test']

     grunt.registerTask 'build', 'Build from latest source', ['concat', 'minify', 'usebanner:allhead', 'usebanner:allfoot', 'copy:images']
-    #grunt.registerTask 'build_stripped', 'Build from latest source w/ test artifacts stripped out', ['concat', 'strip_code', 'minify', 'usebanner:allhead', 'usebanner:allfoot', 'copy:images']
-
-    grunt.registerTask 'package', 'Build a zipped distribution-worthy version', ['build', 'copy:dist', 'strip_code', 'compress']
+    grunt.registerTask 'build_stripped', 'Build from latest source w/ test artifacts stripped out', ['concat', 'strip_code', 'minify', 'usebanner:allhead', 'usebanner:allfoot', 'copy:images']
+
+    grunt.registerTask 'package', 'Build a zipped distribution-worthy version', ['build_stripped', 'copy:dist',  'compress:jquery', 'compress:jqueryS3', 'compress:core', 'compress:coreS3' ]

     grunt.registerTask 'custom', 'Build a custom version', (modules) ->
         util = require './lib/grunt/utils'


chore(Gruntfile): modify *bump* command to tag and commit

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -29,7 +29,6 @@
     # Generate a changelog from git metadata, using the AngularJS commit
     # conventions. View CONVENTIONS.md for a synposis of the conventions with
     # commit examples.
-    # TODO: Test this after a commit w/properly formatted comments -- JR
     changelog:
       options:
         dest: '<%= file.changelog.dest %>'
@@ -42,13 +41,13 @@
           '<%= file.manifest.node %>'
           '<%= file.manifest.bower %>'
         ]
-        commit: false
+        commit: true
         commitMessage: 'chore(release): <%= bump.options.tagName %>'
         commitFiles: [
           '<%= file.manifest.node %>'
           '<%= file.manifest.bower %>'
         ]
-        createTag: false
+        createTag: true
         tagName: '<%= meta.git.tagName %>'
         tagMessage: '<%= meta.git.tagMessage %>'
         push: false


strict

strict

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -1,5 +1,7 @@
 module.exports = (grunt) ->

+  "use strict"
+
   grunt.initConfig
     pkg: grunt.file.readJSON("package.json")
     banner: '/*! <%= pkg.title || pkg.name %> - v<%= pkg.version %> - ' +


Migrate to grunt WIP

Migrate to grunt WIP

Issue #9

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -20,10 +20,21 @@
       all: [
         'src/script/*.coffee'
         ]
-    # uglify:
-
+    concat:
+      main:
+        files:
+          "build/all.js": [
+            'src/script/org-info-src.js'
+            'build/org-info-extensions.js'
+          ]
+    uglify:
+      main:
+        files:
+          "build/all.min.js": "build/all.js"
     concurrent:
       compile: ['stylus:dark', 'stylus:light', 'coffee:main']
+      concat: ['concat']
+      minify: ['uglify:main']
       lint: ['coffeelint:all']

     watch:
@@ -41,7 +52,7 @@
           'src/script/*.coffee'
           '!src/script/_fly*'
           ]
-        tasks: "coffee"
+        tasks: ["coffee", "concat"]
         options:
           spawn: false
           livereload: true
@@ -50,10 +61,12 @@
   grunt.loadNpmTasks "grunt-contrib-stylus"
   grunt.loadNpmTasks 'grunt-contrib-coffee'
   grunt.loadNpmTasks 'grunt-contrib-uglify'
+  grunt.loadNpmTasks 'grunt-contrib-concat'
   grunt.loadNpmTasks 'grunt-concurrent'
   grunt.loadNpmTasks 'grunt-coffeelint'
   grunt.registerTask "default", [
     'concurrent:compile'
-    # 'concurrent:minify'
-    # 'concurrent:lint'
+    'concurrent:concat'
+    'concurrent:minify'
+    'concurrent:lint'
   ]


Revert "Boyscout - remove extra enter"

Revert "Boyscout - remove extra enter"

This reverts commit 318df6d04df78eaca8c89cd350c1be03230a8de4.

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -31,6 +31,7 @@
         src: [
           'build/js/libs/jquery-1.7.2.js'
           'build/js/core.js'
+
           'build/js/wrap/first.js'
           'build/js/plugins/*.js'
           'build/js/classes/*.js'


Removed iosrtc bugfix hack from Gruntfile

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -233,11 +233,6 @@
     }
     rmIosBuild: {
       command: 'rm -rf <%= iosDevPath %>; rm -rf <%= iosDistPath %>'
-    }
-    # Temporary hack until cordova-plugin-iosrtc's next release (waiting for version 2.2.3)
-    updateIosrtcPlugin: {
-      cwd: '<%= iosDevPath %>'
-      command: 'cp ../../../../src/cca/app/scripts/cordova-plugin-iosrtc-bugfixes.js platforms/ios/www/plugins/cordova-plugin-iosrtc/dist/cordova-plugin-iosrtc.js'
     }
   }


Fix latexmk version checking

Fix latexmk version checking

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -161,7 +161,7 @@

 		checkLatexmk: (callback = (error) ->) ->
 			grunt.log.write "Checking latexmk is installed... "
-			exec "latexmk -version", (error, stdout, stderr) ->
+			exec "latexmk --version", (error, stdout, stderr) ->
 				if error? and error.message.match("command not found")
 					grunt.log.error "FAIL."
 					grunt.log.errorlns """
@@ -179,7 +179,7 @@
 						grunt.log.error "Unknown latexmk version"
 					else
 						version = m[1]
-						if semver.gt(version + ".0", "4.39.0")
+						if semver.gte(version + ".0", "4.39.0")
 							grunt.log.writeln "OK."
 							grunt.log.writeln "Running latexmk version #{version}"
 						else


use strict mode

use strict mode

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -83,8 +83,8 @@
       taskName:
         options:
           position: "top"
-          banner: "// <%= pkg.name %> v<%= pkg.version %> | (c) 2013-<%= grunt.template.today('yyyy') %> <%= pkg.author %> | <%= pkg.license %> License"
-          linebreak: true
+          banner: "// <%= pkg.name %> v<%= pkg.version %> | (c) 2013-<%= grunt.template.today('yyyy') %> <%= pkg.author %> | <%= pkg.license %> License\n'use strict';"
+          linebreak: false
         files:
           src: [ "#{distDir}/#{pkg.name}.min.js", "#{distDir}/#{pkg.name}.js" ]


again, integration tests should be here

again, integration tests should be here

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -199,7 +199,7 @@
   'jasmine:queueCov'
 ]

-taskManager.add 'test', ['unit_test']
+taskManager.add 'test', ['unit_test', 'integration_test']

 # Default task, build dev, run tests, make the distribution build.
 taskManager.add 'default', ['base']


Fixed publish task

Fixed publish task

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -37,8 +37,9 @@

         copy:
             publish:
-                src: '<%= target_dir %>'
-                dest: '.'
+                cwd: '<%= target_dir %>'
+                src: '**/*.js'
+                dest: './'

     grunt.loadTasks 'tasks/'
     grunt.loadNpmTasks 'grunt-codo'
@@ -47,10 +48,10 @@
     grunt.loadNpmTasks 'grunt-contrib-coffee'
     grunt.loadNpmTasks 'grunt-contrib-copy'

-    grunt.registerTask 'dist', ['clean:dist', 'coffeelint:dist', 'coffee:dist']
+    grunt.registerTask 'dist', ['clean:dist', 'coffee:dist']
     grunt.registerTask 'doc', ['doc:rules', 'codo']
     grunt.registerTask 'publish', ['copy:publish', 'clean:publish']

-    grunt.registerTask 'default', ['dist', 'doc']
+    grunt.registerTask 'default', ['coffeelint', 'dist', 'doc']

     return


coffee编译顺序调整

coffee编译顺序调整

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -15,8 +15,8 @@
 					"dest/dev/cola.js": sources.coffee.core
 					"dest/dev/widget/widget.js": sources.coffee.widget
 					"dest/dev/widget/base.js": sources.coffee.base
+					"dest/dev/widget/layout.js": sources.coffee.layout
 					"dest/dev/widget/edit.js": sources.coffee.edit
-					"dest/dev/widget/layout.js": sources.coffee.layout
 					"dest/dev/widget/collection.js": sources.coffee.collection
 					"dest/dev/widget/list.js": sources.coffee.list

@@ -239,5 +239,5 @@
 	grunt.registerTask "all", ["clean", "coffee", "less", "mochaTest", "uglify", "copy"]
 	grunt.registerTask "w", ["watch"]
 	grunt.registerTask "build", ["clean:build", "cola-ui-clean", "coffee:cola-core", "coffee:cola-widget",
-								 "less:build", "cola-ui-license", "concat",
-								 "copy:semantic", "rename", "uglify:build", "cssmin", "compress", "clean:workTemp"]+	                             "less:build", "cola-ui-license", "concat",
+	                             "copy:semantic", "rename", "uglify:build", "cssmin", "compress", "clean:workTemp"]


Revert "Get coverage back."

Revert "Get coverage back."

This reverts commit ef28eb86e6fe625e3955d1ca874b27ded829bdd0.

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -77,7 +77,7 @@
       coverage:
         command: "istanbul cover jasmine-node --captureExceptions test && cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js && rm -rf ./coverage"
       jasmine:
-        command: "istanbul cover jasmine-node --captureExceptions test && cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js && rm -rf ./coverage"
+        command: "jasmine-node --captureExceptions test"
       publish:
         command: "npm publish"


Gruntfile: Added compiled task target for karma.

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -127,6 +127,8 @@
         configFile       : 'karma.local.conf.js'
       sauceLabs          :
         configFile       : 'karma.saucelabs.conf.js'
+      compiled           :
+        configFile       : 'karma.compiled.conf.js'

     coveralls            :
       options            :


fix(grunt): release as default task

fix(grunt): release as default task

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -38,5 +38,5 @@
     ]

   grunt.registerTask "default", "Default task aka. build task", [
-    "build"
+    "release"
   ]


Fixed template path issue in Gruntfile

Fixed template path issue in Gruntfile

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -32,8 +32,8 @@
           livereload: true
     hogan:
       main:
-        src: 'src/templates/templates.js'
-        dest: 'src/templates/**/*.mustache'
+        dest: 'src/templates/templates.js'
+        src: 'src/templates/**/*.mustache'
       lib:
         dest: 'lib/templates/templates.js'
         src: 'lib/templates/**/*.mustache'


add uproxy-lib tests to test target

add uproxy-lib tests to test target

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -921,6 +921,12 @@
 ]

 # --- Testing tasks ---
+taskManager.add 'test_lib', [
+  'base'
+].concat _.flatten(
+  Rule.buildAndRunTest(spec, gruntConfig) for spec in Rule.getTests('src', 'lib', ['build-tools', 'integration-tests'])
+)
+
 taskManager.add 'test_core', [
   'base'
 ].concat _.flatten(
@@ -958,6 +964,7 @@
 # This is the target run by Travis. Targets in here should run locally
 # and on Travis/Sauce Labs.
 taskManager.add 'test', [
+  'test_lib'
   'test_core'
   'test_ui'
   'test_chrome'


feat(grunt): remove availability task from sparanoid.com

This task is too personal for this project

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -340,16 +340,6 @@
           {
             from: /("amsf-version">)\d+\.\d+\.\d+/g
             to: "$1<%= config.pkg.version %>"
-          }
-        ]
-
-      availability:
-        src: ["<%= config.app %>/_data/curtana.yml"]
-        dest: "<%= config.app %>/_data/curtana.yml"
-        replacements: [
-          {
-            from: /(free:)(.+)/g
-            to: "$1 true"
           }
         ]

@@ -400,12 +390,6 @@
         tagMessage: 'chore: create tag %VERSION%'
         push: false

-  grunt.registerTask "reset", "Reset user availability", (target) ->
-    grunt.config.set "replace.availability.replacements.0.to", "$1 true"
-    grunt.task.run [
-      "replace:availability"
-    ]
-
   grunt.registerTask "serve", "Fire up a server on local machine for development", [
     "clean"
     "copy:serve"
@@ -434,24 +418,20 @@
     "replace:amsf__switch__update_config"
   ]

-  grunt.registerTask "build", "Build site with `jekyll`, use `--busy` to set availability to false", (target) ->
-    grunt.config.set "replace.availability.replacements.0.to", "$1 false" if grunt.option("busy")
-    grunt.task.run [
-      "replace:availability"
-      "clean"
-      "coffeelint"
-      "uglify"
-      "lesslint"
-      "less:dist"
-      "autoprefixer:dist"
-      "csscomb"
-      "jekyll:dist"
-      "concurrent:dist"
-      "smoosher"
-      "usebanner"
-      "cleanempty"
-      "reset"
-    ]
+  grunt.registerTask "build", "Build site with jekyll", [
+    "clean"
+    "coffeelint"
+    "uglify"
+    "lesslint"
+    "less:dist"
+    "autoprefixer:dist"
+    "csscomb"
+    "jekyll:dist"
+    "concurrent:dist"
+    "smoosher"
+    "usebanner"
+    "cleanempty"
+  ]

   # Release new version
   grunt.registerTask "release", "Build, bump and commit", (type) ->


added production task and removed uglify from "build" task

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -130,7 +130,6 @@
     "coffeelint"
     "browserify"
     "copy"
-    "uglify"
     "jade"
     "stylus"
   ]
@@ -140,6 +139,11 @@
     'watch'
   ]

+  grunt.registerTask 'production', [
+    'build'
+    'uglify'
+  ]
+
   grunt.registerTask 'default', [
     'build'
     'dev'


better name for copyModule

better name for copyModule

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -73,7 +73,7 @@
       noImplicitAny: true
       sourceMap: true
   # Copy all source that is not typescript to the module's build directory.
-  copySrcModule: (name) ->
+  copyModule: (name) ->
     expand: true, cwd: 'src/'
     src: [name + '/**', '!**/*.ts', '!**/*.sass']
     dest: 'build'
@@ -161,7 +161,7 @@
           dest: 'build/'
           onlyIf: 'modified'
         } ] }
-      logger: Rule.copySrcModule 'logger'
+      logger: Rule.copyModule 'logger'
       # Sample apps to demonstrate and run end-to-end tests.
       sampleChat: Rule.copySampleFiles 'peerconnection/samples/chat-webpage', 'lib'
       sampleChat2: Rule.copySampleFiles 'peerconnection/samples/chat2-webpage', 'lib'


Grunt qunit run selected test

Grunt qunit run selected test

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -13,10 +13,13 @@
                     'static/test/**/*.js',
                 ]

+        # grunt qunit (run all tests)
+        # grunt qunit --test foo (run `foo` test)
         qunit:
-            all: [
-                'static/test/**/*.html',
-            ]
+            all:
+                src: [
+                    'static/test/**/' + (grunt.option('test') or '*') + '-test.html',
+                ]

         watch:
             jshint:


Add grunt test for Travis

Add grunt test for Travis

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -37,22 +37,20 @@
         files: ["src/*.coffee", "test/src/*.coffee"]
         tasks: ["build"]

-    simplemocha:
-      all:
-        src: ['test/**/*.coffee']
+    shell:
+      'mocha-phantomjs':
+        command: 'mocha-phantomjs test/index.html'
         options:
-          require: 'test/test-helper'
-          timeout: 3000
-          ignoreLeaks: false
-          ui: 'bdd'
-          compilers: 'coffee:coffee-script'
+          stdout: true
+          stderr: true

-  # These plugins provide necessary tasks.
   grunt.loadNpmTasks "grunt-contrib-coffee"
   grunt.loadNpmTasks "grunt-contrib-watch"
   grunt.loadNpmTasks "grunt-simple-mocha"
   grunt.loadNpmTasks 'grunt-contrib-concat'
+  grunt.loadNpmTasks 'grunt-shell'

   grunt.registerTask "default", ["watch"]
   grunt.registerTask "build",   ["coffee"]
-  grunt.registerTask "test",    ["simplemocha"]
+  grunt.registerTask "test",    ["build", "concat"]
+  grunt.registerTask "test",    ["build", "concat", "shell:mocha-phantomjs"]


fix: Run on all browsers except Android until it is fixed

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -48,10 +48,11 @@
     ]

     browsers = [
-        {
-            browserName: 'chrome'
-            platform: 'Windows 7'
-        }
+        #{
+        #    browserName: 'android'
+        #    platform: 'Linux'
+        #    version: '4.0'
+        #}
         {
             browserName: 'iphone'
             platform: 'OS X 10.8'
@@ -63,21 +64,11 @@
             version: '6'
         }
         {
-            browserName: 'firefox'
-            platform: 'Windows 7'
-            version: '19'
-        }
-        {
             browserName: 'safari'
             platform: 'OS X 10.6'
             version: '5'
         }
         {
-            browserName: 'android'
-            platform: 'Linux'
-            version: '4.0'
-        }
-        {
             browserName: 'internet explorer'
             platform: 'Windows 8'
             version: '10'
@@ -96,6 +87,14 @@
             browserName: 'internet explorer'
             platform: 'Windows XP'
             version: '7'
+        }
+        {
+            browserName: 'chrome'
+            platform: 'Windows 7'
+        }
+        {
+            browserName: 'firefox'
+            platform: 'Windows 7'
         }
     ]


Add jshint option

Add jshint option

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -59,6 +59,7 @@
         validthis: false
         # Environments
         browser: true
+        devel: false

       source: [
         'site/scripts/**/*.js'


Remove file instance from openFiles array when tab is closed.

--- client/ide/views/tabview/idetabview.coffee
+++ client/ide/views/tabview/idetabview.coffee
@@ -27,13 +27,15 @@
     pane.addSubView view
     @tabView.addPane pane

+    pane.once "KDObjectWillBeDestroyed", => @handlePaneRemoved pane
+
   createEditor: (file, content) ->
     file        = file    or FSHelper.createFileFromPath @getDummyFilePath()
     content     = content or ""
     editor      = new EditorPane { file, content, delegate: this }
     paneOptions =
       name      : file.name
-      aceView   : editor.ace
+      editor    : editor

     @createPane_ editor, paneOptions, file

@@ -105,6 +107,10 @@
     for pane, index in @tabView.panes when file is pane.getData()
       @tabView.showPaneByIndex index

+  handlePaneRemoved: (pane) ->
+    file = pane.getData()
+    @openFiles.splice @openFiles.indexOf(file), 1
+
   getDummyFilePath: ->
     return "localfile://Untitled.txt"


Test:VMSharing Check if the invited user can edit files on shared VM

--- client/test/lib/vmsharing/vmsharing.coffee
+++ client/test/lib/vmsharing/vmsharing.coffee
@@ -77,13 +77,18 @@

     browser.pause 2500, -> # wait for user.json creation
       callback = ->
-        helpers.createFile(browser, host, null, null, hostFileName)
-        browser.end()
+        helpers.createFile(browser, host, null, null, hostFileName)
+        browser.refresh()
+        ideHelpers.openFile(browser, host, fileName)
+        ideHelpers.openFile(browser, host, hostFileName)
+

       participantCallback = ->

         browser.waitForElementVisible  hostFileSelector, 20000
         ideHelpers.openFile(browser, host, hostFileName)
+        browser.pause 2000
+        ideHelpers.setTextToEditor(browser, fileContent)

         browser.end()


Enable pistachios

Enable pistachios

--- config/main.rc.coffee
+++ config/main.rc.coffee
@@ -85,7 +85,7 @@
   presence      :
     exchange    : 'services-presence'
   client        :
-    pistachios  : no
+    pistachios  : yes
     version     : version
     minify      : yes
     watch       : no


new fix createVhost

new fix createVhost

--- kites/sharedHosting/api.coffee
+++ kites/sharedHosting/api.coffee
@@ -78,7 +78,7 @@
         log.info "[OK] user #{username} was secured"
         callback? null,"[OK] user #{username} was secured"

-  buildHome : (options,callback)->
+  buildHome = (options,callback)->
     #
     # this methid will make home directory for user, set correct perms and copy all default files in it
     #
@@ -99,7 +99,7 @@
             log.error error = "[ERROR] can't change owner of home directory to UID/GID #{uid} for user #{username}: #{err}"
             callback error
           else
-            @createVhost username:username,uid:uid,(err,res)->
+            createVhost username:username,uid:uid,(err,res)->
               unless err
                 log.info info = "[OK] default vhost and hosmedir for user #{username} is created"
                 callback? null,info
@@ -201,7 +201,7 @@
                         # now we can build home for user
                         ldapClient.unbind (err)->
                           log.error err if err?
-                        @buildHome username:username,uid:parseInt(id), (error,result)->
+                        buildHome username:username,uid:parseInt(id), (error,result)->
                           if error?
                             callback error
                           else
@@ -225,7 +225,7 @@
   #    else
   #      log.error stderr
   #      callback stderr
-  createVhost :do->
+  createVhost = do->

     spawnWrapper = (command, args , callback)->
       wrapper = spawn command,args
@@ -377,3 +377,9 @@
  #                   log.debug "[OK] func:unSuspendUser: /usr/sbin/cagefsctl -w #{userToSuspend}"
  #                   res = "[OK] user #{userToSuspend} was successfully unsuspended"
  #                   log.info res; callback? null, res
+
+ #s = new sharedHosting
+ #options =
+ #  username:'aleksey-m000010'+hat()
+ #  command: "ls -l"
+ #s.executeCommand options,(err,res)->


prettier databases for easier debugging

prettier databases for easier debugging

--- content/db/main.coffee
+++ content/db/main.coffee
@@ -1,5 +1,11 @@
 Loki = require('./loki.coffee')
 debug = require('../debug.coffee')
+Prefs = require('../preferences.coffee')
+
+if Prefs.get('testing')
+  stringify = (data) -> JSON.stringify(data, null, 2)
+else
+  stringify = (data) -> JSON.stringify(data)

 class DBStore
   mode: 'reference'
@@ -24,10 +30,10 @@
             if coll.dirty
               name = "#{dbname}.#{coll.name}"
               debug('DBStore.exportDatabase:', name)
-              conn.queryAsync("REPLACE INTO \"#{dbname}\" (name, data) VALUES (?, ?)", [name, JSON.stringify(coll)])
+              conn.queryAsync("REPLACE INTO \"#{dbname}\" (name, data) VALUES (?, ?)", [name, stringify(coll)])

           # TODO: only save if dirty? What about collection removal? Other data that may have changed on the DB?
-          conn.queryAsync("REPLACE INTO \"#{dbname}\" (name, data) VALUES (?, ?)", [dbname, JSON.stringify(Object.assign({}, dbref, {collections: dbref.collections.map((coll) -> coll.name)}))])
+          conn.queryAsync("REPLACE INTO \"#{dbname}\" (name, data) VALUES (?, ?)", [dbname, stringify(Object.assign({}, dbref, {collections: dbref.collections.map((coll) -> coll.name)}))])

           return
         )


Update linter configuration on Atom

--- atom/dot-atom/config.cson
+++ atom/dot-atom/config.cson
@@ -96,7 +96,8 @@
     interpreter: "~/.pyenv/shims/python, python, python.exe"
     pylamaVersion: "external"
     usePylint: true
-  "linter-ui-default": {}
+  "linter-ui-default":
+    decorateOnTreeView: "Files and Directories"
   "markdown-preview-plus":
     enablePandoc: true
     grammars: [


Fix validation logs

Fix validation logs

--- app/assets/javascripts/frontend/form-validation.js.coffee
+++ app/assets/javascripts/frontend/form-validation.js.coffee
@@ -330,9 +330,10 @@
   # As it really tricky to find out the validation which blocks form
   # and do not display any error massage on form
   log_this: (question, validator, message) ->
-    step_title = $.trim($(".js-step-link.step-current").text())
+    step_data = question.closest(".js-step-condition").data("step")
+    step_title = $.trim($("a.js-step-link[data-step='#{step_data}']").text())
     q_ref = $.trim(question.find("h2 span.visuallyhidden").text())
-    q_title = $.trim(question.find("h2").text())
+    q_title = $.trim(question.find("h2").first().text())

     if typeof console != "undefined"
       console.log "-----------------------------"


Make upcoming lectures into a scrolly fadey inny outy carousel

--- widgets/lecturelist/lecturelist.coffee
+++ widgets/lecturelist/lecturelist.coffee
@@ -1,10 +1,14 @@
 class Dashing.Lecturelist extends Dashing.Widget

   ready: ->
+    @currentIndex = 0
+    @items = $(@node).find('li')
+    @nextItem()
+    @startCarousel()

   onData: (data) ->
+    @currentIndex = 0
     i = 0
-    node = $(@get('node'))
     if data.items.length == 0
       @set 'empty', true
     while i < data.items.length
@@ -19,4 +23,16 @@
       data.items[i].people = people

       i++
+
+  startCarousel: ->
+    @items.hide()
+    setInterval(@nextItem, 10000)
+
+  nextItem: =>
+    items = @get('items')
+    if items
+      console.log(items[@currentIndex])
+      $(items[@currentIndex]).fadeOut =>
+        @currentIndex = (@currentIndex + 1) % items.length
+        $(items[@currentIndex]).fadeIn()


Fixes measure display on view mode. Related to #954.

--- app/assets/javascripts/leaflet/reactive_measure.js.coffee
+++ app/assets/javascripts/leaflet/reactive_measure.js.coffee
@@ -379,7 +379,7 @@

     if layers.getLayers().length > 0
       layers.eachLayer (layer) =>
-        if typeof layer.getMeasure() is 'function'
+        if typeof layer.getMeasure is 'function'
           m = layer.getMeasure()
           @options.measure.perimeter += m.perimeter
           @options.measure.area += m.area


Remove redundant margin function in subclass

--- app/assets/javascripts/photo_overlay_dimensions.js.coffee
+++ app/assets/javascripts/photo_overlay_dimensions.js.coffee
@@ -76,11 +76,6 @@
   leftPaneWidth: ->
     @width() - @commentWidth

-  margin: ->
-    margin = (@maxWidth() - @width()) / 2
-    return margin unless margin < 1
-    @minMargin
-
   top: ->
     window.scrollY + @minMargin


Wait for host loading in perf measurements

--- app/js/jail_iframe/classes/performance_measurement.coffee
+++ app/js/jail_iframe/classes/performance_measurement.coffee
@@ -26,9 +26,10 @@
       (padder + o.offset).substr(-offset_col_width)
     ).join('\n')

-FactlinkJailRoot.core_loaded_promise.then( ->
-  FactlinkJailRoot.delay 1000
-).then( ->
+FactlinkJailRoot.core_loaded_promise
+.then( -> FactlinkJailRoot.host_loaded_promise)
+.then( -> FactlinkJailRoot.delay 1000)
+.then( ->
   console.log document.readyState
   if window.performance && window.performance.timing
     'fetchStart responseEnd domLoading domInteractive domContentLoadedEventEnd domComplete loadEventEnd'


Save builder on object

Save builder on object

--- fabricator/mesh.coffee
+++ fabricator/mesh.coffee
@@ -10,7 +10,8 @@

 class TerrainMesh
   constructor: (@terrainData) ->
-
+    @builder = new TerrainBuilder(SAMPLES_PER_SIDE, SAMPLES_PER_SIDE, 1.0)
+    @getGeometry()
   terrainZScale: ->
     # Multiplying one sample by this factor gives the value in meters
     metersPerIncrement = OUT_RANGE/IN_RANGE
@@ -22,15 +23,14 @@

   getGeometry: ->
     return @geometry if @geometry?
-    builder = new TerrainBuilder(SAMPLES_PER_SIDE, SAMPLES_PER_SIDE, 1.0)
     console.log "Scale: ", @terrainZScale()
-    builder.applyElevation(@terrainData, zScale: (@terrainZScale()))
-    @geometry = builder.geom
+    @builder.applyElevation(@terrainData, zScale: (@terrainZScale()))
+    @geometry = @builder.geom

   asSTL: ->
-    toSTL(@getGeometry())
+    toSTL(@geometry)

   asX3D: ->
-    toX3D(@getGeometry(), "terrain")
+    toX3D(@builder, "terrain")

 module.exports = TerrainMesh


:bug: Prevent error raised when disposing the view

Fixes richrace/highlight-selected#67

--- lib/minimap-highlight-selected-view.coffee
+++ lib/minimap-highlight-selected-view.coffee
@@ -1,3 +1,5 @@
+{CompositeDisposable} = require 'atom'
+
 module.exports = ->
   highlightSelectedPackage = atom.packages.getLoadedPackage('highlight-selected')

@@ -28,3 +30,15 @@
       return unless atom.workspace.getActiveTextEditor()?
       return unless @fakeEditor.getActiveTextEditor()?
       super
+
+    subscribeToActiveTextEditor: ->
+      @selectionSubscription?.dispose()
+      @selectionSubscription = new CompositeDisposable
+
+      if editor = @getActiveEditor()
+        @selectionSubscription.add editor.onDidAddSelection =>
+          @handleSelection()
+        @selectionSubscription.add editor.onDidChangeSelectionRange =>
+          @handleSelection()
+
+      @handleSelection()


Improve link snippet.

Improve link snippet.

--- snippets/language-restructuredtext.cson
+++ snippets/language-restructuredtext.cson
@@ -4,7 +4,7 @@
     'body': '.. image:: ${1:path}\n$0'
   'link':
     'prefix': 'link'
-    'body': '\n\\`${1:Title}<${2:http://link}>\\`_'
+    'body': '\\`${1:Title} <${2:http://link}>\\`_$0'
   'section 1':
     'prefix': 'sec'
     'body': '${1:subsection name}\n================$0\n'


fix timeout handling

fix timeout handling

--- zechat/static/test_conversation.coffee
+++ zechat/static/test_conversation.coffee
@@ -3,14 +3,16 @@
   deferred = Q.defer()

   poll = ->
+    dt = _.now() - t0
+    if dt > timeout
+      clearInterval(interval)
+      deferred.reject('timeout')
+    else
+
     rv = check()
     if rv?
       clearInterval(interval)
       deferred.resolve(rv)
-
-    else if _.now() - t0 > timeout
-      clearInterval(interval)
-      deferred.reject('timeout')

   interval = setInterval(poll, 100)

@@ -38,7 +40,7 @@
         messages = $history.find('.message-text').text()
         return messages if messages.length > 0

-      zc.waitfor(2, get_messages)
+      zc.waitfor(2000, get_messages)
       .then (messages) ->
         expect(messages).toEqual("hello world")
       .catch (err) ->


Fixed backwards compatibility for Vekter exporter


Update Template

Update Template

--- workers/emailnotifications/main.coffee
+++ workers/emailnotifications/main.coffee
@@ -26,28 +26,36 @@
 commonTemplate   = (m)->
   action  = ''
   preview = """
-

-                #{m.realContent.body}
+

+                  #{m.realContent.body}
+

-
             """
   switch m.event
     when 'LikeIsAdded'
       action = "liked your"
-      preview = ''
     when 'PrivateMessageSent'
       action = "sent you a"
     when 'ReplyIsAdded'
-      action  = "commented on your"
+      if m.realContent.origin?._id is m.receiver._id
+        action = "commented on your"
+      else
+        action = "also commented on"
+        # FIXME GG Implement the details
+        # if m.realContent.origin?._id is m.sender._id
+        #   action = "#{action} own"

   """
-    Hi #{m.receiver.profile.firstName},
-
-    #{m.sender.profile.firstName} #{m.sender.profile.lastName} #{action} #{m.contentLink}.
+

+      Hi #{m.receiver.profile.firstName},
+

+
+
#{m.sender.profile.firstName} #{m.sender.profile.lastName} #{action} #{m.contentLink}.

+
     #{preview}

-    --
+
 --

     Management
   """


rename

rename

--- lib/build/build-manager.coffee
+++ lib/build/build-manager.coffee
@@ -38,7 +38,7 @@
       JSON.parse result
     .then (task) ->
       buildStateView.setTask(task)
-
+

     .catch (err) ->
       buildStateView.destroy()
@@ -48,11 +48,11 @@
   sendBuildRequest: (options) ->
     console.log "options:#{options}"
     if options.platform == "android"
-
+
       Q.Promise (resolve, reject, notify) =>
         r = request.post {url:"#{@server}/api/tasks",timeout: 1000*60*10}, (err, httpResponse, body)=>
           if err then reject(err) else resolve(body)
-
+
         form = r.form()
         form.append "access_token","#{atom.config.get('atom-butterfly.puzzleAccessToken')}"
         form.append "builder","cordova-android"
@@ -74,23 +74,23 @@
       Q.Promise (resolve, reject, notify) =>
         r = request.post {url:"#{@server}/api/tasks",timeout: 1000*60*10}, (err, httpResponse, body)=>
           if err then reject(err) else resolve(body)
-
+
         form = r.form()
         form.append "access_token","#{atom.config.get('atom-butterfly.puzzleAccessToken')}"
         form.append "builder","cordova-ios"
         form.append "platform","ios"
-
+
         # 以下四个值需要同时不为空，否则不发送到服务器  如果不填写，那么使用服务器的默认证书
         unless ( (options.Mobileprovision is "") || (options.p12 is "") || (options.p12_password is "") || (options.BundleIdentifier is ""))
-          form.append "mobileprovision",fs.createReadStream(options.Mobileprovision)
+          form.append "mobileprovision",fs.createReadStream(options.mobileprovision)
           form.append "p12",fs.createReadStream(options.p12)
           form.append "p12_password","#{options.p12_password}"
-          form.append "bundleIdentifier","#{options.BundleIdentifier}"
-
+          form.append "bundleIdentifier","#{options.bundleIdentifier}"
+
         # 若不填写，使用默认图标
         unless options.icon is ""
           form.append "icon",fs.createReadStream(options.icon)
-
+
         # # 下面是库连接，只要一下一个值为空，就是使用默认的github地址进行下载
         unless ((options.repository_url is "") || (options.scheme is ""))
           form.append "scheme","#{options.scheme}"
@@ -100,5 +100,5 @@
         form.append "version","#{options.version}"
         form.append "build","#{options.build}"
         form.append "content_src","#{options.content_src}"
-
+
         form.append "asset",fs.createReadStream(options.asset)


fix the repeated find motion bug

fix the repeated find motion bug

--- lib/motions/find-motion.coffee
+++ lib/motions/find-motion.coffee
@@ -17,6 +17,7 @@
     if @backwards
       index = currentPosition.column
       for i in [0..count-1]
+        return if index <= 0 # we can't move backwards any further, quick return
         index = line.lastIndexOf(@input.characters, index-1)
       if index >= 0
         new Point(currentPosition.row, index + @offset)
@@ -24,6 +25,7 @@
       index = currentPosition.column
       for i in [0..count-1]
         index = line.indexOf(@input.characters, index+1)
+        return if index < 0 # no match found
       if index >= 0
         new Point(currentPosition.row, index - @offset)


Fix uncaught reference error for not including utility

--- lib/notational-velocity.coffee
+++ lib/notational-velocity.coffee
@@ -2,6 +2,7 @@
 fs = require 'fs-plus'
 {CompositeDisposable, Disposable} = require 'atom'
 NoteLink = require './notelink'
+Utility = require './utility'

 module.exports =
   config:


Breakdown the R/S pipeline into two methods

--- library/nucleus/routing.coffee
+++ library/nucleus/routing.coffee
@@ -63,17 +63,26 @@
             @emit "recognized", recognized, signature...
             matching = "Request %s matches %s service"
             logger.debug matching.grey, incoming, identify
-            ignite = recognized.upstreamAsync "ignition", ->
-                assert domain = require("domain").create()
-                processor = recognized.process.bind recognized
-                polished = => processor.apply this, signature
-                domain.add eem for eem in [request, response]
-                domain.add recognized; domain.on "error", (error) =>
-                    rescue = recognized.upstreamAsync "rescuing", ->
-                        return next() unless response.headersSent
-                    return rescue error, request, response
-                domain.run -> process.nextTick polished
-            return ignite request, response
+            return @streamline recognized, signature...
+
+    # Streamlining happens once the requested has been matches with
+    # a service that is going to handle it. This method launches the
+    # pipeline of the necessary prerequisites and subroutines to hand
+    # the request off to the service for processing it. Normally it
+    # should not be used outside of the router (middleware) coding.
+    streamline: (recognized, request, response, next) ->
+        assert signature = _.rest arguments or Array()
+        ignite = recognized.upstreamAsync "ignition", ->
+            assert domain = require("domain").create()
+            processor = recognized.process.bind recognized
+            polished = => processor.apply this, signature
+            domain.add eem for eem in [request, response]
+            domain.add recognized; domain.on "error", (error) =>
+                rescue = recognized.upstreamAsync "rescuing", ->
+                    return next() unless response.headersSent
+                return rescue error, request, response
+            domain.run -> process.nextTick polished
+        return ignite request, response

     # Try registering a new routable object. The method checks for
     # the object to be of the correct type, basically making sure


surgery ops to the old coding

surgery ops to the old coding

--- library/nucleus/service.coffee
+++ library/nucleus/service.coffee
@@ -155,7 +155,7 @@
     # readable. Typically, this is a short hash function, such as an
     # MD5 hash represented (stringified) with HEX digesting mechanism.
     @reference: ->
-        installed = _.isString @$reference
+        installed = try _.isString @$reference
         return @$reference if installed is yes
         noOrigin = "#{identify()} has no origin"
         assert hasher = crypto.createHash "md5"
@@ -185,7 +185,7 @@
     # resource regular expression pattern being unescaped to string.
     # Do not confuse it with `qualified` method that deals with URL.
     @location: (location) ->
-        current = => @$location or automatic
+        current = => try @$location or automatic
         automatic = _.head(@resources)?.unescape()
         return current() if arguments.length is 0
         isEmpty = "the location must not be empty"


Spec typo

Spec typo

--- spec/installed-package-view-spec.coffee
+++ spec/installed-package-view-spec.coffee
@@ -92,15 +92,15 @@
         expect(card.refs.keybindingToggle.checked).toBe false
         expect(_.include(atom.config.get('core.packagesWithKeymapsDisabled') ? [], 'language-test')).toBe true

-        keybindingRows = view.element.querySelector('.package-keymap-table tbody tr')
-        expect(keybindingsRows.length).toBe 1
+        keybindingRows = card.element.querySelectorAll('.package-keymap-table tbody tr')
+        expect(keybindingRows.length).toBe 1

         card.refs.keybindingToggle.click()
         expect(card.refs.keybindingToggle.checked).toBe true
         expect(_.include(atom.config.get('core.packagesWithKeymapsDisabled') ? [], 'language-test')).toBe false

-        keybindingRows = view.element.querySelector('.package-keymap-table tbody tr')
-        expect(keybindingsRows.length).toBe 1
+        keybindingRows = card.element.querySelectorAll('.package-keymap-table tbody tr')
+        expect(keybindingRows.length).toBe 1

   describe "when a keybinding is copied", ->
     [pack, card] = []


Display filter errors

Display filter errors

--- modules/player/commands.coffee
+++ modules/player/commands.coffee
@@ -189,11 +189,9 @@
         filters = @util.parseFilters(args, msg.member, true)
         player.updateFilters(filters)
       catch e
-        if e.message
-          return msg.reply 'Something went wrong', false, {
-            description: e.message,
-            color: 0xFF0000
-          }
-        else Core.log e,2
+        return msg.reply 'Something went wrong', false, {
+          description: e.message or e,
+          color: 0xFF0000
+        }

 module.exports = PlayerCommands


modified:   dynaAlert.coffee

modified:   dynaAlert.coffee

--- dynaAlert.coffee
+++ dynaAlert.coffee
@@ -40,6 +40,8 @@
         if e.keyCode is 13
             e.preventDefault()
             return
+    'click button.enterPassword': ( e, t ) ->
+

 @b3.promptIdentity = @b3.Alert::curry {
     dialog: true


relative path loading.

relative path loading.

--- web/site/src/javascript/app.coffee
+++ web/site/src/javascript/app.coffee
@@ -31,7 +31,7 @@
     do App.display_overview

   display_overview: ->
-    $.getJSON '/data/sensors.geojson', (sensor_metadata) ->
+    $.getJSON './data/sensors.geojson', (sensor_metadata) ->
         sensors = sensor_metadata.features
         floors = do (floor_of s for s in sensors).unique
         sensors_by_floor =


fullpieagent testing

fullpieagent testing

--- widgets/fullpie_agent/fullpie_agent.coffee
+++ widgets/fullpie_agent/fullpie_agent.coffee
@@ -100,7 +100,7 @@
         x = c[0]
         y = c[1]
         mx = 1.6
-        my = .8
+        my = 1
         h = Math.sqrt(x*x + y*y)
         r = labelRadius
         if x <= 0


Agent pie: start/end angle pie transition work

--- widgets/fullpie_agent/fullpie_agent.coffee
+++ widgets/fullpie_agent/fullpie_agent.coffee
@@ -1,10 +1,12 @@
 class Dashing.FullpieAgent extends Dashing.Widget

     @accessor 'data'
-    @instanceDataId = ''
-    @oldPieData = {}
-
-    #constructor: ->
+
+    constructor: ->
+        super
+        @instanceDataId = ''
+        @oldPieData = {}
+
     ready: ->
         @instanceDataId = $(@node).attr('data-id')
         console.log('ready -> @instanceDataId: ',@instanceDataId)
@@ -15,7 +17,7 @@

     onData: (data) ->
         console.log('onData')
-
+
         #$(@node).fadeOut().fadeIn()
         @container = $(@node).parent()
         #@instanceDataId = $(@node).attr('data-id')


fullpieagent testing

fullpieagent testing

--- widgets/fullpie_agent/fullpie_agent.coffee
+++ widgets/fullpie_agent/fullpie_agent.coffee
@@ -639,7 +639,7 @@
       maxLabelHeight = Math.max(maxLabelHeight, bbox.height + 10)
       return
     )
-    .transition().duration(1000).ease(.5)
+    .transition()
     .attr('x', (d) ->
       d.x
     ).attr 'y', (d) ->


fullpieagent testing

fullpieagent testing

--- widgets/fullpie_agent/fullpie_agent.coffee
+++ widgets/fullpie_agent/fullpie_agent.coffee
@@ -244,13 +244,7 @@
             .duration(1500)
             #.attrTween("d", pieTween);
             .attrTween("d", (d,i) ->
-                i = d3.interpolate({
-                    startAngle: 0,
-                    endAngle: 0
-                }, {
-                    startAngle: d.startAngle,
-                    endAngle: d.endAngle
-                })
+                i = d3.interpolate({startAngle: 0,endAngle: 0}, {startAngle: d.startAngle,endAngle: d.endAngle})
                 return (t) ->
                     b = i(t);
                     return arc(b)


--- widgets/fullpie_agent/fullpie_agent.coffee
+++ widgets/fullpie_agent/fullpie_agent.coffee
@@ -150,42 +150,42 @@
         path = pathGroup.selectAll('path.pie').data(piedata)
         path.enter().append('path').attr('class', 'pie').attr('fill', (d, i) -> color i)

-        #path.transition().duration(750).attrTween('d', (d,i) ->
-            #theOldDataInPie = @oldPieData ? piedata
-            #console.log('@oldPieData',@oldPieData)
-            ## Interpolate the arcs in data space
-            #s0 = undefined
-            #e0 = undefined
-            #if theOldDataInPie[i]
-            #    s0 = theOldDataInPie[i].startAngle
-            #    e0 = theOldDataInPie[i].endAngle
-            #else if !theOldDataInPie[i] and theOldDataInPie[i - 1]
-            #    s0 = theOldDataInPie[i - 1].endAngle
-            #    e0 = theOldDataInPie[i - 1].endAngle
-            #else if !theOldDataInPie[i - 1] and theOldDataInPie.length > 0
-            #    s0 = theOldDataInPie[theOldDataInPie.length - 1].endAngle
-            #    e0 = theOldDataInPie[theOldDataInPie.length - 1].endAngle
-            #else
-            #    s0 = 0
-            #    e0 = 0
-            #`var i`
-            #i = d3.interpolate({
-            #    startAngle: s0
-            #    endAngle: e0
-            #},
-            #    startAngle: d.startAngle
-            #    endAngle: d.endAngle)
-            #(t) ->
-            #    b = i(t)
-            #    return arc b
+        path.transition().duration(750).attrTween('d', (d,i) ->
+            theOldDataInPie = @oldPieData ? piedata
+            console.log('@oldPieData',@oldPieData)
+            # Interpolate the arcs in data space
+            s0 = undefined
+            e0 = undefined
+            if theOldDataInPie[i]
+                s0 = theOldDataInPie[i].startAngle
+                e0 = theOldDataInPie[i].endAngle
+            else if !theOldDataInPie[i] and theOldDataInPie[i - 1]
+                s0 = theOldDataInPie[i - 1].endAngle
+                e0 = theOldDataInPie[i - 1].endAngle
+            else if !theOldDataInPie[i - 1] and theOldDataInPie.length > 0
+                s0 = theOldDataInPie[theOldDataInPie.length - 1].endAngle
+                e0 = theOldDataInPie[theOldDataInPie.length - 1].endAngle
+            else
+                s0 = 0
+                e0 = 0
+            `var i`
+            i = d3.interpolate({
+                startAngle: s0
+                endAngle: e0
+            },
+                startAngle: d.startAngle
+                endAngle: d.endAngle)
+            (t) ->
+                b = i(t)
+                return arc b
+        )
+        #path.transition().duration(750).attrTween('d', (d) ->
+        #    ip = d3.interpolate(@_current, newAngle)
+        #    @_current = ip(0)
+        #    return (t) ->
+        #        d.endAngle = ip(t)
+        #        return arc(d)
         #)
-        path.transition().duration(750).attrTween('d', (d) ->
-            ip = d3.interpolate(@_current, d)
-            @_current = ip(0)
-            return (t) ->
-                d.endAngle = ip(t)
-                return arc(i(t))
-        )
         path.exit()
             #.transition()
             #.duration(300)


Agent pie: edit transitions

Agent pie: edit transitions

--- widgets/fullpie_agent/fullpie_agent.coffee
+++ widgets/fullpie_agent/fullpie_agent.coffee
@@ -294,6 +294,7 @@
         #.attr("x",0)
         #.attr("y",0)
         .transition()
+            .delay(750)
             .duration(500)
             .attr('x', (d) ->
                 d.x


Add Opera 15 and update statistics

Add Opera 15 and update statistics


Update Atom

Update Atom

--- home/.atom/config.cson
+++ home/.atom/config.cson
@@ -8,7 +8,7 @@
   metrics:
     userId: "ba44e3beb28ecd4cac067ffa00fb25caece41ae8"
   editor:
-    fontFamily: "Hack"
+    fontFamily: "Inconsolata-g"
     showIndentGuide: true
     tabLength: 4
     invisibles: {}


Updated Atom config

Updated Atom config

--- home/.atom/config.cson
+++ home/.atom/config.cson
@@ -94,3 +94,5 @@
     honorStyleSettings: true
     checkStyleDevDependencies: true
   "merge-conflicts": {}
+  "tree-view":
+    hideVcsIgnoredFiles: true


fix: lang switch

fix: lang switch

--- build/html-builder.coffee
+++ build/html-builder.coffee
@@ -97,16 +97,13 @@
         title.replace /T\("?([\w\W]+?)"?\)/, '$1'

     marked_with_filtering_by_lang = (filepath, lang)->
-        items = marked.lexer fs.readFileSync(filepath, 'utf-8')
-        tokens = []
-        skip = false
-        for item in items
-            if item.type is 'heading' and item.depth is 6
-                skip = item.text != lang and item.text != '--'
-                continue
-            if skip then continue
-            tokens.push item
-        marked.parser tokens
+        items = []
+        for line in fs.readFileSync(filepath, 'utf-8').split '\n'
+            if not (m = /^(en|ja):/.exec line)
+                items.push line
+            else if m[1] is lang
+                items.push line.substr(3).replace /^\s+/, ''
+        marked.parser marked.lexer items.join '\n'

     lang_process = (doc)->
         re  = /
([\w\W]+?)<\/code><\/pre>/g


KiteSubscription: add kite filter to app store

--- client/Social/Apps/AppController.coffee
+++ client/Social/Apps/AppController.coffee
@@ -66,6 +66,9 @@

     KD.remote.api.JNewApp.some selector, options, callback

+  doKiteQuery:(selector, options, callback)->
+    KD.remote.api.JKite.list selector, options, callback
+
   createFeed:(view, loadFeed = no)->

     options =
@@ -120,6 +123,12 @@
           dataSource        : (selector, options, callback)=>
             selector['manifest.category'] = 'framework'
             @doQuery selector, options, callback
+
+        kites               :
+          title             : "Kites"
+          noItemFoundText   : "There are no kites yet"
+          dataSource        : (selector, options, callback)=>
+            @doKiteQuery selector, options, callback

         miscellaneous       :
           title             : "Miscellaneous"


TerminalSession: current user plan message box borders are hidden until the plan is fetched

--- client/Terminal/terminalstarttab.coffee
+++ client/Terminal/terminalstarttab.coffee
@@ -7,6 +7,7 @@
     @vmWrapper = new KDCustomHTMLView tagName : 'ul'

     @message = new KDCustomHTMLView cssClass : 'terminal-bottom-message'
+    @message.hide()

     KD.singletons.notificationController.on 'NotificationHasArrived', ({event}) =>
       if event is "VMCreated" or "VMRemoved"
@@ -105,8 +106,8 @@
         upgrade your current plan and use Always On VMs."""
       else
         message = """If you have active sessions which do not belong to an Always-on VM, you can lose your sessions 15 minutes after you log out or if you leave them idle."""
-
       @message.updatePartial message
+      @message.show()


Fix Firefox Profile Edit issues

Fix Firefox Profile Edit issues

--- client/app/CommonViews/FormViews.coffee
+++ client/app/CommonViews/FormViews.coffee
@@ -16,7 +16,7 @@
       @resetInputValue?()
       @unsetClass 'active'
     else if @$().hasClass(classToCheck) and e.which is 13
-      @submit event
+      @submit e

   mouseDown:(event)->
     @showForm()


Client: Activity: Added show notification methods to user actions

--- client/app/lib/flux/actions/user.coffee
+++ client/app/lib/flux/actions/user.coffee
@@ -51,6 +51,31 @@
       reactor.dispatch SEARCH_USERS_FAIL, { err, query }

+showMarkUserAsTrollSuccess = (account) ->
+
+  showNotification "@#{account.profile.nickname} marked as a troll!"
+
+
+showMarkUserAsTrollFail = (err, account) ->
+
+  showErrorNotification err, userMessage: "You are not allowed to mark this user as a troll!"
+
+
+showUnmarkUserAsTrollSuccess = (account) ->
+
+  showErrorNotification "@#{account.profile.nickname} won't be treated as a troll anymore!"
+
+
+showBlockUserFail = (err, account) ->
+
+  showErrorNotification err, userMessage: "You are not allowed to block user!"
+
+
+showBlockUserSuccess = (account) ->
+
+  showNotification "User is blocked!"
+
+
 module.exports = {
   loadAccount
   searchAccounts