diff --git a/app/lib/surface/LayerAdapter.coffee b/app/lib/surface/LayerAdapter.coffee
index e867b65eb..b295dcd01 100644
--- a/app/lib/surface/LayerAdapter.coffee
+++ b/app/lib/surface/LayerAdapter.coffee
@@ -42,7 +42,7 @@ module.exports = LayerAdapter = class LayerAdapter extends CocoClass
   buildAutomatically: true
   buildAsync: true
   resolutionFactor: SPRITE_RESOLUTION_FACTOR
-  defaultActions: ['idle', 'die', 'move', 'move', 'attack']
+  defaultActions: ['idle', 'die', 'move', 'attack']
   numThingsLoading: 0
   lanks: null
   spriteSheet: null
@@ -147,9 +147,6 @@ module.exports = LayerAdapter = class LayerAdapter extends CocoClass
   #- Adding, removing children for WebGL layers.
 
   addLank: (lank) ->
-    # TODO: Move this into the production DB rather than setting it dynamically.
-    if lank.thangType?.get('name') is 'Highlight'
-      lank.thangType.set('spriteType', 'segmented')
     lank.options.resolutionFactor = @resolutionFactor
 
     lank.layer = @
diff --git a/app/locale/pt-BR.coffee b/app/locale/pt-BR.coffee
index e00828b4f..26b3a4328 100644
--- a/app/locale/pt-BR.coffee
+++ b/app/locale/pt-BR.coffee
@@ -99,13 +99,13 @@ module.exports = nativeDescription: "Português do Brasil", englishDescription:
     authenticate_gplus: "Autenticar com G+"
     load_profile: "Carregar Perfil do G+"
     finishing: "Terminando"
-    sign_in_with_facebook: "Conectar com Facebook"
-    sign_in_with_gplus: "Conectar com G+"
+    sign_in_with_facebook: "Conectar com o Facebook"
+    sign_in_with_gplus: "Conectar com o G+"
     signup_switch: "Deseja Criar uma Conta?"
 
   signup:
     email_announcements: "Receber notícias por email."
-    creating: "Criando a nova conta..."
+    creating: "Criando uma nova conta..."
     sign_up: "Criar conta"
     log_in: "Entre com a senha"
     social_signup: "Ou, você pode fazer login pelo Facebook ou G+:"
@@ -137,7 +137,7 @@ module.exports = nativeDescription: "Português do Brasil", englishDescription:
     publish: "Publicar"
     create: "Criar"
     manual: "Manual"
-    fork: "Fork"
+    fork: "Fork" # When used as a verb, like "To fork a repository"
     play: "Jogar" # When used as an action verb, like "Play next level"
     retry: "Tente novamente"
     actions: "Ações"
@@ -239,7 +239,7 @@ module.exports = nativeDescription: "Português do Brasil", englishDescription:
     victory: "Vitória"
     victory_title_prefix: " Vitória "
     victory_title_suffix: " Completado!"
-    victory_sign_up: "Assine para atualizações"
+    victory_sign_up: "Assine para receber atualizações"
     victory_sign_up_poke: "Quer receber as últimas novidades por email? Crie uma conta grátis e nós o manteremos informado!"
     victory_rate_the_level: "Avalie o estágio: " # Only in old-style levels.
     victory_return_to_ladder: "Retornar para a progressão"
@@ -251,7 +251,7 @@ module.exports = nativeDescription: "Português do Brasil", englishDescription:
     victory_hour_of_code_done: "Terminou?"
     victory_hour_of_code_done_yes: "Sim, eu terminei minha Hora da Programação!"
     victory_experience_gained: "XP ganho"
-    victory_gems_gained: "Gems ganhas"
+    victory_gems_gained: "Gemas ganhas"
     victory_new_item: "Novo item"
     victory_viking_code_school: "Pelas barbas do profeta, esse foi um nível difícil! Se você ainda não é um desenvolvedor de software, você deveria ser. Você acaba de ser priorizado para aceitação na Viking Code School, onde você pode aprender mais e se tornar um desenvolvedor web profissional em 14 semanas."
     victory_become_a_viking: "Torne-se um viking"
@@ -288,7 +288,7 @@ module.exports = nativeDescription: "Português do Brasil", englishDescription:
     infinite_loop_title: "Loop Infinito Detectado"
     infinite_loop_description: "O código inicial para construir o mundo nunca parou de rodar. Talvez seja muito lento ou tenha um loop infinito. Ou talvez tenha um bug. Você pode tentar rodar este código novamente ou resetá-lo para o estado inicial. Se isto não consertá-lo, avise-nos por favor."
     check_dev_console: "Você também pode abrir o terminal do desenvolvedor para ver o que pode estar dando errado."
-    check_dev_console_link: "(instruções)"
+    check_dev_console_link: "(Instruções)"
     infinite_loop_try_again: "Tentar novamente"
     infinite_loop_reset_level: "Resetar nível"
     infinite_loop_comment_out: "Comentar Meu Código"
@@ -296,7 +296,7 @@ module.exports = nativeDescription: "Português do Brasil", englishDescription:
     tip_scrub_shortcut: "Ctrl+[ e Ctrl+] rebobina e avança." # {change}
     tip_guide_exists: "Clique no guia no topo da página para informações úteis."
     tip_open_source: "CodeCombat é 100% código aberto!"
-    tip_tell_friends: "Está gostando de CodeCombate? Dibulgue para os seus amigos!"
+    tip_tell_friends: "Está gostando de CodeCombate? Divulgue para os seus amigos!"
     tip_beta_launch: "CodeCombat lançou sua versão beta em outubro de 2013."
     tip_think_solution: "Pense na solução, não no problema."
     tip_theory_practice: "Na teoria, não existe diferença entre teoria e prática. Mas, na prática, há. - Yogi Berra"
@@ -582,15 +582,15 @@ module.exports = nativeDescription: "Português do Brasil", englishDescription:
     press_paragraph_1_link: "Midia Kit"
     press_paragraph_1_suffix: ". Todas as logomarcas e imagens podem ser usadas sem nos contactar previamente."
     team: "Time"
-    george_title: "CEO" # {change}
+    george_title: "Cofundador"
     george_blurb: "Administrador"
-    scott_title: "Programador" # {change}
+    scott_title: "Cofundador"
     scott_blurb: "O Sensato"
-    nick_title: "Programador" # {change}
+    nick_title: "Cofundador"
     nick_blurb: "Guru Motivacional"
     michael_title: "Programador"
     michael_blurb: "Administrador de Sistemas"
-    matt_title: "Programador" # {change}
+    matt_title: "Cofundador"
     matt_blurb: "O Ciclista"
     cat_title: "Chefe Artesão"
     cat_blurb: "Corta-vento"
diff --git a/app/schemas/models/level.coffee b/app/schemas/models/level.coffee
index 291904e25..7872e0ab0 100644
--- a/app/schemas/models/level.coffee
+++ b/app/schemas/models/level.coffee
@@ -29,8 +29,8 @@ defaultTasks = [
   'Release to adventurers via MailChimp.'
 
   'Write the description.'
-  'Translate the sample code comments.'
-  'Add Io/Clojure/Lua/CoffeeScript.'
+  'Add i18n field for the sample code comments.'
+  'Add Clojure/Lua/CoffeeScript.'
   'Write the guide.'
   'Write a loading tip, if needed.'
   'Click the Populate i18n button.'
@@ -40,7 +40,6 @@ defaultTasks = [
   'Release to everyone via MailChimp.'
 
   'Check completion/engagement/problem analytics.'
-  'Do any custom scripting, if needed.'
   'Do thorough set decoration.'
   'Add a walkthrough video.'
 ]
diff --git a/app/views/ladder/LadderPlayModal.coffee b/app/views/ladder/LadderPlayModal.coffee
index 3a729cb9f..473843792 100644
--- a/app/views/ladder/LadderPlayModal.coffee
+++ b/app/views/ladder/LadderPlayModal.coffee
@@ -101,7 +101,7 @@ module.exports = class LadderPlayModal extends ModalView
       {id: 'coffeescript', name: 'CoffeeScript (Experimental)'}
       {id: 'clojure', name: 'Clojure (Experimental)'}
       {id: 'lua', name: 'Lua'}
-      {id: 'io', name: 'Io (Experimental)'}
+      #{id: 'io', name: 'Io (Experimental)'}
     ]
     ctx.league = @options.league
     teamsList = teamDataFromLevel @level
diff --git a/app/views/play/common/LadderSubmissionView.coffee b/app/views/play/common/LadderSubmissionView.coffee
index fa31ba7e6..e22ba3854 100644
--- a/app/views/play/common/LadderSubmissionView.coffee
+++ b/app/views/play/common/LadderSubmissionView.coffee
@@ -1,6 +1,7 @@
 CocoView = require 'views/core/CocoView'
 template = require 'templates/play/common/ladder_submission'
 {createAetherOptions} = require 'lib/aether_utils'
+LevelSession = require 'models/LevelSession'
 
 module.exports = class LadderSubmissionView extends CocoView
   className: 'ladder-submission-view'
@@ -78,14 +79,20 @@ module.exports = class LadderSubmissionView extends CocoView
         # Also submit the mirrorSession after the main session submits successfully.
         mirrorAjaxData = _.clone ajaxData
         mirrorAjaxData.session = @mirrorSession.id
+        mirrorCode = @mirrorSession.get('code')
         if @session.get('team') is 'humans'
           mirrorAjaxData.transpiledCode = 'hero-placeholder-1': transpiledCode['hero-placeholder']
+          mirrorCode['hero-placeholder-1'] = @session.get('code')['hero-placeholder']
         else
           mirrorAjaxData.transpiledCode = 'hero-placeholder': transpiledCode['hero-placeholder-1']
+          mirrorCode['hero-placeholder'] = @session.get('code')['hero-placeholder-1']
         mirrorAjaxOptions = _.clone ajaxOptions
         mirrorAjaxOptions.data = mirrorAjaxData
-        ajaxOptions.success = ->
-          $.ajax '/queue/scoring', mirrorAjaxOptions
+        ajaxOptions.success = =>
+          patch = code: mirrorCode, codeLanguage: @session.get('codeLanguage'), submittedCodeLanguage: @session.get('submittedCodeLanguage')
+          tempSession = new LevelSession _id: @mirrorSession.id
+          tempSession.save patch, patch: true, type: 'PUT', success: ->
+            $.ajax '/queue/scoring', mirrorAjaxOptions
 
       $.ajax '/queue/scoring', ajaxOptions
 
diff --git a/app/views/play/level/tome/CastButtonView.coffee b/app/views/play/level/tome/CastButtonView.coffee
index c0cdb423b..bba485b16 100644
--- a/app/views/play/level/tome/CastButtonView.coffee
+++ b/app/views/play/level/tome/CastButtonView.coffee
@@ -101,7 +101,9 @@ module.exports = class CastButtonView extends CocoView
     @casting = false
     if @hasCastOnce  # Don't play this sound the first time
       @playSound 'cast-end', 0.5
-      _.delay (=> @ladderSubmissionView?.rankSession()), 1000 if @ladderSubmissionView
+      myHeroID = if me.team is 'ogres' then 'Hero Placeholder 1' else 'Hero Placeholder'
+      if @ladderSubmissionView and not e.world.thangMap[myHeroID]?.errorsOut
+        _.delay (=> @ladderSubmissionView?.rankSession()), 1000 if @ladderSubmissionView
     @hasCastOnce = true
     @updateCastButton()
     @world = e.world
diff --git a/app/views/play/level/tome/Spell.coffee b/app/views/play/level/tome/Spell.coffee
index 7e08eafa8..bfe920e48 100644
--- a/app/views/play/level/tome/Spell.coffee
+++ b/app/views/play/level/tome/Spell.coffee
@@ -36,7 +36,7 @@ module.exports = class Spell
     else
       @setLanguage 'javascript'
     @useTranspiledCode = @shouldUseTranspiledCode()
-    console.log 'Spell', @spellKey, 'is using transpiled code (should only happen if it\'s an enemy/spectate writable method).' if @useTranspiledCode
+    #console.log 'Spell', @spellKey, 'is using transpiled code (should only happen if it\'s an enemy/spectate writable method).' if @useTranspiledCode
 
     @source = @originalSource
     @parameters = p.parameters
diff --git a/app/views/play/modal/PlayHeroesModal.coffee b/app/views/play/modal/PlayHeroesModal.coffee
index 0b104f575..382716511 100644
--- a/app/views/play/modal/PlayHeroesModal.coffee
+++ b/app/views/play/modal/PlayHeroesModal.coffee
@@ -113,7 +113,7 @@ module.exports = class PlayHeroesModal extends ModalView
         {id: 'coffeescript', name: "CoffeeScript (#{$.i18n.t('choose_hero.experimental')})"}
         {id: 'clojure', name: "Clojure (#{$.i18n.t('choose_hero.experimental')})"}
         {id: 'lua', name: 'Lua'}
-        {id: 'io', name: "Io (#{$.i18n.t('choose_hero.experimental')})"}
+        #{id: 'io', name: "Io (#{$.i18n.t('choose_hero.experimental')})"}
       ]
 
   onHeroChanged: (e) ->
diff --git a/scripts/helpScoutToCloseIO.js b/scripts/helpScoutToCloseIO.js
new file mode 100644
index 000000000..0e233cf9d
--- /dev/null
+++ b/scripts/helpScoutToCloseIO.js
@@ -0,0 +1,221 @@
+// Copy sales leads from HelpScout to Close.io based on HelpScout tags
+
+// TODO: handle leads with multiple email addresses
+// TODO: some feedback email threads get broken up in Close.io
+
+var CloseIo = function  (apiKey, mailboxEmail) {
+  this.apiKey = apiKey;
+  this.mailboxEmail = mailboxEmail;
+}
+CloseIo.prototype.createLead = function (conversation, done) {
+  console.log('Close.Io - Creating lead for', conversation.customer.email);
+  var data = {
+    contacts: [{
+      emails: [{
+        email: conversation.customer.email,
+        type: 'office'
+      }],
+      name: conversation.customer.firstName + ' ' + conversation.customer.lastName
+    }]
+  };
+  var options = {
+    uri: 'https://' + this.apiKey+ ':X@app.close.io/api/v1/lead/',
+    body: JSON.stringify(data)
+  };
+  request.post(options, function (error, response, body) {
+    if (error) {
+      return done(error);
+    }
+    return done(null, JSON.parse(body));
+  });
+}
+CloseIo.prototype.getActivities = function (leadID, done) {
+  // console.log('Close.Io - Retrieving activities for lead', leadID);
+  request.get('https://' + this.apiKey + ':X@app.close.io/api/v1/activity/email/?lead_id=' + leadID, function(error, response, body) {
+    if (error) {
+      return done(error);
+    }
+    return done(null, JSON.parse(body));
+  });
+}
+CloseIo.prototype.getLead = function (conversation, done) {
+  // console.log('Close.Io - Retrieving contact', conversation.customer.email);
+  var uri = 'https://' + this.apiKey + ':X@app.close.io/api/v1/lead/?query=email_address:' + conversation.customer.email;
+  request.get(uri, (function(error, response, body) {
+    if (error) return done(error);
+    var leads = JSON.parse(body);
+    if (leads.data.length === 1) {
+      return done(null, leads.data[0]);
+    }
+    else if (leads.data.length > 1) {
+      return done('ERROR: too many leads returned for ' + conversation.customer.email + ' ' + leads.data.length);
+    }
+    this.createLead(conversation, (function(error, lead) {
+      if (error) return done(error);
+      return done(null, lead);
+    }).bind(this));
+  }).bind(this));
+}
+CloseIo.prototype.updateActivity = function (activities, lead, conversation, conversationThread, done) {
+  // console.log('Close.Io - Updating email thread', conversation.subject);
+  var data = {
+    body_html: conversationThread.body,
+    contact_id: lead.contacts[0].id,
+    date_created: conversationThread.createdAt,
+    lead_id: lead.id,
+    sender: conversationThread.createdBy.email,
+    _type: 'Email'
+  }
+  if (conversation.subject) {
+    data.subject = conversation.subject;
+    if (data.subject.substring(0, 4) === 'Re: ') {
+      data.subject = data.subject.substring(4);
+    }
+  }
+  if (conversationThread.createdBy.email === this.mailboxEmail) {
+    data.status = 'sent';
+    data.to = [conversationThread.customer.email];
+  }
+  else {
+    data.status = 'inbox';
+    data.to = [this.mailboxEmail];
+  }
+  for (var i = 0; i < activities.data.length; i++) {
+    if (activities.data[i].body_html === data.body_html
+      && new Date(activities.data[i].date_created).getTime() == new Date(data.date_created).getTime()) {
+      // console.log('Close.Io - Found existing email', data.subject, data.date_created);
+      return done();
+    }
+  }
+  var options = {
+    uri: 'https://' + this.apiKey + ':X@app.close.io/api/v1/activity/email/',
+    body: JSON.stringify(data)
+  };
+  request.post(options, function (error, response, body) {
+    if (error) {
+      return done(error);
+    }
+    return done();
+  });
+}
+CloseIo.prototype.updateLead = function (conversation, done) {
+  console.log('Close.Io - Updating lead', conversation.customer.email);
+  this.getLead(conversation, (function(error, lead) {
+    if (error) return done(error);
+    this.updateLeadEmails(lead, conversation, (function(error) {
+      if (error) {
+        console.log(error);
+        return;
+      }
+    }).bind(this));
+  }).bind(this));
+}
+CloseIo.prototype.updateLeadEmails = function (lead, conversation, done) {
+  console.log('Close.Io - Updating lead emails', lead.display_name, conversation.subject);
+  if (conversation.type !== 'email') return done();
+  this.getActivities(lead.id, (function(error, activities) {
+      if (error) return done(error);
+      for (var i = 0; i < conversation.threads.length; i++) {
+        if (conversation.threads[i].type !== 'message') continue;
+        if (conversation.threads[i].state !== 'published') continue;
+        if (!conversation.threads[i].body || conversation.threads[i].body.length === 0) continue;
+        this.updateActivity(activities, lead, conversation, conversation.threads[i], done);
+      }
+    }).bind(this));
+}
+
+var HelpScout = function  (apiKey, mailboxEmails, searchTag) {
+  this.apiKey = apiKey;
+  this.mailboxEmails = mailboxEmails;
+  this.searchTag = searchTag;
+}
+HelpScout.prototype.getConversation = function (conversationId, done) {
+  // console.log('HelpScout - Retrieving conversation', conversationId);
+  request.get('https://' + this.apiKey + ':X@api.helpscout.net/v1/conversations/' + conversationId + '.json', function (error, response, body) {
+    if (error) return done(error);
+    var conversation = JSON.parse(body);
+    return done(null, conversation.item);
+  });
+}
+HelpScout.prototype.getConversations = function (mailboxId, done) {
+  // console.log('HelpScout - Retrieving conversations for mailbox', mailboxId);
+  var results = [];
+  var fetchPage = (function (page) {
+    // console.error("HelpScout - Fetching conversations page", page);
+    var uri = 'https://' + this.apiKey + ':X@api.helpscout.net/v1/mailboxes/' + mailboxId + '/conversations.json'
+    uri += '?page=' + page + '&tag=' + this.searchTag;
+    request.get(uri, function (error, response, body) {
+      if (error) return done(error);
+      var conversations = JSON.parse(body);
+      results = results.concat(conversations.items);
+      if (conversations.page < conversations.pages) {
+        return fetchPage(page + 1);
+      }
+      return done(null, results);
+    });
+  }).bind(this);
+  fetchPage(1);
+}
+HelpScout.prototype.getMailboxes = function (done) {
+  // console.log('HelpScout - Retrieving mailboxes');
+  var results = [];
+  request.get('https://' + this.apiKey + ':X@api.helpscout.net/v1/mailboxes.json', (function (error, response, body) {
+    if (error) return done(error);
+    var mailboxes = JSON.parse(body);
+    for (var i = 0 ; i < mailboxes.items.length; i++) {
+      if (this.mailboxEmails.indexOf(mailboxes.items[i].email) >= 0) {
+        results.push(mailboxes.items[i]);
+      }
+    }
+    return done(null, results);
+  }).bind(this));
+}
+
+// Main program
+
+if (process.argv.length !== 4) {
+  log("Usage: node <script> <HelpScout API key> <Close.io API key>");
+  process.exit();
+}
+
+var request = require('request');
+var helpScout = new HelpScout(process.argv[2], ['support@codecombat.com', 'team@codecombat.com'], 'make the sale');
+var closeIo = new CloseIo(process.argv[3], 'matt@codecombat.com');
+
+helpScout.getMailboxes(function (error, mailboxes) {
+  if (error) {
+    console.log(error);
+    return;
+  }
+  for (var i = 0; i < mailboxes.length; i++) {
+    var mailbox = mailboxes[i];
+    helpScout.getConversations(mailbox.id, function(error, conversations) {
+      if (error) {
+        console.log(error);
+        return;
+      }
+      console.log(mailbox.email, 'mailbox has', conversations.length, 'conversations');
+      for (var i = 0; i < conversations.length; i++) {
+        if (conversations[i].type !== 'email') continue;
+
+        if (i > 8) {
+          console.log('TODO: process all the conversations');
+          break;
+        }
+
+        helpScout.getConversation(conversations[i].id, function(error, conversation) {
+          if (error) {
+            console.log(error);
+            return;
+          }
+          closeIo.updateLead(conversation, function(error, lead) {
+            if (error) {
+              console.log(error);
+              return;
+            }
+          });
+        });
+      }
+    });
+  }
+});
diff --git a/server/queues/scoring/getTwoGames.coffee b/server/queues/scoring/getTwoGames.coffee
index 573506771..a55c3e4f2 100644
--- a/server/queues/scoring/getTwoGames.coffee
+++ b/server/queues/scoring/getTwoGames.coffee
@@ -17,7 +17,7 @@ sessionSelectionString = 'team totalScore transpiledCode submittedCodeLanguage t
 sendSessionsResponse = (res) ->
   (err, sessions) ->
     if err then return errors.serverError res, "Couldn't get two games to simulate: #{err}"
-    unless sessions.length is 2
+    unless _.filter(sessions).length is 2
       console.log 'No games to score.', sessions.length
       res.send 204, 'No games to score.'
       return res.end()
@@ -110,5 +110,3 @@ findEarliestSubmission = (queryParams, callback) ->
     return callback err if err
     result = earliestSubmissionCache[cacheKey] = earliest?.submitDate
     callback null, result
-
-