cooldown finilazation

cooldown finilazation

--- src/cooldown.coffee
+++ src/cooldown.coffee
@@ -11,7 +11,7 @@
   target: 100

 player.update()
-
+

 player.I.health #=> 51

 player.update()


Style.

Style.

--- tests/tests.coffee
+++ tests/tests.coffee
@@ -864,7 +864,7 @@
       #{ FOO_COMPONENT_CONTENT() }
     """

-  testComponents: =>
+  testComponents: ->
     componentTemplate = BlazeComponent.getComponent('MainComponent').renderComponent()

     @assertTrue componentTemplate
@@ -927,22 +927,22 @@

     @assertEqual trim(output), trim COMPONENT_CONTENT 'SubComponent'

-  testGetComponent: =>
+  testGetComponent: ->
     @assertEqual BlazeComponent.getComponent('MainComponent'), MainComponent
     @assertEqual BlazeComponent.getComponent('FooComponent'), FooComponent
     @assertEqual BlazeComponent.getComponent('SubComponent'), SubComponent
     @assertEqual BlazeComponent.getComponent('unknown'), null

-  testComponentName: =>
+  testComponentName: ->
     @assertEqual MainComponent.componentName(), 'MainComponent'
     @assertEqual FooComponent.componentName(), 'FooComponent'
     @assertEqual SubComponent.componentName(), 'SubComponent'
     @assertEqual BlazeComponent.componentName(), null

-  testSelfRegister: =>
+  testSelfRegister: ->
     @assertTrue BlazeComponent.getComponent 'SelfRegisterComponent'

-  testUnregisteredComponent: =>
+  testUnregisteredComponent: ->
     componentTemplate = UnregisteredComponent.renderComponent()

     @assertTrue componentTemplate
@@ -981,7 +981,7 @@
     # We have not extended any helper on purpose, so they should still use "UnregisteredComponent".
     @assertEqual trim(output), trim COMPONENT_CONTENT 'SelfNameUnregisteredComponent', 'UnregisteredComponent'

-  testErrors: =>
+  testErrors: ->
     @assertThrows =>
       BlazeComponent.register()
     ,
@@ -1593,7 +1593,7 @@
       @assertArgumentsOnCreatedStateChanges ArgumentsComponent.onCreatedStateChanges
   ]

-  testExistingClassHierarchy: =>
+  testExistingClassHierarchy: ->
     # We want to allow one to reuse existing class hierarchy they might already have and only
     # add the Meteor components "nature" to it. This is simply done by extending the base class
     # and base class prototype with those from a wanted base class and prototype.
@@ -1606,7 +1606,7 @@

     @assertEqual trim(output), trim COMPONENT_CONTENT 'ExistingClassHierarchyComponent', 'ExistingClassHierarchyComponent', 'ExistingClassHierarchyBase'

-  testMixins: =>
+  testMixins: ->
     DependencyMixin.calls = []

     componentTemplate = BlazeComponent.getComponent('WithMixinsComponent').renderComponent()
@@ -1637,7 +1637,7 @@
       #{ COMPONENT_CONTENT 'SubComponent' }
     """

-  testMixinEvents: =>
+  testMixinEvents: ->
     FirstMixin.calls = []
     SecondMixin.calls = []
     SubComponent.calls = []
@@ -1690,7 +1690,7 @@

     Blaze.remove renderedComponent

-  testAfterCreateValue: =>
+  testAfterCreateValue: ->
     # We want to test that also properties added in onCreated hook are available in the template.
     componentTemplate = BlazeComponent.getComponent('AfterCreateValueComponent').renderComponent()

@@ -1728,7 +1728,7 @@
       Blaze.remove @renderedComponent
   ]

-  testBlockComponent: =>
+  testBlockComponent: ->
     output = Blaze.toHTMLWithData Template.testBlockComponent,
       top: '42'

@@ -2470,7 +2470,7 @@
   ]

   # Test for https://github.com/peerlibrary/meteor-blaze-components/issues/30.
-  testTemplateDynamic: =>
+  testTemplateDynamic: ->
     componentTemplate = BlazeComponent.getComponent('TemplateDynamicTestComponent').renderComponent()

     @assertTrue componentTemplate


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- test/clamp.coffee
+++ test/clamp.coffee
@@ -10,5 +10,6 @@
   ok obj.clamp

 test 'it should clamp value between its provided min and max', ->
+  obj = GameO

 module()


name returns to eliminate brackets

name returns to eliminate brackets

--- test/mocks.coffee
+++ test/mocks.coffee
@@ -38,12 +38,12 @@
     # store into results
     Result.browserify = array: array, options: options
     # return this mock when browserify.bundle() is called
-    return it =
+    return browserifyObject =
       bundle: ->
         # store this was run
         Result.browserify.bundle = true
         # return a mock readable stream
-        return {
+        return bundleObject =
           # store the encoding it's told to use
           setEncoding: (encoding) -> Result.browserify.encoding = encoding

@@ -69,7 +69,6 @@
           pipe: (exorcist) ->
             Result.exorcist.piped = exorcist
             return this
-        }

       # store received transform name and options
       transform: (transformName, transformOptions) ->


Whitespace fix.

Whitespace fix.

--- test/tests.coffee
+++ test/tests.coffee
@@ -82,5 +82,3 @@

 }).export(module)
-
-


whoops, this was waay too fast

whoops, this was waay too fast

--- src/lib/config.iced
+++ src/lib/config.iced
@@ -17,7 +17,7 @@
     max_size : 16
   timeouts :
     cache : 5*60
-    document : 15
+    document : 2*60
     input : 5*60
   server:
     host : "oneshallpass.com"


starting to think about this...

starting to think about this...

--- src/lib/derive.iced
+++ src/lib/derive.iced
@@ -189,8 +189,13 @@

   ##-----------------------------------------

-  constructor : (i) -> super i
+  constructor : (input, @_keymode = 0x1) ->
+    super input
+
+  ##-----------------------------------------
+
   version : () -> 2
+  set_keymode : (k) -> @_keymode = k

   ##-----------------------------------------

@@ -200,7 +205,7 @@

     # The initial setup as per PBKDF2, with email as the salt
     hmac = C.algo.HMAC.create C.algo.SHA512, @passphrase()
-    block_index = C.lib.WordArray.create [ 0x1 ]
+    block_index = C.lib.WordArray.create [ @_keymode ]
     block = hmac.update(@email()).finalize block_index
     hmac.reset()


when logging out, clear all forms

when logging out, clear all forms


prime citekey cache on first install

prime citekey cache on first install

--- chrome/content/zotero-better-bibtex/keymanager.coffee
+++ chrome/content/zotero-better-bibtex/keymanager.coffee
@@ -57,6 +57,12 @@

     for row in Zotero.DB.query('select k.itemID, k.citekey, k.citekeyFormat, i.libraryID from betterbibtex.keys k join items i on k.itemID = i.itemID')
       @keys.insert({itemID: @integer(row.itemID), libraryID: row.libraryID, citekey: row.citekey, citekeyFormat: row.citekeyFormat})
+
+    # select non-note, non-attachment items that don't have a cached key, and generate one, to make sure the cache is
+    # complete. Should only run after first installation, as after that all new items or item changes will generate
+    # keys, but better safe than sorry.
+    for row in Zotero.DB.query('select itemID from items where itemType not in (0, 14) and itemID not in (select itemID from betterbibtex.keys)')
+      @get({itemID: row.itemID})

   reset: ->
     Zotero.DB.query('delete from betterbibtex.keys')


ComputePlansModalPaid: createVM: route to /IDE after create

--- client/app/lib/providers/computeplansmodalpaid.coffee
+++ client/app/lib/providers/computeplansmodalpaid.coffee
@@ -275,9 +275,12 @@

     computeController.create {
       provider : "koding", stack, storage, region, snapshotId
-    }, (err, machine)=>
+    }, (err, machine) =>

       return  if showError err

       @createVMButton.hideLoader()
       @destroy()
+
+      kd.singletons.router.handleRoute '/IDE'
+


Getting rid of an alert. People don't like alerts.

--- common/lib/xmodule/xmodule/js/src/capa/display.coffee
+++ common/lib/xmodule/xmodule/js/src/capa/display.coffee
@@ -257,7 +257,11 @@
     Logger.log 'problem_save', @answers
     $.postWithPrefix "#{@url}/problem_save", @answers, (response) =>
       if response.success
-        alert 'Saved'
+        if @el.find('.save_message').length
+            @el.find('.save_message').animate(opacity: 0, 500).animate(opacity: 1, 500)
+        else
+            saveMessage = "
Your answers have been saved but not graded. Hit 'Check' to grade them.
"
+            @el.find('.action').after(saveMessage)
       @updateProgress response

   refreshMath: (event, element) =>


remove unused parameter

remove unused parameter

--- src/notebook.coffee
+++ src/notebook.coffee
@@ -270,11 +270,10 @@

     output_cell

-  create_notebook_run_context = (input_cell, output_cell) ->
+  create_notebook_run_context = (input_cell) ->
     notebook = input_cell.notebook
     run_context =
       notebook: notebook
-      cell: output_cell
       input_cell: input_cell
       default_options: notebook.default_options
       set_code: (code) ->


wrap long line

wrap long line

--- src/opensong.coffee
+++ src/opensong.coffee
@@ -179,7 +179,8 @@
         textLineArr = []

         # while we have lines that match a textLine create an html table row
-        while (textLine = lyricsLines.shift()) and (m = textLine.match(/^([ 1-9])(.*)/))
+        while (textLine = lyricsLines.shift()) and \
+              (m = textLine.match(/^([ 1-9])(.*)/))
           textArr = []
           textLineNr = m[1]
           textLine = m[2]


Fix for exception on listener removal

Fix for exception on listener removal

--- framer/Layer.coffee
+++ framer/Layer.coffee
@@ -592,7 +592,9 @@
 		super event, listener

 		@_element.removeEventListener event, listener
-		@_eventListeners[event] = _.without @_eventListeners[event], listener
+
+		if @_eventListeners
+			@_eventListeners[event] = _.without @_eventListeners[event], listener

 	removeAllListeners: ->


Another update on nl-NL.coffee  ;-) (#4879)

* Update nl-NL.coffee

* Update nl-NL.coffee

* Update nl-NL.coffee

* Update nl-NL.coffee

* Update nl-NL.coffee

--- app/locale/nl-NL.coffee
+++ app/locale/nl-NL.coffee
@@ -15,7 +15,7 @@
     designed_with: "Designed with teachers in mind"
     real_code: "Echte, zelf geschreven code"
     from_the_first_level: "vanaf het eerste level"
-#    getting_students: "Getting students to typed code as quickly as possible is critical to learning programming syntax and proper structure."
+    getting_students: "Leerlingen zo snel mogelijk zelf code laten schrijven is een bepalende factor in het ontwikkelen van programmeervaardigheden, zoals de juiste structuur, opbouw en syntax."
     educator_resources: "Ondersteuning voor leerkrachten"
     course_guides: "en lesgidsen"
 #    teaching_computer_science: "Teaching computer science does not require a costly degree, because we provide tools to support educators of all backgrounds."
@@ -32,7 +32,7 @@
 #    struggle: "productive struggle"
 #    kind_of_struggle: "the kind of struggle that results in learning that’s engaging and"
     motivating: "motiverend"
-#    not_tedious: "not tedious."
+    not_tedious: "niet saai."
 #    gaming_is_good: "Studies suggest gaming is good for children’s brains. (it’s true!)"
 #    game_based: "When game-based learning systems are"
     compared: "vergeleken"
@@ -66,8 +66,8 @@
   nav:
     map: "Kaart"
     play: "Levels" # The top nav bar entry where players choose which levels to play
-#    community: "Community"
-#    courses: "Courses"
+    community: "Groepen"
+    courses: "Lessen"
     blog: "Blog"
     forum: "Forum"
     account: "Account"
@@ -121,15 +121,15 @@
     play_as: "Speel als" # Ladder page
 #    get_course_for_class: "Assign Game Development and more to your classes!"
 #    request_licenses: "Contact our school specialists for details."
-#    compete: "Compete!" # Course details page
-#    spectate: "Spectate" # Ladder page
-#    players: "players" # Hover over a level on /play
-#    hours_played: "hours played" # Hover over a level on /play
-#    items: "Items" # Tooltip on item shop button from /play
-#    unlock: "Unlock" # For purchasing items and heroes
+    compete: "Doe mee!" # Course details page
+    spectate: "Kijk" # Ladder page
+    players: "spelers" # Hover over a level on /play
+    hours_played: "uren gespeeld" # Hover over a level on /play
+    items: "Spullen" # Tooltip on item shop button from /play
+    unlock: "Vrijmaken" # For purchasing items and heroes
     confirm: "Bevestig"
-#    owned: "Owned" # For items you own
-#    locked: "Locked"
+    owned: "Eigendom" # For items you own
+    locked: "Nog gesloten"
     available: "Beschikbaar"
 #    skills_granted: "Skills Granted" # Property documentation details
     heroes: "Helden" # Tooltip on hero shop button from /play
@@ -138,20 +138,20 @@
 #    poll: "Poll" # Tooltip on poll button from /play
     next: "Volgende" # Go from choose hero to choose inventory before playing a level
     change_hero: "Verander je held" # Go back from choose inventory to choose hero
-#    change_hero_or_language: "Change Hero or Language"
+    change_hero_or_language: "Verander van held of programmeertaal"
     buy_gems: "Koop edelstenen"
     subscribers_only: "Aleen voor abonnees!"
     subscribe_unlock: "Abonneer je om vrij te spelen!"
 #    subscriber_heroes: "Subscribe today to immediately unlock Amara, Hushbaum, and Hattori!"
-#    subscriber_gems: "Subscribe today to purchase this hero with gems!"
+    subscriber_gems: "Schrijf je in om deze held te kopen met edelstenen!"
     anonymous: "Anonieme speler"
     level_difficulty: "Moeilijkheid: "
     awaiting_levels_adventurer_prefix: "We brengen iedere week nieuwe levels uit."
     awaiting_levels_adventurer: "Schrijf je in als avonturier"
     awaiting_levels_adventurer_suffix: "om nieuwe levels als eerste te spelen."
     adjust_volume: "Pas volume aan"
-#    campaign_multiplayer: "Multiplayer Arenas"
-#    campaign_multiplayer_description: "... in which you code head-to-head against other players."
+    campaign_multiplayer: "Multiplayer Arenas"
+    campaign_multiplayer_description: "... waarin je tegen andere spelers codeert."
     brain_pop_done: "Je hebt de ogres verslagen met je code! Je wint!"
     brain_pop_challenge: "Daag jezelf uit door het level uit te spelen met een andere programmeertaal!"
     replay: "Speel nog een keer"
@@ -229,20 +229,20 @@
     sign_in_with_gplus: "Log in met Google"
     signup_switch: "Wil je een account aanmaken?"

-#  signup:
-#    complete_subscription: "Complete Subscription"
-#    create_student_header: "Create Student Account"
-#    create_teacher_header: "Create Teacher Account"
-#    create_individual_header: "Create Individual Account"
-#    email_announcements: "Receive announcements about new CodeCombat levels and features!"
-#    sign_in_to_continue: "Sign in or create an account to continue"
+  signup:
+    complete_subscription: "Inschrijving afronden"
+    create_student_header: "Maak Leerlingaccount "
+    create_teacher_header: "Maak docentenaccount"
+    create_individual_header: "Maak een Individueel"
+    email_announcements: "Ontvang aankondigingen over nieuwe CodeCombat levels en mogelijkheden!"
+    sign_in_to_continue: "Log in of maak een account aan om door te gaan"
 #    teacher_email_announcements: "Keep me updated on new teacher resources, curriculum, and courses!"
-#    creating: "Creating Account..."
-#    sign_up: "Sign Up"
-#    log_in: "log in with password"
+    creating: "Account Aanmaken..."
+    sign_up: "Meld je aan"
+    log_in: "log in met wachtwoord"
 #    required: "You need to log in before you can go that way."
-#    login_switch: "Already have an account?"
-#    optional: "optional"
+    login_switch: "Heb je al een account?"
+    optional: "optioneel"
 #    connected_gplus_header: "You've successfully connected with Google+!"
 #    connected_gplus_p: "Finish signing up so you can log in with your Google+ account."
 #    connected_facebook_header: "You've successfully connected with Facebook!"
@@ -251,53 +251,53 @@
 #    birthday: "Birthday"
 #    parent_email_blurb: "We know you can't wait to learn programming — we're excited too! Your parents will receive an email with further instructions on how to create an account for you. Email {{email_link}} if you have any questions."
 #    classroom_not_found: "No classes exist with this Class Code. Check your spelling or ask your teacher for help."
-#    checking: "Checking..."
-#    account_exists: "This email is already in use:"
-#    sign_in: "Sign in"
-#    email_good: "Email looks good!"
-#    name_taken: "Username already taken! Try {{suggestedName}}?"
-#    name_available: "Username available!"
-#    name_is_email: "Username may not be an email"
-#    choose_type: "Choose your account type:"
-#    teacher_type_1: "Teach programming using CodeCombat!"
+    checking: "Controleren..."
+    account_exists: "Dit email adres wordt al gebruikt:"
+    sign_in: "Log in"
+    email_good: "Email ziet er goed uit!"
+    name_taken: "Gebruikersnaam is al in gebruik! Probeer anders {{suggestedName}}?"
+    name_available: "Gebruikersnaam beschikbaar!"
+    name_is_email: "Gebruikersnaam mag geen emailadres zijn"
+    choose_type: "Kies je account type:"
+    teacher_type_1: "Doceer programmeren met CodeCombat!"
 #    teacher_type_2: "Set up your class"
 #    teacher_type_3: "Access Course Guides"
-#    teacher_type_4: "View student progress"
-#    signup_as_teacher: "Sign up as a Teacher"
+    teacher_type_4: "Bekijk voortgang van leerlingen"
+    signup_as_teacher: "Schrijf je in als docent"
 #    student_type_1: "Learn to program while playing an engaging game!"
-#    student_type_2: "Play with your class"
+    student_type_2: "Speel met je klas"
 #    student_type_3: "Compete in arenas"
-#    student_type_4: "Choose your hero!"
+    student_type_4: "Kies je held!"
 #    student_type_5: "Have your Class Code ready!"
-#    signup_as_student: "Sign up as a Student"
+    signup_as_student: "Schrijf je in als Leerling"
 #    individuals_or_parents: "Individuals & Parents"
 #    individual_type: "For players learning to code outside of a class. Parents should sign up for an account here."
 #    signup_as_individual: "Sign up as an Individual"
 #    enter_class_code: "Enter your Class Code"
-#    enter_birthdate: "Enter your birthdate:"
-#    parent_use_birthdate: "Parents, use your own birthdate."
+    enter_birthdate: "Vul je geboortedatum in:"
+    parent_use_birthdate: "Ouder/verzorger, gebruik je eigen geboortedatum."
 #    ask_teacher_1: "Ask your teacher for your Class Code."
-#    ask_teacher_2: "Not part of a class? Create an "
-#    ask_teacher_3: "Individual Account"
-#    ask_teacher_4: " instead."
-#    about_to_join: "You're about to join:"
-#    enter_parent_email: "Enter your parent’s email address:"
+    ask_teacher_2: "Maak je geen deel uit van een klas? Maak dan een "
+    ask_teacher_3: "Individueel Account"
+    ask_teacher_4: " aan in plaats daarvan."
+    about_to_join: "Je staat op het punt je in te schrijven:"
+    enter_parent_email: "Voer het email adres van je ouders in:"
 #    parent_email_error: "Something went wrong when trying to send the email. Check the email address and try again."
 #    parent_email_sent: "We’ve sent an email with further instructions on how to create an account. Ask your parent to check their inbox."
 #    account_created: "Account Created!"
 #    confirm_student_blurb: "Write down your information so that you don't forget it. Your teacher can also help you reset your password at any time."
 #    confirm_individual_blurb: "Write down your login information in case you need it later. Verify your email so you can recover your account if you ever forget your password - check your inbox!"
 #    write_this_down: "Write this down:"
-#    start_playing: "Start Playing!"
+    start_playing: "Begin met Spelen!"
 #    sso_connected: "Successfully connected with:"
 #    select_your_starting_hero: "Select Your Starting Hero:"
 #    you_can_always_change_your_hero_later: "You can always change your hero later."
-#    finish: "Finish"
+    finish: "Rond af"
 #    teacher_ready_to_create_class: "You're ready to create your first class!"
 #    teacher_students_can_start_now: "Your students will be able to start playing the first course, Introduction to Computer Science, immediately."
 #    teacher_list_create_class: "On the next screen you will be able to create a new class."
 #    teacher_list_add_students: "Add students to the class by clicking the View Class link, then sending your students the Class Code or URL. You can also invite them via email if they have email addresses."
-#    teacher_list_resource_hub_1: "Check out the"
+    teacher_list_resource_hub_1: "Lees de"
 #    teacher_list_resource_hub_2: "Course Guides"
 #    teacher_list_resource_hub_3: "for solutions to every level, and the"
 #    teacher_list_resource_hub_4: "Resource Hub"
@@ -307,7 +307,7 @@
 #    want_codecombat_in_school: "Want to play CodeCombat all the time?"
 #    eu_confirmation: "I agree to allow CodeCombat to store my data on US servers."
 #    eu_confirmation_place_of_processing: "Learn more about the possible risks"
-#    eu_confirmation_student: "If you are not sure, ask your teacher."
+    eu_confirmation_student: "Vraag je leraar als je het niet zeker weet."
 #    eu_confirmation_individual: "If you do not want us to store your data on US servers, you can always keep playing anonymously without saving your code."

   recover:
@@ -485,36 +485,36 @@
 #    failing: "Failing"
     reload: "Herlaad"
     reload_title: "Alle Code opnieuw laden?"
-#    reload_really: "Are you sure you want to reload this level back to the beginning?"
+    reload_really: "Weet je zeker dat je dit level weer vanaf het begin wil laden?"
     reload_confirm: "Alles opnieuw laden"
-#    test_level: "Test Level"
+    test_level: "Test Level"
     victory: "Gewonnen"
     victory_title_prefix: ""
     victory_title_suffix: " Gereed"
-#    victory_sign_up: "Sign Up to Save Progress"
-#    victory_sign_up_poke: "Want to save your code? Create a free account!"
-#    victory_rate_the_level: "How fun was this level?"
+    victory_sign_up: "Schrijf je in om je voortgang te bewaren"
+    victory_sign_up_poke: "Wil je je code bewaren? Maak een gratis account!"
+    victory_rate_the_level: "Hoe leuk was dit level?"
     victory_return_to_ladder: "Keer terug naar de Ladder"
-#    victory_saving_progress: "Saving Progress"
-#    victory_go_home: "Go Home"
+    victory_saving_progress: "Voortgang opslaan"
+    victory_go_home: "Keer terug naar beginscherm"
     victory_review: "Vertel ons meer!"
-#    victory_review_placeholder: "How was the level?"
+    victory_review_placeholder: "Hoe was het level?"
     victory_hour_of_code_done: "Ben Je Klaar?"
-#    victory_hour_of_code_done_yes: "Yes, I'm finished with my Hour of Code™!"
-    victory_experience_gained: "XP # Keywords--these translations show up on hover, so please translate them all, even if it's kind of long. (In the code editor, they will still be in English.)"
+    victory_hour_of_code_done_yes: "Ja, ik ben klaar met mijn Hour of Code™!"
+    # victory_experience_gained: "XP # Keywords--these translations show up on hover, so please translate them all, even if it's kind of long. (In the code editor, they will still be in English.)"
     victory_gems_gained: "Edelstenen verdiend"
     victory_new_item: "Nieuw Item"
-#    victory_new_hero: "Nieuwe Held"
+    victory_new_hero: "Nieuwe Held"
 #    victory_viking_code_school: "Holy smokes, that was a hard level you just beat! If you aren't already a software developer, you should be. You just got fast-tracked for acceptance with Viking Code School, where you can take your skills to the next level and become a professional web developer in 14 weeks."
     victory_become_a_viking: "Word een Viking"
 #    victory_no_progress_for_teachers: "Progress is not saved for teachers. But, you can add a student account to your classroom for yourself."
-    tome_cast_button_run: "Ren"
-    tome_cast_button_running: "Aan het rennen"
-    tome_cast_button_ran: "Gerend"
+    tome_cast_button_run: "Begin"
+    tome_cast_button_running: "Bezig"
+    tome_cast_button_ran: "Gereed"
     tome_submit_button: "Dien in"
-#    tome_reload_method: "Reload original code to restart the level"
-#    tome_available_spells: "Available Spells"
-#    tome_your_skills: "Your Skills"
+    tome_reload_method: "Herlaad de orginele code om het level te herstarten"
+    tome_available_spells: "Beschikbare toverspreuken"
+    tome_your_skills: "Jouw vaardigheden"
     hints: "Aanwijzingen"
     hints_title: "Aanwijzing {{number}}"
     code_saved: "Code Opgeslagen"
@@ -531,7 +531,7 @@
     infinite_loop_title: "Oneindige lus ontdekt"
 #    infinite_loop_description: "The initial code to build the world never finished running. It's probably either really slow or has an infinite loop. Or there might be a bug. You can either try running this code again or reset the code to the default state. If that doesn't fix it, please let us know."
 #    check_dev_console: "You can also open the developer console to see what might be going wrong."
-#    check_dev_console_link: "(instructions)"
+    check_dev_console_link: "(instructies)"
     infinite_loop_try_again: "Probeer opnieuw"
 #    infinite_loop_reset_level: "Reset Level"
 #    infinite_loop_comment_out: "Comment Out My Code"
@@ -655,16 +655,16 @@

   game_menu:
     inventory_tab: "Inventaris"
-    save_load_tab: "Opslaam/Laden"
+    save_load_tab: "Opslaan/Laden"
     options_tab: "Opties"
     guide_tab: "Gids"
     guide_video_tutorial: "Video uitleg"
     guide_tips: "Tips"
     multiplayer_tab: "Multiplayer"
     auth_tab: "Word lid"
-#    inventory_caption: "Equip your hero"
+    inventory_caption: "Kleed je held aan"
     choose_hero_caption: "Kies je held en taal"
-#    options_caption: "Configure settings"
+    options_caption: "Instellingen veranderen"
     guide_caption: "Documenten en tips"
     multiplayer_caption: "Speel met vrienden!"
     auth_caption: "Sla je voortgang op."
@@ -675,31 +675,31 @@
     top_players: "De beste spelers van"
     day: "Vandaag"
     week: "Deze week"
-#    all: "All-Time"
+    all: "Alle tijden"
     latest: "Laatste"
-#    time: "Win Time"
-#    damage_taken: "Damage Taken"
-#    damage_dealt: "Damage Dealt"
-#    difficulty: "Difficulty"
+    time: "Tijd"
+    damage_taken: "Schade opgelopen"
+    damage_dealt: "Schade uitgedeeld"
+    difficulty: "Moeilijkheidsgraad"
     gold_collected: "Goud gevonden"
     survival_time: "Overleefd"
     defeated: "Vijanden verslagen"
     code_length: "Regels Code"
-#    score_display: "__scoreType__: __score__"
+    score_display: "__scoreType__: __score__"

   inventory:
-#    equipped_item: "Equipped"
+    equipped_item: "Nu bij je"
     required_purchase_title: "Vereist"
     available_item: "Beschikbaar"
     restricted_title: "Nu niet bruikbaar"
     should_equip: "(twee keer klikken om aan te trekken)"
     equipped: "(aangetrokken)"
-#    locked: "(locked)"
-#    restricted: "(restricted in this level)"
-#    equip: "Equip"
-#    unequip: "Unequip"
+    locked: "(niet bruikbaar)"
+    restricted: "(niet toegestaan in dit level)"
+    equip: "aandoen"
+    unequip: "uitdoen"
     warrior_only: "alleen voor Krijger"
-#    ranger_only: "Ranger Only"
+    ranger_only: "alleen voor Ranger"
     wizard_only: "Alleen voor Tovenaar"

   buy_gems:
@@ -708,13 +708,13 @@
     chest_gems: "Een kist met edelstenen"
     purchasing: "Kopen..."
     declined: "Er is een probleem met je kaart"
-#    retrying: "Server error, retrying."
+    retrying: "Fout bij de server, ik probeer het nogmaals."
     prompt_title: "Onvoldoende edelstenen"
-#    prompt_body: "Do you want to get more?"
+    prompt_body: "Wil je meer edelstenen kopen?"
     prompt_button: "Betreed winkel "
-#    recovered: "Previous gems purchase recovered. Please refresh the page."
+    recovered: "EErder gekochte edelstenen zijn hersteld. Herlaad de pagina."
     price: "x{{gems}} / mnd"
-#    buy_premium: "Buy Premium"
+    buy_premium: "Koop Premium"
     purchase: "Koop"
     purchased: "Gekocht"

@@ -772,21 +772,21 @@
 #    support_part1: "Need help with payment or prefer PayPal? Email"
 #    support_part2: "support@codecombat.com"

-#  announcement:
-#    now_available: "Now available for subscribers!"
+  announcement:
+    now_available: "Nu beschikbaar voor leden!"
 #    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_name: "Raaf"
 #    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_name: "Blauwe vos"
 #    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!"
@@ -803,13 +803,13 @@
 #    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_block: "Een ijsblok"
 #    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_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."
@@ -837,28 +837,28 @@
 #    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"

-#  choose_hero:
-#    choose_hero: "Choose Your Hero"
-#    programming_language: "Programming Language"
-#    programming_language_description: "Which programming language do you want to use?"
-#    default: "Default"
-#    experimental: "Experimental"
-#    python_blurb: "Simple yet powerful, great for beginners and experts."
-#    javascript_blurb: "The language of the web. (Not the same as Java.)"
-#    coffeescript_blurb: "Nicer JavaScript syntax."
-#    lua_blurb: "Game scripting language."
-#    java_blurb: "(Subscriber Only) Android and enterprise."
-#    status: "Status"
-#    weapons: "Weapons"
-#    weapons_warrior: "Swords - Short Range, No Magic"
-#    weapons_ranger: "Crossbows, Guns - Long Range, No Magic"
-#    weapons_wizard: "Wands, Staffs - Long Range, Magic"
-#    attack: "Damage" # Can also translate as "Attack"
-#    health: "Health"
-#    speed: "Speed"
-#    regeneration: "Regeneration"
-#    range: "Range" # As in "attack or visual range"
-#    blocks: "Blocks" # As in "this shield blocks this much damage"
+  choose_hero:
+    choose_hero: "Kies je held"
+    programming_language: "Programmeertaal"
+    programming_language_description: "Welke programmeertaal wil je gebruiken?"
+    default: "Standaardoptie"
+    experimental: "Experimenteel"
+    python_blurb: "Simpel maar krachtig, ideaal voor beginnende programmeurs en experts."
+    javascript_blurb: "De taal van het web. (Niet hetzelfde als Java.)"
+    coffeescript_blurb: "Makkelijkere JavaScript commando's."
+    lua_blurb: "Taal voor het scripten in games."
+    java_blurb: "(Alleen voor abonnementen) Android en enterprise."
+    status: "Status"
+    weapons: "Wapens"
+    weapons_warrior: "Zwaarden - Korte Afstand, Geen Magie"
+    weapons_ranger: "Kruisbogen, Pistolen - Lange Afstand, Geen Magie"
+    weapons_wizard: "Toverstaf, Staf - Lange Afstand, Magie"
+    attack: "Schade" # Can also translate as "Attack"
+    health: "Gezondheid"
+    speed: "Snelheid"
+    regeneration: "Herstel"
+    range: "Afstand" # As in "attack or visual range"
+    blocks: "Stopkracht" # As in "this shield blocks this much damage"
 #    backstab: "Backstab" # As in "this dagger does this much backstab damage"
 #    skills: "Skills"
 #    attack_1: "Deals"
@@ -867,35 +867,35 @@
 #    health_1: "Gains"
 #    health_2: "of listed"
 #    health_3: "armor health."
-#    speed_1: "Moves at"
-#    speed_2: "meters per second."
+    speed_1: "Beweegt met "
+    speed_2: "meters per seconde."
 #    available_for_purchase: "Available for Purchase" # Shows up when you have unlocked, but not purchased, a hero in the hero store
 #    level_to_unlock: "Level to unlock:" # 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: "Only certain heroes can play this level."

-#  skill_docs:
+  skill_docs:
 #    function: "function" # skill types
-#    method: "method"
-#    snippet: "snippet"
-#    number: "number"
+    method: "methode"
+    snippet: "stukje"
+    number: "nummer"
 #    array: "array"
-#    object: "object"
-#    string: "string"
+    object: "object"
+    string: "reeks tekens"
 #    writable: "writable" # Hover over "attack" in Your Skills while playing a level to see most of this
-#    read_only: "read-only"
-#    action: "Action"
+    read_only: "alleen-lezen"
+    action: "Actie"
 #    spell: "Spell"
-#    action_name: "name"
+    action_name: "naam"
 #    action_cooldown: "Takes"
 #    action_specific_cooldown: "Cooldown"
 #    action_damage: "Damage"
 #    action_range: "Range"
 #    action_radius: "Radius"
 #    action_duration: "Duration"
-#    example: "Example"
-#    ex: "ex" # Abbreviation of "example"
-#    current_value: "Current Value"
-#    default_value: "Default value"
+    example: "Voorbeeld"
+    ex: "bijv" # Abbreviation of "example"
+    current_value: "Huidige waarde"
+    default_value: "Standaard waarde"
 #    parameters: "Parameters"
 #    required_parameters: "Required Parameters"
 #    optional_parameters: "Optional Parameters"
@@ -1250,12 +1250,12 @@
     rem_hero: "Verwijder held"
     status: "Status"
     complete_2: "Gereed"
-#    started_2: "Started"
-#    not_started_2: "Not Started"
-#    view_solution: "Click to view solution."
+    started_2: "Begonnen"
+    not_started_2: "Niet Begonnen"
+    view_solution: "Klik om de oplossing te zien."
 #    view_attempt: "Click to view attempt."
 #    latest_achievement: "Latest Achievement"
-#    playtime: "Playtime"
+    playtime: "Speeltijd"
 #    last_played: "Last played"
 #    leagues_explanation: "Play in a league against other clan members in these multiplayer arena instances."
 #    track_concepts1: "Track concepts"
@@ -1263,32 +1263,32 @@
 #    track_concepts2b: "learned by each member"
 #    track_concepts3a: "Track levels completed for each student"
 #    track_concepts3b: "Track levels completed for each member"
-#    track_concepts4a: "See your students'"
-#    track_concepts4b: "See your members'"
-#    track_concepts5: "solutions"
+    track_concepts4a: "Bekijk je leerling zijn/haar"
+    track_concepts4b: "Bekijk je deelnemer zijn/haar"
+    track_concepts5: "oplossingen"
 #    track_concepts6a: "Sort students by name or progress"
 #    track_concepts6b: "Sort members by name or progress"
-#    track_concepts7: "Requires invitation"
-#    track_concepts8: "to join"
+    track_concepts7: "Vereist uitnodiging"
+    track_concepts8: "om deel te nemen"
 #    private_require_sub: "Private clans require a subscription to create or join."

-#  courses:
+  courses:
 #    create_new_class: "Create New Class"
 #    solutions_require_licenses: "Level solutions are available for teachers who have licenses."
 #    unnamed_class: "Unnamed Class"
 #    edit_settings1: "Edit Class Settings"
-#    add_students: "Add Students"
-#    stats: "Statistics"
+    add_students: "Voeg Leerlingen Toe"
+    stats: "Statistieken"
 #    student_email_invite_blurb: "Your students can also use class code <strong>__classCode__</strong> when creating a Student Account, no email required."
 #    total_students: "Total students:"
 #    average_time: "Average level play time:"
 #    total_time: "Total play time:"
 #    average_levels: "Average levels completed:"
 #    total_levels: "Total levels completed:"
-#    students: "Students"
-#    concepts: "Concepts"
-#    play_time: "Play time:"
-#    completed: "Completed:"
+    students: "Studenten"
+    concepts: "Concepten"
+#    play_time: "Speeltijd:"
+    completed: "Afgerond:"
 #    enter_emails: "Separate each email address by a line break or commas"
 #    send_invites: "Invite Students"
 #    number_programming_students: "Number of Programming Students"
@@ -1297,7 +1297,7 @@
 #    enroll_paid: "Enroll Students in Paid Courses"
 #    get_enrollments: "Get More Licenses"
 #    change_language: "Change Course Language"
-#    keep_using: "Keep Using"
+    keep_using: "Blijf Gebruiken"
 #    switch_to: "Switch To"
 #    greetings: "Greetings!"
 #    back_classrooms: "Back to my classrooms"
@@ -1305,7 +1305,7 @@
 #    back_courses: "Back to my courses"
 #    edit_details: "Edit class details"
 #    purchase_enrollments: "Purchase Student Licenses"
-#    remove_student: "remove student"
+    remove_student: "verwijder leerling"
 #    assign: "Assign"
 #    to_assign: "to assign paid courses."
 #    student: "Student"
@@ -1338,12 +1338,12 @@
 #    course_complete: "Course Complete"
 #    play_arena: "Play Arena"
 #    view_project: "View Project"
-#    start: "Start"
+    start: "Start"
 #    last_level: "Last level played"
-#    not_you: "Not you?"
-#    continue_playing: "Continue Playing"
+    not_you: "Ben je dit niet?"
+    continue_playing: "Blijf spelen"
 #    option1_header: "Invite Students by Email"
-#    remove_student1: "Remove Student"
+    remove_student1: "Verwijder Leerling"
 #    are_you_sure: "Are you sure you want to remove this student from this class?"
 #    remove_description1: "Student will lose access to this classroom and assigned classes. Progress and gameplay is NOT lost, and the student can be added back to the classroom at any time."
 #    remove_description2: "The activated paid license will not be returned."
@@ -1473,8 +1473,8 @@
 #    courses: "Course Guides"
 #    enrollments: "Student Licenses"
 #    resources: "Resources"
-#    help: "Help"
-#    language: "Language"
+    help: "Hulp"
+    language: "Taal"
 #    edit_class_settings: "edit class settings"
 #    access_restricted: "Account Update Required"
 #    teacher_account_required: "A teacher account is required to access this content."
@@ -1516,7 +1516,7 @@
 #    concepts_used: "Concepts used by Student:"
 #    concept_checked: "Concept checked:"
 #    completed: "Completed"
-#    practice: "Practice"
+    practice: "Oefen"
 #    started: "Started"
 #    no_progress: "No progress"
 #    not_required: "Not required"


Add color to macro name for global ..., local..., etc

--- grammars/stata.cson
+++ grammars/stata.cson
@@ -129,10 +129,20 @@
     ]
   }
   {
+    'match': '\\b(gl(o|ob|oba|obal)?)\\s+\\b([A-Za-z_][A-Za-z0-9_]{0,31})\\b'
     'captures':
       '1':
         'name': 'storage.modifier.macro.stata'
-    'match': '\\b(gl(o|ob|oba|obal)?|loc(a|al)?|tempvar|tempname|tempfile)\\b'
+      '3':
+        'name': 'entity.name.type.class.stata'
+}
+  {
+    'match': '\\b(loc(a|al)?|tempvar|tempname|tempfile)\\s+\\b([A-Za-z_][A-Za-z0-9_]{0,30})\\b'
+    'captures':
+      '1':
+        'name': 'storage.modifier.macro.stata'
+      '3':
+        'name': 'entity.name.type.class.stata'
   }
   {
     'comment': 'keywords that delimit flow conditionals'
@@ -189,7 +199,7 @@
   {
     'begin': '^\\s*(program)\\s*(de(f|fi|fin|fine)?|di(r)?|drop|l(i|is|ist)?)?\\s+(?=[A-Za-z_][A-Za-z0-9_]*)'
     'beginCaptures':
-      '5':
+      '2':
         'name': 'storage.type.function.stata'
     'end': '(\\()|\\s*($\\n?|#.*$\\n?)'
     'endCaptures':


Update nl-NL.coffee

Update nl-NL.coffee

Another set of tweaks and updates

--- app/locale/nl-NL.coffee
+++ app/locale/nl-NL.coffee
@@ -26,14 +26,14 @@
     learn_more: "Lees verder"
     classroom_in_a_box: "Een kant-en-klare digitale klas voor programmeerlessen."
     codecombat_is: "CodeCombat is een platform waarmee leerlingen leren programmeren door het spelen van een spel."
-    our_courses: "Onze lessen zijn specifiek ontwikkeld om uit te springen in een klas-opzet, zelfs voor leraren met geen ervaring met programmeren."
+    our_courses: "Onze lessen zijn specifiek ontwikkeld voor een klasomgeving, zelfs voor leraren zonder programmeerervaring."
     designed_with: "Gemaakt voor leraren"
     real_code: "Echte, getypde code"
     from_the_first_level: "vanaf het eerste level"
     getting_students: "Leerlingen zo snel mogelijk echte code laten schrijven is noodzakelijk voor het leren van programmeer syntax en correcte structuur."
     educator_resources: "Hulpmiddelen voor docenten"
     course_guides: "en lesbrieven"
-    teaching_computer_science: "Je hebt geen diploma infomatica nodig om te kunnen programmeren, wij verschaffen de materialen waarmee elke docent programmeerles kan geven."
+    teaching_computer_science: "Je hebt geen infomatica diploma nodig om te kunnen programmeren, wij verschaffen de materialen waarmee elke docent programmeerles kan geven."
     accessible_to: "Bereikbaar voor"
     everyone: "iedereen"
     democratizing: "Programmeerles toegankelijk maken is onze filosofie. Iedereen moet de kans krijgen om te leren programmeren."
@@ -607,18 +607,18 @@
     editor_config_behaviors_description: "Automatisch aanvullen van (gekrulde) haakjes en aanhalingstekens."

   about:
-#    main_title: "If you want to learn to program, you need to write (a lot of) code."
-#    main_description: "At CodeCombat, our job is to make sure you're doing that with a smile on your face."
-#    mission_link: "Mission"
-#    team_link: "Team"
-#    community_link: "Community"
-#    story_link: "Story"
-#    careers_link: "Careers"
-#    press_link: "Press"
-#    mission_title: "Our mission: make programming accessible to every student on Earth."
-#    mission_description_1: "Programming is magic. It's the ability to create things from pure imagination. We started CodeCombat to give learners the feeling of wizardly power at their fingertips by using typed code." # {change}
+    main_title: "Als je wilt leren programmeren, zul je (heel veel) code moeten schrijven."
+    main_description: "Bij CodeCombat, zien we het als onze taak dat je dit doet met een lach op je gezicht."
+    mission_link: "Missie"
+    team_link: "Team"
+    community_link: "Community"
+    story_link: "Ons verhaal"
+    careers_link: "Carrière"
+    press_link: "Media"
+    mission_title: "Onze missie: programmeerles toegankelijk maken voor iedere leerling op aarde."
+    mission_description_1: "Programmeren is magisch. Het stelt je in staat jouw fantasie om te zetten in wonderlijke creaties. We zijn CodeCombat gestart om leerlingen het gevoel te geven dat ze magische krachten bezitten in de puntjes van hun vingers typed code." # {change}
 #    mission_description_2: "As it turns out, that enables them to learn faster too. WAY faster. It's like having a conversation instead of reading a manual. We want to bring that conversation to every school and to every student, because everyone should have the chance to learn the magic of programming." # {change}
-#    team_title: "Meet the CodeCombat team"
+    team_title: "Over ons"
 #    team_values: "We value open and respectful dialog, where the best idea wins. Our decisions are grounded in customer research and our process is focused on delivering tangible results for them. Everyone is hands-on, from our CEO to our Github contributors, because we value growth and learning in our team."
     nick_title: "Programmeur" # {change}
     nick_blurb: "Motivatie Goeroe"
@@ -652,44 +652,44 @@
 #    number_contributors: "Over 450 contributors have lent their support and time to this project."
 #    story_title: "Our story so far"
 #    story_subtitle: "Since 2013, CodeCombat has grown from a mere set of sketches to a living, thriving game."
-#    story_statistic_1a: "5,000,000+"
+    story_statistic_1a: "5,000,000+"
 #    story_statistic_1b: "total players"
 #    story_statistic_1c: "have started their programming journey through CodeCombat"
 #    story_statistic_2a: "We’ve been translated into over 50 languages — our players hail from"
 #    story_statistic_2b: "200+ countries"
 #    story_statistic_3a: "Together, they have written"
-#    story_statistic_3b: "1 billion lines of code and counting"
+    story_statistic_3b: "1 miljard regels code en de teller loopt door"
 #    story_statistic_3c: "across six different programming languages"
 #    story_long_way_1: "Though we've come a long way..."
 #    story_sketch_caption: "Nick's very first sketch depicting a programming game in action."
 #    story_long_way_2: "we still have much to do before we complete our quest, so..."
 #    jobs_title: "Come work with us and help write CodeCombat history!"
 #    jobs_subtitle: "Don't see a good fit but interested in keeping in touch? See our \"Create Your Own\" listing."
-#    jobs_benefits: "Employee Benefits"
+    jobs_benefits: "Arbeidsvoorwaarden"
 #    jobs_benefit_1: "Competitive salary and options"
 #    jobs_benefit_2: "15 day minimum vacation policy, excluding company holidays"
 #    jobs_benefit_3: "Work from home flexibility"
 #    jobs_benefit_4: "Unlimited sick/personal days"
 #    jobs_benefit_5: "Professional development and continuing education support"
 #    jobs_benefit_6: "Medical/dental/vision insurance"
-#    learn_more: "Learn More"
+    learn_more: "Lees verder"
 #    jobs_custom_title: "Create Your Own"
 #    jobs_custom_description: "Are you passionate about CodeCombat but don't see a job listed that matches your qualifications? Write us and show how you think you can contribute to our team. We'd love to hear from you!"
 #    jobs_custom_contact_1: "Send us a note at"
 #    jobs_custom_contact_2: "introducing yourself and we might get in touch in the future!"
-#    contact_title: "Press & Contact"
-#    contact_subtitle: "Need more information? Get in touch with us at"
-#    screenshots_title: "Game Screenshots"
-#    screenshots_hint: "(click to view full size)"
-#    downloads_title: "Download Assets & Information"
-#    about_codecombat: "About CodeCombat"
-#    logo: "Logo"
-#    screenshots: "Screenshots"
+    contact_title: "Media & Contact"
+    contact_subtitle: "Zoek je meer informatie? Neem contact met ons op!"
+    screenshots_title: "Game Screenshots"
+    screenshots_hint: "(klik voor grote versie)"
+    downloads_title: "Download Pakketten & Informatie"
+    about_codecombat: "Over CodeCombat"
+    logo: "Logo"
+    screenshots: "Screenshots"
 #    character_art: "Character Art"
-#    download_all: "Download All"
-#    previous: "Previous"
-#    next: "Next"
-#    location_title: "We're located in downtown SF:"
+    download_all: "Download Alles"
+    previous: "Vorige"
+    next: "Volgende"
+    location_title: "We zijn gevestigd in SF:"

   teachers:
     who_for_title: "Voor wie is CodeCombat?"
@@ -705,19 +705,19 @@
 #    title: "Request a Quote"
 #    subtitle: "Get CodeCombat in your classroom, club, school or district!"
 #    email_exists: "User exists with this email."
-#    phone_number: "Phone number"
+    phone_number: "Telefoonnummer"
 #    phone_number_help: "Where can we reach you during the workday?"
-#    role_label: "Your role"
+    role_label: "Jouw rol"
 #    role_help: "Select your primary role."
 #    tech_coordinator: "Technology coordinator"
-#    advisor: "Advisor"
-#    principal: "Principal"
+    advisor: "Adviseur"
+    principal: "Schoolhoofd"
 #    superintendent: "Superintendent"
-#    parent: "Parent"
-#    organization_label: "Name of School/District"
-#    city: "City"
-#    state: "State"
-#    country: "Country"
+    parent: "Ouder/verzorger"
+    organization_label: "Schoolnaam"
+    city: "Stad"
+    state: "Provincie"
+    country: "Land"
 #    num_students_help: "How many do you anticipate enrolling in CodeCombat?"
 #    education_level_label: "Education Level of Students"
 #    education_level_help: "Choose as many as apply."
@@ -1151,7 +1151,7 @@
     ambassador_title: "Ambassadeur"
     ambassador_title_description: "(Ondersteuning)"
     ambassador_summary: "Bewaar de vrede op onze forums en help mensen met vragen. Onze ambassadeurs helpen CodeCombat te presenteren aan de buitenwereld."
-#    teacher_title: "Teacher"
+    teacher_title: "Leraar"

   editor:
     main_title: "CodeCombat Editors"
@@ -1517,7 +1517,7 @@
     strings: "Strings"
     variables: "Variabelen"
     vectors: "Vectoren"
-#    while_loops: "While Loops"
+    while_loops: "While Loops"
     recursion: "Recursie"

   delta:


init disposable IPFS executable

init disposable IPFS executable

--- test/integration/ipfs_tests.coffee
+++ test/integration/ipfs_tests.coffee
@@ -38,7 +38,7 @@

   it 'can fetch an IPFS tree', ->
     @timeout 30000
-    # result = run "ipfs init", quiet: true, relaxed: true
+    result = run "#{ipfsNode.exec} init", relaxed: true #quiet: true,
     result = run "#{ipfsNode.exec} add -r -q #{path.join __dirname, '../fixtures/a'} | tail -n 1"#, quiet: true
     hash = result.output.trim()
     adaptor.fetch rootNodeId: hash


cleaned spaces

cleaned spaces


fix navigation bug with right left and stacked slides

--- lib/app.core.coffee
+++ lib/app.core.coffee
@@ -25,9 +25,9 @@
   if not fromSlide
     fromSlide = slideDeck.slides[0]

-  tryHorVerMove = (idxs, fallbackIdxs) ->
+  tryHorVerMove = (idxs) ->
     newslide = slideDeck.get(_.extend({h: fromSlide.h, v: fromSlide.v}, idxs))
-    newslide or (fallbackIdxs and tryHorVerMove(fallbackIdxs)) or  fromSlide
+    newslide or fromSlide

   fs = fromSlide
   switch direction
@@ -40,9 +40,9 @@
     when "down"
       tryHorVerMove(v: fs.v + 1)
     when "left"
-      tryHorVerMove({h: fs.h - 1}, {h: fs.h - 1, v: 0})
+      tryHorVerMove({h: fs.h - 1, v: 0})
     when "right"
-      tryHorVerMove({h: fs.h + 1}, {h: fs.h + 1, v: 0})
+      tryHorVerMove({h: fs.h + 1, v: 0})

 ################################################################################
 EVENTS =
@@ -91,8 +91,7 @@
   paused: false

 EventHandlers =
-  AskQuestion: (state, ev) ->
-     state
+  AskQuestion: (state, ev) -> state
   ToggleOverview: (state, ev) ->
     mode: toggle(state.mode, [Modes.overview, Modes.normal])


typos caught by ES6 work

typos caught by ES6 work

--- lib/compiler.coffee
+++ lib/compiler.coffee
@@ -78,6 +78,8 @@

 { ExitableScope, TryExitableScope, SwitchExitableScope, LoopExitableScope } = require 'exitable-scope'

+{ reportError } = require 'errors'
+
 types = require 'types'
 consts = require 'consts'
 runtime = require 'runtime'
@@ -1365,11 +1367,11 @@
                         #key = if property.key.type is Identifier then @getAtom property.key.name else @visit property.key

                         if propkey.type is ComputedPropertyKey
-                                propkey = @visit property.key.expression
+                                propkey = @visit propkey.expression
                         else if propkey.type is Literal
-                                propkey = @getAtom String(property.key.value)
+                                propkey = @getAtom String(propkey.value)
                         else if propkey.type is Identifier
-                                propkey = @getAtom property.key.name
+                                propkey = @getAtom propkey.name

                         if prop_map.has("init")
                                 val = @visit(prop_map.get("init").value)
@@ -1777,8 +1779,8 @@
                         ir.setInsertPoint saved_insert_point
                         rv = @createLoad arguments_alloca, "load_arguments"
                         return rv
-
-                throw new Error "identifier not found: #{exp.arguments[0].name}"
+
+                reportError(ReferenceError, "identifier not found: #{exp.arguments[0].name}", @filename, exp.arguments[0].loc)

         handleSetLocal: (exp, opencode) ->
                 dest = @findIdentifierInScope exp.arguments[0].name


Ratio fix. Closed #52

Ratio fix. Closed #52

--- app/routes/index.coffee
+++ app/routes/index.coffee
@@ -5,6 +5,9 @@
 IndexRoute = Ember.Route.extend AuthenticatedRouteMixin,

   setupController: (controller)->
+    if controller.get 'ratio'
+      # Return if the ratio is already assigned.
+      return
     ratio = @store.push 'ratio',
       id: 1
       affected: 0


Improve search

Improve search

--- app/views/search.coffee
+++ app/views/search.coffee
@@ -6,12 +6,10 @@
     @searchResults = new SearchResults

   events:
-    'keypress .search-query' : 'searchCollection'
-    'blur' : 'stopSearch'
+    'keyup .search-query' : 'searchCollection'
+    'blur .search-query' : 'stopSearch'

-  render: (query) =>
-    projectResults = @projectCollection.filter (project) ->
-      not _.isEmpty(project.get('name').match query)
+  render: (projectResults) =>
     @$el.append @searchResults.render(projectResults).el
     @

@@ -19,12 +17,13 @@
     if e.which is 13
       @stopSearch e
     else
-      query = @$('.search-query').val()
-      @render new RegExp query
+      query = new RegExp e.currentTarget.value
+      results = @projectCollection.filter (project) ->
+        not _.isEmpty(project.get('name').toLowerCase().match query)
+      @render(results)

   stopSearch: (e) =>
     if e.type is 'focusout' or e.which is 13
-      @searchResults.remove()
-
+      setTimeout @searchResults.remove, 10

 module.exports = Search


Don't bother removing temp jar. Output to /tmp/.

--- lib/grammars.coffee
+++ lib/grammars.coffee
@@ -141,13 +141,13 @@
         code = context.getCode(true)
         tmpFile = GrammarUtils.createTempFileWithCode(code, ".kt")
         jarName = tmpFile.replace /\.kt$/, ".jar"
-        args = ['-c', "kotlinc #{tmpFile} -include-runtime -d #{jarName} && java -jar #{jarName} && rm #{jarName}"]
+        args = ['-c', "kotlinc #{tmpFile} -include-runtime -d #{jarName} && java -jar #{jarName}"]
         return args
     "File Based":
       command: "bash"
       args: (context) ->
         jarName = context.filename.replace /\.kt$/, ".jar"
-        args = ['-c', "kotlinc #{context.filepath} -include-runtime -d #{jarName} && java -jar #{jarName} && rm #{jarName}"]
+        args = ['-c', "kotlinc #{context.filepath} -include-runtime -d /tmp/#{jarName} && java -jar /tmp/#{jarName}"]
         return args

   LilyPond:


Fixing startup error described in #5 related with problems with Mercurial binary path.

--- lib/hg-utils.coffee
+++ lib/hg-utils.coffee
@@ -245,7 +245,13 @@
       params = [params]
     child = spawnSync('hg', params)
     if child.status != 0
-      throw new Error(child.stderr.toString())
+      if child.stderr
+        throw new Error(child.stderr.toString())
+
+      if child.stdout
+        throw new Error(child.stdout.toString())
+
+      throw new Error('Erro trying to execute Mercurial binary with params \'' + params + '\'')
     return child.stdout.toString()

   handleHgError: (error) ->


fix typo

fix typo

--- src/renderer.coffee
+++ src/renderer.coffee
@@ -9,7 +9,7 @@
       'html' : { 'height': '100%' }
       'body': {
         'cursor': 'text'
-        'font-family': "'Helvetica', 'Arial', san-serif"
+        'font-family': "'Helvetica', 'Arial', sans-serif"
         'font-size': '13px'
         'height': '100%'
         'line-height': '1.154'


Fix long-standing bug that messed with permissions until server restart

Cause was a wild-group query like `/*/search/hello` from a non-logged-in
user (so no username set).  This caused accidental clobbering of
`naturallyVisibleQuery`.  Turned the latter into a function to make sure
this can't happen in the future.

--- lib/messages.coffee
+++ lib/messages.coffee
@@ -66,7 +66,8 @@
   recurse message
   descendants

-naturallyVisibleQuery =
+## Recompute this every time to make sure no one modifies it.
+naturallyVisibleQuery = ->
   published: $ne: false    ## published is false or Date
   deleted: $ne: true
   private: $ne: true
@@ -77,7 +78,7 @@
     if user?.username
       re = atRe user
       $or: [
-        naturallyVisibleQuery
+        naturallyVisibleQuery()
       ,
         "authors.#{escapeUser user.username}": $exists: true
       ,
@@ -86,7 +87,7 @@
         body: re
       ]
     else
-      naturallyVisibleQuery
+      naturallyVisibleQuery()
   ## Wild group case effectively unions over all groups
   ## (duplicating logic below when it helps make shorter queries).
   if group == wildGroup


Refactored the code

Refactored the code

--- lib/provider.coffee
+++ lib/provider.coffee
@@ -5,19 +5,18 @@
   selector: '.source.js, .source.coffee'
   suggestionPriority: -1
   filterSuggestions: true
+  completions: {}

   loadCompletions: ->
-    @completions = {class: [], property: [], method: []}
     fs.readFile(
       path.resolve(__dirname, '..', 'completions.json'),
       (err, data) => @completions = JSON.parse(data) unless err?)

   getSuggestions: ({prefix}) ->
     return [] if prefix.length < 3
-    class_names = @makeSuggestions('class', prefix)
-    property_names = @makeSuggestions('property', prefix)
-    method_names = @makeSuggestions('method', prefix)
-    class_names.concat(property_names, method_names)

-  makeSuggestions: (type, prefix) ->
-    ({type: type, text: name} for name in @completions[type])
+    completions = []
+    for type, names of @completions
+      for name in names
+        completions.push({type: type, text: name})
+    completions


Add first version of library with comments, ported from Javascript in existing project.

--- lib/reporter.coffee
+++ lib/reporter.coffee
@@ -0,0 +1,163 @@
+###
+  @class
+
+  Simple reporter for Jasmine. Using Notification API from Chrome/Chromium browser,
+  for report results of running specs.
+
+  @author Alexey Plutalov <demiazz.py@gmail.com>
+  @since Jasmine Webkit Reporter 0.1
+###
+class jasmine.WebkitReporter extends jasmine.Reporter
+
+  ###
+    Title using for header of notification. May used for identify specs.
+
+    @type {String}
+    @default "jasmine"
+  ###
+  title: "Jasmine"
+
+  ###
+    This is ID used for replacing notifications with this ID, when creating new
+    notification.
+
+    @type {String}
+    @default "jasmine"
+
+    @see Notification API Draft
+  ###
+  replaceId: "jasmine"
+
+  ###
+    Timeout used for set timeout before notification be autoclosed. If timeout
+    is equal 0, then notification not be autoclosed.
+
+    @type {Integer}
+    @default 0
+  ###
+  timeout: 0
+
+  ###
+    Passed icon is a icon for notification, when all specs are passed.
+
+    @type {String}
+    @default ""
+  ###
+  passedIcon: ""
+
+  ###
+    Failed icon is a icon for notification, when at least one spec are failed.
+
+    @type {String}
+    @default ""
+  ###
+  failedIcon: ""
+
+  ###
+    Running icons is a icon for notification, while specs running.
+
+    @type {String}
+    @default ""
+  ###
+  runningIcon: ""
+
+  ###
+    WebkitReporter constructor.
+
+    Options:
+      * title
+      * replaceId
+      * timeout
+      * passedIcon
+      * failedIcon
+      * runningIcon
+
+    @param {Object|null} options - options for reporter
+  ###
+  constructor: (options = {}) ->
+    if options
+      @title = options.title              if options.title
+      @replaceId = options.replaceId      if options.replaceId
+      @timeout = options.timeout          if options.timeout
+      @passedIcon = options.passedIcon    if options.passedIcon
+      @failedIcon = options.failedIcon    if options.failedIcon
+      @runningIcon = options.runningIcon  if options.runningIcon
+    @startedAt =  null
+    @finishedAt = null
+    return
+
+  ###
+    Callback for jasmine.Runner, when Runner starting.
+
+    If notification permission is not allowed then request permission
+    instead show notification.
+
+    @param {jasmine.Runner} runner jasmine.Runner for reporting.
+  ###
+  reportRunnerStarting: (runner) ->
+    if jasmine.getGlobal().webkitNotifications.checkPermission() == 0
+      @startedAt = new Date()
+      @finishedAt = null
+      if @title and @title.length > 0
+        title = "#{@title}: RUNNING"
+      else
+        title = "RUNNING"
+      @showReport @runningIcon, title, "Running specs. Please wait..."
+    else
+      jasmine.getGlobal().webkitNotifications.requestPermission()
+    return
+
+  ###
+    Callback for jasmine.Runner, when Runner finished.
+
+    If notification permission is not allowed then request permission
+    instead show notification.
+
+    @param {jasmine.Runner} runner jasmine.Runner for reporting.
+  ###
+  reportRunnerResults: (runner) ->
+    @finishedAt = new Date()
+
+    if jasmine.getGlobal().webkitNotifications.checkPermission() == 0
+      icon = ""
+      title = ""
+      message = ""
+
+      time = (@finishedAt.getTime() - @startedAt.getTime()) / 1000
+      title = @title + ": " if @title and @title.length > 0
+
+      results = runner.results()
+
+      if results.failedCount > 0
+        icon = @failedIcon
+        title += "FAILED"
+      else
+        icon = @passedIcon
+        title += "PASSED"
+
+      message += "#{results.totalCount} spec#{if results.totalCount == 1 then "" else "s"}"
+      message += ", #{results.failedCount} failure#{ if results.failedCount == 1 then "" else "s"}"
+      message += " in #{time}s"
+
+      @showReport icon, title, message
+    else
+      jasmine.getGlobal().webkitNotifications.requestPermission()
+    return
+
+  ###
+    Show notification by Notification API. Set timeout for autoclose if exist.
+
+    @param {String} icon - icon for notification
+    @param {String} title - title for notification
+    @param {String} message - message for notification
+  ###
+  showReport: (icon, title, message) ->
+    notification = jasmine.getGlobal().webkitNotifications.createNotification(icon, title, message)
+    notification.replaceId = @replaceId
+    notification.show()
+    if @timeout > 0
+      setTimeout () ->
+        notification.cancel()
+        return
+      , @timeout
+    return


Add MediaConnection for audio/video

Add MediaConnection for audio/video

--- app/static/scripts/connections.coffee
+++ app/static/scripts/connections.coffee
@@ -52,30 +52,63 @@
         @pjs.on 'connection', @onConnection

     onConnection    : (conn) =>
-        peer = new PC conn, @emitter
-
-    connect         : (peerUid) =>
-        conn = @pjs.connect peerUid
-        peer = new PC conn, @emitter
-
-class PC
+        @createDataConnection conn
+
+    connect         : (uid) =>
+        conn = @pjs.connect uid
+        @createDataConnection conn
+
+    createDataConnection    : (conn) =>
+        dc = new DC conn, @emitter
+        @emitter.trigger 'peer.dataconnection', { dc: dc }
+
+    onCall          : (call) =>
+        @createMediaConnection call
+
+    call            : (uid, stream) =>
+        call = @pjs.call uid, stream
+        @createMediaConnection call
+
+    createMediaConnection   : (call) =>
+        mc = new MC call, @emitter
+        @emitter.trigger 'peer.mediaconnection', { mc: mc }
+
+class DC
     constructor : (@conn, @emitter) ->
         @conn.on 'open', @onOpen
         @conn.on 'data', @onData
+        @conn.on 'close', @onClose
+        @conn.on 'error', errorHandler

     onOpen      : () =>
-        @send 'peer.uid', {}

     onData      : (data) =>
-        if data.type is 'peer.uid'
-            data.peer = @
         @emitter.trigger data.type, data
+
+    onClose     : () =>

     send        : (type, data) =>
         @conn.send { type: type, data: data }

     close       : () =>
         do @conn.close
+
+class MC
+    constructor : (@call, @emitter) ->
+        @call.on 'stream', @onStream
+        @call.on 'close', @onClose
+        @call.on 'error', errorHandler
+
+    onStream    : (stream) =>
+        data =
+            video   : createVideoTag stream
+            uid     : @call.peer
+        @emitter.trigger 'stream.create', data
+
+    onClose     : () =>
+
+    sendStream   : (stream) =>
+        @call.answer stream

 class Connections
     constructor : (@emitter, @uid, @rid, @wsPortal, @pjsPortal) ->
@@ -129,9 +162,15 @@
         @emitter.on 'peer.list', (event, data) =>
             for peer in data.peers
                 @pjs.connect peer.id
-        @emitter.on 'peer.uid', (event, data) =>
-            @peers[data.peer.peer] = data.peer
-            @sendStreamState data.peer.peer
+        @emitter.on 'peer.dataconnection', (event, data) =>
+            if !@peers[data.pc.peer]?
+                @peers[data.pc.peer] = {}
+            @peers[data.pc.peer].pc = data.pc
+            @sendStreamState data.pc.peer
+        @emitter.on 'peer.mediaconnection', (event, data) =>
+            if !@peers[data.mc.peer]?
+                @peers[data.mc.peer] = {}
+            @peers[data.mc.peer].mc = data.mc
         @emitter.on 'peer.remove', (event, data) =>
             if @peers[data.id]?
                 @removePeer data.id


Added a generic wulin form library to ajaxify forms and handle notifications as well as form disable / enable, etc.


Fix gradient calculation

Fix gradient calculation


style: Follow the GNU options convention

--- test/integration/cli/cli-test.coffee
+++ test/integration/cli/cli-test.coffee
@@ -521,7 +521,7 @@
         # the "pass" and the ":"
         assert.include runtimeInfo.dredd.stdout, 'pass:'

-    describe 'when suppressing color with --color false', ->
+    describe 'when suppressing color with --color=false', ->
       runtimeInfo = undefined

       before (done) ->
@@ -532,8 +532,7 @@
         args = [
           './test/fixtures/single-get.apib'
           "http://127.0.0.1:#{DEFAULT_SERVER_PORT}"
-          '--color'
-          'false'
+          '--color=false'
         ]
         runDreddCommandWithServer(args, app, (err, info) ->
           runtimeInfo = info


fix(cibuild): unlinkSync => rmdirSync

fix(cibuild): unlinkSync => rmdirSync

--- build/tasks/build-task.coffee
+++ build/tasks/build-task.coffee
@@ -174,7 +174,7 @@
     apmPackageDir = path.join(apmInstallDir, 'node_modules', 'atom-package-manager')
     for name in fs.readdirSync(apmPackageDir)
       fs.renameSync path.join(apmPackageDir, name), path.join(apmInstallDir, name)
-    fs.unlinkSync(apmPackageDir)
+    fs.rmdirSync(apmPackageDir)

     if process.platform is 'darwin'
       grunt.file.recurse path.join('build', 'resources', 'mac'), (sourcePath, rootDirectory, subDirectory='', filename) ->


JContextMenu: add missin 'require' JContextMenuTreeViewController

--- src/components/contextmenu/contextmenu.coffee
+++ src/components/contextmenu/contextmenu.coffee
@@ -1,6 +1,6 @@
 KDView                         = require './../../core/view.coffee'
 KDCustomHTMLView               = require './../../core/customhtmlview.coffee'
-JContextMenuTreeViewController = './contextmenutreeviewcontroller.coffee'
+JContextMenuTreeViewController = require './contextmenutreeviewcontroller.coffee'

 module.exports = class JContextMenu extends KDView


Fix issue where random users are being added to groups

--- interactive/app/controllers/interactive/group.coffee
+++ interactive/app/controllers/interactive/group.coffee
@@ -134,16 +134,22 @@
     emails = @emails.val()
     hideTalk = @hideTalk.is ':checked'

-    if emails.search(", ") isnt -1
-      emails = emails.split ', '
+    unless emails is ""
+      if emails.search(", ") isnt -1
+        emails = emails.split ', '
+      else
+        emails = emails.split ','
+      console.log emails
+
+      if @groupId
+        UserGroup.inviteUsers @groupId, emails unless _.isEmpty emails
+      else
+        newGroup = UserGroup.newGroup name, hideTalk
+        newGroup.onSuccess (result) ->
+          UserGroup.inviteUsers result.id, emails unless _.isEmpty emails
+    else if not @groupId
+      UserGroup.newGroup name, hidetalk
     else
-      emails = emails.split ','
-
-    if @groupId
-      UserGroup.inviteUsers @groupId, emails
-    else
-      newGroup = UserGroup.newGroup name, hideTalk
-      newGroup.onSuccess (result) ->
-        UserGroup.inviteUsers result.id, emails
+      @submitButton.removeAttr 'disabled'

 module.exports = Group


discussions now using regular comments, let's expand on that

--- server/app/bongo/models/messages/discussion.coffee
+++ server/app/bongo/models/messages/discussion.coffee
@@ -1,32 +1,3 @@
-# JDiscussion
-#  |_ JDiscussionReply*
-#      |_ JComment*
-
-class JDiscussionReply extends JComment
-  {secure} = require 'bongo'
-  @share()
-  @set
-  	relationships     :
-  	  comment         : JComment
-  	  participant     :
-  	    targetType    : JAccount
-  	    as            : ['author','commenter']
-  	  likedBy         :
-  	    targetType    : JAccount
-  	    as            : 'like'
-  	  repliesActivity :
-  	    targetType    : CRepliesActivity
-  	    as            : 'repliesActivity'
-  	  tag             :
-  	    targetType    : JTag
-  	    as            : 'tag'
-  	  follower        :
-  	    as            : 'follower'
-  	    targetType    : JAccount
-
-
-# dont forget about garbage collection when a reply gets deleted
-
 class JDiscussion extends JPost

   {secure} = require 'bongo'
@@ -39,7 +10,7 @@
     sharedMethods : JPost.sharedMethods
     schema        : JPost.schema
     relationships     :
-      comment         : JDiscussionReply
+      comment         : JComment
       participant     :
         targetType    : JAccount
         as            : ['author','commenter']
@@ -71,11 +42,8 @@
       meta    : data.meta
     JPost::modify.call @, client, discussion, callback

-  reply : secure (client, data, callback)->
-    log "reply data is ", data
-    discussion =
-      body: data
-    JReply::reply.call @, client, discussion, callback
+  reply: secure (client, comment, callback)->
+    JPost::reply.call @, client, JComment, comment, callback

 class CDiscussionActivity extends CActivity
   @share()


FileUpload: "getName" returns webkitRelativePath if available.

This is helpful for directory uploads.

--- src/elements/FileUpload/FileUploadFile.coffee
+++ src/elements/FileUpload/FileUploadFile.coffee
@@ -74,7 +74,7 @@
 		@_batch

 	getName: ->
-		@_file.name
+		@_file.webkitRelativePath or @_file.name

 	getStatus: ->
 		@__progress.status


remove kue

remove kue

--- npmfile.coffee
+++ npmfile.coffee
@@ -2,5 +2,4 @@
 require 'nodemailer'
 require 'imap'
 require 'mailparser'
-require 'kue'
 require 'mimelib'


Add a couple animations to defaultActions while game-dev lazy rendering isn't working

--- app/models/ThangType.coffee
+++ app/models/ThangType.coffee
@@ -38,7 +38,7 @@
   urlRoot: '/db/thang.type'
   building: {}
   editableByArtisans: true
-  @defaultActions: ['idle', 'die', 'move', 'attack']
+  @defaultActions: ['idle', 'die', 'move', 'attack', 'trick', 'cast']

   initialize: ->
     super()


fixing #160

fixing #160

--- src/Bacon.coffee
+++ src/Bacon.coffee
@@ -449,6 +449,8 @@
     acc = toOption(seed)
     subscribe = (sink) =>
       initSent = false
+      unsub = nop
+      reply = Bacon.more
       sendInit = ->
         if !initSent
           initSent = true
@@ -467,8 +469,8 @@
             sink (event.apply(_.always(acc.get())))
         else
           if event.isEnd()
-            sendInit()
-          sink event
+            reply = sendInit()
+          sink event unless reply == Bacon.noMore
       sendInit()
       unsub
     new Property(subscribe)


Add blueprint model.

Add blueprint model.

--- app/models/extension.coffee
+++ app/models/extension.coffee
@@ -1,14 +1,13 @@
 Extension = DS.Model.extend
   name: DS.attr 'string'
   slug: DS.attr 'string'
-  #blueprints: DS.hasMany 'blueprint'
+  blueprints: DS.hasMany 'blueprint'

 Extension.reopenClass
   FIXTURES: [
-    { id: 1, name: 'Users', slug: 'users', blueprints: [] }
-    { id: 2, name: 'Pages', slug: 'pages', blueprints: [] }
-    { id: 3, name: 'Store', slug: 'store', blueprints: [] }
+    { id: 1, name: 'Users', slug: 'users', blueprints: [1, 2] }
+    { id: 3, name: 'Store', slug: 'store', blueprints: [3, 4] }
   ]

 `export default Extension`


added shortcut method for right anchor coordinates

--- oriDomi.coffee
+++ oriDomi.coffee
@@ -232,7 +232,7 @@
           panel.style[transformOriginProp] = 'right'
           x = -((@vPanels * @panelWidth) - (@panelWidth * i))
           if i is 1
-            panel.style[transformProp] = @_transform [@panelWidth * (@vPanels - 1), 0]
+            panel.style[transformProp] = @_transform [@_getRightAnchorCoord(), 0]
           else
             panel.style[transformProp] = @_transform [-@panelWidth, 0]

@@ -306,6 +306,10 @@
       @hPanels

+  _getRightAnchorCoord: ->
+    @panelWidth * (@vPanels - 1) - @vPanels + 1
+
+
   _accordionDefaults:
     anchor: 'left'
     sticky: true


reset shading when calling ramp

reset shading when calling ramp

--- oriDomi.coffee
+++ oriDomi.coffee
@@ -535,21 +535,11 @@
     return if !normalized
     [angle, anchor, options] = normalized
     @panels[anchor][1].style[css.transform] = @_transform angle
-    @_callback options
-
-
-
-    if anchor isnt @lastAnchor
-      return @reset =>
-        @_showStage anchor
-        setTimeout =>
-          @ramp angle, options
-        , 0
-
-    @lastAngle = angle = @_normalizeAngle angle
-    rotation = @_getRotation anchor, angle
-
-    @panels[anchor][1].style[css.transform] = @_transform @_getXy(1, anchor), rotation
+    for i in [2...@panels[anchor].length]
+      @panels[anchor][i].style[css.transform] = @_transform 0
+
+      if @shading
+        @_setShader i, anchor, 0

     @_callback options


alias shading: true as shading: 'hard'

alias shading: true as shading: 'hard'

--- oridomi.coffee
+++ oridomi.coffee
@@ -411,6 +411,7 @@
     @_lastOp  = anchor: anchorList[0]
     @_xLast   = @_yLast = 0
     @_shading = @_settings.shading
+    @_shading = 'hard' if @_shading is true

     if @_shading
       @_shaders    = {}


use grab cursor

use grab cursor

--- oridomi.coffee
+++ oridomi.coffee
@@ -746,10 +746,7 @@
   # Gives the element a resize cursor to prompt the user to drag the mouse.
   _setCursor: ->
     if @_touchEnabled
-      if @lastAnchor is 'left' or @lastAnchor is 'right'
-        @stageEl.style.cursor = 'ew-resize'
-      else
-        @stageEl.style.cursor = 'ns-resize'
+      @stageEl.style.cursor = css.grab
     else
       @stageEl.style.cursor = 'default'


mark oridomi override styling as important

--- oridomi.coffee
+++ oridomi.coffee
@@ -248,17 +248,18 @@

   addStyle elClasses.active,
-    backgroundColor: 'transparent'
-    backgroundImage: 'none'
-    boxSizing:       'border-box'
-    border:          'none'
-    outline:         'none'
+    backgroundColor: 'transparent !important'
+    backgroundImage: 'none !important'
+    boxSizing:       'border-box !important'
+    border:          'none !important'
+    outline:         'none !important'
+    padding:         '0 !important'
     position:        'relative'
-    transformStyle:  p3d
+    transformStyle:  p3d + ' !important'

   addStyle elClasses.clone,
-    margin:    '0'
-    boxSizing: 'border-box'
+    margin:    '0 !important'
+    boxSizing: 'border-box !important'

   addStyle elClasses.holder,
     width:          '100%'
@@ -293,12 +294,10 @@
     addStyle elClasses['shader' + capitalize anchor], background: getGradient anchor

   addStyle elClasses.content,
-    width:     '100%'
-    height:    '100%'
-    margin:    '0'
-    position:  'relative'
-    float:     'none'
-    boxSizing: 'border-box'
+    margin:    '0 !important'
+    position:  'relative !important'
+    float:     'none !important'
+    boxSizing: 'border-box !important'

   addStyle elClasses.mask,
     width:     '100%'


Update token link text

Update token link text

--- backend/ide-init.coffee
+++ backend/ide-init.coffee
@@ -48,7 +48,7 @@
   tokenLink.title = 'https://learn.co/ide/token'
   tokenLink.href = 'https://learn.co/ide/token'
   tokenLink.setAttribute 'style', 'text-decoration: underline;'
-  tokenLink.appendChild document.createTextNode 'https://learn.co/ile/token'
+  tokenLink.appendChild document.createTextNode 'https://learn.co/ide/token'
   tokenLinkDiv.appendChild tokenText
   tokenLinkDiv.appendChild tokenLink
   oauthPrompt.appendChild oauthLabel


Add a function to formated file size to 'utils' module

--- app/coffee/utils.coffee
+++ app/coffee/utils.coffee
@@ -105,6 +105,22 @@
 startswith = (str1, str2) ->
     return _.str.startsWith(str1, str2)

+
+sizeFormat = (input, precision=1) ->
+    if isNaN(parseFloat(input)) or not isFinite(input)
+        return "-"
+
+    if input == 0
+        return "0 bytes"
+
+    units = ["bytes", "KB", "MB", "GB", "TB", "PB"]
+    number = Math.floor(Math.log(input) / Math.log(1024))
+    if number > 5
+        number = 5
+    size = (input / Math.pow(1024, number)).toFixed(precision)
+    return  "#{size} #{units[number]}"
+
+
 taiga = @.taiga
 taiga.bindOnce = bindOnce
 taiga.mixOf = mixOf
@@ -120,3 +136,4 @@
 taiga.joinStr = joinStr
 taiga.debounce = debounce
 taiga.startswith = startswith
+taiga.sizeFormat = sizeFormat


Fix snowplow schema calculation.

Fix snowplow schema calculation.

--- app/core/Tracker.coffee
+++ app/core/Tracker.coffee
@@ -131,7 +131,7 @@

     # SnowPlow
     window.snowplow 'trackUnstructEvent',
-      schema: 'iglu:com.codecombat/' + event + '/jsonschema/1-0-0'
+      schema: 'iglu:com.codecombat/' + action + '/jsonschema/1-0-0'
       data: properties


Update nl-NL.coffee (#3829)

Update nl-NL.coffee (#3829)

translated some lines in the signup section.

--- app/locale/nl-NL.coffee
+++ app/locale/nl-NL.coffee
@@ -132,7 +132,7 @@
     help_suff: "en we nemen contact op!"

   modal:
-#    cancel: "Cancel"
+    cancel: "Annuleren"
     close: "Sluiten"
     okay: "Oké"

@@ -256,13 +256,13 @@
     signup_switch: "Wil je een account maken?"

   signup:
-#    create_student_header: "Create Student Account"
-#    create_teacher_header: "Create Teacher Account"
-#    create_individual_header: "Create Individual Account"
-#    create_header: "Create Account"
+    create_student_header: "Creëer studenten account"
+    create_teacher_header: "Creeër leraren account"
+    create_individual_header: "Creeër persoonlijk account"
+    create_header: "Creëer Account"
     email_announcements: "Ontvang aankondigingen via e-mail" # {change}
     creating: "Account aanmaken..."
-#    create_account: "Create Account"
+    create_account: "Creëer account"
     sign_up: "Aanmelden"
     log_in: "inloggen met wachtwoord"
     required: "Je moet inloggen om daarheen te gaan."
@@ -270,7 +270,7 @@
     school_name: "Schoolnaam en stad"
     optional: "optioneel"
     school_name_placeholder: "Voorbeeld middelbare school, Amsterdam"
-#    connect_with: "Connect with:"
+    connect_with: "Verbind met:"
     connected_gplus_header: "Je bent ingelogd met Google+!"
     connected_gplus_p: "Maak je inschrijving compleet zodat je kan inloggen met je Google+ account."
     gplus_exists: "Jouw Google+ account is al gekoppeld!"
@@ -280,35 +280,35 @@
     hey_students: "Leerlingen, voer hier de klassencode van je docent in."
     birthday: "Verjaardag"
 #    parent_email_blurb: "We know you can't wait to learn programming — we're excited too! Your parents will receive an email with further instructions on how to create an account for you. Email {{email_link}} if you have any questions."
-#    classroom_not_found: "No classes exist with this Class Code. Check your spelling or ask your teacher for help."
-#    checking: "Checking..."
-#    account_exists: "This email is already in use:" # {change}
-#    sign_in: "Sign in"
-#    email_good: "Email looks good!"
-#    name_taken: "Username already taken! Try {{suggestedName}}?"
-#    name_available: "Username available!"
-#    name_is_email: "Username may not be an email"
-#    choose_type: "Choose your account type:"
-#    teacher_type_1: "Teach programming using CodeCombat!"
-#    teacher_type_2: "Set up your class"
+    classroom_not_found: "Er zijn geen klassen met deze klassencode. Controleer je spelling of vraag je leraar om hulp."
+    checking: "Controleren..."
+    account_exists: "Dit emailadres bestaat al:" # {change}
+    sign_in: "Log in"
+    email_good: "Email ziet er goed uit!"
+    name_taken: "Gebruikersnaam bestaat al! Probeer {{suggestedName}}?"
+    name_available: "Gebruikersnaam beschikbaar!"
+    name_is_email: "Gebruikersnaam mag geen email zijn"
+    choose_type: "Kies je account type:"
+    teacher_type_1: "Leer ze programmeren met gebruik van CodeCombat!"
+    teacher_type_2: "Maak je klas"
 #    teacher_type_3: "Access Course Guides"
-#    teacher_type_4: "View student progress"
-#    signup_as_teacher: "Sign up as a Teacher"
-#    student_type_1: "Learn to program while playing an engaging game!"
-#    student_type_2: "Play with your class"
-#    student_type_3: "Compete in arenas"
-#    student_type_4: "Choose your hero!"
-#    student_type_5: "Have your Class Code ready!"
-#    signup_as_student: "Sign up as a Student"
-#    individuals_or_parents: "Individuals & Parents"
-#    individual_type: "For players learning to code outside of a class. Parents should sign up for an account here."
-#    signup_as_individual: "Sign up as an Individual"
-#    enter_class_code: "Enter your Class Code"
-#    enter_birthdate: "Enter your birthdate:"
-#    ask_teacher_1: "Ask your teacher for your Class Code."
-#    ask_teacher_2: "Not part of a class? Create an "
-#    ask_teacher_3: "Individual Account"
-#    ask_teacher_4: " instead."
+    teacher_type_4: "Bekijk voortgang studenten"
+    signup_as_teacher: "Registreer als een docent"
+    student_type_1: "Leer programmeren terwijl je een uitdagend spel speelt!"
+    student_type_2: "Speel met je klas"
+    student_type_3: "Strijd in arena's"
+    student_type_4: "Kies je held!"
+    student_type_5: "Heb je klassencode bij de hand!"
+    signup_as_student: "Registreer als een student"
+    individuals_or_parents: "Individueel & Ouders"
+    individual_type: "Voor spelers die leren coderen buiten school. Ouders moeten zich hier aanmelden."
+    signup_as_individual: "Registreer als een individu (persoonlijk)"
+    enter_class_code: "Vul je klassencode in"
+    enter_birthdate: "Vul je geboortedatum in:"
+    ask_teacher_1: "Vraag je leraar om een klassencode."
+    ask_teacher_2: "Maak je geen deel uit een klas? Maak dan een "
+    ask_teacher_3: "Individuele account"
+    ask_teacher_4: "."
 #    about_to_join: "You're about to join:"
 #    enter_parent_email: "Enter your parent’s email address:"
 #    parent_email_error: "Something went wrong when trying to send the email. Check the email address and try again."


Run copy-i18n-tags (#5880)

Run copy-i18n-tags (#5880)

Co-authored-by: CoCo CI <5df1af3d7600b97ee69552caffeccf9dfd29ab8f@codecombat.com>

--- app/locale/rot13.coffee
+++ app/locale/rot13.coffee
@@ -30,7 +30,7 @@
     classroom_in_box_blurb1: "Ratntr rirel fghqrag fb gung gurl oryvrir pbqvat vf sbe gurz."
     classroom_in_box_blurb2: "Rzcbjre nal rqhpngbe gb srry pbasvqrag jura grnpuvat pbqvat."
     classroom_in_box_blurb3: "Vafcver nyy fpubby yrnqref gb perngr n jbeyq-pynff pbzchgre fpvrapr cebtenz."
-    covid19_banner_blurb: "Cneragf, obbx lbhe puvyq'f svefg yvir bayvar pbqvat pynff sbe serr!" # {punatr}
+    covid19_banner_blurb: "Cneragf, obbx lbhe puvyq'f svefg yvir bayvar pbqvat pynff sbe serr!"
     creativity_rigor_title: "Jurer Perngvivgl Zrrgf Evtbe"
     creativity_rigor_subtitle1: "Znxr pbqvat sha naq grnpu erny-jbeyq fxvyyf"
     creativity_rigor_blurb1: "Fghqragf glcr erny Clguba naq WninFpevcg juvyr cynlvat tnzrf gung rapbhentr gevny-naq-reebe, pevgvpny guvaxvat, naq perngvivgl. Fghqragf gura nccyl gur pbqvat fxvyyf gurl’ir yrnearq ol qrirybcvat gurve bja tnzrf naq jrofvgrf va cebwrpg-onfrq pbhefrf."


feat(core) Can now specify config JSON as query param

--- app/scripts/main.coffee
+++ app/scripts/main.coffee
@@ -1,10 +1,19 @@
+
+# why didn't browsers standardize this?
+# http://stackoverflow.com/a/5158301
+getParameterByName = (name) ->
+    match = RegExp('[?&]' + name + '=([^&]*)').exec(window.location.search)
+    match && decodeURIComponent(match[1].replace(/\+/g, ' '))
+
 window.hydrated =
     Models: {}
     Collections: {}
     Views: {}
     Routers: {}
-    init: ->
+    init: (config) ->
         'use strict'
+
+        config = config || '/apps.json'

         apps = new this.Collections.Apps

@@ -13,15 +22,21 @@

         apps.fetch
             cache: false
-            url: '/apps.json'
+            url: config
             success: (collection, response, options) ->
                 $el = appsView.render().$el
                 $('#apps').html $el
                 collection
             error: (collection, response, options) ->
-                console.error "Error in fectching apps.json"
-                alert "There was an error retrieving apps data"
+                msg = "Error fetching config at #{config}"
+                console.error msg
+                alert msg

 $(document).ready ->
     'use strict'
-    hydrated.init();
+
+    # get config JSON url
+    config = getParameterByName("config")
+
+    # init backbone
+    hydrated.init(config);


Add school sites to the loaded data.

Add school sites to the loaded data.

--- app/scripts/main.coffee
+++ app/scripts/main.coffee
@@ -4,4 +4,4 @@
   setView([47.61, -122.33], 13)

 featureLayer = L.mapbox.featureLayer().addTo(map)
-featureLayer.loadURL('http://zillowhack.hud.opendata.arcgis.com/datasets/2a462f6b548e4ab8bfd9b2523a3db4e2_0.geojson?where=FORMAL_PARTICIPANT_NAME%20like%20\'%25Seattle%20Housing%20Authority%25\'&geometry={"xmin":-13644455.898275688,"ymin":6030489.247026406,"xmax":-13589421.237910435,"ymax":6053382.136997785,"spatialReference":{"wkid":102100}}')
+featureLayer.loadURL('/data/school_sites.json')


Fix reference to Wedge in common/base

Fix reference to Wedge in common/base

--- bokehjs/src/coffee/common/base.coffee
+++ bokehjs/src/coffee/common/base.coffee
@@ -203,7 +203,7 @@
     Rect:                     'renderer/glyph/rect'
     Segment:                  'renderer/glyph/segment'
     Text:                     'renderer/glyph/text'
-    Wedget:                   'renderer/glyph/wedge'
+    Wedge:                    'renderer/glyph/wedge'

     Asterisk:                 'renderer/glyph/marker/asterisk'
     CircleCross:              'renderer/glyph/marker/circle_cross'


 Merge branch 'master.notificationMulticast' into 'master'

Master.Notification Multicast

--- workers/emailnotifications/main.coffee
+++ workers/emailnotifications/main.coffee
@@ -172,8 +172,7 @@
         return

       return  unless result
-
-      { state, key, email } = result
+      { state, key } = result
       if not daily and state isnt true
         log 'User disabled e-mails, ignored for now.'
         notification.update $set: status: 'postponed', (err)->
@@ -184,7 +183,10 @@
           return callback err  if err
           # string usually email if sender is not a user
           sender ?= notification.senderEmail
-          details = {sender, receiver, event, email, key, notification}
+          # Since we have retrieved email config in the beginning, email becomes
+          # a global variable. Therefore we have changed the email assignment here
+          details = {sender, receiver, event, key, email: result.email, notification}
+
           if event is 'FollowHappened'
             cb details
           else


Remove unused client file

Remove unused client file

--- apps/user/client.coffee
+++ apps/user/client.coffee
@@ -1,68 +0,0 @@
-#
-# The client-side code for a User Profile
-#
-
-Backbone = require "backbone"
-Backbone.$ = $
-_ = require 'underscore'
-scrollFrame = require 'scroll-frame'
-sd = require("sharify").data
-mediator = require '../../lib/mediator.coffee'
-User = require "../../models/user.coffee"
-UserBlocks = require '../../collections/user_blocks.coffee'
-FollowBlocks = require '../../collections/follow_blocks.coffee'
-InfiniteView = require '../../components/pagination/infinite_view.coffee'
-Filter = require '../../components/filter/index.coffee'
-PathView = require '../../components/path/client/path_view.coffee'
-MetaEditableAttributeView = require '../../components/editable_attribute/client/meta_editable_attribute_view.coffee'
-UserBlockCollectionView = require '../../components/block_collection/client/user_block_collection_view.coffee'
-setupBlockCollection = require '../../components/blocks/container/client/index.coffee'
-
-module.exports.init = ->
-  current_user = mediator.shared.current_user
-  user = new User sd.USER
-
-  unless sd.CURRENT_PATH.indexOf('/index') > -1
-    if sd.FOLLOWING || sd.FOLLOWERS
-      blocks = new FollowBlocks sd.BLOCKS,
-        object_id: sd.USER.id
-        object_type: 'users'
-        suffix: if sd.FOLLOWING then 'ing' else 'ers'
-    else
-      blocks = new UserBlocks sd.BLOCKS,
-        user_slug: sd.USER.slug
-
-      _.extend blocks.options,
-        subject: sd.SUBJECT
-        sort: sd.SORT || ''
-        seed: sd.SEED || ''
-
-    options =
-      model: user
-      $el: $('.profile-contents')
-      collection: blocks
-
-    _.extend(options, { subject: sd.SUBJECT }) if sd.SUBJECT
-    _.extend(options, { sort: sd.SORT }) if sd.SORT
-
-    setupBlockCollection options
-
-    blocks.on 'remove', ->
-      unless ( blocks.any (block) -> block.get('class') is 'Tip' )
-        mediator.shared.current_user.save show_tour: false
-
-  new PathView
-    el: $('section.path--header')
-    model: user
-
-  new MetaEditableAttributeView
-    model: user
-    el: $("#metadata--about .metadata__content")
-    _attribute: 'description'
-    _kind: 'markdown'
-    wait: true
-
-  user.on 'edit:success', ->
-    $.ajax
-      method: 'GET'
-      url: "#{user.href()}/update"


Group projects by basecamp URL

Group projects by basecamp URL

--- src/components/WebService/Basecamp/ReadProject.coffee
+++ src/components/WebService/Basecamp/ReadProject.coffee
@@ -51,10 +51,11 @@

     parseProject: (data) ->
         target = @outPorts.out
+        id = "https://#{@hostname}/projects/"
         parser = new xml2js.Parser
         parser.on "end", (projects) ->
             projects.project.forEach (project) ->
-                target.send project
+                target.send project, id
         parser.parseString data

 exports.getComponent = ->


fix(absolute css urls): in libs and bower_components ensure path is set correctly

--- src/plugins/gulp-absolute-css-urls.coffee
+++ src/plugins/gulp-absolute-css-urls.coffee
@@ -53,7 +53,7 @@
 		# console.log "Base: #{base} | Rel: #{rel}"
 		base        = base.split '/'
 		# console.log base
-		base        = base[base.length-2]
+		base        = base[base.length-1]
 		base        = "/#{base}" # /libs
 		# console.log "Base: #{base}"
 		rel         = rel.split '/'


KodingKontrol:: createKite: listen for close events and invalidate cache

--- client/Main/kite/kodingkontrol.coffee
+++ client/Main/kite/kodingkontrol.coffee
@@ -115,6 +115,9 @@

     kite = KontrolJS::createKite.call this, options

+    kite.on 'close', (event)=>
+      if event?.code is 1002 and event?.reason is "Can't connect to server"
+        KiteCache.unset query

     kite.connect()  if kite.name is 'klient'


Refactored: removed unused code

Refactored: removed unused code

--- client/app/views/todolist_view.coffee
+++ client/app/views/todolist_view.coffee
@@ -10,7 +10,6 @@
     id: "todo-list"
     tagName: "div"
     el: "#todo-list"
-    isEditMode: false

     ### Constructor ####

@@ -47,38 +46,6 @@
     # Listeners
     ###

-    # When add is clicked a new task is added to the top of the task list.
-    # Adding task is done after task was created on the server.
-    onAddClicked: (event) =>
-        task = new Task done: false, description: "new task", list: @model.id
-        task.save null,
-            success: (data) =>
-                data.url = "tasks/#{data.id}/"
-                console.debug data
-                @tasks.add data
-                $(".task:first .description").focus()
-                helpers.selectAll($(".task:first .description"))
-
-                @displayCreationInfos()
-
-            error: ->
-                alert "An error occured while saving data"
-
-    # When edit is clicked, edition widgets are displayed (editions widgets are
-    # better for touch interfaces).
-    onEditClicked: (event) =>
-        if not @isEditMode
-            @.$(".task:not(.done) .task-buttons").show()
-            @newButton.show()
-            @isEditMode = true
-            @showButtonsButton.html "hide buttons"
-        else
-            @.$(".task-buttons").hide()
-            @newButton.hide()
-            @isEditMode = false
-            @showButtonsButton.html "show buttons"
-
-
     ###
     # Functions
     ###
@@ -109,8 +76,6 @@
                     @$(".task:first .description").focus()

                     @displayCreationInfos()
-                else
-                    @onAddClicked() if @model? and @model.id?

                 @$(@tasks.view.el).spin()
             error: =>


add test for decryptSync()

add test for decryptSync()

--- test/encrypt.coffee
+++ test/encrypt.coffee
@@ -384,6 +384,70 @@
 			done()

+describe 'document.decryptSync()', ->
+	simpleTestDoc7 = null
+	before (done) ->
+		simpleTestDoc7 = new BasicEncryptedModel
+			text: 'Unencrypted text'
+			bool: true
+			num: 42
+			date: new Date '2014-05-19T16:39:07.536Z'
+			id2: '5303e65d34e1e80d7a7ce212'
+			arr: ['alpha', 'bravo']
+			mix: { str: 'A string', bool: false }
+			buf: new Buffer 'abcdefg'
+			idx: 'Indexed'
+
+		simpleTestDoc7.encrypt (err) ->
+			assert.equal err, null
+			done()
+
+	after (done) ->
+		simpleTestDoc7.remove (err) ->
+			assert.equal err, null
+			done()
+
+	it 'should return an unencrypted version', (done) ->
+		simpleTestDoc7.decryptSync()
+		assert.propertyVal simpleTestDoc7, 'text', 'Unencrypted text'
+		assert.propertyVal simpleTestDoc7, 'bool', true
+		assert.propertyVal simpleTestDoc7, 'num', 42
+		assert.property simpleTestDoc7, 'date'
+		assert.equal simpleTestDoc7.date.toString(), new Date("2014-05-19T16:39:07.536Z").toString()
+		assert.propertyVal simpleTestDoc7, 'id2', mongoose.Schema.Types.ObjectId '5303e65d34e1e80d7a7ce212'
+		assert.lengthOf simpleTestDoc7.arr, 2
+		assert.equal simpleTestDoc7.arr[0], 'alpha'
+		assert.equal simpleTestDoc7.arr[1], 'bravo'
+		assert.property simpleTestDoc7, 'mix'
+		assert.deepEqual simpleTestDoc7.mix, { str: 'A string', bool: false }
+		assert.property simpleTestDoc7, 'buf'
+		assert.equal simpleTestDoc7.buf.toString(), 'abcdefg'
+		assert.propertyVal simpleTestDoc7, 'idx', 'Indexed'
+		assert.property simpleTestDoc7, '_id'
+		assert.notProperty simpleTestDoc7, '_ct'
+		done()
+
+	it 'should return an unencrypted version even if document already decrypted', (done) ->
+		simpleTestDoc7.decryptSync()
+		assert.propertyVal simpleTestDoc7, 'text', 'Unencrypted text'
+		assert.propertyVal simpleTestDoc7, 'bool', true
+		assert.propertyVal simpleTestDoc7, 'num', 42
+		assert.property simpleTestDoc7, 'date'
+		assert.equal simpleTestDoc7.date.toString(), new Date("2014-05-19T16:39:07.536Z").toString()
+		assert.propertyVal simpleTestDoc7, 'id2', mongoose.Schema.Types.ObjectId '5303e65d34e1e80d7a7ce212'
+		assert.lengthOf simpleTestDoc7.arr, 2
+		assert.equal simpleTestDoc7.arr[0], 'alpha'
+		assert.equal simpleTestDoc7.arr[1], 'bravo'
+		assert.property simpleTestDoc7, 'mix'
+		assert.deepEqual simpleTestDoc7.mix, { str: 'A string', bool: false }
+		assert.property simpleTestDoc7, 'buf'
+		assert.equal simpleTestDoc7.buf.toString(), 'abcdefg'
+		assert.propertyVal simpleTestDoc7, 'idx', 'Indexed'
+		assert.property simpleTestDoc7, '_id'
+		assert.notProperty simpleTestDoc7, '_ct'
+		done()
+
+
 describe '"fields" option', ->
 	it 'should encrypt fields iff they are in the passed in "fields" array even if those fields are indexed', (done) ->
 		EncryptedFieldsModelSchema = mongoose.Schema


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- test/metered.coffee
+++ test/metered.coffee
@@ -10,7 +10,9 @@
 test "should respect 0 being set as the meter attribute", ->
   obj = GameObject
     health: 0
-    maxHealth:
+    maxHealth: 110
+
+  obj.

 test "should set max<Attribute> if it isn't present in the including object", ->
   obj = GameObject


Simplify getPageId

Simplify getPageId

For some reason, page uuids without version numbers were not being
matched. Streamlining the matching process fixed it; probably the
internal id had a version, and we didn’t test that arrangement.

--- src/scripts/models/contents/collection.coffee
+++ src/scripts/models/contents/collection.coffee
@@ -48,14 +48,23 @@
         else
           return node.getPage(num-page)

-    _getPageId: (id) ->
-      for node in @get('contents').models
-        if node is id or node.get('id') is id or node.getVersionedId() is id or
-        node.get('shortId').match(///^#{id}///)
-          return node
-        else if node.isSection()
-          result = node.getPage(id)
-          return result if result
+    allPages: (nodes=@get('contents').models, collection=[]) ->
+      _.each nodes, (node) =>
+        if node.isSection()
+          children = node.get('contents').models
+          @allPages(children, collection)
+        else
+          collection.push(node)
+      collection
+
+    _getPageFromId: (id) ->
+      pages = @allPages()
+      idPattern = ///^#{id}///
+      for page in pages
+        id = page.get('id')
+        if page.get('id').match(idPattern) or
+        page.get('shortId').match(idPattern)
+          return page

       return

@@ -63,7 +72,7 @@
       if typeof page is 'number'
         return @_getPageNum(page)

-      return @_getPageId(page)
+      return @_getPageFromId(page)

     toJSON: (options = {}) ->
       results = super(arguments...)


prevent fail on trying to create a regex from invalid string from being a blocking error

--- src/scripts/models/contents/collection.coffee
+++ src/scripts/models/contents/collection.coffee
@@ -52,7 +52,12 @@

     _getPageFromId: (id) ->
       pages = @allPages()
-      idPattern = ///^#{id}///
+      try
+        idPattern = ///^#{id}///
+      catch error
+        console.warn 'Cannot form valid Regex for _getPageFromId -- ', id
+        return null
+
       for page in pages
         id = page.get('id')
         if page.get('id').match(idPattern) or


upd version

upd version

--- jquery-badyl.coffee
+++ jquery-badyl.coffee
@@ -1,11 +1,11 @@
 ###
 @name jquery-badyl
 @description Meet Badyl – bootstrap affix-like wheel reinvent.
-@version 1.8.0
+@version 1.8.1
 @author Se7enSky studio <info@se7ensky.com>
 ###

-###! jquery-badyl 1.8.0 http://github.com/Se7enSky/jquery-badyl###
+###! jquery-badyl 1.8.1 http://github.com/Se7enSky/jquery-badyl###

 plugin = ($) ->